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
Quintiq file version 2.0
#parent: #root
Method ActivateNonHierarchicalGoals (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const RunContextForCapacityPlanning runcontext,
  const LibOpt_Scope scope
) const
{
  Description: 'Activate goal of current level, deactivate previous level goal, and freeze total goal value of previous goal'
  TextBody:
  [*
      // Set time limit and gap according to selected algorithm run level
    if ( not this.CurrentSubOptimizerLevel().IsExtraPTQTYLevelMetaOptimizer() ) 
    {
      this.SetCPLEXParametersNonHierarchicalGoal( program, this.CurrentSubOptimizerLevel().GetStrategyLevelMacroPlan(), scope );
    }
      
    // Freeze total value of goals at previous level
    previouslevel := this.CurrentSubOptimizerLevel().PreviousSubOptimizerLevel(); 
    previouslevel_slmp := guard( previouslevel.GetStrategyLevelMacroPlan(), constnull( StrategyLevelMacroPlan ) ); 
    
    if( not isnull( previouslevel ) ) // for the very first initialization from the algorithm tab currentrunlevel will be null (nothing to remove/freeze).  
    {
      debuginfo(  'removing goal term for ', previouslevel.LevelNumber(), ' currentrunlevelkey = ', previouslevel.Key() ); 
      goalvar := program.GoalForLevelVariables().Get( previouslevel_slmp ); 
      debuginfo(  'goal var optimal val = ', goalvar.OptimalValue(), ' program goal = ', program.GoalValue() ); 
      
      // remove goal var from goal
      program.Goal().Term( goalvar ).Coefficient( 0.0 );
      
      // Set lower bound for removed goal var
      goalvalue := program.GoalValue();
      // The goal slack is the relative slack times the goal value
      // To avoid problems related to very small goal values, the relative goal slack is also used as a lowerbound of the slack
      slackformeta := ifexpr( this.CurrentSubOptimizerLevel().IsExtraPTQTYLevelMetaOptimizer(), this.IsExecutePTQTYRelativeGoalSlack(), 0.0 ); // adding some slack in case of ptqty goal to avoid numerical issues 
      slackfactor := ifexpr(  runcontext.IsMetaIteration(), slackformeta, previouslevel_slmp.RelativeGoalSlack() ); 
      slack := abs( slackfactor * goalvalue );
      if ( slack < previouslevel_slmp.FeasibilityTolerance() ) 
      {
        slack := 100.0; // avoid epsilon logic Quintiq
        slack := 0.0; 
      }
    
      lowerbound := goalvalue - slack;
      
      if ( this.CurrentSubOptimizerLevel().LevelNumber() = 0 or guard( previouslevel_slmp.KPIUpperBound() = 0, false ) ) // guard for case we have the extra PTQTY level (has no corresponding slevel mp)
      {
        lowerbound := minvalue(  lowerbound, 0.0 ); // never fix more than >= 0 when we know this is optimal  
      }
      
      goalvar.LowerBound( lowerbound ); 
      debuginfo(  'Setting lowerbound' , lowerbound, ' for goal var level ', previouslevel.LevelNumber(), 'slack=', slack, 'slackfactor=', slackfactor, 'goalvar name=', goalvar.Name() );
    }
    
      // add variable for next level to goal
    if ( this.CurrentSubOptimizerLevel().IsExtraPTQTYLevelMetaOptimizer() ) 
    {
      this.AddPTQtyGoal( scope, program, program.Goal() );   
    }
    else
    {
      nextgoalvar := program.GoalForLevelVariables().Get( this.CurrentSubOptimizerLevel().GetStrategyLevelMacroPlan() );  
      program.Goal().NewTerm( 1.0, nextgoalvar );
    }
    
    if ( this.DoLevelCollapse( runcontext ) )
    {
      slackgoal := program.GoalForLevelVariables().Get( this.GetRunLevel( 0 ) ); 
      program.Goal().NewTerm( this.OptionCollapseLevelWeight(), slackgoal ); 
      program.Goal().Term( slackgoal ).Coefficient( this.OptionCollapseLevelWeight() ); // ensure we don't keep adding it 
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}