lazhen
2025-01-09 8afe90b633046db39042aada36b88193062f8cff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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( ", " ) );
  *]
}