haorenhui
2023-10-30 6d6cc10d9e8e242661da7fd655dec155a09d676c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
Quintiq file version 2.0
#parent: #root
Method SetKPILowerBounds (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const RunContextForCapacityPlanning runcontext,
  Boolean scopefrompreprod
) const
{
  TextBody:
  [*
    if ( runcontext.IsMetaIteration() and not this.IsFullPlanMetaPriorFocus() ) 
    {
      message := ''; 
      debuginfo( ifexpr(  scopefrompreprod, 'Also fixing focus level because scope produced by pre-production selector', '' ) );  
      rcm := this.GetRunContextMeta(); 
      if ( rcm.OptionCPLEXFixModelBoundsForGoals() ) 
      {
        size := counter(  this, MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, slm, true, slm.Level() >= 1 ); // exclude 0 level for slack
        bounds := RealVector::Construct( size ); 
        usage := BooleanVector::Construct( size ); 
        
        traverse( this, 
                  MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, 
                  level, 
                  1 <= level.Level() 
                  and level.Level() <= this.FocusLevel() ) 
        {
         level_TotalBoundFromPlan := program.RetrieveReal( 'collect_values_model_TotalBoundFromPlan' + [String] level.Level() ); // workaround because cannot write to attribute 
          
          // workaround for not being able to use attributes 
          level_SetCPLEXBoundFromPlan := program.RetrieveReal( 'collect_values_model_SetCPLEXBoundFromPlan' + [String] level.Level() ) > 0.5; 
          level_TotalBoundFromPlan := program.RetrieveReal( 'collect_values_model_TotalBoundFromPlan' + [String] level.Level() ); 
          
          bounds.Set( level.Level() - 1, level_TotalBoundFromPlan ); 
          if ( level_SetCPLEXBoundFromPlan and level.Level() < this.FocusLevel() + ifexpr(  scopefrompreprod or runcontext.UseCampaignSequenceOptimizer(), 1, 0 ) ) // if scope is made by pre production selector then we also fix focus level 
          {                                                                                                                                                         // for campaign sequence optimizer we also fix, because the campaign level gets reoptimized each time
            message := message +  'Setting bound for level=' +[String] level.Level() +  'kpi >= '+ [String]  level_TotalBoundFromPlan + String::NewLine(); 
            
            usage.Set( level.Level() - 1, true ); 
            goalvar := program.GoalForLevelVariables().Get( level ); 
            totallotsizevar := program.TotalLotSizeVariables().Get(); 
            totalspipcapvar := program.TotalStockingPointCapacityVariables().Get(); 
            totalblendingvar := program.TotalBlendingVariables().Get(); 
    
            constr := program.GoalLevelBoundForMetaConstraints().New( level ); 
            constr.Sense( '>=' ); 
            constr.RHSValue( level_TotalBoundFromPlan ); 
            if ( level.NeedsMetaGoalSlack( this.FocusLevel() ) ) 
            {
              
              goalslackvar := program.GoalLevelSlackVariables().Get( level ); 
              scalefactorforslackdefconstraint := this.ScaleConstraintTerm( typeofexpression( goalslackvar ), typeof( MPTotalSlackConstraint ) );
              goalslackvar.UpperBound( 0.01 ); 
              constr.NewTerm( 1.0, program.GoalLevelSlackVariables().Get( level ) ); // deliberately omitting scale factor.
              slackdefconstraint := program.TotalSlackConstraints().Get(); 
              slackdefconstraint.NewTerm( -1.0 * scalefactorforslackdefconstraint, goalslackvar ); 
            }
            
            this.FilterCPLEXNoise( constr, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate
            goalcons := program.GoalConstraints().Get( level );
            traverse( goalcons.Terms(), 
                      Elements, 
                      t, 
                      not t.Variable() = goalvar
                      and not typeofexpression( t.Variable() ) = typeof (MPGoalLevelSlackVariable )
                      and not typeofexpression( t.Variable() ) = typeof( MPTotalStockingPointCapacityMetaVariable ) )
            {
              if ( t.Variable() = totallotsizevar ) 
              {
                c := program.UpperBoundForTotalLotSizeMetaConstraints().New();
                value_collect_values_model_TotalLotSizeVariables := program.RetrieveReal( 'collect_values_model_TotalLotSizeVariables' );  // workaround for attribute 
                c.RHSValue( value_collect_values_model_TotalLotSizeVariables ); 
                c.Sense( '<=' ); 
                c.NewTerm( 1.0, totallotsizevar ); 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate
                message := message + 'Setting upper bound total lot size = ' + [String] c.RHSValue() + String::NewLine(); 
              }
              else if ( t.Variable() = totalspipcapvar )
              {
                totalstockingpointviolation := program.RetrieveReal( 'collect_values_model_TotalStockingPointCapacityVariables' );
                c := program.UpperBoundForTotalSPIPCapacityMetaConstraints().New(); 
                c.RHSValue( totalstockingpointviolation ); 
                c.Sense( '<=' ); 
                c.NewTerm( 1.0, totalspipcapvar ); 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate
                message := message + 'Setting upper bound for spip cap variable = ' + [String] c.RHSValue() + String::NewLine();  
              }
              else if ( t.Variable() = totalblendingvar ) 
              {
                value_collectvalues_model_TotalBlendingViolation := program.RetrieveReal( 'collectvalues_model_TotalBlendingViolation' ); 
                c := program.UpperBoundForTotalBlendingMetaConstraints().New(); 
                c.RHSValue( value_collectvalues_model_TotalBlendingViolation ); 
                c.Sense( '<=' ); 
                c.NewTerm( 1.0, totalblendingvar ); 
                this.FilterCPLEXNoise( c, 1.0 ); // this constraint is excluded from the parallel init, so need to do the filtering separate
                message := message + 'Setting upper bound total blending = ' + [String] c.RHSValue() + String::NewLine(); 
              }
              else
              {
                constr.NewTerm( t.Coefficient(), t.Variable() ); 
              } 
            } 
          }
        }
      }
      debuginfo( message ); 
      program.StoreString( 'message_kpilowerbound', message ); // workaround because method needs to be const
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}