| Quintiq file version 2.0 | 
| #parent: #root | 
| Method Search ( | 
|   ProductInStockingPointInPeriodPlanningLeaf pispip | 
| ) as Boolean | 
| { | 
|   Description: 'Search procedure to determine safety stock level of a given pispip' | 
|   TextBody: | 
|   [* | 
|     period := pispip.MEIO_PeriodNumber();   | 
|     node := pispip.ProductInStockingPoint_MP();  | 
|     pisp_sl := pispip.GetServiceLevelPercentage() / 100 | 
|     capped_margin := minvalue( this.MEIO_Parameters().InitialGuessMarigin(), pisp_sl ); | 
|     guess := pisp_sl - capped_margin; | 
|     target := 0.0;  | 
|      | 
|     // Make an initial guess of target level based on the inverse of the cumulative distribution of the demand at the given PISPIP | 
|     if( pispip.SalesDemandQuantity() = 0 ) | 
|     { | 
|       if ( this.MEIO_Parameters().OptionMakeInitialGuessForNoSalesDemand() )  | 
|       { | 
|         leafset := selectset( MEIO_Engine::GetTreePISP( node ), Elements, n, true, n.MEIO_IsLeaf() );    | 
|         avgdemand := average( leafset, Elements, leaf, true, leaf.GetPISPIPFromPeriodNumber( period ).MEIO_DemandExpectedValue() );  | 
|         avgstd := average( leafset, Elements, leaf, true, leaf.GetPISPIPFromPeriodNumber( period ).MEIO_DemandStandardDeviation() );   | 
|         avgdistr := MEIO_Engine::GetRandomDistribution( avgdemand, avgstd );  | 
|         target := maxvalue( avgdistr.Quantile( guess ) -  | 
|                               avgdemand,  | 
|                               0 );  | 
|       } | 
|     } | 
|     else | 
|     { | 
|       target := maxvalue( MEIO_Engine::GetDemandDistribution( node, period ).Quantile( guess ) -  | 
|                             MEIO_Engine::GetDemandExpectedValue( node, period ),  | 
|                             0 );  | 
|     } | 
|      | 
|     service_level := 0.0; | 
|     iter := 1; | 
|     continue := pispip.ProductInStockingPoint_MP().Echelon()>1 | 
|                 and (pispip.DependentDemandAndSalesDemandQuantity() > 0 or not pispip.ProductInStockingPoint_MP().IsMostDownstreamPisp() ); | 
|     std := 0.0;  | 
|     reachservicelevel := false;  | 
|     if( continue ) | 
|     { | 
|       std := this.AggregateStd( pispip.ProductInStockingPoint_MP(), pispip.MEIO_PeriodNumber() ); //get the standard deviation of the sales demand | 
|     } | 
|     smallesttarget_formaxservicelevel := target; // keep track of this and fall back on it if we do not manage to reach the required service level | 
|     maxservicelevelsofar := 0.0;  | 
|      | 
|     while( continue ) // While stopping condition is not reached, continue to predict service level for increasing targets  | 
|     { | 
|       this.CallForServiceLevel( node, period, target, service_level, iter ); | 
|      | 
|       // Create snapshot | 
|       snapshot := null( MEIO_Snapshot );  | 
|       if( this.MEIO_Parameters().CreateSnapshots() ) | 
|       { | 
|         snapshot := MEIO_Snapshot::Create( this,  | 
|                                            iter, | 
|                                            std,  | 
|                                            target,  | 
|                                            service_level,  | 
|                                            pispip.ProductInStockingPoint_MP().Name(),  | 
|                                            pispip.MEIO_PeriodNumber(),  | 
|                                            MEIO_Snapshot::SEARCH(),  | 
|                                            pisp_sl,  | 
|                                            this.SupplyChain(),  | 
|                                            -1.0, // max service level so far - supplied below | 
|                                            -1.0 );  // min target for max service level -supplied below  | 
|                                          | 
|         } | 
|        | 
|       reachservicelevel := service_level >= pisp_sl;  | 
|       continue := not reachservicelevel | 
|                   and iter < this.MEIO_Parameters().NrOfIterations(); | 
|                    | 
|       if ( MEIO_Engine::RoundToImprovementTolerance( service_level ) > maxservicelevelsofar )  | 
|       { | 
|         smallesttarget_formaxservicelevel := target;  | 
|         maxservicelevelsofar := MEIO_Engine::RoundToImprovementTolerance( service_level );  | 
|       } | 
|       if ( this.MEIO_Parameters().CreateSnapshots() )  | 
|       { | 
|         snapshot.MaxRoundedServiceLevelSoFar( maxservicelevelsofar );  | 
|         snapshot.MinTargetForMaxRoundedServiceLevel( smallesttarget_formaxservicelevel );  | 
|       }                | 
|       iter := iter + 1; | 
|        | 
|       // Increase target for next step | 
|       target := target + this.GetTargetIncrement( service_level, std, pispip ); | 
|     } // while loop   | 
|      | 
|     if ( not reachservicelevel ) // did not manage to reach the service level, pick smallest target reaching max level  | 
|     { | 
|       pispip.MEIO_Target( smallesttarget_formaxservicelevel );  | 
|       pispip.MEIO_Stockin( maxservicelevelsofar );  | 
|      | 
|       if( this.MEIO_Parameters().CreateSnapshots() ) | 
|       { | 
|         MEIO_Snapshot::Create( this,  | 
|                                iter, | 
|                                std,  | 
|                                smallesttarget_formaxservicelevel,  | 
|                                maxservicelevelsofar,  | 
|                                pispip.ProductInStockingPoint_MP().Name(),  | 
|                                pispip.MEIO_PeriodNumber(),  | 
|                                MEIO_Snapshot::SEARCH() + MEIO_Engine::ServiceLevelNotReached(),  | 
|                                pisp_sl,  | 
|                                this.SupplyChain(),  | 
|                                maxservicelevelsofar,  | 
|                                smallesttarget_formaxservicelevel );   | 
|       } | 
|     } | 
|      | 
|     return true; | 
|   *] | 
| } |