| 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; | 
|   *] | 
| } |