/** * Main visit function * * Visit function to process an automaton (directed, cyclic, discontinuous * graph). No more detailed methods are defined, since the process of * visiting is highly dependent on the concrete visitor implementation. * * Optionally labels may be passed for each node in the graph, which might * be used during the rendering process. * * Returns a string, containing a DOT specification of the graph, to be * rendered with graphviz. * * @param slAutomaton $automaton * @param array $labels * @return string */ public function visit(slAutomaton $automaton, array $labels = array()) { $content = <<<EOSTYLE digraph G { node [ fontname = Arial, fontcolor = "#2e3436", fontsize = 10, style = filled, color = "#2e3436", fillcolor = "#babdb6", shape = ellipse ]; splines = true; overlap = false; EOSTYLE; foreach ($automaton->getNodes() as $node) { $content .= sprintf(" \"%s\" [label = \"%s\"]\n", $node, isset($labels[(string) $node]) ? $labels[(string) $node] : $node); } $content .= "\n"; foreach ($automaton->getNodes() as $node) { foreach ($automaton->getOutgoing($node) as $dst) { if ($automaton instanceof slTypeAutomaton) { $content .= sprintf(" \"%s\" -> \"%s\" [label = \"%s\"]\n", $node, $dst, $automaton->getEdgeLabel($node, $dst)); } else { $content .= sprintf(" \"%s\" -> \"%s\"\n", $node, $dst); } } } return $content . "}\n"; }
/** * Main visit function * * Visit function to process an automaton (directed, cyclic, discontinuous * graph). No more detailed methods are defined, since the process of * visiting is highly dependent on the concrete visitor implementation. * * Optionally labels may be passed for each node in the graph, which might * be used during the rendering process. * * Returns an array with the support for each node, which just represents * the number of incoming edges. * * @param slAutomaton $automaton * @return array */ public function visit(slAutomaton $automaton, array $labels = array()) { $nodes = $automaton->getNodes(); $ranks = array(); foreach ($nodes as $node) { $ranks[$node] = count($automaton->getIncoming($node)); } return $ranks; }
/** * Main visit function * * Visit function to process an automaton (directed, cyclic, discontinuous * graph). No more detailed methods are defined, since the process of * visiting is highly dependent on the concrete visitor implementation. * * Optionally labels may be passed for each node in the graph, which might * be used during the rendering process. * * Returns an array with values for each node, representing their "imporance" * in the graph based on Googles PageRank algorithm. * * @param slAutomaton $automaton * @return array */ public function visit(slAutomaton $automaton, array $labels = array()) { $nodes = $automaton->getNodes(); $ranks = array(); foreach ($nodes as $node) { $ranks[$node] = 1; } for ($i = 0; $i < $this->iterations; ++$i) { foreach ($nodes as $node) { $rank = 0; foreach ($automaton->getIncoming($node) as $src) { $pr = $ranks[$src]; $c = count($automaton->getOutgoing($src)); $rank += $pr / $c; } $ranks[$node] = 1 - $this->dampingFactor + $this->dampingFactor * $rank; } } return $ranks; }
/** * Calculate equivalent nodes * * Calculate groups of nodes, which are contained in their respective * transitive reflexive closure in the automaton. * * Returns an automaton consisting of nodes, which each links to such a * node group. * * @param slCountingSingleOccurenceAutomaton $automaton * @return void */ protected function calculateEquivalencyAutomaton(slAutomaton $automaton) { $nodeValues = $automaton->getNodes(); $nodes = array_keys($nodeValues); $nodeCount = count($nodes); $equivalent = array(); $skip = array(); // Find equivalence classes in automaton for ($i = 0; $i < $nodeCount; ++$i) { if (isset($skip[$i])) { continue; } $this->equivalenceClasses[$nodes[$i]] = array($nodes[$i]); $equivalent[$nodes[$i]] = $nodes[$i]; for ($j = $i + 1; $j < $nodeCount; ++$j) { if (in_array($nodes[$i], $automaton->transitiveClosure($nodes[$j])) && in_array($nodes[$j], $automaton->transitiveClosure($nodes[$i]))) { $this->equivalenceClasses[$nodes[$i]][] = $nodes[$j]; $equivalent[$nodes[$j]] = $nodes[$i]; // The mutal containment in eachs reflexive transitive // closure is obviously symetric $skip[$j] = true; } } } // Readd edges between equivalency classes based on source automaton $equivalencyAutomaton = new slAutomaton(); foreach ($this->equivalenceClasses as $name => $nodes) { $equivalencyAutomaton->addNode($name); foreach ($nodes as $node) { foreach ($automaton->getOutgoing($node) as $dst) { if ($name !== $equivalent[$dst]) { $equivalencyAutomaton->addEdge($name, $equivalent[$dst]); } } } } return $equivalencyAutomaton; }
/** * Merge current automaton with given automaton * * @param slAutomaton $automaton * @return void */ public function merge(slAutomaton $automaton) { foreach ($automaton->getNodes() as $identifier => $node) { if (!isset($this->nodes[$identifier])) { $this->addNode($node); } } foreach ($automaton->getNodes() as $identifier => $node) { foreach ($automaton->getOutgoing($node) as $dst) { $this->addEdge($node, $dst); } } }