hongji.li
2023-11-07 1a1ba3ad5ed9e4380185aa1ccad20204a0e5f115
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
Quintiq file version 2.0
#parent: #root
Method CreateTree (
  GraphProgram program
) as GraphProgramGraph
{
  Description: 'Create tree from graph program run result'
  TextBody:
  [*
    // Get graph and value sets
    graph := program.Graph( MEIO_Treeify::GetGraphName(this.MEIO_Engine().Product_MP().Name()), this );
    leadtimes := program.EdgeValueSet( MEIO_Treeify::GetEdgeValueSetLeadtimes() );
    weights := program.EdgeValueSet( MEIO_Treeify::GetEdgeValueSetWeights() );
    utilized := program.EdgeValueSet( MEIO_Treeify::GetEdgeValueSetUtilized() );
    
    debuginfo( 'HANDLE RESULT', 
               'Graph:', MEIO_Treeify::GetGraphName( this.MEIO_Engine().Product_MP().Name()),
               'Current run', this.MEIO_Engine().CurrentRun()  );
    
    // Select root, create shortest past algortihm and create new tree graph
    root := select( graph, Nodes, node, node.Name() = MEIO_Treeify::GetArtificialRootName() );
    sp := program.ShortestPathAlgorithm( MEIO_Treeify::GetShortestPathName() );
    tree := program.NewDirectedGraph( MEIO_Treeify::GetTreeName( this.MEIO_Engine().CurrentRun(), this.MEIO_Engine().Product_MP().Name() ), this );
    
    existing_tree := true;
    
    
    traverse( graph, Nodes, node)
    {
      // Find path between current node and root
      path := sp.Result().Path( root, node );
      echelon := path.Edges( relsize ); 
      // Calculate echelon number
      if( root <> node )
      {
        node.Object1().astype( ProductInStockingPoint_MP ).Echelon( echelon );
      }
      // Traverse all edges in the path  
      traverse( path, Edges, edge )
      {
        node_to := edge.Output();
        pisp_to := node_to.Object1().astype( ProductInStockingPoint_MP )
        // Only add to-node if its active and have positive leadtime
        // Continue to look from an appropriate from-node
        // Should have positive leadtime and be active in MEIO
        if( pisp_to.IsActiveInMEIO() and leadtimes.Get( edge ) > 0 )
        {
          // Uncollapse to-node
          pisp_to.MEIO_IsCollapsedPISP( false );
          node_from := edge.Input();
          pisp_from := node_from.Object1().astype( ProductInStockingPoint_MP )
          supedge := select( path, Edges, e, e.Output() = node_from );
          // Check if from-node is suitable
          continue_looking := not ( node_from = root ) and ( not pisp_from.IsActiveInMEIO() or leadtimes.Get( supedge ) = 0 );
          // Get leadtime of edge
          leadtime := leadtimes.Get( edge );
          // Update weight of edge
          weights.Set( edge, weights.Get( edge ) + this.GetEdgePenalty() );
          // Keep track of if the tree has been generated before, by seeing if all edges has been utilized
          existing_tree := existing_tree and utilized.Get( edge ) = 1.0;
          utilized.Set( edge, 1.0 );
          while( continue_looking )
          {
            // Continue to look for suitable from-pisp if needed
            pisp_from.MEIO_IsCollapsedPISP( true );
            subpath := sp.Result().Path( root, node_from );
            sortededges := selectsortedset( subpath, Edges, e, true, -e.Output().Object1().astype( ProductInStockingPoint_MP ).Echelon() ); 
            //traverse( subpath, Edges, subedge, continue_looking )
            traverse( sortededges, Elements, subedge, continue_looking )
            {
              node_from := subedge.Input();
              pisp_from := node_from.Object1().astype( ProductInStockingPoint_MP )
              supedge := select( path, Edges, e, e.Output() = node_from );
              continue_looking := not ( node_from = root ) and ( not pisp_from.IsActiveInMEIO() or leadtimes.Get( supedge ) = 0 );
              // Aggregate leadtime as we traverse the path
              leadtime := leadtime + leadtimes.Get( subedge );
              weights.Set( subedge, weights.Get( subedge ) + this.GetEdgePenalty() );
              existing_tree := existing_tree and utilized.Get( subedge ) = 1.0;
              utilized.Set( subedge, 1.0 );
            }  
          }
          // Add to- and from-nodes selected to new tree graph. Keep leadtimes on edges in new tree.
          treeNode_from := tree.FindNode( node_from.Name(), node_from.Object1() );
          if( isnull( treeNode_from ) )
          {
            treeNode_from := tree.NewNode( node_from.Name(), node_from.Object1() );
          }
          treeNode_to := tree.FindNode( node_to.Name(), node_to.Object1() );
          if( isnull( treeNode_to ) )
          {
            treeNode_to := tree.NewNode( node_to.Name(), node_to.Object1() );
          }
          treeEdge := tree.FindEdge( edge.Name(), treeNode_from, treeNode_to );
          if( isnull( treeEdge ) )
          {
            treeEdge := tree.NewEdge( edge.Name(), treeNode_from, treeNode_to );
          }
          leadtimes.Set( treeEdge, leadtime );
        }
        else
        {
          pisp_to.MEIO_IsCollapsedPISP( true );
        }
      }
    }
    
    this.DeleteMEIO_Trees(); // Clear MEIO_Parent, MEIO_Child relations for all PISPs. 
    
    
    debuginfo( 'CREATING TREE',
               'Tree:',  MEIO_Treeify::GetTreeName( this.MEIO_Engine().CurrentRun(), this.MEIO_Engine().Product_MP().Name() ), 
               'Current run', this.MEIO_Engine().CurrentRun() );
    traverse( tree, Edges, edge )
    {
      //debuginfo( 'output='+  edge.Output().Name() + separator + 'input=', edge.Input().Name() + separator + [String]leadtimes.Get( edge ) );
      edge.Output().Object1().astype( ProductInStockingPoint_MP ).MEIO_Leadtime( [Number]leadtimes.Get( edge ) );
      if ( edge.Input().Name() = MEIO_Treeify::GetArtificialRootName() ) 
      {
        this.MEIO_Engine().Product_MP().MEIO_Child( relinsert, edge.Output().Object1().astype( ProductInStockingPoint_MP ) ); 
      }
      else
      {
        edge.Input().Object1().astype( ProductInStockingPoint_MP ).MEIO_Child( relinsert, edge.Output().Object1().astype( ProductInStockingPoint_MP ) ); 
      }
    }
    
    Transaction::Transaction().Propagate( attribute( ProductInStockingPoint_MP, MEIO_IsLeaf ) ); // need to have for later computation in engine
    
    debuginfo( '#### start print tree ####' ); 
    this.MEIO_Engine().PrintTree();
    debuginfo( '#### end print tree ####' ); 
    
    return tree;
  *]
}