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