Quintiq file version 2.0
|
#parent: #root
|
Method PositionNodes
|
{
|
Description: 'Position the nodes on the X axis.'
|
TextBody:
|
[*
|
program := LibOpt_Utility::ConstructMathematicalProgramWithoutAnalysis();
|
|
nodes := selectset( this, UIGraphRow.UIGraphNode, node, true );
|
|
// In this algorithm we use abs dist parts.
|
// To calculate |x| (the absolute value of x) we do create 2 new variables x_pos and x_neg
|
// Then we add the following constraints:
|
// x = x_pos - x_neg
|
// x_pos, x_neg >= 0
|
// Either x_pos = x and x_neg = 0, or x_neg = x and x_pos = 0.
|
// With this, we know that |x| = x_pos + x_neg
|
|
// We use |x| for the distance to the average parent and the average child.
|
// The average parent is the average of the position of all its parents.
|
// Similarly, the average child is the average of the positions of all its children.
|
|
abs_dist_parts := construct( Strings );
|
abs_dist_parts.Add( LibOpt_UIGraph::VarDistParents( true ) );
|
abs_dist_parts.Add( LibOpt_UIGraph::VarDistParents( false ) );
|
abs_dist_parts.Add( LibOpt_UIGraph::VarDistChildren( true ) );
|
abs_dist_parts.Add( LibOpt_UIGraph::VarDistChildren( false ) );
|
|
traverse( nodes, Elements, node )
|
{
|
var := program.NewContinuousVariable( LibOpt_UIGraph::VarX(), node );
|
var.LowerBound( node.Width() / 2 );
|
var.UpperBound( Real::MaxReal() );
|
|
traverse( abs_dist_parts, Elements, abs_dist_part )
|
{
|
var_abs_dist_part := program.NewContinuousVariable( abs_dist_part, node );
|
var_abs_dist_part.LowerBound( 0.0 );
|
var_abs_dist_part.UpperBound( Real::MaxReal() );
|
}
|
}
|
|
// Constraint on order of nodes, making sure nodes do not overlap.
|
traverse( nodes, Elements, node, not isnull( node.Previous() ) )
|
{
|
var_prev := program.Variable( LibOpt_UIGraph::VarX(), node.Previous() );
|
var := program.Variable( LibOpt_UIGraph::VarX(), node );
|
constr := program.NewConstraint( LibOpt_UIGraph::ConstrChain(), node );
|
constr.NewTerm( 1.0, var );
|
constr.NewTerm( -1.0, var_prev );
|
constr.Sense( MPConstraintSense::GreaterOrEqual().AsString() );
|
constr.RHSValue( node.Previous().Width() / 2 + node.Width() / 2 + this.Offset() );
|
}
|
|
// Calculate the abs( dist ) w.r.t. the average parent
|
traverse( nodes, Elements, node )
|
{
|
parents := selectset( node, Incoming.Origin, n, not isnull( n.UIGraphRow() ) );
|
LibOpt_UIGraph::NewAbsConstraint( program, node, parents,
|
LibOpt_UIGraph::ConstrCalcDistParents(),
|
LibOpt_UIGraph::VarDistParents( true ),
|
LibOpt_UIGraph::VarDistParents( false ),
|
average( node, Incoming, arc, not isnull( arc.Origin().UIGraphRow() ), arc.First().X() ) );
|
}
|
|
// Calculate the abs( dist ) w.r.t. the average child
|
traverse( nodes, Elements, node )
|
{
|
children := selectset( node, Outgoing.Destination, n, not isnull( n.UIGraphRow() ) );
|
LibOpt_UIGraph::NewAbsConstraint( program, node, children,
|
LibOpt_UIGraph::ConstrCalcDistChildren(),
|
LibOpt_UIGraph::VarDistChildren( true ),
|
LibOpt_UIGraph::VarDistChildren( false ),
|
average( node, Outgoing, arc, not isnull( arc.Destination().UIGraphRow() ), arc.Last().X() ) );
|
}
|
|
// Goal
|
goal := program.Goal();
|
traverse( nodes, Elements, node )
|
{
|
goal.NewTerm( 1.0, program.Variable( LibOpt_UIGraph::VarDistParents( true ), node ) );
|
goal.NewTerm( 1.0, program.Variable( LibOpt_UIGraph::VarDistParents( false ), node ) );
|
goal.NewTerm( 1.0, program.Variable( LibOpt_UIGraph::VarDistChildren( true ), node ) );
|
goal.NewTerm( 1.0, program.Variable( LibOpt_UIGraph::VarDistChildren( false ), node ) );
|
}
|
|
program.Execute();
|
|
{
|
constr := program.NewConstraint( LibOpt_UIGraph::ConstrGoal() );
|
constr.Sense( MPConstraintSense::LessOrEqual().AsString() );
|
constr.RHSValue( program.GoalValue() );
|
traverse( goal.Terms(), Elements, term )
|
{
|
constr.NewTerm( term.Coefficient(), term.Variable() );
|
term.Coefficient( 0.0 );
|
}
|
|
width := program.NewContinuousVariable( LibOpt_UIGraph::VarWidth() );
|
traverse( this, UIGraphRow, row, row.UIGraphNode( relsize ) > 0 )
|
{
|
constr := program.NewConstraint( LibOpt_UIGraph::ConstrMaxWidth(), row );
|
constr.NewTerm( 1.0, width );
|
constr.NewTerm( -1.0, program.Variable( LibOpt_UIGraph::VarX(), row.Last() ) );
|
constr.Sense( MPConstraintSense::GreaterOrEqual().AsString() );
|
constr.RHSValue( 0.0 );
|
}
|
|
program.Goal().NewTerm( 1.0, width );
|
|
if( not program.Execute() )
|
{
|
epsilon := 0.0001;
|
constr.RHSValue( constr.RHSValue() + epsilon );
|
program.Execute();
|
}
|
}
|
// Handle result
|
traverse( nodes, Elements, node )
|
{
|
var := program.Variable( LibOpt_UIGraph::VarX(), node );
|
node.X( var.OptimalValue() );
|
}
|
*]
|
InterfaceProperties { Accessibility: 'Module' }
|
}
|