Quintiq file version 2.0
|
#parent: #root
|
Method InitConstraintsSequentialAtEnd (
|
CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
|
const RunContextForCapacityPlanning runcontext,
|
const LibOpt_Scope scope,
|
const constcontent ProductInStockingPointInPeriodPlanningLeafs leafplanningpispips
|
) const
|
{
|
Description: 'method to be executed after parallel cplex constraint init has taken places ( used for initialzing items that need data from multiple threads)'
|
TextBody:
|
[*
|
|
// Define the goals for each level
|
this.InitConstraintsForGoalsForLevelGoal( program,runcontext, scope ); // lkeep last because for meta we obtain values from existing plan before this
|
|
if ( runcontext.IsMetaIteration()
|
and this.FocusLevel() > 0
|
and this.GetRunContextMeta().OptionFixDemandSlackVar()
|
and this.DoLevelCollapse( runcontext ) )
|
{
|
traverse( leafplanningpispips, Elements, pispip )
|
{
|
boundforvar := pispip.DependentDemandUnfulfilledQuantity()
|
this.FreezeSlackVariableMeta( program, pispip, boundforvar, program.DemandSlackVariables().Get( pispip ), program.TotalSlackConstraints().Get() );
|
}
|
|
if( runcontext.GetConsiderTotalUserSupply( scope ) )
|
{
|
pispipsforconstraint := runcontext.GetPISPISPForUserSupplyConstraint( scope, leafplanningpispips );
|
|
traverse( pispipsforconstraint, Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip )
|
{
|
// constr constraint UoM: PISP
|
constr := program.TotalSlackUserSupplyConstraints().Get();
|
varover := program.UserTotalSupplyOverVariables().Get( pispip );
|
varunder := program.UserTotalSupplyUnderVariables().Get( pispip );
|
oversupply := maxvalue( 0.0, pispip.SupplyQuantity() - pispip.TotalSupplyUser() );
|
undersupply := maxvalue( 0.0, pispip.TotalSupplyUser() - pispip.SupplyQuantity() );
|
this.FreezeSlackVariableMeta( program, pispip, oversupply, varover, constr );
|
this.FreezeSlackVariableMeta( program, pispip, undersupply, varunder, constr );
|
}
|
}
|
}
|
|
if ( runcontext.UseCampaignSequenceOptimizer() and runcontext.RunWithDebugCampaignCombis() )
|
{
|
// for running with manual fixed combis (debugging) it easy not to have selected a combi for a unit period, so we add a slack variable to safeguard against it
|
level_zero := select( this, MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, slm, true, slm.Level() = 0 );
|
traverse( scope.GetUnitPeriodInOptimizerRunConst(), Elements.OptCampaignUnitSubPeriod, ocusp )
|
{
|
constr := program.CalcDurationOfOptCampaignUnitSubPeriodConstraints().Get( ocusp );
|
debuginfo( 'Warning - running with fixed campaign combis. Adding slack variable ', constr.Name() );
|
slackvar := program.SlackDebugCampaignCombisVariables().New( ocusp );
|
c := program.GoalConstraints().Get( level_zero );
|
c.NewTerm( -1000.0, slackvar );
|
constr.NewTerm( 1.0, slackvar );
|
}
|
}
|
|
// Define PosInvPastLast variable in case inventory holding needs to be computed
|
if ( runcontext.IsMetaIteration() and this.GetInitializeFinancialConstraints( runcontext ) )
|
{
|
constname := typeof( MPDefinePosInvPastLastConstraint );
|
|
scalefactor_posinvpastlast_const := this.ScaleConstraintTerm( typeof( MPPosInvQtyPastLastVariable ), constname );
|
scalefactor_invqty_const := this.ScaleConstraintTerm( typeof( MPInvQtyVariable ), constname );
|
scalefactor_rhs_constr := this.ScaleConstraintRHS( constname, 1.0 );
|
|
traverse( scope.GetProductInStockingPointInOptimizerRunConst(), Elements, pisp )
|
{
|
|
|
|
last := pisp.LatestPISPIPInScope();
|
current := guard( last.Next().astype( ProductInStockingPointInPeriodPlanningLeaf ), null( ProductInStockingPointInPeriodPlanningLeaf ) );
|
|
while ( not isnull( current ) )
|
{
|
var := program.PosInvQtyPastLastVariables().Get( current );
|
|
// PosInvPastLast_current >= current.InventoryLevelEnd + (InvQty_last - last.InventoryLevelEnd )
|
//
|
// example: if we decrease the inventory of last by 5 this says PosInvPastLast_current >= current.InventoryLevelEnd - 5.
|
// meaning if current.InventoryLevelEnd is <= 5, we can avoid inventory holding cost
|
// similarly if we increase by 5, posInvPastLast_current >= current.InventoryLevelEnd + 5 and we collect inventory holding cost in case previous inventory was bigger than 5
|
|
c := program.DefinePosInvPastLastConstraints().New( current );
|
c.Sense( '>=' );
|
c.RHSValue( ( current.InventoryLevelEnd() - last.InventoryLevelEnd() ) * scalefactor_rhs_constr );
|
c.NewTerm( 1.0 * scalefactor_posinvpastlast_const, var );
|
c.NewTerm( -1.0 * scalefactor_invqty_const, program.InvQtyVariables().Get( last ) );
|
|
this.FilterCPLEXNoise( c, 1.0 );
|
|
current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );
|
}
|
}
|
}
|
|
traverse( runcontext, UserPeriodTask, pt, pt.HasUserQuantity() and pt.HasDependentDemandUserQuantity() ) // deal with potential infeasible manual fixed planning, where both
|
{ // periodtask dependent demand and new supply quantity are set
|
slackconstr := program.TotalSlackConstraints().Get();
|
period := pt.UnitPeriod().Period_MP();
|
|
constddqtyname := typeof( MPOperationDependentDemandQtyConstraint );
|
constddpartialname := typeof( MPPartialOperationDependentDemandQtyConstraint );
|
constslack := typeof( MPTotalSlackConstraint );
|
|
scalefactor_slack_constpartial := this.ScaleConstraintTerm( typeof( MPPartialOperationDependentDemandQtySlackNegVariable ), constddpartialname );
|
scalefactor_partialslack_slackconst := this.ScaleConstraintTerm( typeof( MPPartialOperationDependentDemandQtySlackNegVariable ), constslack );
|
scalefactor_slack_slackconst := this.ScaleConstraintTerm( typeof( MPOperationDependentDemandQtySlackNegVariable ), constslack );
|
scalefactor_slack_constdd := this.ScaleConstraintTerm( typeof( MPOperationDependentDemandQtySlackNegVariable ), constddqtyname );
|
|
|
traverse( pt, DependentDemand, dd, dd.HasUserQuantity() )
|
{
|
pispipperiod := dd.ProductInStockingPointInPeriodPlanningLeaf().Period_MP();
|
input := dd.ProcessInput().astype( OperationInput );
|
if ( pt.Operation().HasLeadTime() )
|
{
|
c := program.PartialOperationDependentDemandQtyConstraints().Find( input, pispipperiod, period );
|
if ( not isnull( c ) )
|
{
|
slacknegvar := program.PartialOperationDependentDemandQtySlackNegVariables().New( input, pispipperiod, period );
|
slackposvar := program.PartialOperationDependentDemandQtySlackPosVariables().New( input, pispipperiod, period );
|
c.NewTerm( 1.0 * scalefactor_slack_constpartial, slackposvar );
|
c.NewTerm( -1.0 * scalefactor_slack_constpartial, slacknegvar );
|
|
slackconstr.NewTerm( -1.0 * scalefactor_partialslack_slackconst, slacknegvar );
|
slackconstr.NewTerm( -1.0 * scalefactor_partialslack_slackconst, slackposvar );
|
}
|
}
|
else
|
{
|
c := program.OperationDependentDemandQtyConstraints().Find( input, period );
|
if ( not isnull( c ) )
|
{
|
slackposvar := program.OperationDependentDemandQtySlackPosVariables().New( input, period );
|
slacknegvar := program.OperationDependentDemandQtySlackNegVariables().New( input, period );
|
c.NewTerm( 1.0 * scalefactor_slack_constdd, slackposvar );
|
c.NewTerm( -1.0 * scalefactor_slack_constdd, slacknegvar );
|
|
slackconstr.NewTerm( -1.0 * scalefactor_slack_slackconst, slacknegvar );
|
slackconstr.NewTerm( -1.0 * scalefactor_slack_slackconst, slackposvar );
|
}
|
}
|
}
|
}
|
|
program.GenerateNames(); // need to otherwise .sav files are anonymized
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|