TopologicalOrder::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 22
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace TemplesOfCode\NodesAndEdges\DFS;
4
5
use InvalidArgumentException;
6
use TemplesOfCode\NodesAndEdges\Graph;
7
8
9
/**
10
 * Class TopologicalOrder
11
 *
12
 * Extracts topological order from a digraph
13
 *
14
 * @package TemplesOfCode\NodesAndEdges\DFS
15
 */
16
class TopologicalOrder
17
{
18
    /**
19
     * rank[v] = rank of vertex v in order
20
     *
21
     * @var array
22
     */
23
    private $rank;
24
25
    /**
26
     * @var array
27
     */
28
    protected $order;
29
30
    /**
31
     * @var Graph
32
     */
33
    protected $graph;
34
35
    /**
36
     * TopologicalOrder constructor.
37
     *
38
     * @param Graph $g
39
     */
40
    public function __construct(Graph $g)
41
    {
42
        $this->graph = $g;
43
        // delegate cycle finding to type
44
        $finder = new DirectedCycle($g);
45
        // see if any were found
46
        if ($finder->hasCycle()) {
47
            // there is at least one, we cannot continue
48
            return;
49
        }
50
        // run a dfs on g
51
        $dfs = new DepthFirstOrder($g);
52
        // get the revere order
53
        $this->order = $dfs->reversePostorder();
54
        // init the rank list
55
        $this->rank = array_fill(0, $g->getVertices(), 0);
56
        // init
57
        $i = 0;
58
        // iterate over the
59
        foreach ($this->order as $vertex) {
60
            // set
61
            $this->rank[$vertex] = $i++;
62
        }
63
    }
64
65
66
    /**
67
     * Returns a topological order if the digraph has a topological order,
68
     * and null otherwise.
69
     *
70
     * @return array a topological order of the vertices (as an iterable) if the
71
     *    digraph has a topological order (or equivalently, if the digraph is a DAG),
72
     *    and null otherwise
73
     */
74
    public function order()
75
    {
76
        // return list
77
        return $this->order;
78
    }
79
80
    /**
81
     * Does the digraph have a topological order?
82
     *
83
     * @return bool true if the digraph has a topological order (or equivalently,
84
     *    if the digraph is a DAG), and false otherwise
85
     */
86
    public function hasOrder()
87
    {
88
        // return check
89
        return !empty($this->order);
90
    }
91
92
93
    /**
94
     * The the rank of vertex v in the topological order;
95
     * -1 if the digraph is not a DAG
96
     *
97
     * @param int $vertex the vertex
98
     * @return int the position of $vertex in a topological order
99
     *    of the digraph; -1 if the digraph is not a DAG
100
     * @throws InvalidArgumentException unless 0 <= v < V
101
     */
102
    public function rank(int $vertex)
103
    {
104
        // validate
105
        Graph::validateVertex($vertex, $this->graph->getVertices());
106
        // check for order
107
        if ($this->hasOrder()) {
108
            // return the rank
109
            return $this->rank[$vertex];
110
        }
111
        else {
112
            // is not a DAG
113
            return -1;
114
        }
115
    }
116
}