/** * 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; }
/** * Remove the given edge from the graph * * Removes the given edge from the graph, but keep the associated nodes. * * Returns false, if one of the nodes did not exist, and true otherwise. * * @param string $src * @param string $dst * @return bool */ public function removeEdge($src, $dst) { if (parent::removeEdge($src, $dst)) { unset($this->reverseEdges[(string) $dst][(string) $src]); return true; } return false; }
/** * 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; }
/** * Merge singleton nodes * * All equivalency classes which consist of just one nodes are considered * singleton nodes. This method merges all maximum sets of singleton nodes, * which share the same successors and precedessors. * * @param slAutomaton $automaton * @return void */ protected function mergeSingletonNodes(slAutomaton $automaton) { $classes = array_keys($this->equivalenceClasses); $classCount = count($classes); for ($i = 0; $i < $classCount; ++$i) { if (!isset($this->equivalenceClasses[$classes[$i]]) || count($this->equivalenceClasses[$classes[$i]]) > 1) { // We only care for singletons continue; } for ($j = $i + 1; $j < $classCount; ++$j) { if (!isset($this->equivalenceClasses[$classes[$j]]) || count($this->equivalenceClasses[$classes[$j]]) > 1) { // We only care for singletons continue; } if ($automaton->getOutgoing($classes[$i]) === $automaton->getOutgoing($classes[$j]) && $automaton->getIncoming($classes[$i]) === $automaton->getIncoming($classes[$j])) { $this->equivalenceClasses[$classes[$i]][] = $classes[$j]; unset($this->equivalenceClasses[$classes[$j]]); $automaton->removeNode($classes[$j]); } } } }
/** * 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); } } }