/** * @expectedException BadMethodCallException * @expectedExceptionMessage Unsupported comparator method: foo */ public function testMagicCallThrowsExceptionForUnknownMethod() { $one = new IntType(1); $c = new Comparator(); //use default engine $this->assertEquals(true, $c->foo($one, $one)); }
/** * 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'); }
/** * @param NumericMatrix $mA * @param NumericTypeInterface $start * @param NumericTypeInterface $target * @param NumericTypeInterface $limit * * @return NumericMatrix */ protected function walk(NumericMatrix $mA, NumericTypeInterface $start, NumericTypeInterface $target, NumericTypeInterface $limit) { $zero = TypeFactory::createInt(0); $one = TypeFactory::createInt(1); $calc = new Calculator(); $comp = new Comparator(); $lim = $calc->sub($limit, $one); $walk = [$start]; while ($comp->neq($start, $target) && $comp->neq($lim, $zero)) { $start = $mA('MarkovWeightedRandom', $start); $walk[] = $start; $lim = $calc->sub($lim, $one); } return new NumericMatrix($walk); }
/** * Construct a Matrix with all entries set to IntType(0) * * @param NumericTypeInterface $rows Number of required rows * @param NumericTypeInterface $cols Number of required columns * * @throws \InvalidArgumentException */ public function __construct(NumericTypeInterface $rows, NumericTypeInterface $cols) { $comp = new Comparator(); $one = TypeFactory::createInt(1); if ($comp->lt($rows, $one)) { throw new \InvalidArgumentException('$rows must be >= 1'); } if ($comp->lt($cols, $one)) { throw new \InvalidArgumentException('$cols must be >= 1'); } $f = function ($row, $col) { return TypeFactory::createInt(0); }; parent::__construct($f, $rows, $cols); }
/** * Does the matrix exhibit this attribute * * @param Matrix $mA * * @return boolean */ public function is(Matrix $mA) { try { $this->assertMatrixIsNumeric($mA)->assertMatrixIsSquare($mA); } catch (MatrixException $e) { return false; } //we've already assured it is square, now make sure we at least have a // cyclic probability if ($mA->rows() < 2 || $mA->columns() < 2) { return false; } $sumDerivative = new Sum(); $firstRow = $mA('Rowslice', [1])->derive($sumDerivative); $comp = new Comparator(); //check that each row has same sum foreach (range(2, $mA->rows()) as $row) { if ($comp->neq($firstRow, $mA('RowSlice', [$row])->derive($sumDerivative)) != 0) { return false; } } return true; }
/** * Perform Guass Jordan Elimination on the two supplied matrices * * @param NumericMatrix $mA First matrix to act on - required * @param NumericMatrix $extra Second matrix to act upon - required * * @return \Chippyash\Math\Matrix\DecompositionAbstractDecomposition Fluent Interface * * @throws \Chippyash\Math\Matrix\Exceptions\SingularMatrixException */ public function decompose(NumericMatrix $mA, $extra = null) { $this->assertParameterIsMatrix($extra, 'Parameter extra is not a matrix')->assertMatrixIsNumeric($extra, 'Parameter extra is not a numeric matrix')->assertMatrixIsSquare($mA, 'Parameter mA is not a square matrix')->assertMatrixRowsAreEqual($mA, $extra, 'mA->rows != extra->rows'); $rows = $mA->rows(); $dA = $mA->toArray(); $dB = $extra->toArray(); $zero = function () { return RationalTypeFactory::create(0, 1); }; $one = function () { return RationalTypeFactory::create(1, 1); }; $calc = new Calculator(); $comp = new Comparator(); $ipiv = array_fill(0, $rows, $zero()); $indxr = array_fill(0, $rows, 0); $indxc = array_fill(0, $rows, 0); // find the pivot element by searching the entire matrix for its largest value, but excluding columns already reduced. $irow = $icol = 0; for ($i = 0; $i < $rows; $i++) { $big = $zero(); for ($j = 0; $j < $rows; $j++) { if ($comp->neq($ipiv[$j], $one())) { for ($k = 0; $k < $rows; $k++) { if ($comp->eq($ipiv[$k], $zero())) { $absVal = $dA[$j][$k]->abs(); if ($comp->gt($absVal, $big)) { unset($big); $big = clone $absVal; $irow = $j; $icol = $k; } } elseif ($comp->gt($ipiv[$k], $one())) { throw new SingularMatrixException('GaussJordanElimination'); } } } } //Now interchange row to move the pivot element to a diagonal $ipiv[$icol] = $calc->add($ipiv[$icol], $one()); if ($irow != $icol) { $this->swapRows($dA, $irow, $icol); $this->swapRows($dB, $irow, $icol); } // Remember permutations to later $indxr[$i] = $irow; $indxc[$i] = $icol; if ($comp->eq($dA[$icol][$icol], $zero())) { throw new SingularMatrixException('GaussJordanElimination'); } // Now divide the found row to make the pivot element 1 // To maintain arithmetic integrity we use the reciprocal to multiply by $pivinv = $calc->reciprocal($dA[$icol][$icol]); $this->multRow($dA, $icol, $pivinv, $calc); $this->multRow($dB, $icol, $pivinv, $calc); // And reduce all other rows but the pivoted row with the value of the pivot row for ($ll = 0; $ll < $rows; $ll++) { if ($ll != $icol) { $multiplier = clone $dA[$ll][$icol]; $multiplier->negate(); $this->addMultipleOfOtherRowToRow($dA, $multiplier, $icol, $ll, $calc); $this->addMultipleOfOtherRowToRow($dB, $multiplier, $icol, $ll, $calc); } } } $this->set('left', $this->createCorrectMatrixType($mA, $dA)); $this->set('right', $this->createCorrectMatrixType($extra, $dB)); return clone $this; }
/** * Check equality of each matrix entry * Also check that matrices are same type if $strict * * @override ancestor * * @param \Chippyash\Matrix\Matrix $mB * @param boolean $strict * * @return boolean */ protected function checkEntryEquality(Matrix $mB, $strict) { if ($strict) { if (get_class($this) !== get_class($mB)) { return false; } } $dA = $this->toArray(); $dB = $mB->toArray(); $m = $this->rows(); $n = $this->columns(); $comp = new Comparator(); for ($i = 0; $i < $m; $i++) { for ($j = 0; $j < $n; $j++) { if ($strict) { if ($dA[$i][$j] !== $dB[$i][$j]) { return false; } } else { if ($comp->neq($dA[$i][$j], $dB[$i][$j])) { return false; } } } } return true; }
/** * Complex Pow - raise number to the exponent * Will return a ComplexType * Exponent must be non complex * * @param ComplexType $a operand * @param NI $exp Exponent * * @return ComplexType * * @throws \InvalidArgumentException If exponent is complex */ public function complexPow(ComplexType $a, NI $exp) { if ($exp instanceof ComplexType) { $comp = new Comparator(); $zero = new IntType(0); $real = 0; $imaginary = 0; if (!($comp->eq($a->r(), $zero) && $comp->eq($a->i(), $zero))) { list($real, $imaginary) = $this->getPowExponentPartsFromPolar($a, $exp); } return new ComplexType(RationalTypeFactory::fromFloat($real), RationalTypeFactory::fromFloat($imaginary)); } //non complex //de moivres theorum //z^n = r^n(cos(n.theta) + sin(n.theta)i) //where z is a complex number, r is the radius $n = $exp(); $nTheta = $n * $a->theta()->get(); $pow = pow($a->modulus()->get(), $n); $real = cos($nTheta) * $pow; $imaginary = sin($nTheta) * $pow; return new ComplexType(RationalTypeFactory::fromFloat($real), RationalTypeFactory::fromFloat($imaginary)); }
/** * LU Decomposition constructor. * * @param \Chippyash\Math\Matrix\NumericMatrix $mA */ protected function LUDecomposition(NumericMatrix $mA) { // Use a "left-looking", dot-product, Crout/Doolittle algorithm. $LU = $mA->toArray(); $m = $this->rows = $mA->rows(); $n = $this->cols = $mA->columns(); for ($i = 0; $i < $m; $i++) { $this->piv[$i] = $i; } $this->pivsign = 1; $LUrowi = []; $LUcolj = []; $calc = new Calculator(); $comp = new Comparator(); $zeroInt = $this->createCorrectScalarType($mA, 0); // Outer loop. for ($j = 0; $j < $n; $j++) { // Make a copy of the j-th column to localize references. for ($i = 0; $i < $m; $i++) { $LUcolj[$i] =& $LU[$i][$j]; } // Apply previous transformations. for ($i = 0; $i < $m; $i++) { $LUrowi = $LU[$i]; // Most of the time is spent in the following dot product. $kmax = min($i, $j); $s = clone $zeroInt; for ($k = 0; $k < $kmax; $k++) { $s = $calc->add($s, $calc->mul($LUrowi[$k], $LUcolj[$k])); } $LUcolj[$i] = $calc->sub($LUcolj[$i], $s); $LUrowi[$j] = $LUcolj[$i]; } // Find pivot and exchange if necessary. $p = $j; for ($i = $j + 1; $i < $m; $i++) { if ($comp->gt($LUcolj[$i]->abs(), $LUcolj[$p]->abs())) { $p = $i; } } if ($p != $j) { for ($k = 0; $k < $n; $k++) { //swap $t = $LU[$p][$k]; $LU[$p][$k] = $LU[$j][$k]; $LU[$j][$k] = $t; } $k = $this->piv[$p]; $this->piv[$p] = $this->piv[$j]; $this->piv[$j] = $k; $this->pivsign = $this->pivsign * -1; } // Compute multipliers. if ($j < $m && $comp->neq($LU[$j][$j], $zeroInt)) { for ($i = $j + 1; $i < $m; $i++) { $LU[$i][$j] = $calc->div($LU[$i][$j], $LU[$j][$j]); } } } $this->set('LU', $this->createCorrectMatrixType($mA, $LU)); }