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