/** * Return the modulus, also known as absolute value or magnitude of this number * = sqrt(r^2 + i^2); * * @return \Chippyash\Type\Number\Rational\GMPRationalType */ public function modulus() { if ($this->isReal()) { //sqrt(r^2 + 0^2) = sqrt(r^2) = abs(r) /** @noinspection PhpUndefinedMethodInspection */ return $this->value['real']->abs(); } //get r^2 and i^2 $sqrR = array('n' => gmp_pow($this->value['real']->numerator()->gmp(), 2), 'd' => gmp_pow($this->value['real']->denominator()->gmp(), 2)); $sqrI = array('n' => gmp_pow($this->value['imaginary']->numerator()->gmp(), 2), 'd' => gmp_pow($this->value['imaginary']->denominator()->gmp(), 2)); //r^2 + i^2 $den = $this->lcm($sqrR['d'], $sqrI['d']); $numRaw = gmp_strval(gmp_add(gmp_div_q(gmp_mul($sqrR['n'], $den), $sqrR['d']), gmp_div_q(gmp_mul($sqrI['n'], $den), $sqrI['d']))); $num = TypeFactory::createInt($numRaw); //sqrt(num/den) = sqrt(num)/sqrt(den) //now this a fudge - we ought to be able to get a proper square root using //factors etc but what we do instead is to do an approximation by converting //to intermediate rationals using as much precision as we can i.e. // rNum = GMPRationaType(sqrt(num)) // rDen = GMPRationalType(sqrt(den)) // mod = rN/1 * 1/rD $rNum = RationalTypeFactory::fromFloat(sqrt($num())); $rDen = RationalTypeFactory::fromFloat(sqrt(gmp_strval($den))); $modN = gmp_mul($rNum->numerator()->gmp(), $rDen->denominator()->gmp()); $modD = gmp_mul($rNum->denominator()->gmp(), $rDen->numerator()->gmp()); return RationalTypeFactory::create((int) gmp_strval($modN), (int) gmp_strval($modD)); }
public function testInvokeProxiesToDerive() { $f = $this->object; $m = new NumericMatrix([]); $this->assertInstanceOf('Chippyash\\Math\\Matrix\\NumericMatrix', $f($m)); $this->assertEquals([[TypeFactory::createInt(2)]], $f($m)->toArray()); }
/** * @inheritDoc */ protected function doCompute(NumericTypeInterface $a, NumericTypeInterface $b, Calculator $calc) { if ($this->getComparator()->compare($b, TypeFactory::createInt(0)) === 0) { return null; } return $calc->div($a, $b); }
/** * Convert if possible a supplied argument to a strong numeric type * * @param int|float|string|NumericTypeInterface $numerator * @return Chippyash\Type\Interfaces\NumericTypeInterface * @throws UndefinedComputationException */ protected function convertNumberToNumeric($value) { switch (gettype($value)) { case 'integer': return TypeFactory::createInt($value); case 'double': return TypeFactory::createRational($value); case 'string': try { if (is_numeric($value)) { $value = floatval($value); } return TypeFactory::createRational($value); } catch (\Exception $e) { try { return TypeFactory::createComplex($value); } catch (\Exception $ex) { throw new MatrixException("The string representation of the number ('{$value}') is invalid for a complex"); } } case 'object': if ($value instanceof NumericTypeInterface) { return $value; } else { throw new MatrixException('NumberToNumeric expects int, float, string or Rational value'); } case 'NULL': return TypeFactory::createInt(0); case 'boolean': return TypeFactory::createInt($value ? 1 : 0); default: throw new MatrixException('NumberToNumeric expects int, float, string or Rational '); } }
public function testInvokeProxiesToCompute() { $this->object->expects($this->exactly(2))->method('compute')->will($this->returnValue(new NumericMatrix([[2]]))); $f = $this->object; $m = new NumericMatrix(array()); $this->assertInstanceOf('Chippyash\\Math\\Matrix\\NumericMatrix', $f($m)); $this->assertEquals([[TypeFactory::createInt(2)]], $f($m)->toArray()); }
public function setUp() { RequiredType::getInstance()->set(RequiredType::TYPE_NATIVE); $this->object = new AsciiNumeric(); $this->rationalOne = TypeFactory::createRational(TypeFactory::createInt(1), TypeFactory::createInt(1)); $this->rationalHalf = TypeFactory::createRational(TypeFactory::createInt(1), TypeFactory::createInt(2)); $this->complexTwo = TypeFactory::createComplex(TypeFactory::createRational(TypeFactory::createInt(2), TypeFactory::createInt(1)), TypeFactory::createRational(TypeFactory::createInt(0), TypeFactory::createInt(1))); $this->complexThree = TypeFactory::createComplex(TypeFactory::createRational(TypeFactory::createInt(3), TypeFactory::createInt(1)), TypeFactory::createRational(TypeFactory::createInt(-3), TypeFactory::createInt(2))); }
function createMatrix($size) { $c = 0; $fn = function ($r, $c) use(&$c) { return RationalTypeFactory::create($c++, 1); }; $iSize = TypeFactory::createInt($size); return MatrixFactory::createFromFunction($fn, $iSize, $iSize, new StringType('rational')); }
private function toStrongType(array $values) { $ret = []; foreach ($values as $r => $row) { foreach ($row as $c => $item) { $ret[$r][$c] = TypeFactory::createInt($item); } } return $ret; }
public function testYouCanPickTheNextLinkInAChain() { $chain = new NumericMatrix([[2, 0, 6, 2], [0, 0, 6, 4], [8, 1, 1, 0], [0, 5, 0, 5]]); $res = [2 => 0, 3 => 0]; for ($x = 0; $x < 100; $x++) { $test = $this->sut->derive($chain, TypeFactory::createInt(2)); $res[$test() - 1]++; } $this->assertEquals(100, array_sum($res)); }
public function testConstructGivesExpectedOutput() { $expected = [[TypeFactory::createInt(0), TypeFactory::createInt(-1), TypeFactory::createInt(-2)], [TypeFactory::createInt(1), TypeFactory::createInt(0), TypeFactory::createInt(-1)], [TypeFactory::createInt(2), TypeFactory::createInt(1), TypeFactory::createInt(0)]]; $this->object = new FunctionMatrix($this->function, TypeFactory::createInt(3), TypeFactory::createInt(3)); $this->assertEquals($expected, $this->object->toArray()); $this->assertTrue($this->object->is('Complete')); $this->assertTrue($this->object->is('Square')); $this->assertFalse($this->object->is('Empty')); $this->assertFalse($this->object->is('RowVector')); $this->assertFalse($this->object->is('ColumnVector')); }
/** * Create a new scalar based on type of original matrix * * @param \Chippyash\Math\Matrix\NumericMatrix $originalMatrix * @param scalar $scalar * @return Chippyash\Type\Interfaces\NumericTypeInterface * */ protected function createCorrectScalarType(NumericMatrix $originalMatrix, $scalar) { if ($scalar instanceof NumericTypeInterface) { if ($originalMatrix instanceof RationalMatrix) { return $scalar->asRational(); } if ($originalMatrix instanceof ComplexMatrix) { return $scalar->asComplex(); } return $scalar; } if ($originalMatrix instanceof ComplexMatrix) { if (is_numeric($scalar)) { return ComplexTypeFactory::create($scalar, 0); } if (is_string($scalar)) { try { return RationalTypeFactory::create($scalar)->asComplex(); } catch (\Exception $e) { //do nothing } } if (is_bool($scalar)) { return ComplexTypeFactory::create($scalar ? 1 : 0, 0); } return ComplexTypeFactory::create($scalar); } if ($originalMatrix instanceof RationalMatrix) { if (is_bool($scalar)) { $scalar = $scalar ? 1 : 0; } return RationalTypeFactory::create($scalar); } //handling for NumericMatrix if (is_int($scalar)) { return TypeFactory::createInt($scalar); } elseif (is_float($scalar)) { return TypeFactory::createRational($scalar); } elseif (is_bool($scalar)) { return TypeFactory::createInt($scalar ? 1 : 0); } elseif (is_string($scalar)) { try { return TypeFactory::createRational($scalar); } catch (\InvalidArgumentException $e) { try { return ComplexTypeFactory::create($scalar); } catch (\InvalidArgumentException $e) { //do nothing } } } throw new ComputationException('Scalar parameter is not a supported type for numeric matrices: ' . getType($scalar)); }
/** * ShiftMatrix constructor. * * @param IntType $size Number of required rows and columns * @param StringType $shiftType SM_TYPE_UPPER|SM_TYPE_LOWER * @param IntType|null $identityType Type of identity entries: default == IdentityType::IDM_TYPE_INT * */ public function __construct(IntType $size, StringType $shiftType, IntType $identityType = null) { $mA = (new Identity())->create([$size()]); $new = TypeFactory::createInt(0); $fS = new Shift(); if ($shiftType() == self::SM_TYPE_UPPER) { $mB = $fS($mA, [1, $new]); } if ($shiftType() == self::SM_TYPE_LOWER) { $mB = $fS($mA, [-1, $new]); } parent::__construct($mB); }
/** * 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); }
/** * @inheritDoc */ public function derive(NumericMatrix $mA, $extra = null) { if ($mA->is('empty')) { return TypeFactory::createInt(0); } if ($mA->is('singleitem')) { return $mA->get(1, 1); } $calc = new Calculator(); return array_reduce($mA->toArray(), function ($c1, $row) use($calc) { return array_reduce($row, function ($carry, $item) use($calc) { return $calc->add($item, $carry); }, $c1); }, TypeFactory::createInt(0)); }
/** * 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); }
/** * Construct a complete Matrix with all entries set to Chippyash/Type * Takes a source matrix or array (which can be incomplete and converts each * entry to Chippyash/Type), setting a default value if entry does not exist. * * If a NumericMatrix is supplied as $source, the data is cloned into the Matrix * with no further checks. * * @param NumericMatrix|array $source Array to initialise the matrix with * @param mixed $normalizeDefault Value to set missing vertices * @throws \Chippyash\Math\Matrix\Exceptions\MathMatrixException */ public function __construct($source, $normalizeDefault = 0) { if ($source instanceof self) { $this->store($source->toArray()); return; } if (is_array($source)) { if (is_int($normalizeDefault)) { $default = TypeFactory::createInt($normalizeDefault); } elseif (is_float($normalizeDefault)) { $default = RationalTypeFactory::fromFloat($normalizeDefault); } elseif (!$normalizeDefault instanceof NumericTypeInterface) { throw new MathMatrixException('NumericMatrix expects numeric default value'); } else { $default = $normalizeDefault; } parent::__construct($source, false, true, $default); } else { throw new MathMatrixException('NumericMatrix expects NumericMatrix or array as source data'); } }
/** * @param RationalType $radius * @param RationalType $sin * * @return array * * @throws InvalidTypeException */ private static function getImaginaryPartsFromRadiusAndSin(RationalType $radius, RationalType $sin) { return array(TypeFactory::create('int', $radius->numerator()->get() * $sin->numerator()->get()), TypeFactory::create('int', $radius->denominator()->get() * $sin->denominator()->get())); }
public function testYouCanPlaceALimitOnTheWalk() { $chain = new NumericMatrix($this->chainData()); $res = $this->sut->transform($chain, array('start' => TypeFactory::createInt(4), 'target' => TypeFactory::createInt(2), 'limit' => TypeFactory::createInt(2))); $this->assertEquals(2, $res->columns()); $this->assertEquals(1, $res->rows()); }
/** * @expectedException InvalidArgumentException * @expectedExceptionMessage $cols must be >= 1 */ public function testConstructingWithColsLessThanOneThrowsException() { $zero = TypeFactory::createInt(0); $one = TypeFactory::createInt(1); new ZeroMatrix($one, $zero); }
public function computeMatrices() { //set required type as data is generated before tests RequiredType::getInstance()->set(RequiredType::TYPE_NATIVE); return [[[[1, 2, 3], [3, 2, 1], [2, 1, 3]], [[TypeFactory::createInt(2), TypeFactory::createInt(4), TypeFactory::createInt(6)], [TypeFactory::createInt(6), TypeFactory::createInt(4), TypeFactory::createInt(2)], [TypeFactory::createInt(4), TypeFactory::createInt(2), TypeFactory::createInt(6)]], 2], [[[1, 2, 3]], [[RationalTypeFactory::create(2.5), RationalTypeFactory::create(5.0), RationalTypeFactory::create(7.5)]], 2.5], [[[1.5, 2.5, 3.5]], [[RationalTypeFactory::create(3.0), RationalTypeFactory::create(5.0), RationalTypeFactory::create(7.0)]], 2], [[[1.12, 2.12, 3.12]], [[RationalTypeFactory::create(1.12), RationalTypeFactory::create(2.12), RationalTypeFactory::create(3.12)]], 1.0], [[[1, 2, 3]], [[TypeFactory::createInt(1), TypeFactory::createInt(2), TypeFactory::createInt(3)]], true], [[[1, 2, 3]], [[TypeFactory::createInt(0), TypeFactory::createInt(0), TypeFactory::createInt(0)]], false], [[[true, false]], [[TypeFactory::createInt(1), TypeFactory::createInt(0)]], true], [[[true, false]], [[TypeFactory::createInt(0), TypeFactory::createInt(0)]], false]]; }
public function testSetNumberTypeToDefaultWillSetGmpIfAvailable() { RequiredType::getInstance()->set(RequiredType::TYPE_DEFAULT); $this->assertInstanceOf('Chippyash\\Type\\Number\\Rational\\GMPRationalType', TypeFactory::create('rational', 2)); }
/** * Create and return a Numeric Identity Matrix with IntType entries * * @param \Chippyash\Type\Number\IntType $size * @return \Chippyash\Math\Matrix\NumericMatrix */ public static function numericIdentity(IntType $size) { return new self($size, TypeFactory::createInt(self::IDM_TYPE_INT)); }
/** * @requires extension gmp * @runInSeparateProcess */ public function testCreatingFloatsViaTypeFactoryUnderGmpWillReturnGMPRationalType() { RequiredType::getInstance()->set(RequiredType::TYPE_GMP); $this->assertInstanceOf('Chippyash\\Type\\Number\\Rational\\GMPRationalType', TypeFactory::create('float', 2 / 3)); }
/** * Return number as a FloatType number. * * @return \Chippyash\Type\Number\FloatType * @throws NotRealComplexException */ public function asFloatType() { if ($this->isReal()) { return TypeFactory::create('float', $this->value['real']->get()); } else { throw new NotRealComplexException(); } }
public function validNumerics() { return [[2], [2.5], ['12.45'], ['2/5'], [true], [false], ['2+3i'], [TypeFactory::createComplex(2)], [TypeFactory::createInt(2)], [TypeFactory::createFloat(2)], [TypeFactory::createRational(2)], [null]]; }
} else { echo "{$op}({$tA}({$p1})) = {$tR}({$res})" . PHP_EOL; } } catch (InvalidTypeException $e) { $msg = $e->getMessage(); echo "{$tA}({$p1}) {$op} {$tB}({$p2}) is invalid: {$msg}" . PHP_EOL; } } $iphp = 19; $fphp = 13.27; $i = F::create('int', 6); $w = F::create('whole', 21); $n = F::create('natural', 13); $f = F::create('float', 2.26); $r = F::Create('rational', '2/3'); $c = F::create('complex', '2+6i'); $items = [$iphp, $i, $w, $n, $fphp, $f, $r, $c]; echo "Library supported arithmetic operations and return types\n"; echo "Non complex numbers\n"; echo "Addition\n\n"; foreach ($items as $a) { foreach ($items as $b) { display('add', $a, $b); } } echo "\nSubtraction\n\n"; foreach ($items as $a) { foreach ($items as $b) { display('sub', $a, $b); } }
public function mixedMatrices() { return [[[[1, 2, 3]], TypeFactory::createInt(6)], [[[1], [2], [3]], TypeFactory::createInt(6)], [[[1, 2, 3], [1, 2, 3]], TypeFactory::createInt(12)], [[[1.1, 2, 3], [1, 2.2, 3]], RationalTypeFactory::fromFloat(12.3)], [[[0.5, 0.5]], RationalTypeFactory::create(1)]]; }
* we get into an overflow situation. * * Setting tolerance to a lower number, say 1e-6, will compute faster but at the * expense of accuracy */ RationalTypeFactory::setDefaultFromFloatTolerance(1.0E-15); /** * Set the required number type. System will automatically use GMP if * it is available. You can force it to use native PHP thus: */ RequiredType::getInstance()->set(RequiredType::TYPE_NATIVE); //now create 10000 numbers for the test //try playing with this figure to see the results $numbers = []; for ($x = 1; $x < 10001; $x++) { $numbers[$x] = TypeFactory::create('int', $x); } //create primes $primes = []; $start = microtime(true); foreach ($numbers as $key => $number) { $primes[$key] = $number->primeFactors(); } $end = microtime(true); $time = $end - $start; echo "{$time} secs.\n"; echo "And the results were:\n"; foreach ($primes as $key => $res) { $p = array_keys($res); $e = array_values($res); $factors = "{$key}=>";
/** * Exception to non commutative rule */ public function testMultiplicationByAnIdentityMatrixIsCommmutative() { $mA = $this->square; $mB = new IdentityMatrix(TypeFactory::createInt($mA->rows())); $this->assertEquals($this->object->compute($mA, $mB), $this->object->compute($mB, $mA)); }