| Quintiq file version 2.0 | 
| #parent: #root | 
| GraphProgram SetHierarchyIsCyclic | 
| { | 
|   AsyncPriority: 'Default' | 
|   Description: 'Checks if a set hierarchy is cyclic.' | 
|   ExecutionText: | 
|   [* | 
|     graph := program.Graph( 'graph' ); | 
|      | 
|     cda := program.NewCycleDetectionAlgorithm( 'cyclic', graph ); | 
|     cda.ReportResult( true ); | 
|      | 
|     //cda.GraphFileName('TestGraph.dot'); | 
|   *] | 
|   InitializationText: | 
|   [* | 
|     // Initialize the graph | 
|     graph := program.NewDirectedGraph( 'graph' ); | 
|      | 
|     // Retrieve objects | 
|     objs := selectset( this, SetObject.astype( LibDMF_HierarchyObject ), hObject, true ); | 
|      | 
|     // Initialize the nodes | 
|     traverse( objs, Elements, obj ) | 
|     { | 
|       graph.NewNode( obj.ID() ); | 
|     } | 
|      | 
|     // Initialize the edges | 
|     traverse( objs, Elements, obj ) | 
|     { | 
|       // Check if the object has a parent | 
|       // If true, create an edge | 
|       // Skip cases where pointing to invalid parent | 
|       parentNode := select( graph, Nodes, node, | 
|                             node.Name() = obj.ParentID() ); | 
|      | 
|       if( not isnull( parentNode ) ) | 
|       { | 
|         child  := graph.Node( obj.ID() ); | 
|      | 
|         graph.NewEdge( obj.ParentID() + '+' + obj.ID(), parentNode, child ); | 
|       } | 
|     } | 
|      | 
|     // Sanity check should be implemented for missing parent | 
|   *] | 
|   ResultText: | 
|   [* | 
|     cda := program.CycleDetectionAlgorithm( 'cyclic' ); | 
|     //cda.ReportResult( true ); | 
|      | 
|     // Store results in attributes | 
|     this.IsCyclic( cda.Result().IsCyclic() ); | 
|      | 
|     nodes := selectuniquevalues( cda.Result().ReportCycle(), Edges.Input, input, | 
|                                  true, | 
|                                  input.Name() ); | 
|      | 
|     this.IsCyclicResult(  nodes.ToString( ", " ) ); | 
|   *] | 
| } |