%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/tjamichg/cursos.tjamich.gob.mx/vendor/clue/graph/src/Set/
Upload File :
Create Path :
Current File : /home/tjamichg/cursos.tjamich.gob.mx/vendor/clue/graph/src/Set/Edges.php

<?php

namespace Fhaculty\Graph\Set;

use Fhaculty\Graph\Edge\Base as Edge;
use Fhaculty\Graph\Exception\InvalidArgumentException;
use Fhaculty\Graph\Exception\OutOfBoundsException;
use Fhaculty\Graph\Exception\UnderflowException;

/**
 * A Set of Edges
 *
 * Contains any number of Edge (directed and/or undirected) instances.
 *
 * The Set is a readonly instance and it provides methods to get single Edge
 * instances or to get a new Set of Edges. This way it's safe to pass around
 * the original Set of Edges, because it will never be modified.
 */
class Edges implements \Countable, \IteratorAggregate, EdgesAggregate
{
    /**
     * order by edge weight
     *
     * @var int
     * @see Edge::getWeight()
     */
    const ORDER_WEIGHT = 1;

    /**
     * order by edge capacity
     *
     * @var int
     * @see Edge::getCapacity()
     */
    const ORDER_CAPACITY = 2;

    /**
     * order by remaining capacity on edge (maximum capacity - current flow)
     *
     * @var int
     * @see Edge::getCapacityRemaining()
     */
    const ORDER_CAPACITY_REMAINING = 3;

    /**
     * order by edge flow
     *
     * @var int
     * @see Edge::getFlow()
     */
    const ORDER_FLOW = 4;

    /**
     * random/shuffled order
     *
     * @var int
     */
    const ORDER_RANDOM = 5;

    protected $edges = array();

    /**
     * create new Edges instance
     *
     * You can pass in just about anything that can be expressed as a Set of
     * Edges, such as:
     * - an array of Edge instances
     * - any Algorithm that implements the EdgesAggregate interface
     * - a Graph instance or
     * - an existing Set of Edges which will be returned as-is
     *
     * @param array|Edges|EdgesAggregate $edges
     * @return Edges
     */
    public static function factory($edges)
    {
        if ($edges instanceof EdgesAggregate) {
            return $edges->getEdges();
        }
        return new self($edges);
    }

    /**
     * create new Edges instance that references the given source array of Edge instances
     *
     * Any changes in the referenced source array will automatically be
     * reflected in this Set of Edges, e.g. if you add an Edge instance to the
     * array, it will automatically be included in this Set.
     *
     * @param array $edgesArray
     * @return Edges
     */
    public static function factoryArrayReference(array &$edgesArray)
    {
        $edges = new static();
        $edges->edges =& $edgesArray;
        return $edges;
    }

    /**
     * instantiate new Set of Edges
     *
     * @param array $edges
     */
    public function __construct(array $edges = array())
    {
        $this->edges = $edges;
    }

    /**
     * get array index for given Edge
     *
     * @param Edge $edge
     * @throws OutOfBoundsException
     * @return mixed
     */
    public function getIndexEdge(Edge $edge)
    {
        $id = array_search($edge, $this->edges, true);
        if ($id === false) {
            throw new OutOfBoundsException('Given edge does NOT exist');
        }
        return $id;
    }

    /**
     * return first Edge in this set of Edges
     *
     * some algorithms do not need a particular edge, but merely a (random)
     * starting point. this is a convenience function to just pick the first
     * edge from the list of known edges.
     *
     * @return Edge               first Edge in this set of Edges
     * @throws UnderflowException if set is empty
     * @see self::getEdgeOrder()  if you need to apply ordering first
     */
    public function getEdgeFirst()
    {
        if (!$this->edges) {
            throw new UnderflowException('Does not contain any edges');
        }
        reset($this->edges);

        return current($this->edges);
    }

    /**
     * return last Edge in this set of Edges
     *
     * @return Edge               last Edge in this set of Edges
     * @throws UnderflowException if set is empty
     */
    public function getEdgeLast()
    {
        if (!$this->edges) {
            throw new UnderflowException('Does not contain any edges');
        }
        end($this->edges);

        return current($this->edges);
    }

    /**
     * return Edge at given array index
     *
     * @param mixed $index
     * @throws OutOfBoundsException if the given index does not exist
     * @return Edge
     */
    public function getEdgeIndex($index)
    {
        if (!isset($this->edges[$index])) {
            throw new OutOfBoundsException('Invalid edge index');
        }
        return $this->edges[$index];
    }

    /**
     * return first Edge that matches the given callback filter function
     *
     * @param callable $callbackCheck
     * @return Edge
     * @throws UnderflowException if no Edge matches the given callback filter function
     * @uses self::getEdgeMatchOrNull()
     * @see self::getEdgesMatch() if you want to return *all* Edges that match
     */
    public function getEdgeMatch($callbackCheck)
    {
        $ret = $this->getEdgeMatchOrNull($callbackCheck);
        if ($ret === null) {
            throw new UnderflowException('No edge found');
        }
        return $ret;
    }

    /**
     * checks whethere there's an Edge that matches the given callback filter function
     *
     * @param callable $callbackCheck
     * @return bool
     * @see self::getEdgeMatch() to return the Edge instance that matches the given callback filter function
     * @uses self::getEdgeMatchOrNull()
     */
    public function hasEdgeMatch($callbackCheck)
    {
        return ($this->getEdgeMatchOrNull($callbackCheck) !== null);
    }

    /**
     * get a new set of Edges that match the given callback filter function
     *
     * This only keeps Edge elements if the $callbackCheck returns a bool
     * true and filters out everything else.
     *
     * Edge index positions will be left unchanged.
     *
     * @param callable $callbackCheck
     * @return Edges a new Edges instance
     * @see self::getEdgeMatch()
     */
    public function getEdgesMatch($callbackCheck)
    {
        return new static(array_filter($this->edges, $callbackCheck));
    }

    /**
     * get new set of Edges ordered by given criterium $orderBy
     *
     * Edge index positions will be left unchanged.
     *
     * @param  int                      $orderBy  criterium to sort by. see self::ORDER_WEIGHT, etc.
     * @param  bool                     $desc     whether to return biggest first (true) instead of smallest first (default:false)
     * @return Edges                    a new Edges set ordered by the given $orderBy criterium
     * @throws InvalidArgumentException if criterium is unknown
     */
    public function getEdgesOrder($orderBy, $desc = false)
    {
        if ($orderBy === self::ORDER_RANDOM) {
            // shuffle the edge positions
            $keys = array_keys($this->edges);
            shuffle($keys);

            // re-order according to shuffled edge positions
            $edges = array();
            foreach ($keys as $key) {
                $edges[$key] = $this->edges[$key];
            }

            // create iterator for shuffled array (no need to check DESC flag)
            return new static($edges);
        }

        $callback = $this->getCallback($orderBy);
        $array    = $this->edges;

        uasort($array, function (Edge $va, Edge $vb) use ($callback, $desc) {
            $ra = $callback($desc ? $vb : $va);
            $rb = $callback($desc ? $va : $vb);

            if ($ra < $rb) {
                return -1;
            } elseif ($ra > $rb) {
                return 1;
            } else {
                return 0;
            }
        });

        return new static($array);
    }

    /**
     * get first edge ordered by given criterium $orderBy
     *
     * @param  int                      $orderBy  criterium to sort by. see self::ORDER_WEIGHT, etc.
     * @param  bool                     $desc     whether to return biggest (true) instead of smallest (default:false)
     * @return Edge
     * @throws InvalidArgumentException if criterium is unknown
     * @throws UnderflowException       if no edges exist
     */
    public function getEdgeOrder($orderBy, $desc=false)
    {
        if (!$this->edges) {
            throw new UnderflowException('No edge found');
        }
        // random order
        if ($orderBy === self::ORDER_RANDOM) {
            // just return by random key (no need to check for DESC flag)
            return $this->edges[array_rand($this->edges)];
        }

        $callback = $this->getCallback($orderBy);

        $ret = NULL;
        $best = NULL;
        foreach ($this->edges as $edge) {
            $now = $callback($edge);

            if ($ret === NULL || ($desc && $now > $best) || (!$desc && $now < $best)) {
                $ret = $edge;
                $best = $now;
            }
        }

        return $ret;
    }

    /**
     * return self reference to Set of Edges
     *
     * @return Edges
     * @see self::factory()
     */
    public function getEdges()
    {
        return $this;
    }

    /**
     * get a new set of Edges where each Edge is distinct/unique
     *
     * @return Edges a new Edges instance
     */
    public function getEdgesDistinct()
    {
        $edges = array();
        foreach ($this->edges as $edge) {
            // filter duplicate edges
            if (!in_array($edge, $edges, true)) {
                $edges []= $edge;
            }
        }

        return new Edges($edges);
    }

    /**
     * get intersection of Edges with given other Edges
     *
     * The intersection contains all Edge instances that are present in BOTH
     * this set of Edges and the given set of other Edges.
     *
     * Edge index/keys will be preserved from original array.
     *
     * Duplicate Edge instances will be kept if the corresponding number of
     * Edge instances is also found in $otherEdges.
     *
     * @param Edges|Edge[] $otherEdges
     * @return Edges a new Edges set
     */
    public function getEdgesIntersection($otherEdges)
    {
        $otherArray = self::factory($otherEdges)->getVector();

        $edges = array();
        foreach ($this->edges as $eid => $edge) {
            $i = array_search($edge, $otherArray, true);

            if ($i !== false) {
                // remove from other array in order to check for duplicate matches
                unset($otherArray[$i]);

                $edges[$eid] = $edge;
            }
        }

        return new static($edges);
    }

    /**
     * return array of Edge instances
     *
     * @return Edge[]
     */
    public function getVector()
    {
        return array_values($this->edges);
    }

    /**
     * count number of Edges
     *
     * @return int
     * @see self::isEmpty()
     */
    #[\ReturnTypeWillChange]
    public function count()
    {
        return count($this->edges);
    }

    /**
     * check whether this Set of Edges is empty
     *
     * A Set if empty if no single Edge instance is added. This is faster
     * than calling `count() === 0`.
     *
     * @return bool
     */
    public function isEmpty()
    {
        return !$this->edges;
    }

    /**
     * get Iterator
     *
     * This method implements the IteratorAggregate interface and allows this
     * Set of Edges to be used in foreach loops.
     *
     * @return \IteratorIterator
     */
    #[\ReturnTypeWillChange]
    public function getIterator()
    {
        return new \IteratorIterator(new \ArrayIterator($this->edges));
    }

    /**
     * call given $callback on each Edge and sum their results
     *
     * @param callable $callback
     * @return number
     * @throws InvalidArgumentException for invalid callbacks
     * @uses self::getCallback()
     */
    public function getSumCallback($callback)
    {
        $callback = $this->getCallback($callback);

        // return array_sum(array_map($callback, $this->edges));

        $sum = 0;
        foreach ($this->edges as $edge) {
            $sum += $callback($edge);
        }
        return $sum;
    }

    private function getEdgeMatchOrNull($callbackCheck)
    {
        $callbackCheck = $this->getCallback($callbackCheck);

        foreach ($this->edges as $edge) {
            if ($callbackCheck($edge)) {
                return $edge;
            }
        }
        return null;
    }

    /**
     * get callback/Closure to be called on Edge instances for given callback identifier
     *
     * @param callable|int $callback
     * @throws InvalidArgumentException
     * @return callable
     */
    private function getCallback($callback)
    {
        if (is_callable($callback)) {
            if (is_array($callback)) {
                $callback = function (Edge $edge) use ($callback) {
                    return call_user_func($callback, $edge);
                };
            }
            return $callback;
        }

        static $methods = array(
            self::ORDER_WEIGHT => 'getWeight',
            self::ORDER_CAPACITY => 'getCapacity',
            self::ORDER_CAPACITY_REMAINING => 'getCapacityRemaining',
            self::ORDER_FLOW => 'getFlow'
        );

        if (!is_int($callback) || !isset($methods[$callback])) {
            throw new InvalidArgumentException('Invalid callback given');
        }

        $method = $methods[$callback];

        return function (Edge $edge) use ($method) {
            return $edge->$method();
        };
    }
}

Zerion Mini Shell 1.0