chippyash/Math-Matrix

View on GitHub
src/Chippyash/Math/Matrix/Formatter/DirectedGraph.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
/*
 * Math-Matrix library
 *
 * @author Ashley Kitson <akitson@zf4.biz>
 * @copyright Ashley Kitson, UK, 2016
 * @licence GPL V3 or later : http://www.gnu.org/licenses/gpl.html
 * @link http://en.wikipedia.org/wiki/Matrix_(mathematics)
 */
namespace Chippyash\Math\Matrix\Formatter;

use Assembler\FFor;
use Chippyash\Math\Matrix\NumericMatrix;
use Chippyash\Math\Type\Comparator;
use Chippyash\Matrix\Interfaces\FormatterInterface;
use Chippyash\Matrix\Matrix;
use Chippyash\Type\TypeFactory;
use Graphp\GraphViz\GraphViz;
use Fhaculty\Graph\Graph;
use Monad\Collection;

/**
 * Create a Graphviz directed graph definition
 */
class DirectedGraph implements FormatterInterface
{
    /**
     * Format the matrix contents for outputting
     *
     * @param Matrix $mA Matrix to format
     * @param array $options Options for formatter
     *  - attribs => Collection of VertexDescription
     *  - optional: edgeFunc => function($weight){return $newWeight;}
     *  - optional: output:string script|object default = script
     *
     * If output is script, return the graphviz dot file contents
     * If output is object then return Fhaculty\Graph\Graph for your own
     * processing via Graphp\GraphViz\GraphViz
     *
     * @return Graph|string
     */
    public function format(Matrix $mA, array $options = array())
    {
        if (!$mA instanceof NumericMatrix) {
            throw new \InvalidArgumentException('Matrix is not NumericMatrix');
        }
        return FFor::create(['mA' => $mA, 'graph' => new Graph(), 'options' => $options])
            ->attribs(function($options) {
                $attribs = array_key_exists('attribs', $options) ? $options['attribs'] : new Collection([],'string');
                if ($attribs instanceof Collection) {
                    return $attribs;
                }
                throw new \InvalidArgumentException('options[attribs]');
            })
            ->edgeFunc(function($options) {
                $edgeFunc = array_key_exists('edgeFunc', $options) ? $options['edgeFunc'] : function($w){return $w;};
                if ($edgeFunc instanceof \Closure) {
                    return $edgeFunc;
                }
                throw new \InvalidArgumentException('pptions[edgeFunc]');
            })
            ->output(function($options) {
                return array_key_exists('output', $options) ? $options['output'] : 'script';
            })
            ->vertices(function(Collection $attribs, Matrix $mA, Graph $graph) {
                $vertices = [];
                foreach(range(0, $mA->rows()-1) as $idx) {
                    if (array_key_exists($idx, $attribs)) {
                        $attribute = $attribs[$idx];
                        $vertices[$idx+1] = $graph->createVertex($attribute->getName());
                        foreach($attribute->getAttributes() as $key => $val) {
                            $vertices[$idx+1]->setAttribute($key, $val);
                        }
                    } else {
                        $vertices[$idx+1] = $graph->createVertex();
                    }
                }
                return $vertices;
            })
            ->graphViz(function(Graph $graph, Matrix $mA, array $vertices, \Closure $edgeFunc, $output) {
                $comp = new Comparator();
                $zero = TypeFactory::createInt(0);
                $rows = $mA->rows();
                for ($row = 1; $row <= $rows; $row++) {
                    for ($col = 1; $col <= $rows; $col++) {
                        if ($comp->compare($zero, $mA->get($row, $col)) != 0) {
                            $vertices[$row]->createEdgeTo($vertices[$col])
                                ->setWeight($edgeFunc($mA->get($row, $col)->get()));
                        }
                    }
                }

                return $output == 'script' ? (new GraphViz())->createScript($graph) : $graph;
            })
            ->fyield('graphViz');
    }
}