From 9ef5d4ae2c25f6e9a7d316e26e0e0200937eaf84 Mon Sep 17 00:00:00 2001 From: ATM-Nicolas <31647290+ATM-Nicolas@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:01:16 +0200 Subject: [PATCH] NEW : Library including math and financial functions (#25035) --- COPYRIGHT | 1 + .../markrogoyski/math-php/CHANGELOG.md | 960 ++++++ .../markrogoyski/math-php/LICENSE.txt | 21 + .../includes/markrogoyski/math-php/README.md | 2796 +++++++++++++++++ .../markrogoyski/math-php/composer.json | 41 + .../src/Exception/BadDataException.php | 7 + .../src/Exception/OutOfBoundsException.php | 7 + .../markrogoyski/math-php/src/Finance.php | 780 +++++ .../RootFinding/NewtonsMethod.php | 61 + .../RootFinding/Validation.php | 40 + 10 files changed, 4714 insertions(+) create mode 100644 htdocs/includes/markrogoyski/math-php/CHANGELOG.md create mode 100644 htdocs/includes/markrogoyski/math-php/LICENSE.txt create mode 100644 htdocs/includes/markrogoyski/math-php/README.md create mode 100644 htdocs/includes/markrogoyski/math-php/composer.json create mode 100644 htdocs/includes/markrogoyski/math-php/src/Exception/BadDataException.php create mode 100644 htdocs/includes/markrogoyski/math-php/src/Exception/OutOfBoundsException.php create mode 100644 htdocs/includes/markrogoyski/math-php/src/Finance.php create mode 100644 htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/NewtonsMethod.php create mode 100644 htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/Validation.php diff --git a/COPYRIGHT b/COPYRIGHT index 96c39a39650..7a04b5d8a0a 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -26,6 +26,7 @@ PHP libraries: EvalMath 1.0 BSD Yes Safe math expressions evaluation Escpos-php 3.0 MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert +MathPHP 2.8.1 MIT License Yes Modern math library for PHP Mobiledetect 2.8.41 MIT License Yes Detect mobile devices browsers NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package) PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency diff --git a/htdocs/includes/markrogoyski/math-php/CHANGELOG.md b/htdocs/includes/markrogoyski/math-php/CHANGELOG.md new file mode 100644 index 00000000000..215cde3b5e3 --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/CHANGELOG.md @@ -0,0 +1,960 @@ +# MathPHP Change Log + +## v2.8.1 - 2023-05-18 + +### Improvements +* Internal improvements to improve conformance with static analysis tools + +## v2.8.0 - 2023-05-07 + +### New Features +* Matrix `rowAddVector` +* Matrix `columnAddVector` + +### Improvements +* Better error handling and exception message in `Sequence\NonIntenger::hyperharmonic` +* Internal code improvements to conform to static analysis checks + +### Backwards Incompatible Changes +* Helper method names changed (public abstract methods but not part of published interface) + * `NumericalDifferentiation::isTargetInPoints` changed to `assertTargetInPoints` + * `NumericalDifferentiation::isSpacingConstant` changed to `assertSpacingConstant` + +## v2.7.0 - 2022-12-31 + +### Improvements +* Improved algorithm for `regularizedIncompleteBeta`: Addresses issue 458 +* Issue 456: Improved PHPDoc blocks: Changed "number" to "int|float" +* Added PHP 8.2 for CI test target + +## v2.6.0 - 2022-04-10 + +### Improvements +* `Average::truncatedMean` behavior at 50% trim made consistent +* PHP 8.1 compatibility improvements + +### Backwards Incompatible Changes +# `Average::truncatedMean` throws exception if trim percent greater than 50% rather than error or unpredictable results. + +## v2.5.0 - 2021-11-21 + +### New Features +* Special function `logbeta` +* Special function `logGamma` +* Special function `logGammaCorr` +* Special function `stirlingError` + +### Improvements +* Improvements in StudentT continuous distribution +* Improvements in special function `gamma` +* Improvements in special function `beta` + +### Bug Fixes +* Issue 393 (regularizedIncompleteBeta NAN) +* Issue 429 (Linear regression CI division by zero) + +## v2.4.0 - 2021-07-27 + +### New Features +* Complex Exponential (`exp`) +* Complex Exponentiation (`pow`) +* Zipf's Law Discrete Distribution +* Generalized harmonic non-integer sequence + +### Improvements +* Fixed Complex `polarForm` to compute the right values +* Fixed `hyperharnomic` non-integer sequence. Previously was computing the wrong thing +* Fixed how `ArbitraryInterger` handles `pow` of negative exponents + +### Backwards Incompatible Changes +* Complex `polarForm` now returns an array rather than a Complex number, as the Complex return was incorrect +* Interface to `hyperharmonic` non-integer sequence changed due to previous implementation being incorrect + +## v2.3.0 - 2021-07-14 + +### New Features +* Matrix SVD (Singular Value Decomposition) +* Polynomial companion matrix + +## v2.2.0 - 2021-07-11 + +### New Features +* PLS (Partial Least Squares Regression) + +### Improvements +* Add custom `__debugInfo` to `NumericMatrix` + +## v2.1.0 - 2021-07-07 + +### New Features +* Quaternion numbers + +## v2.0.0 - 2021-05-09 + +### New Features +* Matrix Improvements + * `walk` method to map a function to all values without mutation or returning a value + * `MatrixFactory` creates more matrix types + * `MatrixFactory::createNumeric` to create `NumericMatrix` types + * `MatrixFactory::createFromRowVector` + * `MatrixFactory::createFromColumnVector` + * Internal `ObjectMatrix` improvements + * Add `trace` + * Add `scalarMultiply` + * Add initial `ComplexMatrix` +* Sample data People + +### Improvements +* Bug fixes + * Issue 414 fixed - PCA/Eigenvalue convergence + * Issue 413 fixed - matrix solve with singular matrix using RREF + +## Migration - Upgrading to v2.0 from v1.0 +* PHP minimum version now 7.2 (was 7.0) +* Deprecated code removed (backwards-incompatible change) + * `MathPHP\Statistics\Distance::kullbackLeiblerDivergence` removed (Use `MathPHP\Statistics\Divergence::kullbackLeibler` instead) + * `MathPHP\Statistics\Distance::jensenShannonDivergence` removed (Use `MathPHP\Statistics\Divergence::jensenShannon` instead) + * Matrix Decompositions no longer implement `\ArrayAccess` interface to access decomposition matrixes. Use properties instead. + * `MathPHP\LinearAlgebra\Decomposition\Cholesky` + * `$cholesky['L']`, `$cholesky['Lᵀ']`, `$cholesky['LT']` removed, use `$cholesky->L`, `$cholesky->Lᵀ`, `$cholesky->LT` instead. + * `MathPHP\LinearAlgebra\Decomposition\Crout` + * `$crout['L']`, `$crout['U']` removed, use `$crout->L`, `$crout->U` instead. + * `MathPHP\LinearAlgebra\Decomposition\LU` + * `$LU['L']`, `LU['U']`, `LU['P']` removed, use `$LU->L`, `$LU->U`, `$LU->P` instead. + * `MathPHP\LinearAlgebra\Decomposition\QR` + * `$QR['Q']`, `$QR['R']` removed, use `$QR->Q`, `$QR->R` instead. +* Methods renamed (backwards-incompatible change) + * `MathPHP\Statistics\Distance::bhattacharyyaDistance` renamed to `MathPHP\Statistics\Distance::bhattacharyya` + * `MathPHP\Statistics\Distance::hellingerDistance` renamed to `MathPHP\Statistics\Distance::hellinger` +* Moved Functionality (backwards-incompatible change) + * `MathPHP\Functions\Polynomial` moved to `MathPHP\Expression\Polynomial` + * `MathPHP\Functions\Piecewise` moved to `MathPHP\Expression\Piecewise` +* Matrix internal refactoring + * Note: These changes will not affect any client code as long as matrices were created using `MatrixFactory`. + * `Matrix` is not a base abstract class for all matrix classes to extend + * `Matrix` renamed `NumericMatrix` + * `Matrix` base method `createZeroValue` + * Use case is various `ObjectMatrix` classes that implement `ObjectArithmetic` + * `RowVector` removed. Use `MatrixFactory::createFromRowVector` instead + * `ColumnVector` removed. Use `MatrixFactory::createFromColumnVector` instead + +## v1.11.0 - 2021-05-09 + +### Improvements +* Bugfix (Issue 413): Matrix solve with singular matrix using RREF +* Bugfix (Issue 414): PCA/Eigenvalue convergence + +## v1.10.0 - 2020-12-19 + +### Improvements +* Bugfix (Issue 356): Fix Finance IRR NANs + +## v1.9.0 - 2020-12-13 + +### New Features +* Vector min and max +* Arithmetic isqrt (integer square root) + +### Improvements +* Remove Travis CI (Moved CI to Github Actions in v1.8.0 release) +* Rearrange non-code files + +## v1.8.0 - 2020-12-11 + +### Improvements +* Improve permutations algorithm to be more efficient and more numerically stable +* Qualify PHP function names with root namespace +* Move CI to Github Actions + +## v1.7.0 - 2020-11-15 + +### New Features +* Algebra linear equation of one variable +* Rational number inverse +* Rational number pow + +### Improvements +* Improve combinations algorithm to be more efficient and more numerically stable +* Internal Matrix class reorganization + +## v1.6.0 - 2020-10-22 + +### New Features +* Special function regularized lower incomplete gamma +* Cereal sample data set + +### Improvements +* Define boundary condition for lower incomplete gamma function + +## v1.5.0 - 2020-10-12 + +### New Features +* Matrix LU solve +* Matrix QR solve + +### Improvements +* Bugfix (Issue 386) Matrix solve improvements +* Matrix solve has optional method parameter to force a solve method +* Bugfix ArbitraryInteger multiplication sign not taken into account + +## v1.4.0 - 2020-10-02 + +### New Features +* Multivariate Regular Grid Interpolation +* Jensen-Shannon Distance +* Canberra Distance +* Search Sorted +* Search ArgMax +* Search NanArgMax +* Search ArgMin +* Search NanArgMin +* Search NonZero + +### Improvements + * Divergence factored out of Distance into new Divergence class + +### Backwards Incompatible Changes + * Legacy Distance divergences marked as deprecated (To be removed in v2.0.0) + +## v1.3.0 - 2020-08-24 + +### New Features +* LinearAlgebra\Vector + * Angle between two vectors + * L¹ distance of two vectors + * L² distance of two vectors + * Minkowski distance of two vectors +* Statistics\Distance + * Minkowski distance + * Euclidean distance (L² distance) + * Manhattan distance (Taxicab geometry, L¹ distance, etc.) + * Cosine distance + * Cosine similarity + +## v1.2.0 - 2020-07-24 + +### New Features +* Ranking + * Ordinal ranking + * Standard competition ranking + * Modified competition ranking + * Fractional ranking + +### Improvements +* (Issue 380) Fixed Spearman's Rho calculation when there are rank ties + +## v1.1.0 - 2020-04-19 + +### New Features +- Arithmetic modulo + +### Improvements +- Improved matrix multiplication performance using cache-oblivious algorithm optimization + +## v1.0.0 - 2020-04-14 + +Initial version 1.0.0 release! + +## v0.62.0 - 2020-04-08 + +### Improvements +- Internal improvements + +## v0.61.0 - 2020-03-22 + +### New Features +* Multivariate Hypergeometric distribution + +## v0.60.0 - 2020-02-27 + +### New Features +- Sample Data + - MtCars + - Iris + - ToothGrowth + - PlantGrowth + - UsArrests + +## v0.59.0 - 2020-02-19 + +### New Features +- Add population and sample kurtosis +- Changed default kurtosis algorithm to the more common population kurtosis +- kurtosis now takes an optional parameter to set the kurtosis type algorithm + +## v0.58.0 - 2020-02-06 + +### Improvements +* Changed default skewness algorithm to the more common sample skewness +* skewness now takes an optional parameter to set the skewness type algorithm +* Improvements to skewness algorithms + +## v0.57.0 - 2020-01-07 + +### New Features +* Number\Rational basic getters + * getWholePart + * getNumerator + * getDenominator +* Set Theory n-ary Cartesian product + +### Improvements +* Data direction control for Matrix meanDeviation and covarianceMatrix +* Algebra factors performance improvement + +## v0.56.0 - 2019-12-03 + +### New Features +* Number Theory + * isDeficientNumber + * isAbundantNumber + * aliquotSum + * radical + * totient + * cototient + * reducedTotient + * mobius + * isSquarefree + * isRefactorableNumber + * isSphenicNumber + * numberOfDivisors + * sumOfDivisors + +### Improvements +* Optimization of prime factorization algorithm + +## v0.55.0 - 2019-11-19 + +### New Features +- Arbitrary length integers + +### Improvements +- Factorial optimization + +## v0.54.0 - 2019-10-12 + +### New Features +- Matrix isNilpotent +- Matrix isRectangularDiagonal +- Matrix mapRows +- MathPHP logo + +### Improvements +* MatrixFactory random matrix custom lower and upper bounds for random number +* PSR-12 style compliance +* Bugfix: powerIteration random failure - [Issue 346](https://github.com/markrogoyski/math-php/issues/346) + +## v0.53.0 - 2019-09-09 + +### New Features +* Matrix QR decomposition using Householder reflections +* Matrix Householder transformation +* MatrixFactory random matrix +* MatrixFactory givens rotation matrix +* Matrix isIdempotent +* Matrix Eigenvalue power iteration +* Matrix Eigenvalue jacobi method +* Arithmetic root (nᵗʰ root) +* Vector arithmetic multiply and divide +* Vector Iterator interface + +### Improvements +* Internal improvements to Matrix +* Matrix decompositions returned as objects +* Matrix Cholesky decomposition provides L transpose + +## v0.52.0 - 2019-07-11 + +### New Features +* Grubb's test for statistical outliers + +## v0.51.0 - 2019-06-05 + +### New Features +* Matrix rowSums +* Matrix columnSums +* Matrix rowMeans +* Matrix columnMeans +* Matrix isNormal +* MatrixFactory diagonal matrix creation method +* MatrixFactory vandermonde matrix creation method + +### Improvements +* Set custom Matrix tolerances +* Various internal improvements + +### Backwards Incompatible Changes +* Remove Matrix sampleMeans (use rowMeans or columnMeans instead) +* MatrixFactory create method only works with 2d arrays. 1d arrays no longer work. (use diagonal and vandermonde factory methods instead) +* Statistics methods throw exceptions instead of returning null on bad input +* Change return type of LagrangePolynomial to Polynomial + +## v0.50.0 - 2019-04-22 + +### New Features +* Matrix isOrthogonal +* Matrix isEqual +* Harmonic sequence +* Hyperharmonic sequence +* Map\Single reciprocal + +### Improvements +* Support methods for almost equal +* Matrix getDiagonalElements works for non-square matrices +* Use more efficient algorithm in Matrix isSymmetric +* Use more efficient algorithm in Matrix isSkewSymmetric + +### Backwards Incompatible Changes +* Statistics methods throw exceptions instead of returning null on bad input + +## v0.49.0 - 2019-02-23 + +### New Features +- Matrix augmentAbove +- Matrix augmentLeft + +### Improvements +- Object matrix multiplication + +## v0.48.0 - 2018-12-15 + +### New Features +- Matrix submatrix +- Mahalanobis distance +- Bernoulli distribution mean, median, mode and variance +- Binomial distribution mean and variance +- Geometric distribution mean, median, mode and variance +- Hypergeometric distribution mode and variance +- NegativeBinomial (Pascal) distribution CDF, mean, mode and variance +- Poisson distribution mean, median, mode and variance +- Discrete Uniform distribution variance + +### Improvements +- Binomial distribution PMF uses more numerically stable multiplication method +- Fix potential divide by zero in TheilSen regression + +### Backwards Incompatible Changes +- Multinomial distribution moved from Discrete to Multivariate namespace + +## v0.47.0 - 2018-11-21 + +### New Features +* Beta distribution median, mode, variance +* Cauchy distribution variance +* ChiSquared distribution mode, variance +* Exponential distribution median, mode, variance +* F distribution mode, variance +* Gamma distribution median, mode, variance +* Laplace distribution mode, variance +* Logistic distribution mode, vaiance +* LogLogistic distribution median, mode, variance +* LogNormal distribution mode, variance +* Normal distribution mode, variance +* StandardNormal distribution mode, variance +* StudentT distribution mode, variance +* Uniform distribution median, mode, variance +* Weibull distribution median, mode + +### Improvements +* Normal distribution rand algorithm changed to Box–Muller transform + +## v0.46.0 - 2018-10-28 + +### New Features +* NumberTheory isPerfectNumber +* Sequence perfectNumber + +### Improvements +* Improve README documentation for continuous distributions +* Updates to build tools +* General improvements + +## v0.45.0 - 2018-09-24 + +### Improvements +- Add Beta distribution inverse quantile function +- Improvements to Weibull distribution +- Improvements to Cauchy distribution +- Improvements to Laplace distribution +- Improvements to Logistic distribution +- Improvements to LogNormal distribution +- Improvements to Normal distribution +- Improvements to Pareto distribution +- Improvements to Algebra cubic/quartic complex root handling + +## v0.44.0 - 2018-08-29 + +### Improvements +- [[Issue 271]](https://github.com/markrogoyski/math-php/issues/271) Improvements to documentation +- [[Issue 269]](https://github.com/markrogoyski/math-php/issues/269) Add closed-form inverse function for Exponential distribution + +## v0.43.0 - 2018-05-21 + +### New Features +* Arithmetic copySign +* Matrix negate +* Matrix isSkewSymmetric + +## v0.42.0 - 2018-05-09 + +### New Features +* Weighted mean +* Weighted sample variance +* Weighted covariance +* Weighted correlation coefficient + +### Improvements +* Minor code improvements + +## v0.41.0 - 2018-04-23 + +### New Features +* Arithmetic almostEqual + +### Improvements +* Statistics\Average::mode improved to work with non-integer values +* Various minor code improvements + +## v0.40.0 - 2018-03-22 + +### New Features +* Simpler interface for Significance ```tTest``` for one and two samples + +### Improvements +* T test for two samples uses more robust Welch test +* Improvements to Normal and Standard Normal continuous distributions +* General improvements to continuous distributions + +## v0.39.0 - 2018-02-27 + +### Improvements +* Upgrade unit testing framework to PHPUnit 6 +* Update unit tests for PHPUnit 6 compatibility +* Add PHP 7.2 to continuous integration tests + +## v0.38.0 - 2017-12-10 + +### Improvements +* Percentile reimplemented to use linear interpolation between closest ranks method - Second variant, C = 1 +* General code improvements +* Better error and exception handling + +## v0.37.0 - 2017-10-23 + +### Improvements +- Change probability distributions to be objects instead of static methods + +### Backwards Incompatible Changes +- Change probability distributions to be objects instead of static methods + +## v0.36.0 - 2017-09-26 + +### New Features +* Rational number +* Gamma distribution mean + +### Improvements +* Add .gitignore file + +## v0.35.0 - 2017-08-20 + +### New Features +* Matrix isTridiagonal +* Matrix isUpperHessenberg +* Matrix isLowerHessenberg +* Matrix getSuperdiagonalElements +* Matrix getSubdiagonalElements + +### Improvements +* [Issue 242 - documentation improvement](https://github.com/markrogoyski/math-php/issues/242) + +## v0.34.0 - 2017-08-12 + +### New Features +- Multivariate normal distribution + +## v0.33.0 - 2017-08-04 + +### New Features +- Kernel density estimation + +## v0.32.0 - 2017-07-24 + +### New Features +* Matrix Crout decomposition +* Categorical discrete distribution + +## v0.31.0 - 2017-07-02 + +### New Features +* Hypergeometric distribution +* Discrete uniform distribution + +## v0.30.0 - 2017-06-11 + +### New Features +* Dirichlet multivariate distribution +* Gamma distribution +* Initial eigenvalue matrix method +* Initial eigenvector matrix method +* Confidence ellipse + +### Improvements +* Internal Bitwise addition + +## v0.29.0 - 2017-05-21 + +### New Features +- Matrix rank +- ObjectArithmetic interface +- Polynomial implements ObjectArithmetic +- ObjectSquareMatrix +- Polynomial negate + +### Improvements +- Refactor Matrix REF algorithm +- Refactor Matrix RREF algorithm +- Support functions for better handling of infinitesimal floating-point zero-like quantities +- Fix bug in Polynomial degree calculation +- Refactored Polynomial::add() to be simpler and faster + +## v0.28.0 - 2017-05-02 + +### New Features +* Matrix adjugate +* Polynomial subtract + +### Improvements +* Internal refactoring/improvements + * Tests namespace for unit tests + * Standardize method naming convention + * Update PHPUnit exception assertion + * Replace class strings in tests with class constants + +## v0.27.0 - 2017-04-23 + +### New Features +* Matrix + * Cholesky decomposition + * isRref + * Exchange matrix + * isInvolutory + * isSignature + * Hilbert matrix + * isUpperBidiagonal + * isLowerBidiagonal + * isBidiagonal +* Quartic function roots +* Trigonometry unit circle +* Integer + * isOdd + * isEven + +## v0.26.0 - 2017-04-15 + +### New Features +* Initial Complex number class +* Complex number support to quadratic and cubic equations +* Initial Eigenvalue strategy class (2x2 and 3x3 matrices using root equations) +* Matrix + * isLowerTriangular + * isUpperTriangular + * isTriangular + * isDiagonal +* Beta function convenience method + +### Improvements +* Add BadDataException to LeastSquares regression method trait if degrees of freedom is 0 +* Complex Root of Quadratic Function + +## v0.25.0 - 2017-04-01 + +### New Features +* Matrix + * isSingular + * isNonsingular + * isInvertible + * leadingPrincipalMinor + * isPositiveDefinite + * isPositiveSemidefinite + * isNegativeDefinite + * isNegativeSemidefinite +* Number Theory + * Integer coprime +* Arithmetic + * digitSum + * digitalRoot +* Basic sequences + * digitSum + * digitalRoot + +## v0.24.0 - 2017-03-26 + +### New Features +* Arithmetic cube root +* Algebra cubic equation +* Matrix Kronecker sum +* Vector Kronecker product +* Number theory prime factorization + +### Improvements +* Improved quadratic equation edge case handling + +## v0.23.0 - 2017-03-12 + +### New Features +* Number Theory - Integers + * Perfect powers +* Advanced Sequences + * Perfect powers + * Not perfect powers + * Primes up to n +* Algebra + * Quadratic equation + +## v0.22.0 - 2017-01-31 + +### New Features +* Circular statistics (directional statistics) + * Circular mean + * Resultant length + * Mean resultant length + * Circular variance + * Circular standard deviation + * Describe +* Finance profitability index + +### Improvements +* Update Finance payback to be both simple and discounted payback + +## v0.21.0 - 2017-01-23 + +### New Features +* Finance interest payment +* Finance principle payment on an annuity +* Finance payback +* Make files for unit tests, linting, and code coverage + +## v0.20.0 - 2017-01-12 + +### New Features +* Finance net present value +* Finance rate function +* Finance internal rate of return +* Finance modified internal rate of return +* Finance payment periods of an annuity + +### Improvements +* Update Newton's Method to handle non-convergence and infinite slopes. + +## v0.19.0 - 2016-12-31 + +### New Features +* Matrix sample mean +* Matrix mean deviation form +* Covariance matrix +* Matrix representation as array of column vectors +* Finance future value +* Finance present value + +## v0.18.0 - 2016-12-28 + +### New Features +* Joint entropy +* Rényi entropy +* Perplexity +* Matrix scalar division +* Finance: Annual Equivalent Rate (AER) + +### Improvements +* Fix vector pnorm to take absolute value of each element + +### Backwards Incompatible Changes +* Refactor distances and divergences from InformationTheory\Entropy to Statistics\Distance + +## v0.17.0 - 2016-12-21 + +### New Features +* Two-sample z significance test + +## v.0.16.0 - 2016-12-18 + +### New Features +* Information Theory + * Shannon entropy (bits, nats, hartleys) + * Cross entropy + * Bhattacharyya distance + * Kullback-Leibler divergence + * Hellinger distance + * Jensen-Shannon divergence +* Linear Algebra + * vectorMultiply method on Matrix to return Vector when multiply with a Vector + +## v0.15.0 - 2016-11-10 + +### New Features +* Lazy caterer's sequence +* Magic squares sequence + +## v0.14.0 - 2016-10-28 + +### New Features +* Look-and-say sequence + +## v0.13.0 - 2016-10-17 + +### New Features +* Custom exception classes + +### Improvements +* Refactor exceptions to use custom exception classes + +## v0.12.0 - 2016-10-06 + +### New Features +* Softmax function +* Effect size η² (Eta-squared) +* Effect size η²p (Partial eta-squared) +* Effect size ω² (omega-squared) +* Effect size Cohen's ƒ² +* Effect size Cohen's q +* Effect size Cohen's d +* Effect size Hedges' g +* Effect size Glass' Δ (glass' delta) + +### Improvements +* Replace mt_rand with random_int + +## v0.11.0 - 2016-10-01 + +### Backwards Incompatible Changes +* Change root namespace from Math to MathPHP + * (Run composer update to update autoloader) + +## v0.10.0 - 2016-09-28 + +### New Features +* Clamped Cubic Spline Interpolation +* Custom variable in Polynomial class + +## v0.9.0 - 2016-09-27 + +### New Features +* Natural cubic spline interpolation +* Vector direct product + +## v0.8.0 - 2016-09-22 + +### New Features +* Set Theory +* Matrix kronecker product +* Matrix augment below + +### Backwards Incompatible Changes +* Some null return values changed to NAN when computation is invalid + + +## v0.7.0 - 2016-09-19 + +### New Features +* Matrix solve linear system of equations +* Noncentral T distribution +* Piecewise function class +* Initial Finance class (pmt function) +* Vector scalar multiplication +* Vector normalization +* Vector scalar division +* Vector perpendicular operator +* Vector projections +* Vector perp and perp dot product + +### Improvements +* Add getters to Polynomial for degree and coefficients +* Improvements to gamma function + +## v0.6.1 - 2016-09-11 + +### Improvements +* Fix matrix determinant calculation + +## v0.6.0 - 2016-09-10 + +### New Features +* Polynomial class +* Vector cross product + +## v0.5.0 - 2016-09-07 + +### New Features +* Numerical Differentiation (\Math\NumericalAnalysis\NumericalDifferentiation) + * Three Point Formula (\Math\NumericalAnalysis\NumericalDifferentiation\ThreePointFormula) + * Five Point Formula (\Math\NumericalAnalysis\NumericalDifferentiation\FivePointFormula) + * SecondDerivativeMidpointFormula (\Math\NumericalAnalysis\NumericalDifferentiation\SecondDerivativeMidpointFormula) +* Two-way ANOVA (\Math\Statistics\ANOVA) + +## v0.4.0 - 2016-09-07 + +### New Features + +* Nevilles Method (\Math\NumericalAnalysis\Interpolation) +* Newton Polynomial (\Math\NumericalAnalysis\Interpolation) + +## v0.3.0 - 2016-09-06 + +### New Features + +* Lagrange polynomials (\Math\NumericalAnalysis\Interpolation) +* Function arithmetic (\Math\Functions\Arithmetic) + +## v0.2.0 - 2016-09-05 + +### New Features + +* One-way ANOVA (```Math\Statistics\ANOVA```) +* χ² Table (```Math\Probability\Distribution\Table```) +* Five number summary (```Math\Statistics\Descriptive```) +* Simple sum of squares (```Math\Statistics\RandomVariable```) + +### Improvements + +* Refactor probability distribution tables (```Math\Probability\Distribution\Table```) +* Minor refactors + +### Backwards Incompatible Changes + +* Move probability distribution tables to new namespace + * From ```Math\Probability``` to ```Math\Probability\Distribution\Table``` + +## v0.1.0 - 2016-09-02 + +### New Features + + * Algebra + * Functions + - Map + - Special Functions + * Linear Algebra + - Matrix + - Vector + * Numerical Analysis + - Numerical Integration + - Root Finding + * Probability + - Combinatorics + - Distributions + * Continuous + * Discrete + - Standard Normal Table (Z Table) + - t Distribution Table + * Sequences + - Basic + - Advanced + * Statistics + - Averages + - Correlation + - Descriptive + - Distributions + - Experiments + - Random Variables + - Regressions + - Significance Testing \ No newline at end of file diff --git a/htdocs/includes/markrogoyski/math-php/LICENSE.txt b/htdocs/includes/markrogoyski/math-php/LICENSE.txt new file mode 100644 index 00000000000..9e297cb14d5 --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Mark Rogoyski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/htdocs/includes/markrogoyski/math-php/README.md b/htdocs/includes/markrogoyski/math-php/README.md new file mode 100644 index 00000000000..71a125b8ed3 --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/README.md @@ -0,0 +1,2796 @@ +![MathPHP Logo](https://github.com/markrogoyski/math-php/blob/master/docs/image/MathPHPLogo.png?raw=true) + +### MathPHP - Powerful Modern Math Library for PHP + +The only library you need to integrate mathematical functions into your applications. It is a self-contained library in pure PHP with no external dependencies. + +[![Coverage Status](https://coveralls.io/repos/github/markrogoyski/math-php/badge.svg?branch=master)](https://coveralls.io/github/markrogoyski/math-php?branch=master) +[![License](https://poser.pugx.org/markrogoyski/math-php/license)](https://packagist.org/packages/markrogoyski/math-php) + +Features +-------- + * [Algebra](#algebra) + * [Arithmetic](#arithmetic) + * Expression + - [Polynomial](#expression---polynomial) + * [Finance](#finance) + * Functions + - [Map](#functions---map---single-array) + - [Special Functions](#functions---special-functions) + * Information Theory + - [Entropy](#information-theory---entropy) + * Linear Algebra + - [Matrix](#linear-algebra---matrix) + - [Vector](#linear-algebra---vector) + * Numbers + - [Arbitrary Integer](#number---arbitrary-length-integers) + - [Complex](#number---complex-numbers) + - [Quaternion](#number---quaternion) + - [Rational](#number---rational-numbers) + * Number Theory + - [Integers](#number-theory---integers) + * Numerical Analysis + - [Interpolation](#numerical-analysis---interpolation) + - [Numerical Differentiation](#numerical-analysis---numerical-differentiation) + - [Numerical Integration](#numerical-analysis---numerical-integration) + - [Root Finding](#numerical-analysis---root-finding) + * Probability + - [Combinatorics](#probability---combinatorics) + - Distributions + * [Continuous](#probability---continuous-distributions) + * [Discrete](#probability---discrete-distributions) + * [Multivariate](#probability---multivariate-distributions) + * [Tables](#probability---distribution-tables) + * [Sample Data](#sample-data) + * [Search](#search) + * Sequences + - [Basic](#sequences---basic) + - [Advanced](#sequences---advanced) + - [NonInteger](#sequences---non-integer) + * [Set Theory](#set-theory) + * Statistics + - [ANOVA](#statistics---anova) + - [Averages](#statistics---averages) + - [Circular](#statistics---circular) + - [Correlation](#statistics---correlation) + - [Descriptive](#statistics---descriptive) + - [Distance](#statistics---distance) + - [Distributions](#statistics---distributions) + - [Divergence](#statistics---divergence) + - [Effect Size](#statistics---effect-size) + - [Experiments](#statistics---experiments) + - [Kernel Density Estimation](#statistics---kernel-density-estimation) + - Multivariate + * [PCA (Principal Component Analysis)](#statistics---multivariate---principal-component-analysis) + * [PLS (Partial Least Squares Regression)](#statistics---multivariate---partial-least-squares-regression) + - [Outlier](#statistics---outlier) + - [Random Variables](#statistics---random-variables) + - [Regressions](#statistics---regressions) + - [Significance Testing](#statistics---significance-testing) + * [Trigonometry](#trigonometry) + +Setup +----- + + Add the library to your `composer.json` file in your project: + +```javascript +{ + "require": { + "markrogoyski/math-php": "2.*" + } +} +``` + +Use [composer](http://getcomposer.org) to install the library: + +```bash +$ php composer.phar install +``` + +Composer will install MathPHP inside your vendor folder. Then you can add the following to your +.php files to use the library with Autoloading. + +```php +require_once __DIR__ . '/vendor/autoload.php'; +``` + +Alternatively, use composer on the command line to require and install MathPHP: + +``` +$ php composer.phar require markrogoyski/math-php:2.* +``` + +### Minimum Requirements + * PHP 7.2 + + Note: For PHP 7.0 and 7.1, use v1.0 (`markrogoyski/math-php:1.*`) + +Usage +----- + +### Algebra +```php +use MathPHP\Algebra; + +// Greatest common divisor (GCD) +$gcd = Algebra::gcd(8, 12); + +// Extended greatest common divisor - gcd(a, b) = a*a' + b*b' +$gcd = Algebra::extendedGcd(12, 8); // returns array [gcd, a', b'] + +// Least common multiple (LCM) +$lcm = Algebra::lcm(5, 2); + +// Factors of an integer +$factors = Algebra::factors(12); // returns [1, 2, 3, 4, 6, 12] + +// Linear equation of one variable: ax + b = 0 +[$a, $b] = [2, 4]; // 2x + 4 = 0 +$x = Algebra::linear($a, $b); + +// Quadratic equation: ax² + bx + c = 0 +[$a, $b, $c] = [1, 2, -8]; // x² + 2x - 8 +[$x₁, $x₂] = Algebra::quadratic($a, $b, $c); + +// Discriminant: Δ = b² - 4ac +[$a, $b, $c] = [2, 3, 4]; // 3² - 4(2)(4) +$Δ = Algebra::discriminant($a, $b, $c); + +// Cubic equation: z³ + a₂z² + a₁z + a₀ = 0 +[$a₃, $a₂, $a₁, $a₀] = [2, 9, 3, -4]; // 2x³ + 9x² + 3x -4 +[$x₁, $x₂, $x₃] = Algebra::cubic($a₃, $a₂, $a₁, $a₀); + +// Quartic equation: a₄z⁴ + a₃z³ + a₂z² + a₁z + a₀ = 0 +[$a₄, $a₃, $a₂, $a₁, $a₀] = [1, -10, 35, -50, 24]; // z⁴ - 10z³ + 35z² - 50z + 24 = 0 +[$z₁, $z₂, $z₃, $z₄] = Algebra::quartic($a₄, $a₃, $a₂, $a₁, $a₀); +``` + +### Arithmetic +```php +use MathPHP\Arithmetic; + +$√x = Arithmetic::isqrt(8); // 2 Integer square root +$³√x = Arithmetic::cubeRoot(-8); // -2 +$ⁿ√x = Arithmetic::root(81, 4); // nᵗʰ root (4ᵗʰ): 3 + +// Sum of digits +$digit_sum = Arithmetic::digitSum(99); // 18 +$digital_root = Arithmetic::digitalRoot(99); // 9 + +// Equality of numbers within a tolerance +$x = 0.00000003458; +$y = 0.00000003455; +$ε = 0.0000000001; +$almostEqual = Arithmetic::almostEqual($x, $y, $ε); // true + +// Copy sign +$magnitude = 5; +$sign = -3; +$signed_magnitude = Arithmetic::copySign($magnitude, $sign); // -5 + +// Modulo (Differs from PHP remainder (%) operator for negative numbers) +$dividend = 12; +$divisor = 5; +$modulo = Arithmetic::modulo($dividend, $divisor); // 2 +$modulo = Arithmetic::modulo(-$dividend, $divisor); // 3 +``` + +### Expression - Polynomial +```php +use MathPHP\Expression\Polynomial; + +// Polynomial x² + 2x + 3 +$coefficients = [1, 2, 3] +$polynomial = new Polynomial($coefficients); + +// Evaluate for x = 3 +$x = 3; +$y = $polynomial($x); // 18: 3² + 2*3 + 3 + +// Calculus +$derivative = $polynomial->differentiate(); // Polynomial 2x + 2 +$integral = $polynomial->integrate(); // Polynomial ⅓x³ + x² + 3x + +// Arithmetic +$sum = $polynomial->add($polynomial); // Polynomial 2x² + 4x + 6 +$sum = $polynomial->add(2); // Polynomial x² + 2x + 5 +$difference = $polynomial->subtract($polynomial); // Polynomial 0 +$difference = $polynomial->subtract(2); // Polynomial x² + 2x + 1 +$product = $polynomial->multiply($polynomial); // Polynomial x⁴ + 4x³ + 10x² + 12x + 9 +$product = $polynomial->multiply(2); // Polynomial 2x² + 4x + 6 +$negated = $polynomial->negate(); // Polynomial -x² - 2x - 3 + +// Data +$degree = $polynomial->getDegree(); // 2 +$coefficients = $polynomial->getCoefficients(); // [1, 2, 3] + +// String representation +print($polynomial); // x² + 2x + 3 + +// Roots +$polynomial = new Polynomial([1, -3, -4]); +$roots = $polynomial->roots(); // [-1, 4] + +// Companion matrix +$companion = $polynomial->companionMatrix(); +``` + +### Finance +```php +use MathPHP\Finance; + +// Financial payment for a loan or annuity with compound interest +$rate = 0.035 / 12; // 3.5% interest paid at the end of every month +$periods = 30 * 12; // 30-year mortgage +$present_value = 265000; // Mortgage note of $265,000.00 +$future_value = 0; +$beginning = false; // Adjust the payment to the beginning or end of the period +$pmt = Finance::pmt($rate, $periods, $present_value, $future_value, $beginning); + +// Interest on a financial payment for a loan or annuity with compound interest. +$period = 1; // First payment period +$ipmt = Finance::ipmt($rate, $period, $periods, $present_value, $future_value, $beginning); + +// Principle on a financial payment for a loan or annuity with compound interest +$ppmt = Finance::ppmt($rate, $period, $periods, $present_value, $future_value = 0, $beginning); + +// Number of payment periods of an annuity. +$periods = Finance::periods($rate, $payment, $present_value, $future_value, $beginning); + +// Annual Equivalent Rate (AER) of an annual percentage rate (APR) +$nominal = 0.035; // APR 3.5% interest +$periods = 12; // Compounded monthly +$aer = Finance::aer($nominal, $periods); + +// Annual nominal rate of an annual effective rate (AER) +$nomial = Finance::nominal($aer, $periods); + +// Future value for a loan or annuity with compound interest +$payment = 1189.97; +$fv = Finance::fv($rate, $periods, $payment, $present_value, $beginning) + +// Present value for a loan or annuity with compound interest +$pv = Finance::pv($rate, $periods, $payment, $future_value, $beginning) + +// Net present value of cash flows +$values = [-1000, 100, 200, 300, 400]; +$npv = Finance::npv($rate, $values); + +// Interest rate per period of an annuity +$beginning = false; // Adjust the payment to the beginning or end of the period +$rate = Finance::rate($periods, $payment, $present_value, $future_value, $beginning); + +// Internal rate of return +$values = [-100, 50, 40, 30]; +$irr = Finance::irr($values); // Rate of return of an initial investment of $100 with returns of $50, $40, and $30 + +// Modified internal rate of return +$finance_rate = 0.05; // 5% financing +$reinvestment_rate = 0.10; // reinvested at 10% +$mirr = Finance::mirr($values, $finance_rate); // rate of return of an initial investment of $100 at 5% financing with returns of $50, $40, and $30 reinvested at 10% + +// Discounted payback of an investment +$values = [-1000, 100, 200, 300, 400, 500]; +$rate = 0.1; +$payback = Finance::payback($values, $rate); // The payback period of an investment with a $1,000 investment and future returns of $100, $200, $300, $400, $500 and a discount rate of 0.10 + +// Profitability index +$values = [-100, 50, 50, 50]; +$profitability_index = Finance::profitabilityIndex($values, $rate); // The profitability index of an initial $100 investment with future returns of $50, $50, $50 with a 10% discount rate +``` + +### Functions - Map - Single Array +```php +use MathPHP\Functions\Map; + +$x = [1, 2, 3, 4]; + +$sums = Map\Single::add($x, 2); // [3, 4, 5, 6] +$differences = Map\Single::subtract($x, 1); // [0, 1, 2, 3] +$products = Map\Single::multiply($x, 5); // [5, 10, 15, 20] +$quotients = Map\Single::divide($x, 2); // [0.5, 1, 1.5, 2] +$x² = Map\Single::square($x); // [1, 4, 9, 16] +$x³ = Map\Single::cube($x); // [1, 8, 27, 64] +$x⁴ = Map\Single::pow($x, 4); // [1, 16, 81, 256] +$√x = Map\Single::sqrt($x); // [1, 1.414, 1.732, 2] +$∣x∣ = Map\Single::abs($x); // [1, 2, 3, 4] +$maxes = Map\Single::max($x, 3); // [3, 3, 3, 4] +$mins = Map\Single::min($x, 3); // [1, 2, 3, 3] +$reciprocals = Map\Single::reciprocal($x); // [1, 1/2, 1/3, 1/4] +``` + +### Functions - Map - Multiple Arrays +```php +use MathPHP\Functions\Map; + +$x = [10, 10, 10, 10]; +$y = [1, 2, 5, 10]; + +// Map function against elements of two or more arrays, item by item (by item ...) +$sums = Map\Multi::add($x, $y); // [11, 12, 15, 20] +$differences = Map\Multi::subtract($x, $y); // [9, 8, 5, 0] +$products = Map\Multi::multiply($x, $y); // [10, 20, 50, 100] +$quotients = Map\Multi::divide($x, $y); // [10, 5, 2, 1] +$maxes = Map\Multi::max($x, $y); // [10, 10, 10, 10] +$mins = Map\Multi::mins($x, $y); // [1, 2, 5, 10] + +// All functions work on multiple arrays; not limited to just two +$x = [10, 10, 10, 10]; +$y = [1, 2, 5, 10]; +$z = [4, 5, 6, 7]; +$sums = Map\Multi::add($x, $y, $z); // [15, 17, 21, 27] +``` + +### Functions - Special Functions +```php +use MathPHP\Functions\Special; + +// Gamma function Γ(z) +$z = 4; +$Γ = Special::gamma($z); +$Γ = Special::gammaLanczos($z); // Lanczos approximation +$Γ = Special::gammaStirling($z); // Stirling approximation +$l = Special::logGamma($z); +$c = Special::logGammaCorr($z); // Log gamma correction + +// Incomplete gamma functions - γ(s,t), Γ(s,x), P(s,x) +[$x, $s] = [1, 2]; +$γ = Special::lowerIncompleteGamma($x, $s); +$Γ = Special::upperIncompleteGamma($x, $s); +$P = Special::regularizedLowerIncompleteGamma($x, $s); + +// Beta function +[$x, $y] = [1, 2]; +$β = Special::beta($x, $y); +$lβ = Special::logBeta($x, $y); + +// Incomplete beta functions +[$x, $a, $b] = [0.4, 2, 3]; +$B = Special::incompleteBeta($x, $a, $b); +$Iₓ = Special::regularizedIncompleteBeta($x, $a, $b); + +// Multivariate beta function +$αs = [1, 2, 3]; +$β = Special::multivariateBeta($αs); + +// Error function (Gauss error function) +$error = Special::errorFunction(2); // same as erf +$error = Special::erf(2); // same as errorFunction +$error = Special::complementaryErrorFunction(2); // same as erfc +$error = Special::erfc(2); // same as complementaryErrorFunction + +// Hypergeometric functions +$pFq = Special::generalizedHypergeometric($p, $q, $a, $b, $c, $z); +$₁F₁ = Special::confluentHypergeometric($a, $b, $z); +$₂F₁ = Special::hypergeometric($a, $b, $c, $z); + +// Sign function (also known as signum or sgn) +$x = 4; +$sign = Special::signum($x); // same as sgn +$sign = Special::sgn($x); // same as signum + +// Logistic function (logistic sigmoid function) +$x₀ = 2; // x-value of the sigmoid's midpoint +$L = 3; // the curve's maximum value +$k = 4; // the steepness of the curve +$x = 5; +$logistic = Special::logistic($x₀, $L, $k, $x); + +// Sigmoid function +$t = 2; +$sigmoid = Special::sigmoid($t); + +// Softmax function +$𝐳 = [1, 2, 3, 4, 1, 2, 3]; +$σ⟮𝐳⟯ⱼ = Special::softmax($𝐳); + +// Log of the error term in the Stirling-De Moivre factorial series +$err = Special::stirlingError($n); +``` + +### Information Theory - Entropy +```php +use MathPHP\InformationTheory\Entropy; + +// Probability distributions +$p = [0.2, 0.5, 0.3]; +$q = [0.1, 0.4, 0.5]; + +// Shannon entropy +$bits = Entropy::shannonEntropy($p); // log₂ +$nats = Entropy::shannonNatEntropy($p); // ln +$harts = Entropy::shannonHartleyEntropy($p); // log₁₀ + +// Cross entropy +$H⟮p、q⟯ = Entropy::crossEntropy($p, $q); // log₂ + +// Joint entropy +$P⟮x、y⟯ = [1/2, 1/4, 1/4, 0]; +H⟮x、y⟯ = Entropy::jointEntropy($P⟮x、y⟯); // log₂ + +// Rényi entropy +$α = 0.5; +$Hₐ⟮X⟯ = Entropy::renyiEntropy($p, $α); // log₂ + +// Perplexity +$perplexity = Entropy::perplexity($p); // log₂ +``` + +### Linear Algebra - Matrix +```php +use MathPHP\LinearAlgebra\Matrix; +use MathPHP\LinearAlgebra\MatrixFactory; + +// Create an m × n matrix from an array of arrays +$matrix = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]; +$A = MatrixFactory::create($matrix); + +// Basic matrix data +$array = $A->getMatrix(); // Original array of arrays +$rows = $A->getM(); // number of rows +$cols = $A->getN(); // number of columns + +// Basic matrix element getters (zero-based indexing) +$row = $A->getRow(2); +$col = $A->getColumn(2); +$Aᵢⱼ = $A->get(2, 2); +$Aᵢⱼ = $A[2][2]; + +// Row operations +[$mᵢ, $mⱼ, $k] = [1, 2, 5]; +$R = $A->rowInterchange($mᵢ, $mⱼ); +$R = $A->rowExclude($mᵢ); // Exclude row $mᵢ +$R = $A->rowMultiply($mᵢ, $k); // Multiply row mᵢ by k +$R = $A->rowDivide($mᵢ, $k); // Divide row mᵢ by k +$R = $A->rowAdd($mᵢ, $mⱼ, $k); // Add k * row mᵢ to row mⱼ +$R = $A->rowAddScalar($mᵢ, $k); // Add k to each item of row mᵢ +$R = $A->rowAddVector($mᵢ, $V); // Add Vector V to row mᵢ +$R = $A->rowSubtract($mᵢ, $mⱼ, $k); // Subtract k * row mᵢ from row mⱼ +$R = $A->rowSubtractScalar($mᵢ, $k); // Subtract k from each item of row mᵢ + +// Column operations +[$nᵢ, $nⱼ, $k] = [1, 2, 5]; +$R = $A->columnInterchange($nᵢ, $nⱼ); +$R = $A->columnExclude($nᵢ); // Exclude column $nᵢ +$R = $A->columnMultiply($nᵢ, $k); // Multiply column nᵢ by k +$R = $A->columnAdd($nᵢ, $nⱼ, $k); // Add k * column nᵢ to column nⱼ +$R = $A->columnAddVector($nᵢ, $V); // Add Vector V to column nᵢ + +// Matrix augmentations - return a new Matrix +$⟮A∣B⟯ = $A->augment($B); // Augment on the right - standard augmentation +$⟮A∣I⟯ = $A->augmentIdentity(); // Augment with the identity matrix +$⟮A∣B⟯ = $A->augmentBelow($B); +$⟮A∣B⟯ = $A->augmentAbove($B); +$⟮B∣A⟯ = $A->augmentLeft($B); + +// Matrix arithmetic operations - return a new Matrix +$A+B = $A->add($B); +$A⊕B = $A->directSum($B); +$A⊕B = $A->kroneckerSum($B); +$A−B = $A->subtract($B); +$AB = $A->multiply($B); +$2A = $A->scalarMultiply(2); +$A/2 = $A->scalarDivide(2); +$−A = $A->negate(); +$A∘B = $A->hadamardProduct($B); +$A⊗B = $A->kroneckerProduct($B); + +// Matrix operations - return a new Matrix +$Aᵀ   = $A->transpose(); +$D   = $A->diagonal(); +$A⁻¹ = $A->inverse(); +$Mᵢⱼ = $A->minorMatrix($mᵢ, $nⱼ); // Square matrix with row mᵢ and column nⱼ removed +$Mk = $A->leadingPrincipalMinor($k); // kᵗʰ-order leading principal minor +$CM = $A->cofactorMatrix(); +$B = $A->meanDeviation(); // optional parameter to specify data direction (variables in 'rows' or 'columns') +$S = $A->covarianceMatrix(); // optional parameter to specify data direction (variables in 'rows' or 'columns') +$adj⟮A⟯ = $A->adjugate(); +$Mᵢⱼ = $A->submatrix($mᵢ, $nᵢ, $mⱼ, $nⱼ) // Submatrix of A from row mᵢ, column nᵢ to row mⱼ, column nⱼ +$H = $A->householder(); + +// Matrix value operations - return a value +$tr⟮A⟯ = $A->trace(); +$|A| = $a->det(); // Determinant +$Mᵢⱼ = $A->minor($mᵢ, $nⱼ); // First minor +$Cᵢⱼ = $A->cofactor($mᵢ, $nⱼ); +$rank⟮A⟯ = $A->rank(); + +// Matrix vector operations - return a new Vector +$AB = $A->vectorMultiply($X₁); +$M = $A->rowSums(); +$M = $A->columnSums(); +$M = $A->rowMeans(); +$M = $A->columnMeans(); + +// Matrix norms - return a value +$‖A‖₁ = $A->oneNorm(); +$‖A‖F = $A->frobeniusNorm(); // Hilbert–Schmidt norm +$‖A‖∞ = $A->infinityNorm(); +$max = $A->maxNorm(); + +// Matrix reductions +$ref = $A->ref(); // Matrix in row echelon form +$rref = $A->rref(); // Matrix in reduced row echelon form + +// Matrix decompositions +// LU decomposition +$LU = $A->luDecomposition(); +$L = $LU->L; // lower triangular matrix +$U = $LU->U; // upper triangular matrix +$P = $LU-P; // permutation matrix + +// QR decomposition +$QR = $A->qrDecomposition(); +$Q = $QR->Q; // orthogonal matrix +$R = $QR->R; // upper triangular matrix + +// SVD (Singular Value Decomposition) +$SVD = $A->svd(); +$U = $A->U; // m x m orthogonal matrix +$V = $A->V; // n x n orthogonal matrix +$S = $A->S; // m x n diagonal matrix of singular values +$D = $A->D; // Vector of diagonal elements from S + +// Crout decomposition +$LU = $A->croutDecomposition(); +$L = $LU->L; // lower triangular matrix +$U = $LU->U; // normalized upper triangular matrix + +// Cholesky decomposition +$LLᵀ = $A->choleskyDecomposition(); +$L = $LLᵀ->L; // lower triangular matrix +$LT = $LLᵀ->LT; // transpose of lower triangular matrix + +// Eigenvalues and eigenvectors +$eigenvalues = $A->eigenvalues(); // array of eigenvalues +$eigenvecetors = $A->eigenvectors(); // Matrix of eigenvectors + +// Solve a linear system of equations: Ax = b +$b = new Vector(1, 2, 3); +$x = $A->solve($b); + +// Map a function over each element +$func = function($x) { + return $x * 2; +}; +$R = $A->map($func); // using closure +$R = $A->map('abs'); // using callable + +// Map a function over each row +$array = $A->mapRows('array_reverse'); // using callable returns matrix-like array of arrays +$array = $A->mapRows('array_sum'); // using callable returns array of aggregate calculations + +// Walk maps a function to all values without mutation or returning a value +$A->walk($func); + +// Matrix comparisons +$bool = $A->isEqual($B); + +// Matrix properties - return a bool +$bool = $A->isSquare(); +$bool = $A->isSymmetric(); +$bool = $A->isSkewSymmetric(); +$bool = $A->isSingular(); +$bool = $A->isNonsingular(); // Same as isInvertible +$bool = $A->isInvertible(); // Same as isNonsingular +$bool = $A->isPositiveDefinite(); +$bool = $A->isPositiveSemidefinite(); +$bool = $A->isNegativeDefinite(); +$bool = $A->isNegativeSemidefinite(); +$bool = $A->isLowerTriangular(); +$bool = $A->isUpperTriangular(); +$bool = $A->isTriangular(); +$bool = $A->isDiagonal(); +$bool = $A->isRectangularDiagonal(); +$bool = $A->isUpperBidiagonal(); +$bool = $A->isLowerBidiagonal(); +$bool = $A->isBidiagonal(); +$bool = $A->isTridiagonal(); +$bool = $A->isUpperHessenberg(); +$bool = $A->isLowerHessenberg(); +$bool = $A->isOrthogonal(); +$bool = $A->isNormal(); +$bool = $A->isIdempotent(); +$bool = $A->isNilpotent(); +$bool = $A->isInvolutory(); +$bool = $A->isSignature(); +$bool = $A->isRef(); +$bool = $A->isRref(); + +// Other representations of matrix data +$vectors = $A->asVectors(); // array of column vectors +$D = $A->getDiagonalElements(); // array of the diagonal elements +$d = $A->getSuperdiagonalElements(); // array of the superdiagonal elements +$d = $A->getSubdiagonalElements(); // array of the subdiagonal elements + +// String representation - Print a matrix +print($A); +/* + [1, 2, 3] + [2, 3, 4] + [3, 4, 5] + */ + +// PHP Predefined Interfaces +$json = json_encode($A); // JsonSerializable +$Aᵢⱼ = $A[$mᵢ][$nⱼ]; // ArrayAccess +``` + +#### Linear Algebra - Matrix Construction (Factory) +```php +$matrix = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], +]; + +// Matrix factory creates most appropriate matrix +$A = MatrixFactory::create($matrix); + +// Matrix factory can create a matrix from an array of column vectors +use MathPHP\LinearAlgebra\Vector; +$X₁ = new Vector([1, 4, 7]); +$X₂ = new Vector([2, 5, 8]); +$X₃ = new Vector([3, 6, 9]); +$A = MatrixFactory::createFromVectors([$X₁, $X₂, $X₃]); + +// Create from row or column vector +$A = MatrixFactory::createFromRowVector([1, 2, 3]); // 1 × n matrix consisting of a single row of n elements +$A = MatrixFactory::createFromColumnVector([1, 2, 3]); // m × 1 matrix consisting of a single column of m elements + +// Specialized matrices +[$m, $n, $k, $angle, $size] = [4, 4, 2, 3.14159, 2]; +$identity_matrix = MatrixFactory::identity($n); // Ones on the main diagonal +$zero_matrix = MatrixFactory::zero($m, $n); // All zeros +$ones_matrix = MatrixFactory::one($m, $n); // All ones +$eye_matrix = MatrixFactory::eye($m, $n, $k); // Ones (or other value) on the k-th diagonal +$exchange_matrix = MatrixFactory::exchange($n); // Ones on the reverse diagonal +$downshift_permutation_matrix = MatrixFactory::downshiftPermutation($n); // Permutation matrix that pushes the components of a vector down one notch with wraparound +$upshift_permutation_matrix = MatrixFactory::upshiftPermutation($n); // Permutation matrix that pushes the components of a vector up one notch with wraparound +$diagonal_matrix = MatrixFactory::diagonal([1, 2, 3]); // 3 x 3 diagonal matrix with zeros above and below the diagonal +$hilbert_matrix = MatrixFactory::hilbert($n); // Square matrix with entries being the unit fractions +$vandermonde_matrix = MatrixFactory::vandermonde([1, 2, 3], 4); // 4 x 3 Vandermonde matrix +$random_matrix = MatrixFactory::random($m, $n); // m x n matrix of random integers +$givens_matrix = MatrixFactory::givens($m, $n, $angle, $size); // givens rotation matrix +``` + +### Linear Algebra - Vector +```php +use MathPHP\LinearAlgebra\Vector; + +// Vector +$A = new Vector([1, 2]); +$B = new Vector([2, 4]); + +// Basic vector data +$array = $A->getVector(); +$n = $A->getN(); // number of elements +$M = $A->asColumnMatrix(); // Vector as an nx1 matrix +$M = $A->asRowMatrix(); // Vector as a 1xn matrix + +// Basic vector elements (zero-based indexing) +$item = $A->get(1); + +// Vector numeric operations - return a value +$sum = $A->sum(); +$│A│ = $A->length(); // same as l2Norm +$max = $A->max(); +$min = $A->min(); +$A⋅B = $A->dotProduct($B); // same as innerProduct +$A⋅B = $A->innerProduct($B); // same as dotProduct +$A⊥⋅B = $A->perpDotProduct($B); +$radAngle = $A->angleBetween($B); // angle in radians +$degAngle = $A->angleBetween($B, $inDegrees = true); // angle in degrees +$taxicabDistance = $A->l1Distance($B); // same as minkowskiDistance($B, 1) +$euclidDistance = $A->l2Distance($B); // same as minkowskiDistance($B, 2) +$minkowskiDistance = $A->minkowskiDistance($B, $p = 2); + +// Vector arithmetic operations - return a Vector +$A+B = $A->add($B); +$A−B = $A->subtract($B); +$A×B = $A->multiply($B); +$A/B = $A->divide($B); +$kA = $A->scalarMultiply($k); +$A/k = $A->scalarDivide($k); + +// Vector operations - return a Vector or Matrix +$A⨂B = $A->outerProduct($B); // Same as direct product +$AB = $A->directProduct($B); // Same as outer product +$AxB = $A->crossProduct($B); +$A⨂B = $A->kroneckerProduct($B); +$ = $A->normalize(); +$A⊥ = $A->perpendicular(); +$projᵇA = $A->projection($B); // projection of A onto B +$perpᵇA = $A->perp($B); // perpendicular of A on B + +// Vector norms - return a value +$l₁norm = $A->l1Norm(); +$l²norm = $A->l2Norm(); +$pnorm = $A->pNorm(); +$max = $A->maxNorm(); + +// String representation +print($A); // [1, 2] + +// PHP standard interfaces +$n = count($A); // Countable +$json = json_encode($A); // JsonSerializable +$Aᵢ = $A[$i]; // ArrayAccess +foreach ($A as $element) { ... } // Iterator +``` + +### Number - Arbitrary Length Integers +```php +use MathPHP\Number; +use MathPHP\Functions; + +// Create arbitrary-length big integers from int or string +$bigInt = new Number\ArbitraryInteger('876937869482938749389832'); + +// Unary functions +$−bigInt = $bigInt->negate(); +$√bigInt = $bigInt->isqrt(); // Integer square root +$│bitInt│ = $bigInt->abs(); // Absolute value +$bigInt! = $bigInt->fact(); +$bool = $bigInt->isPositive(); + +// Binary functions +$sum = $bigInt->add($bigInt); +$difference = $bigInt->subtract($bigInt); +$product = $bigInt->multiply($bigInt); +$quotient = $bigInt->intdiv($divisor); +$mod = $bigInt->mod($divisor); +[$quotient, $mod] = $bigInt->fullIntdiv($divisor); +$pow = $bigInt->pow($exponent); +$shifted = $bigInt->leftShift(2); + +// Comparison functions +$bool = $bigInt->equals($bigInt); +$bool = $bigInt->greaterThan($bigInt); +$bool = $bigInt->lessThan($bigInt); + +// Conversions +$int = $bigInt->toInt(); +$float = $bigInt->toFloat(); +$binary = $bigInt->toBinary(); +$string = (string) $bigInt; + +// Functions +$ackermann = Functions\ArbitraryInteger::ackermann($bigInt); +$randomBigInt = Functions\ArbitaryInteger::rand($intNumberOfBytes); +``` + +### Number - Complex Numbers +```php +use MathPHP\Number\Complex; + +[$r, $i] = [2, 4]; +$complex = new Complex($r, $i); + +// Accessors +$r = $complex->r; +$i = $complex->i; + +// Unary functions +$conjugate = $complex->complexConjugate(); +$│c│ = $complex->abs(); // absolute value (modulus) +$arg⟮c⟯ = $complex->arg(); // argument (phase) +$√c = $complex->sqrt(); // positive square root +[$z₁, $z₂] = $complex->roots(); +$c⁻¹ = $complex->inverse(); +$−c = $complex->negate(); +[$r, $θ] = $complex->polarForm(); + +// Binary functions +$c+c = $complex->add($complex); +$c−c = $complex->subtract($complex); +$c×c = $complex->multiply($complex); +$c/c = $complex->divide($complex); + +// Other functions +$bool = $complex->equals($complex); +$string = (string) $complex; +``` + +### Number - Quaternion +```php +Use MathPHP\Number\Quaternion; + +$r = 4; +$i = 1; +$j = 2; +$k = 3; + +$quaternion = new Quaternion($r, $i, $j, $k); + +// Get individual parts +[$r, $i, $j, $k] = [$quaternion->r, $quaternion->i, $quaternion->j, $quaternion->k]; + +// Unary functions +$conjugate = $quaternion->complexConjugate(); +$│q│ = $quaternion->abs(); // absolute value (magnitude) +$quaternion⁻¹ = $quaternion->inverse(); +$−q = $quaternion->negate(); + +// Binary functions +$q+q = $quaternion->add($quaternion); +$q−q = $quaternion->subtract($quaternion); +$q×q = $quaternion->multiply($quaternion); +$q/q = $quaternion->divide($quaternion); + +// Other functions +$bool = $quaternion->equals($quaternion); +``` + +### Number - Rational Numbers +```php +use MathPHP\Number\Rational; + +$whole = 0; +$numerator = 2; +$denominator = 3; + +$rational = new Rational($whole, $numerator, $denominator); // ²/₃ + +// Get individual parts +$whole = $rational->getWholePart(); +$numerator = $rational->getNumerator(); +$denominator = $rational->getDenominator(); + +// Unary functions +$│rational│ = $rational->abs(); +$inverse = $rational->inverse(); + +// Binary functions +$sum = $rational->add($rational); +$diff = $rational->subtract($rational); +$product = $rational->multiply($rational); +$quotient = $rational->divide($rational); +$exponentiation = $rational->pow(2); + +// Other functions +$bool = $rational->equals($rational); +$float = $rational->toFloat(); +$string = (string) $rational; +``` + +### Number Theory - Integers +```php +use MathPHP\NumberTheory\Integer; + +$n = 225; + +// Prime factorization +$factors = Integer::primeFactorization($n); + +// Divisor function +$int = Integer::numberOfDivisors($n); +$int = Integer::sumOfDivisors($n); + +// Aliquot sums +$int = Integer::aliquotSum($n); // sum-of-divisors - n +$bool = Integer::isPerfectNumber($n); // n = aliquot sum +$bool = Integer::isDeficientNumber($n); // n > aliquot sum +$bool = Integer::isAbundantNumber($n); // n < aliquot sum + +// Totients +$int = Integer::totient($n); // Jordan's totient k=1 (Euler's totient) +$int = Integer::totient($n, 2); // Jordan's totient k=2 +$int = Integer::cototient($n); // Cototient +$int = Integer::reducedTotient($n); // Carmichael's function + +// Möbius function +$int = Integer::mobius($n); + +// Radical/squarefree kernel +$int = Integer::radical($n); + +// Squarefree +$bool = Integer::isSquarefree($n); + +// Refactorable number +$bool = Integer::isRefactorableNumber($n); + +// Sphenic number +$bool = Integer::isSphenicNumber($n); + +// Perfect powers +$bool = Integer::isPerfectPower($n); +[$m, $k] = Integer::perfectPower($n); + +// Coprime +$bool = Integer::coprime(4, 35); + +// Even and odd +$bool = Integer::isEven($n); +$bool = Integer::isOdd($n); +``` + +### Numerical Analysis - Interpolation +```php +use MathPHP\NumericalAnalysis\Interpolation; + +// Interpolation is a method of constructing new data points with the range +// of a discrete set of known data points. +// Each integration method can take input in two ways: +// 1) As a set of points (inputs and outputs of a function) +// 2) As a callback function, and the number of function evaluations to +// perform on an interval between a start and end point. + +// Input as a set of points +$points = [[0, 1], [1, 4], [2, 9], [3, 16]]; + +// Input as a callback function +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 4]; + +// Lagrange Polynomial +// Returns a function p(x) of x +$p = Interpolation\LagrangePolynomial::interpolate($points); // input as a set of points +$p = Interpolation\LagrangePolynomial::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function + +$p(0) // 1 +$p(3) // 16 + +// Nevilles Method +// More accurate than Lagrange Polynomial Interpolation given the same input +// Returns the evaluation of the interpolating polynomial at the $target point +$target = 2; +$result = Interpolation\NevillesMethod::interpolate($target, $points); // input as a set of points +$result = Interpolation\NevillesMethod::interpolate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function + +// Newton Polynomial (Forward) +// Returns a function p(x) of x +$p = Interpolation\NewtonPolynomialForward::interpolate($points); // input as a set of points +$p = Interpolation\NewtonPolynomialForward::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function + +$p(0) // 1 +$p(3) // 16 + +// Natural Cubic Spline +// Returns a piecewise polynomial p(x) +$p = Interpolation\NaturalCubicSpline::interpolate($points); // input as a set of points +$p = Interpolation\NaturalCubicSpline::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function + +$p(0) // 1 +$p(3) // 16 + +// Clamped Cubic Spline +// Returns a piecewise polynomial p(x) + +// Input as a set of points +$points = [[0, 1, 0], [1, 4, -1], [2, 9, 4], [3, 16, 0]]; + +// Input as a callback function +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +$f’⟮x⟯ = function ($x) { + return 2*$x + 2; +}; +[$start, $end, $n] = [0, 3, 4]; + +$p = Interpolation\ClampedCubicSpline::interpolate($points); // input as a set of points +$p = Interpolation\ClampedCubicSpline::interpolate($f⟮x⟯, $f’⟮x⟯, $start, $end, $n); // input as a callback function + +$p(0); // 1 +$p(3); // 16 + +// Regular Grid Interpolation +// Returns a scalar + +// Points defining the regular grid +$xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +$ys = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; +$zs = [110, 111, 112, 113, 114, 115, 116, 117, 118, 119]; + +// Data on the regular grid in n dimensions +$data = []; +$func = function ($x, $y, $z) { + return 2 * $x + 3 * $y - $z; +}; +foreach ($xs as $i => $x) { + foreach ($ys as $j => $y) { + foreach ($zs as $k => $z) { + $data[$i][$j][$k] = $func($x, $y, $z); + } + } +} + +// Constructing a RegularGridInterpolator +$rgi = new Interpolation\RegularGridInterpolator([$xs, $ys, $zs], $data, 'linear'); // 'nearest' method also available + +// Interpolating coordinates on the regular grid +$coordinates = [2.21, 12.1, 115.9]; +$interpolation = $rgi($coordinates); // -75.18 +``` + +### Numerical Analysis - Numerical Differentiation +```php +use MathPHP\NumericalAnalysis\NumericalDifferentiation; + +// Numerical Differentiation approximates the derivative of a function. +// Each Differentiation method can take input in two ways: +// 1) As a set of points (inputs and outputs of a function) +// 2) As a callback function, and the number of function evaluations to +// perform on an interval between a start and end point. + +// Input as a callback function +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; + +// Three Point Formula +// Returns an approximation for the derivative of our input at our target + +// Input as a set of points +$points = [[0, 1], [1, 4], [2, 9]]; + +$target = 0; +[$start, $end, $n] = [0, 2, 3]; +$derivative = NumericalDifferentiation\ThreePointFormula::differentiate($target, $points); // input as a set of points +$derivative = NumericalDifferentiation\ThreePointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function + +// Five Point Formula +// Returns an approximation for the derivative of our input at our target + +// Input as a set of points +$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4, 25]]; + +$target = 0; +[$start, $end, $n] = [0, 4, 5]; +$derivative = NumericalDifferentiation\FivePointFormula::differentiate($target, $points); // input as a set of points +$derivative = NumericalDifferentiation\FivePointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function + +// Second Derivative Midpoint Formula +// Returns an approximation for the second derivative of our input at our target + +// Input as a set of points +$points = [[0, 1], [1, 4], [2, 9]; + +$target = 1; +[$start, $end, $n] = [0, 2, 3]; +$derivative = NumericalDifferentiation\SecondDerivativeMidpointFormula::differentiate($target, $points); // input as a set of points +$derivative = NumericalDifferentiation\SecondDerivativeMidpointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function +``` + +### Numerical Analysis - Numerical Integration +```php +use MathPHP\NumericalAnalysis\NumericalIntegration; + +// Numerical integration approximates the definite integral of a function. +// Each integration method can take input in two ways: +// 1) As a set of points (inputs and outputs of a function) +// 2) As a callback function, and the number of function evaluations to +// perform on an interval between a start and end point. + +// Trapezoidal Rule (closed Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16]]; +$∫f⟮x⟯dx = NumericalIntegration\TrapezoidalRule::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 4]; +$∫f⟮x⟯dx = NumericalIntegration\TrapezoidalRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function + +// Simpsons Rule (closed Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4,3]]; +$∫f⟮x⟯dx = NumericalIntegration\SimpsonsRule::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 5]; +$∫f⟮x⟯dx = NumericalIntegration\SimpsonsRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function + +// Simpsons 3/8 Rule (closed Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16]]; +$∫f⟮x⟯dx = NumericalIntegration\SimpsonsThreeEighthsRule::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 5]; +$∫f⟮x⟯dx = NumericalIntegration\SimpsonsThreeEighthsRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function + +// Booles Rule (closed Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4, 25]]; +$∫f⟮x⟯dx = NumericalIntegration\BoolesRule::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**3 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 4, 5]; +$∫f⟮x⟯dx = NumericalIntegration\BoolesRuleRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function + +// Rectangle Method (open Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16]]; +$∫f⟮x⟯dx = NumericalIntegration\RectangleMethod::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 4]; +$∫f⟮x⟯dx = NumericalIntegration\RectangleMethod::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function + +// Midpoint Rule (open Newton-Cotes formula) +$points = [[0, 1], [1, 4], [2, 9], [3, 16]]; +$∫f⟮x⟯dx = NumericalIntegration\MidpointRule::approximate($points); // input as a set of points + +$f⟮x⟯ = function ($x) { + return $x**2 + 2 * $x + 1; +}; +[$start, $end, $n] = [0, 3, 4]; +$∫f⟮x⟯dx = NumericalIntegration\MidpointRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function +``` + +### Numerical Analysis - Root Finding +```php +use MathPHP\NumericalAnalysis\RootFinding; + +// Root-finding methods solve for a root of a polynomial. + +// f(x) = x⁴ + 8x³ -13x² -92x + 96 +$f⟮x⟯ = function($x) { + return $x**4 + 8 * $x**3 - 13 * $x**2 - 92 * $x + 96; +}; + +// Newton's Method +$args = [-4.1]; // Parameters to pass to callback function (initial guess, other parameters) +$target = 0; // Value of f(x) we a trying to solve for +$tol = 0.00001; // Tolerance; how close to the actual solution we would like +$position = 0; // Which element in the $args array will be changed; also serves as initial guess. Defaults to 0. +$x = RootFinding\NewtonsMethod::solve($f⟮x⟯, $args, $target, $tol, $position); // Solve for x where f(x) = $target + +// Secant Method +$p₀ = -1; // First initial approximation +$p₁ = 2; // Second initial approximation +$tol = 0.00001; // Tolerance; how close to the actual solution we would like +$x = RootFinding\SecantMethod::solve($f⟮x⟯, $p₀, $p₁, $tol); // Solve for x where f(x) = 0 + +// Bisection Method +$a = 2; // The start of the interval which contains a root +$b = 5; // The end of the interval which contains a root +$tol = 0.00001; // Tolerance; how close to the actual solution we would like +$x = RootFinding\BisectionMethod::solve($f⟮x⟯, $a, $b, $tol); // Solve for x where f(x) = 0 + +// Fixed-Point Iteration +// f(x) = x⁴ + 8x³ -13x² -92x + 96 +// Rewrite f(x) = 0 as (x⁴ + 8x³ -13x² + 96)/92 = x +// Thus, g(x) = (x⁴ + 8x³ -13x² + 96)/92 +$g⟮x⟯ = function($x) { + return ($x**4 + 8 * $x**3 - 13 * $x**2 + 96)/92; +}; +$a = 0; // The start of the interval which contains a root +$b = 2; // The end of the interval which contains a root +$p = 0; // The initial guess for our root +$tol = 0.00001; // Tolerance; how close to the actual solution we would like +$x = RootFinding\FixedPointIteration::solve($g⟮x⟯, $a, $b, $p, $tol); // Solve for x where f(x) = 0 +``` + +### Probability - Combinatorics +```php +use MathPHP\Probability\Combinatorics; + +[$n, $x, $k] = [10, 3, 4]; + +// Factorials +$n! = Combinatorics::factorial($n); +$n‼︎ = Combinatorics::doubleFactorial($n); +$x⁽ⁿ⁾ = Combinatorics::risingFactorial($x, $n); +$x₍ᵢ₎ = Combinatorics::fallingFactorial($x, $n); +$!n = Combinatorics::subfactorial($n); + +// Permutations +$nPn = Combinatorics::permutations($n); // Permutations of n things, taken n at a time (same as factorial) +$nPk = Combinatorics::permutations($n, $k); // Permutations of n things, taking only k of them + +// Combinations +$nCk = Combinatorics::combinations($n, $k); // n choose k without repetition +$nC′k = Combinatorics::combinations($n, $k, Combinatorics::REPETITION); // n choose k with repetition (REPETITION const = true) + +// Central binomial coefficient +$cbc = Combinatorics::centralBinomialCoefficient($n); + +// Catalan number +$Cn = Combinatorics::catalanNumber($n); + +// Lah number +$L⟮n、k⟯ = Combinatorics::lahNumber($n, $k) + +// Multinomial coefficient +$groups = [5, 2, 3]; +$divisions = Combinatorics::multinomial($groups); +``` + +### Probability - Continuous Distributions +```php +use MathPHP\Probability\Distribution\Continuous; + +$p = 0.1; + +// Beta distribution +$α = 1; // shape parameter +$β = 1; // shape parameter +$x = 2; +$beta = new Continuous\Beta($α, $β); +$pdf = $beta->pdf($x); +$cdf = $beta->cdf($x); +$icdf = $beta->inverse($p); +$μ = $beta->mean(); +$median = $beta->median(); +$mode = $beta->mode(); +$σ² = $beta->variance(); + +// Cauchy distribution +$x₀ = 2; // location parameter +$γ = 3; // scale parameter +$x = 1; +$cauchy = new Continuous\Cauchy(x₀, γ); +$pdf = $cauchy->pdf(x); +$cdf = $cauchy->cdf(x); +$icdf = $cauchy->inverse($p); +$μ = $cauchy->mean(); +$median = $cauchy->median(); +$mode = $cauchy->mode(); + +// χ²-distribution (Chi-Squared) +$k = 2; // degrees of freedom +$x = 1; +$χ² = new Continuous\ChiSquared($k); +$pdf = $χ²->pdf($x); +$cdf = $χ²->cdf($x); +$μ = $χ²->mean($x); +$median = $χ²->median(); +$mode = $χ²->mode(); +$σ² = $χ²->variance(); + +// Dirac delta distribution +$x = 1; +$dirac = new Continuous\DiracDelta(); +$pdf = $dirac->pdf($x); +$cdf = $dirac->cdf($x); +$icdf = $dirac->inverse($p); +$μ = $dirac->mean(); + +// Exponential distribution +$λ = 1; // rate parameter +$x = 2; +$exponential = new Continuous\Exponential($λ); +$pdf = $exponential->pdf($x); +$cdf = $exponential->cdf($x); +$icdf = $exponential->inverse($p); +$μ = $exponential->mean(); +$median = $exponential->median(); +$σ² = $exponential->variance(); + +// F-distribution +$d₁ = 3; // degree of freedom v1 +$d₂ = 4; // degree of freedom v2 +$x = 2; +$f = new Continuous\F($d₁, $d₂); +$pdf = $f->pdf($x); +$cdf = $f->cdf($x); +$μ = $f->mean(); +$mode = $f->mode(); +$σ² = $f->variance(); + +// Gamma distribution +$k = 2; // shape parameter +$θ = 3; // scale parameter +$x = 4; +$gamma = new Continuous\Gamma($k, $θ); +$pdf = $gamma->pdf($x); +$cdf = $gamma->cdf($x); +$μ = $gamma->mean(); +$median = $gamma->median(); +$mode = $gamma->mode(); +$σ² = $gamma->variance(); + +// Laplace distribution +$μ = 1; // location parameter +$b = 1.5; // scale parameter (diversity) +$x = 1; +$laplace = new Continuous\Laplace($μ, $b); +$pdf = $laplace->pdf($x); +$cdf = $laplace->cdf($x); +$icdf = $laplace->inverse($p); +$μ = $laplace->mean(); +$median = $laplace->median(); +$mode = $laplace->mode(); +$σ² = $laplace->variance(); + +// Logistic distribution +$μ = 2; // location parameter +$s = 1.5; // scale parameter +$x = 3; +$logistic = new Continuous\Logistic($μ, $s); +$pdf = $logistic->pdf($x); +$cdf = $logistic->cdf($x); +$icdf = $logistic->inverse($p); +$μ = $logistic->mean(); +$median = $logistic->median(); +$mode = $logistic->mode(); +$σ² = $logisitic->variance(); + +// Log-logistic distribution (Fisk distribution) +$α = 1; // scale parameter +$β = 1; // shape parameter +$x = 2; +$logLogistic = new Continuous\LogLogistic($α, $β); +$pdf = $logLogistic->pdf($x); +$cdf = $logLogistic->cdf($x); +$icdf = $logLogistic->inverse($p); +$μ = $logLogistic->mean(); +$median = $logLogistic->median(); +$mode = $logLogistic->mode(); +$σ² = $logLogistic->variance(); + +// Log-normal distribution +$μ = 6; // scale parameter +$σ = 2; // location parameter +$x = 4.3; +$logNormal = new Continuous\LogNormal($μ, $σ); +$pdf = $logNormal->pdf($x); +$cdf = $logNormal->cdf($x); +$icdf = $logNormal->inverse($p); +$μ = $logNormal->mean(); +$median = $logNormal->median(); +$mode = $logNormal->mode(); +$σ² = $logNormal->variance(); + +// Noncentral T distribution +$ν = 50; // degrees of freedom +$μ = 10; // noncentrality parameter +$x = 8; +$noncenetralT = new Continuous\NoncentralT($ν, $μ); +$pdf = $noncenetralT->pdf($x); +$cdf = $noncenetralT->cdf($x); +$μ = $noncenetralT->mean(); + +// Normal distribution +$σ = 1; +$μ = 0; +$x = 2; +$normal = new Continuous\Normal($μ, $σ); +$pdf = $normal->pdf($x); +$cdf = $normal->cdf($x); +$icdf = $normal->inverse($p); +$μ = $normal->mean(); +$median = $normal->median(); +$mode = $normal->mode(); +$σ² = $normal->variance(); + +// Pareto distribution +$a = 1; // shape parameter +$b = 1; // scale parameter +$x = 2; +$pareto = new Continuous\Pareto($a, $b); +$pdf = $pareto->pdf($x); +$cdf = $pareto->cdf($x); +$icdf = $pareto->inverse($p); +$μ = $pareto->mean(); +$median = $pareto->median(); +$mode = $pareto->mode(); +$σ² = $pareto->variance(); + +// Standard normal distribution +$z = 2; +$standardNormal = new Continuous\StandardNormal(); +$pdf = $standardNormal->pdf($z); +$cdf = $standardNormal->cdf($z); +$icdf = $standardNormal->inverse($p); +$μ = $standardNormal->mean(); +$median = $standardNormal->median(); +$mode = $standardNormal->mode(); +$σ² = $standardNormal->variance(); + +// Student's t-distribution +$ν = 3; // degrees of freedom +$p = 0.4; // proportion of area +$x = 2; +$studentT = new Continuous\StudentT::pdf($ν); +$pdf = $studentT->pdf($x); +$cdf = $studentT->cdf($x); +$t = $studentT->inverse2Tails($p); // t such that the area greater than t and the area beneath -t is p +$μ = $studentT->mean(); +$median = $studentT->median(); +$mode = $studentT->mode(); +$σ² = $studentT->variance(); + +// Uniform distribution +$a = 1; // lower boundary of the distribution +$b = 4; // upper boundary of the distribution +$x = 2; +$uniform = new Continuous\Uniform($a, $b); +$pdf = $uniform->pdf($x); +$cdf = $uniform->cdf($x); +$μ = $uniform->mean(); +$median = $uniform->median(); +$mode = $uniform->mode(); +$σ² = $uniform->variance(); + +// Weibull distribution +$k = 1; // shape parameter +$λ = 2; // scale parameter +$x = 2; +$weibull = new Continuous\Weibull($k, $λ); +$pdf = $weibull->pdf($x); +$cdf = $weibull->cdf($x); +$icdf = $weibull->inverse($p); +$μ = $weibull->mean(); +$median = $weibull->median(); +$mode = $weibull->mode(); + +// Other CDFs - All continuous distributions - Replace {$distribution} with desired distribution. +$between = $distribution->between($x₁, $x₂); // Probability of being between two points, x₁ and x₂ +$outside = $distribution->outside($x₁, $x); // Probability of being between below x₁ and above x₂ +$above = $distribution->above($x); // Probability of being above x to ∞ + +// Random Number Generator +$random = $distribution->rand(); // A random number with a given distribution +``` + +### Probability - Discrete Distributions +```php +use MathPHP\Probability\Distribution\Discrete; + +// Bernoulli distribution (special case of binomial where n = 1) +$p = 0.3; +$k = 0; +$bernoulli = new Discrete\Bernoulli($p); +$pmf = $bernoulli->pmf($k); +$cdf = $bernoulli->cdf($k); +$μ = $bernoulli->mean(); +$median = $bernoulli->median(); +$mode = $bernoulli->mode(); +$σ² = $bernoulli->variance(); + +// Binomial distribution +$n = 2; // number of events +$p = 0.5; // probability of success +$r = 1; // number of successful events +$binomial = new Discrete\Binomial($n, $p); +$pmf = $binomial->pmf($r); +$cdf = $binomial->cdf($r); +$μ = $binomial->mean(); +$σ² = $binomial->variance(); + +// Categorical distribution +$k = 3; // number of categories +$probabilities = ['a' => 0.3, 'b' => 0.2, 'c' => 0.5]; // probabilities for categorices a, b, and c +$categorical = new Discrete\Categorical($k, $probabilities); +$pmf_a = $categorical->pmf('a'); +$mode = $categorical->mode(); + +// Geometric distribution (failures before the first success) +$p = 0.5; // success probability +$k = 2; // number of trials +$geometric = new Discrete\Geometric($p); +$pmf = $geometric->pmf($k); +$cdf = $geometric->cdf($k); +$μ = $geometric->mean(); +$median = $geometric->median(); +$mode = $geometric->mode(); +$σ² = $geometric->variance(); + +// Hypergeometric distribution +$N = 50; // population size +$K = 5; // number of success states in the population +$n = 10; // number of draws +$k = 4; // number of observed successes +$hypergeo = new Discrete\Hypergeometric($N, $K, $n); +$pmf = $hypergeo->pmf($k); +$cdf = $hypergeo->cdf($k); +$μ = $hypergeo->mean(); +$mode = $hypergeo->mode(); +$σ² = $hypergeo->variance(); + +// Negative binomial distribution (Pascal) +$r = 1; // number of failures until the experiment is stopped +$P = 0.5; // probability of success on an individual trial +$x = 2; // number of successes +$negativeBinomial = new Discrete\NegativeBinomial($r, $p); +$pmf = $negativeBinomial->pmf($x); +$cdf = $negativeBinomial->cdf($x); +$μ = $negativeBinomial->mean(); +$mode = $negativeBinomial->mode(); +$σ² = $negativeBinomial->variance(); + +// Pascal distribution (Negative binomial) +$r = 1; // number of failures until the experiment is stopped +$P = 0.5; // probability of success on an individual trial +$x = 2; // number of successes +$pascal = new Discrete\Pascal($r, $p); +$pmf = $pascal->pmf($x); +$cdf = $pascal->cdf($x); +$μ = $pascal->mean(); +$mode = $pascal->mode(); +$σ² = $pascal->variance(); + +// Poisson distribution +$λ = 2; // average number of successful events per interval +$k = 3; // events in the interval +$poisson = new Discrete\Poisson($λ); +$pmf = $poisson->pmf($k); +$cdf = $poisson->cdf($k); +$μ = $poisson->mean(); +$median = $poisson->median(); +$mode = $poisson->mode(); +$σ² = $poisson->variance(); + +// Shifted geometric distribution (probability to get one success) +$p = 0.5; // success probability +$k = 2; // number of trials +$shiftedGeometric = new Discrete\ShiftedGeometric($p); +$pmf = $shiftedGeometric->pmf($k); +$cdf = $shiftedGeometric->cdf($k); +$μ = $shiftedGeometric->mean(); +$median = $shiftedGeometric->median(); +$mode = $shiftedGeometric->mode(); +$σ² = $shiftedGeometric->variance(); + +// Uniform distribution +$a = 1; // lower boundary of the distribution +$b = 4; // upper boundary of the distribution +$k = 2; // percentile +$uniform = new Discrete\Uniform($a, $b); +$pmf = $uniform->pmf(); +$cdf = $uniform->cdf($k); +$μ = $uniform->mean(); +$median = $uniform->median(); +$σ² = $uniform->variance(); + +// Zipf distribution +$k = 2; // rank +$s = 3; // exponent +$N = 10; // number of elements +$zipf = new Discrete\Zipf($s, $N); +$pmf = $zipf->pmf($k); +$cdf = $zipf->cdf($k); +$μ = $zipf->mean(); +$mode = $zipf->mode(); +``` + +### Probability - Multivariate Distributions +```php +use MathPHP\Probability\Distribution\Multivariate; + +// Dirichlet distribution +$αs = [1, 2, 3]; +$xs = [0.07255081, 0.27811903, 0.64933016]; +$dirichlet = new Multivariate\Dirichlet($αs); +$pdf = $dirichlet->pdf($xs); + +// Normal distribution +$μ = [1, 1.1]; +$∑ = MatrixFactory::create([ + [1, 0], + [0, 1], +]); +$X = [0.7, 1.4]; +$normal = new Multivariate\Normal($μ, $∑); +$pdf = $normal->pdf($X); + +// Hypergeometric distribution +$quantities = [5, 10, 15]; // Suppose there are 5 black, 10 white, and 15 red marbles in an urn. +$choices = [2, 2, 2]; // If six marbles are chosen without replacement, the probability that exactly two of each color are chosen is: +$distribution = new Multivariate\Hypergeometric($quantities); +$probability = $distribution->pmf($choices); // 0.0795756 + +// Multinomial distribution +$frequencies = [7, 2, 3]; +$probabilities = [0.40, 0.35, 0.25]; +$multinomial = new Multivariate\Multinomial($probabilities); +$pmf = $multinomial->pmf($frequencies); +``` + +### Probability - Distribution Tables +```php +use MathPHP\Probability\Distribution\Table; + +// Provided solely for completeness' sake. +// It is statistics tradition to provide these tables. +// MathPHP has dynamic distribution CDF functions you can use instead. + +// Standard Normal Table (Z Table) +$table = Table\StandardNormal::Z_SCORES; +$probability = $table[1.5][0]; // Value for Z of 1.50 + +// t Distribution Tables +$table = Table\TDistribution::ONE_SIDED_CONFIDENCE_LEVEL; +$table = Table\TDistribution::TWO_SIDED_CONFIDENCE_LEVEL; +$ν = 5; // degrees of freedom +$cl = 99; // confidence level +$t = $table[$ν][$cl]; + +// t Distribution Tables +$table = Table\TDistribution::ONE_SIDED_ALPHA; +$table = Table\TDistribution::TWO_SIDED_ALPHA; +$ν = 5; // degrees of freedom +$α = 0.001; // alpha value +$t = $table[$ν][$α]; + +// χ² Distribution Table +$table = Table\ChiSquared::CHI_SQUARED_SCORES; +$df = 2; // degrees of freedom +$p = 0.05; // P value +$χ² = $table[$df][$p]; +``` + +### Sample Data +```php +use MathPHP\SampleData; + +// Famous sample data sets to experiment with + +// Motor Trend Car Road Tests (mtcars) +$mtCars = new SampleData\MtCars(); +$rawData = $mtCars->getData(); // [[21, 6, 160, ... ], [30.4, 4, 71.1, ... ], ... ] +$labeledData = $mtCars->getLabeledData(); // ['Mazda RX4' => ['mpg' => 21, 'cyl' => 6, 'disp' => 160, ... ], 'Honda Civic' => [ ... ], ...] +$modelData = $mtCars->getModelData('Ferrari Dino'); // ['mpg' => 19.7, 'cyl' => 6, 'disp' => 145, ... ] +$mpgs = $mtCars->getMpg(); // ['Mazda RX4' => 21, 'Honda civic' => 30.4, ... ] +// Getters for Mpg, Cyl, Disp, Hp, Drat, Wt, Qsec, Vs, Am, Gear, Carb + +// Edgar Anderson's Iris Data (iris) +$iris = new SampleData\Iris(); +$rawData = $iris->getData(); // [[5.1, 3.5, 1.4, 0.2, 'setosa'], [4.9, 3.0, 1.4, 0.2, 'setosa'], ... ] +$labeledData = $iris->getLabeledData(); // [['sepalLength' => 5.11, 'sepalWidth' => 3.5, 'petalLength' => 1.4, 'petalWidth' => 0.2, 'species' => 'setosa'], ... ] +$petalLengths = $iris->getSepalLength(); // [5.1, 4.9, 4.7, ... ] +// Getters for SepalLength, SepalWidth, PetalLength, PetalWidth, Species + +// The Effect of Vitamin C on Tooth Growth in Guinea Pigs (ToothGrowth) +$toothGrowth = new SampleData\ToothGrowth(); +$rawData = $toothGrowth->getData(); // [[4.2, 'VC', 0.5], [11.5, 'VC', '0.5], ... ] +$labeledData = $toothGrowth->getLabeledData(); // [['len' => 4.2, 'supp' => 'VC', 'dose' => 0.5], ... ] +$lengths = $toothGrowth->getLen(); // [4.2, 11.5, ... ] +// Getters for Len, Supp, Dose + +// Results from an Experiment on Plant Growth (PlantGrowth) +$plantGrowth = new SampleData\PlantGrowth(); +$rawData = $plantGrowth->getData(); // [[4.17, 'ctrl'], [5.58, 'ctrl'], ... ] +$labeledData = $plantGrowth->getLabeledData(); // [['weight' => 4.17, 'group' => 'ctrl'], ['weight' => 5.58, 'group' => 'ctrl'], ... ] +$weights = $plantGrowth->getWeight(); // [4.17, 5.58, ... ] +// Getters for Weight, Group + +// Violent Crime Rates by US State (USArrests) +$usArrests = new SampleData\UsArrests(); +$rawData = $usArrests->rawData(); // [[13.2, 236, 58, 21.2], [10.0, 263, 48, 44.5], ... ] +$labeledData = $usArrests->getLabeledData(); // ['Alabama' => ['murder' => 13.2, 'assault' => 236, 'urbanPop' => 58, 'rape' => 21.2], ... ] +$stateData = $usArrests->getStateData('Texas'); // ['murder' => 12.7, 'assault' => 201, 'urbanPop' => 80, 'rape' => 25.5] +$murders = $usArrests->getMurders(); // ['Alabama' => 13.2, 'Alaska' => 10.1, ... ] +// Getters for Murder, Assault, UrbanPop, Rape + +// Data from Cereals (cereal) +$cereal = new SampleData\Cereal(); +$cereals = $cereal->getCereals(); // ['B1', 'B2', 'B3', 'M1', 'M2', ... ] +$X = $cereal->getXData(); // [[0.002682755, 0.003370673, 0.004085942, ... ], [0.002781597, 0.003474863, 0.004191472, ... ], ... ] +$Y = $cereal->getYData(); // [[18373, 41.61500, 6.565000, ... ], [18536, 41.40500, 6.545000, ... ], ... ] +$Ysc = $cereal->getYscData(); // [[-0.1005049, 0.6265746, -1.1716630, ... ], [0.9233889, 0.1882929, -1.3185289, ... ], ... ] +// Labeled data: getLabeledXData(), getLabeledYData(), getLabeledYscData() + +// Data from People (people) +$people = new SampleData\People(); +$rawData = $people->getData(); // [198, 92, -1, ... ], [184, 84, -1, ... ], ... ] +$labeledData = $people->getLabeledData(); // ['Lars' => ['height' => 198, 'weight' => 92, 'hairLength' => -1, ... ]] +$names = $people->getNames(); +// Getters for names, height, weight, hairLength, shoeSize, age, income, beer, wine, sex, swim, region, iq +``` + +### Search +```php +use MathPHP\Search; + +// Search lists of numbers to find specific indexes + +$list = [1, 2, 3, 4, 5]; + +$index = Search::sorted($list, 2); // Find the array index where an item should be inserted to maintain sorted order +$index = Search::argMax($list); // Find the array index of the maximum value +$index = Search::nanArgMax($list); // Find the array index of the maximum value, ignoring NANs +$index = Search::argMin($list); // Find the array index of the minimum value +$index = Search::nanArgMin($list); // Find the array index of the minimum value, ignoring NANs +$indices = Search::nonZero($list); // Find the array indices of the scalar values that are non-zero +``` + +### Sequences - Basic +```php +use MathPHP\Sequence\Basic; + +$n = 5; // Number of elements in the sequence + +// Arithmetic progression +$d = 2; // Difference between the elements of the sequence +$a₁ = 1; // Starting number for the sequence +$progression = Basic::arithmeticProgression($n, $d, $a₁); +// [1, 3, 5, 7, 9] - Indexed from 1 + +// Geometric progression (arⁿ⁻¹) +$a = 2; // Scalar value +$r = 3; // Common ratio +$progression = Basic::geometricProgression($n, $a, $r); +// [2(3)⁰, 2(3)¹, 2(3)², 2(3)³] = [2, 6, 18, 54] - Indexed from 1 + +// Square numbers (n²) +$squares = Basic::squareNumber($n); +// [0², 1², 2², 3², 4²] = [0, 1, 4, 9, 16] - Indexed from 0 + +// Cubic numbers (n³) +$cubes = Basic::cubicNumber($n); +// [0³, 1³, 2³, 3³, 4³] = [0, 1, 8, 27, 64] - Indexed from 0 + +// Powers of 2 (2ⁿ) +$po2 = Basic::powersOfTwo($n); +// [2⁰, 2¹, 2², 2³, 2⁴] = [1, 2, 4, 8, 16] - Indexed from 0 + +// Powers of 10 (10ⁿ) +$po10 = Basic::powersOfTen($n); +// [10⁰, 10¹, 10², 10³, 10⁴] = [1, 10, 100, 1000, 10000] - Indexed from 0 + +// Factorial (n!) +$fact = Basic::factorial($n); +// [0!, 1!, 2!, 3!, 4!] = [1, 1, 2, 6, 24] - Indexed from 0 + +// Digit sum +$digit_sum = Basic::digitSum($n); +// [0, 1, 2, 3, 4] - Indexed from 0 + +// Digital root +$digit_root = Basic::digitalRoot($n); +// [0, 1, 2, 3, 4] - Indexed from 0 +``` + +### Sequences - Advanced +```php +use MathPHP\Sequence\Advanced; + +$n = 6; // Number of elements in the sequence + +// Fibonacci (Fᵢ = Fᵢ₋₁ + Fᵢ₋₂) +$fib = Advanced::fibonacci($n); +// [0, 1, 1, 2, 3, 5] - Indexed from 0 + +// Lucas numbers +$lucas = Advanced::lucasNumber($n); +// [2, 1, 3, 4, 7, 11] - Indexed from 0 + +// Pell numbers +$pell = Advanced::pellNumber($n); +// [0, 1, 2, 5, 12, 29] - Indexed from 0 + +// Triangular numbers (figurate number) +$triangles = Advanced::triangularNumber($n); +// [1, 3, 6, 10, 15, 21] - Indexed from 1 + +// Pentagonal numbers (figurate number) +$pentagons = Advanced::pentagonalNumber($n); +// [1, 5, 12, 22, 35, 51] - Indexed from 1 + +// Hexagonal numbers (figurate number) +$hexagons = Advanced::hexagonalNumber($n); +// [1, 6, 15, 28, 45, 66] - Indexed from 1 + +// Heptagonal numbers (figurate number) +$heptagons = Advanced::heptagonalNumber($n); +// [1, 4, 7, 13, 18, 27] - Indexed from 1 + +// Look-and-say sequence (describe the previous term!) +$look_and_say = Advanced::lookAndSay($n); +// ['1', '11', '21', '1211', '111221', '312211'] - Indexed from 1 + +// Lazy caterer's sequence (central polygonal numbers) +$lazy_caterer = Advanced::lazyCaterers($n); +// [1, 2, 4, 7, 11, 16] - Indexed from 0 + +// Magic squares series (magic constants; magic sums) +$magic_squares = Advanced::magicSquares($n); +// [0, 1, 5, 15, 34, 65] - Indexed from 0 + +// Perfect numbers +$perfect_numbers = Advanced::perfectNumbers($n); +// [6, 28, 496, 8128, 33550336, 8589869056] - Indexed from 0 + +// Perfect powers sequence +$perfect_powers = Advanced::perfectPowers($n); +// [4, 8, 9, 16, 25, 27] - Indexed from 0 + +// Not perfect powers sequence +$not_perfect_powers = Advanced::notPerfectPowers($n); +// [2, 3, 5, 6, 7, 10] - Indexed from 0 + +// Prime numbers up to n (n is not the number of elements in the sequence) +$primes = Advanced::primesUpTo(30); +// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - Indexed from 0 +``` + +### Sequences - Non-Integer +```php +use MathPHP\Sequence\NonInteger; + +$n = 4; // Number of elements in the sequence + +// Harmonic sequence +$harmonic = NonInteger::harmonic($n); +// [1, 3/2, 11/6, 25/12] - Indexed from 1 + +// Generalized harmonic sequence +$m = 2; // exponent +$generalized = NonInteger::generalizedHarmonic($n, $m); +// [1, 5 / 4, 49 / 36, 205 / 144] - Indexed from 1 + +// Hyperharmonic sequence +$r = 2; // depth of recursion +$hyperharmonic = NonInteger::hyperharmonic($n, $r); +// [1, 5/2, 26/6, 77/12] - Indexed from 1 +``` + +### Set Theory +```php +use MathPHP\SetTheory\Set; +use MathPHP\SetTheory\ImmutableSet; + +// Sets and immutable sets +$A = new Set([1, 2, 3]); // Can add and remove members +$B = new ImmutableSet([3, 4, 5]); // Cannot modify set once created + +// Basic set data +$set = $A->asArray(); +$cardinality = $A->length(); +$bool = $A->isEmpty(); + +// Set membership +$true = $A->isMember(2); +$true = $A->isNotMember(8); + +// Add and remove members +$A->add(4); +$A->add(new Set(['a', 'b'])); +$A->addMulti([5, 6, 7]); +$A->remove(7); +$A->removeMulti([5, 6]); +$A->clear(); + +// Set properties against other sets - return boolean +$bool = $A->isDisjoint($B); +$bool = $A->isSubset($B); // A ⊆ B +$bool = $A->isProperSubset($B); // A ⊆ B & A ≠ B +$bool = $A->isSuperset($B); // A ⊇ B +$bool = $A->isProperSuperset($B); // A ⊇ B & A ≠ B + +// Set operations with other sets - return a new Set +$A∪B = $A->union($B); +$A∩B = $A->intersect($B); +$A\B = $A->difference($B); // relative complement +$AΔB = $A->symmetricDifference($B); +$A×B = $A->cartesianProduct($B); + +// Other set operations +$P⟮A⟯ = $A->powerSet(); +$C = $A->copy(); + +// Print a set +print($A); // Set{1, 2, 3, 4, Set{a, b}} + +// PHP Interfaces +$n = count($A); // Countable +foreach ($A as $member) { ... } // Iterator + +// Fluent interface +$A->add(5)->add(6)->remove(4)->addMulti([7, 8, 9]); +``` + +### Statistics - ANOVA +```php +use MathPHP\Statistics\ANOVA; + +// One-way ANOVA +$sample1 = [1, 2, 3]; +$sample2 = [3, 4, 5]; +$sample3 = [5, 6, 7]; + ⋮ ⋮ + +$anova = ANOVA::oneWay($sample1, $sample2, $sample3); +print_r($anova); +/* Array ( + [ANOVA] => Array ( // ANOVA hypothesis test summary data + [treatment] => Array ( + [SS] => 24 // Sum of squares (between) + [df] => 2 // Degrees of freedom + [MS] => 12 // Mean squares + [F] => 12 // Test statistic + [P] => 0.008 // P value + ) + [error] => Array ( + [SS] => 6 // Sum of squares (within) + [df] => 6 // Degrees of freedom + [MS] => 1 // Mean squares + ) + [total] => Array ( + [SS] => 30 // Sum of squares (total) + [df] => 8 // Degrees of freedom + ) + ) + [total_summary] => Array ( // Total summary data + [n] => 9 + [sum] => 36 + [mean] => 4 + [SS] => 174 + [variance] => 3.75 + [sd] => 1.9364916731037 + [sem] => 0.6454972243679 + ) + [data_summary] => Array ( // Data summary (each input sample) + [0] => Array ([n] => 3 [sum] => 6 [mean] => 2 [SS] => 14 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963) + [1] => Array ([n] => 3 [sum] => 12 [mean] => 4 [SS] => 50 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963) + [2] => Array ([n] => 3 [sum] => 18 [mean] => 6 [SS] => 110 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963) + ) +) */ + +// Two-way ANOVA +/* | Factor B₁ | Factor B₂ | Factor B₃ | ⋯ +Factor A₁ | 4, 6, 8 | 6, 6, 9 | 8, 9, 13 | ⋯ +Factor A₂ | 4, 8, 9 | 7, 10, 13 | 12, 14, 16| ⋯ + ⋮ ⋮ ⋮ ⋮ */ +$factorA₁ = [ + [4, 6, 8], // Factor B₁ + [6, 6, 9], // Factor B₂ + [8, 9, 13], // Factor B₃ +]; +$factorA₂ = [ + [4, 8, 9], // Factor B₁ + [7, 10, 13], // Factor B₂ + [12, 14, 16], // Factor B₃ +]; + ⋮ + +$anova = ANOVA::twoWay($factorA₁, $factorA₂); +print_r($anova); +/* Array ( + [ANOVA] => Array ( // ANOVA hypothesis test summary data + [factorA] => Array ( + [SS] => 32 // Sum of squares + [df] => 1 // Degrees of freedom + [MS] => 32 // Mean squares + [F] => 5.6470588235294 // Test statistic + [P] => 0.034994350619895 // P value + ) + [factorB] => Array ( + [SS] => 93 // Sum of squares + [df] => 2 // Degrees of freedom + [MS] => 46.5 // Mean squares + [F] => 8.2058823529412 // Test statistic + [P] => 0.0056767297582031 // P value + ) + [interaction] => Array ( + [SS] => 7 // Sum of squares + [df] => 2 // Degrees of freedom + [MS] => 3.5 // Mean squares + [F] => 0.61764705882353 // Test statistic + [P] => 0.5555023440712 // P value + ) + [error] => Array ( + [SS] => 68 // Sum of squares (within) + [df] => 12 // Degrees of freedom + [MS] => 5.6666666666667 // Mean squares + ) + [total] => Array ( + [SS] => 200 // Sum of squares (total) + [df] => 17 // Degrees of freedom + ) + ) + [total_summary] => Array ( // Total summary data + [n] => 18 + [sum] => 162 + [mean] => 9 + [SS] => 1658 + [variance] => 11.764705882353 + [sd] => 3.4299717028502 + [sem] => 0.80845208345444 + ) + [summary_factorA] => Array ( ... ) // Summary data of factor A + [summary_factorB] => Array ( ... ) // Summary data of factor B + [summary_interaction] => Array ( ... ) // Summary data of interactions of factors A and B +) */ +``` + +### Statistics - Averages +```php +use MathPHP\Statistics\Average; + +$numbers = [13, 18, 13, 14, 13, 16, 14, 21, 13]; + +// Mean, median, mode +$mean = Average::mean($numbers); +$median = Average::median($numbers); +$mode = Average::mode($numbers); // Returns an array — may be multimodal + +// Weighted mean +$weights = [12, 1, 23, 6, 12, 26, 21, 12, 1]; +$weighted_mean = Average::weightedMean($numbers, $weights) + +// Other means of a list of numbers +$geometric_mean = Average::geometricMean($numbers); +$harmonic_mean = Average::harmonicMean($numbers); +$contraharmonic_mean = Average::contraharmonicMean($numbers); +$quadratic_mean = Average::quadraticMean($numbers); // same as rootMeanSquare +$root_mean_square = Average::rootMeanSquare($numbers); // same as quadraticMean +$trimean = Average::trimean($numbers); +$interquartile_mean = Average::interquartileMean($numbers); // same as iqm +$interquartile_mean = Average::iqm($numbers); // same as interquartileMean +$cubic_mean = Average::cubicMean($numbers); + +// Truncated mean (trimmed mean) +$trim_percent = 25; // 25 percent of observations trimmed from each end of distribution +$truncated_mean = Average::truncatedMean($numbers, $trim_percent); + +// Generalized mean (power mean) +$p = 2; +$generalized_mean = Average::generalizedMean($numbers, $p); // same as powerMean +$power_mean = Average::powerMean($numbers, $p); // same as generalizedMean + +// Lehmer mean +$p = 3; +$lehmer_mean = Average::lehmerMean($numbers, $p); + +// Moving averages +$n = 3; +$weights = [3, 2, 1]; +$SMA = Average::simpleMovingAverage($numbers, $n); // 3 n-point moving average +$CMA = Average::cumulativeMovingAverage($numbers); +$WMA = Average::weightedMovingAverage($numbers, $n, $weights); +$EPA = Average::exponentialMovingAverage($numbers, $n); + +// Means of two numbers +[$x, $y] = [24, 6]; +$agm = Average::arithmeticGeometricMean($x, $y); // same as agm +$agm = Average::agm($x, $y); // same as arithmeticGeometricMean +$log_mean = Average::logarithmicMean($x, $y); +$heronian_mean = Average::heronianMean($x, $y); +$identric_mean = Average::identricMean($x, $y); + +// Averages report +$averages = Average::describe($numbers); +print_r($averages); +/* Array ( + [mean] => 15 + [median] => 14 + [mode] => Array ( [0] => 13 ) + [geometric_mean] => 14.789726414533 + [harmonic_mean] => 14.605077399381 + [contraharmonic_mean] => 15.474074074074 + [quadratic_mean] => 15.235193176035 + [trimean] => 14.5 + [iqm] => 14 + [cubic_mean] => 15.492307432707 +) */ +``` + +### Statistics - Circular +```php +use MathPHP\Statistics\Circular; + +$angles = [1.51269877, 1.07723915, 0.81992282]; + +$θ = Circular::mean($angles); +$R = Circular::resultantLength($angles); +$ρ = Circular::meanResultantLength($angles); +$V = Circular::variance($angles); +$ν = Circular::standardDeviation($angles); + +// Descriptive circular statistics report +$stats = Circular::describe($angles); +print_r($stats); +/* Array ( + [n] => 3 + [mean] => 1.1354043006436 + [resultant_length] => 2.8786207547493 + [mean_resultant_length] => 0.9595402515831 + [variance] => 0.040459748416901 + [sd] => 0.28740568481722 +); */ +``` + +### Statistics - Correlation +```php +use MathPHP\Statistics\Correlation; + +$X = [1, 2, 3, 4, 5]; +$Y = [2, 3, 4, 4, 6]; + +// Covariance +$σxy = Correlation::covariance($X, $Y); // Has optional parameter to set population (defaults to sample covariance) + +// Weighted covariance +$w = [2, 3, 1, 1, 5]; +$σxyw = Correlation::weightedCovariance($X, $Y, $w); + +// r - Pearson product-moment correlation coefficient (Pearson's r) +$r = Correlation::r($X, $Y); // Has optional parameter to set population (defaults to sample correlation coefficient) + +// Weighted correlation coefficient +$rw = Correlation::weightedCorrelationCoefficient($X, $Y, $w); + +// R² - Coefficient of determination +$R² = Correlation::r2($X, $Y); // Has optional parameter to set population (defaults to sample coefficient of determination) + +// τ - Kendall rank correlation coefficient (Kendall's tau) +$τ = Correlation::kendallsTau($X, $Y); + +// ρ - Spearman's rank correlation coefficient (Spearman's rho) +$ρ = Correlation::spearmansRho($X, $Y); + +// Descriptive correlation report +$stats = Correlation::describe($X, $Y); +print_r($stats); +/* Array ( + [cov] => 2.25 + [r] => 0.95940322360025 + [r2] => 0.92045454545455 + [tau] => 0.94868329805051 + [rho] => 0.975 +) */ + +// Confidence ellipse - create an ellipse surrounding the data at a specified standard deviation +$sd = 1; +$num_points = 11; // Optional argument specifying number of points of the ellipse +$ellipse_data = Correlation::confidenceEllipse($X, $Y, $sd, $num_points); + +``` + +### Statistics - Descriptive +```php +use MathPHP\Statistics\Descriptive; + +$numbers = [13, 18, 13, 14, 13, 16, 14, 21, 13]; + +// Range and midrange +$range = Descriptive::range($numbers); +$midrange = Descriptive::midrange($numbers); + +// Variance (population and sample) +$σ² = Descriptive::populationVariance($numbers); // n degrees of freedom +$S² = Descriptive::sampleVariance($numbers); // n - 1 degrees of freedom + +// Variance (Custom degrees of freedom) +$df = 5; // degrees of freedom +$S² = Descriptive::variance($numbers, $df); // can specify custom degrees of freedom + +// Weighted sample variance +$weights = [0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]; +$σ²w = Descriptive::weightedSampleVariance($numbers, $weights, $biased = false); + +// Standard deviation (For a sample; uses sample variance) +$σ = Descriptive::sd($numbers); // same as standardDeviation; +$σ = Descriptive::standardDeviation($numbers); // same as sd; + +// SD+ (Standard deviation for a population; uses population variance) +$SD+ = Descriptive::sd($numbers, Descriptive::POPULATION); // POPULATION constant = true +$SD+ = Descriptive::standardDeviation($numbers, true); // same as sd with POPULATION constant + +// Coefficient of variation (cᵥ) +$cᵥ = Descriptive::coefficientOfVariation($numbers); + +// MAD - mean/median absolute deviations +$mean_mad = Descriptive::meanAbsoluteDeviation($numbers); +$median_mad = Descriptive::medianAbsoluteDeviation($numbers); + +// Quartiles (inclusive and exclusive methods) +// [0% => 13, Q1 => 13, Q2 => 14, Q3 => 17, 100% => 21, IQR => 4] +$quartiles = Descriptive::quartiles($numbers); // Has optional parameter to specify method. Default is Exclusive +$quartiles = Descriptive::quartilesExclusive($numbers); +$quartiles = Descriptive::quartilesInclusive($numbers); + +// IQR - Interquartile range +$IQR = Descriptive::interquartileRange($numbers); // Same as IQR; has optional parameter to specify quartile method. +$IQR = Descriptive::iqr($numbers); // Same as interquartileRange; has optional parameter to specify quartile method. + +// Percentiles +$twentieth_percentile = Descriptive::percentile($numbers, 20); +$ninety_fifth_percentile = Descriptive::percentile($numbers, 95); + +// Midhinge +$midhinge = Descriptive::midhinge($numbers); + +// Describe a list of numbers - descriptive stats report +$stats = Descriptive::describe($numbers); // Has optional parameter to set population or sample calculations +print_r($stats); +/* Array ( + [n] => 9 + [min] => 13 + [max] => 21 + [mean] => 15 + [median] => 14 + [mode] => Array ( [0] => 13 ) + [range] => 8 + [midrange] => 17 + [variance] => 8 + [sd] => 2.8284271247462 + [cv] => 0.18856180831641 + [mean_mad] => 2.2222222222222 + [median_mad] => 1 + [quartiles] => Array ( + [0%] => 13 + [Q1] => 13 + [Q2] => 14 + [Q3] => 17 + [100%] => 21 + [IQR] => 4 + ) + [midhinge] => 15 + [skewness] => 1.4915533665654 + [ses] => 0.71713716560064 + [kurtosis] => 0.1728515625 + [sek] => 1.3997084244475 + [sem] => 0.94280904158206 + [ci_95] => Array ( + [ci] => 1.8478680091392 + [lower_bound] => 13.152131990861 + [upper_bound] => 16.847868009139 + ) + [ci_99] => Array ( + [ci] => 2.4285158135783 + [lower_bound] => 12.571484186422 + [upper_bound] => 17.428515813578 + ) +) */ + +// Five number summary - five most important sample percentiles +$summary = Descriptive::fiveNumberSummary($numbers); +// [min, Q1, median, Q3, max] +``` + +### Statistics - Distance +```php +use MathPHP\Statistics\Distance; + +// Probability distributions +$X = [0.2, 0.5, 0.3]; +$Y = [0.1, 0.4, 0.5]; + +// Distances +$DB⟮X、Y⟯ = Distance::bhattacharyya($X, $Y); +$H⟮X、Y⟯ = Distance::hellinger($X, $Y); +$D⟮X、Y⟯ = Distance::minkowski($X, $Y, $p = 2); +$d⟮X、Y⟯ = Distance::euclidean($X, $Y); // L² distance +$d₁⟮X、Y⟯ = Distance::manhattan($X, $Y); // L¹ distance, taxicab geometry, city block distance +$JSD⟮X‖Y⟯ = Distance::jensenShannon($X, $Y); +$d⟮X、Y⟯ = Distance::canberra($X, Y); +brayCurtis = Distance::brayCurtis($X, $Y); +$cosine = Distance::cosine($X, $Y); +$cos⟮α⟯ = Distance::cosineSimilarity($X, $Y); + +// Mahalanobis distance +$x = new Matrix([[6], [5]]); +$data = new Matrix([ + [4, 4, 5, 2, 3, 6, 9, 7, 4, 5], + [3, 7, 5, 7, 9, 5, 6, 2, 2, 7], +]); +$otherData = new Matrix([ + [4, 4, 5, 2, 3, 6, 9, 7, 4, 5], + [3, 7, 5, 7, 9, 5, 6, 2, 2, 7], +]); +$y = new Matrix([[2], [2]]); +$D = Distance::mahalanobis($x, $data); // Mahalanobis distance from x to the centroid of the data. +$D = Distance::mahalanobis($x, $data, $y); // Mahalanobis distance between $x and $y using the data. +$D = Distance::mahalanobis($data, $otherData); // Mahalanobis distance between the centroids of two sets of data. +``` + +### Statistics - Distributions +```php +use MathPHP\Statistics\Distribution; + +$grades = ['A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'D', 'F']; + +// Frequency distributions (frequency and relative frequency) +$frequencies = Distribution::frequency($grades); // [ A => 2, B => 4, C => 2, D => 1, F => 1 ] +$relative_frequencies = Distribution::relativeFrequency($grades); // [ A => 0.2, B => 0.4, C => 0.2, D => 0.1, F => 0.1 ] + +// Cumulative frequency distributions (cumulative and cumulative relative) +$cumulative_frequencies = Distribution::cumulativeFrequency($grades); // [ A => 2, B => 6, C => 8, D => 9, F => 10 ] +$cumulative_relative_frequencies = Distribution::cumulativeRelativeFrequency($grades); // [ A => 0.2, B => 0.6, C => 0.8, D => 0.9, F => 1 ] + +// Ranking of data +$values = [1, 2, 2, 3]; +$ordinal_ranking = Distribution::ordinalRanking($values); // 1, 2, 3, 4 +$standard_competition_ranking = Distribution::standardCompetitionRanking($values); // 1, 2, 2, 4 +$modified_competition_ranking = Distribution::modifiedCompetitionRanking($values); // 1, 3, 3, 4 +$fractional_ranking = Distribution::fractionalRanking($values); // 1, 2.5, 2.5, 4 + +// Stem and leaf plot +// Return value is array where keys are the stems, values are the leaves +$values = [44, 46, 47, 49, 63, 64, 66, 68, 68, 72, 72, 75, 76, 81, 84, 88, 106]; +$stem_and_leaf_plot = Distribution::stemAndLeafPlot($values); +// [4 => [4, 6, 7, 9], 5 => [], 6 => [3, 4, 6, 8, 8], 7 => [2, 2, 5, 6], 8 => [1, 4, 8], 9 => [], 10 => [6]] + +// Optional second parameter will print stem and leaf plot to STDOUT +Distribution::stemAndLeafPlot($values, Distribution::PRINT); +/* + 4 | 4 6 7 9 + 5 | + 6 | 3 4 6 8 8 + 7 | 2 2 5 6 + 8 | 1 4 8 + 9 | +10 | 6 +*/ +``` + +### Statistics - Divergence +```php +use MathPHP\Statistics\Divergence; + +// Probability distributions +$X = [0.2, 0.5, 0.3]; +$Y = [0.1, 0.4, 0.5]; + +// Divergences +$Dkl⟮X‖Y⟯ = Divergence::kullbackLeibler($X, $Y); +$JSD⟮X‖Y⟯ = Divergence::jensenShannon($X, $Y); +``` + +### Statistics - Effect Size +```php +use MathPHP\Statistics\EffectSize; + +$SSt = 24; // Sum of squares treatment +$SSE = 300; // Sum of squares error +$SST = 600; // Sum of squares total +$dft = 1; // Degrees of freedom treatment +$MSE = 18; // Mean squares error + +// η² - Eta-squared +$η² = EffectSize::etaSquared($SSt, $SST); +$η²p = EffectSize::partialEtaSquared($SSt, $SSE); + +// ω² - Omega-squared +$ω² = EffectSize::omegaSquared($SSt, $dft, $SST, $MSE); + +// Cohen's ƒ² +$ƒ² = EffectSize::cohensF($η²); +$ƒ² = EffectSize::cohensF($ω²); +$ƒ² = EffectSize::cohensF($R²); + +// Cohen's q +[$r₁, $r₂] = [0.1, 0.2]; +$q = EffectSize::cohensQ($r₁, $r₂); + +// Cohen's d +[$μ₁, $σ₁] = [6.7, 1.2]; +[$μ₂, $σ₂] = [6, 1]; +$d = EffectSize::cohensD($μ₁, $μ₂, $σ₁, $σ₂); + +// Hedges' g +[$μ₁, $σ₁, $n₁] = [6.7, 1.2, 15]; +[$μ₂, $σ₂, $n₂] = [6, 1, 15]; +$g = EffectSize::hedgesG($μ₁, $μ₂, $σ₁, $σ₂, $n₁, $n₂); + +// Glass' Δ +$Δ = EffectSize::glassDelta($μ₁, $μ₂, $σ₂); +``` + +### Statistics - Experiments +```php +use MathPHP\Statistics\Experiment; + +$a = 28; // Exposed and event present +$b = 129; // Exposed and event absent +$c = 4; // Non-exposed and event present +$d = 133; // Non-exposed and event absent + +// Risk ratio (relative risk) - RR +$RR = Experiment::riskRatio($a, $b, $c, $d); +// ['RR' => 6.1083, 'ci_lower_bound' => 2.1976, 'ci_upper_bound' => 16.9784, 'p' => 0.0005] + +// Odds ratio (OR) +$OR = Experiment::oddsRatio($a, $b, $c, $d); +// ['OR' => 7.2171, 'ci_lower_bound' => 2.4624, 'ci_upper_bound' => 21.1522, 'p' => 0.0003] + +// Likelihood ratios (positive and negative) +$LL = Experiment::likelihoodRatio($a, $b, $c, $d); +// ['LL+' => 7.4444, 'LL-' => 0.3626] + +$sensitivity = 0.67; +$specificity = 0.91; +$LL = Experiment::likelihoodRatioSS($sensitivity, $specificity); +``` + +### Statistics - Kernel Density Estimation +```php +use MathPHP\Statistics\KernelDensityEstimation + +$data = [-2.76, -1.09, -0.5, -0.15, 0.22, 0.69, 1.34, 1.75]; +$x = 0.5; + +// Density estimator with default bandwidth (normal distribution approximation) and kernel function (standard normal) +$kde = new KernelDensityEstimation($data); +$density = $kde->evaluate($x) + +// Custom bandwidth +$h = 0.1; +$kde->setBandwidth($h); + +// Library of built-in kernel functions +$kde->setKernelFunction(KernelDensityEstimation::STANDARD_NORMAL); +$kde->setKernelFunction(KernelDensityEstimation::NORMAL); +$kde->setKernelFunction(KernelDensityEstimation::UNIFORM); +$kde->setKernelFunction(KernelDensityEstimation::TRIANGULAR); +$kde->setKernelFunction(KernelDensityEstimation::EPANECHNIKOV); +$kde->setKernelFunction(KernelDensityEstimation::TRICUBE); + +// Set custom kernel function (user-provided callable) +$kernel = function ($x) { + if (abs($x) > 1) { + return 0; + } else { + return 70 / 81 * ((1 - abs($x) ** 3) ** 3); + } +}; +$kde->setKernelFunction($kernel); + +// All customization optionally can be done in the constructor +$kde = new KernelDesnsityEstimation($data, $h, $kernel); +``` + +### Statistics - Multivariate - Principal Component Analysis +```php +use MathPHP\Statistics\Multivariate\PCA; +use MathPHP\LinearAlgebra\MatrixFactory; + +// Given +$matrix = MatrixFactory::create($data); // observations of possibly correlated variables +$center = true; // do mean centering of data +$scale = true; // do standardization of data + +// Build a principal component analysis model to explore +$model = new PCA($matrix, $center, $scale); + +// Scores and loadings of the PCA model +$scores = $model->getScores(); // Matrix of transformed standardized data with the loadings matrix +$loadings = $model->getLoadings(); // Matrix of unit eigenvectors of the correlation matrix +$eigenvalues = $model->getEigenvalues(); // Vector of eigenvalues of components + +// Residuals, limits, critical values and more +$R² = $model->getR2(); // array of R² values +$cumR² = $model->getCumR2(); // array of cummulative R² values +$Q = $model->getQResiduals(); // Matrix of Q residuals +$T² = $model->getT2Distances(); // Matrix of T² distances +$T²Critical = $model->getCriticalT2(); // array of critical limits of T² +$QCritical = $model->getCriticalQ(); // array of critical limits of Q +``` + +### Statistics - Multivariate - Partial Least Squares Regression +```php +use MathPHP\Statistics\Multivariate\PLS; +use MathPHP\LinearAlgebra\MatrixFactory; +use MathPHP\SampleData; + +// Given +$cereal = new SampleData\Cereal(); +$X = MatrixFactory::createNumeric($cereal->getXData()); +$Y = MatrixFactory::createNumeric($cereal->getYData()); + +// Build a partial least squares regression to explore +$numberOfComponents = 5; +$scale = true; +$pls = new PLS($X, $Y, $numberOfComponents, $scale); + +// PLS model data +$C = $pls->getYLoadings(); // Loadings for Y values (each loading column transforms F to U) +$W = $pls->getXLoadings(); // Loadings for X values (each loading column transforms E into T) +$T = $pls->getXScores(); // Scores for the X values (latent variables of X) +$U = $pls->getYScores(); // Scores for the Y values (latent variables of Y) +$B = $pls->getCoefficients(); // Regression coefficients (matrix that best transforms E into F) +$P = $pls->getProjections(); // Projection matrix (each projection column transforms T into Ê) + +// Predict values (use regression model to predict new values of Y given values for X) +$yPredictions = $pls->predict($xMatrix); +``` + +### Statistics - Outlier +```php +use MathPHP\Statistics\Outlier; + +$data = [199.31, 199.53, 200.19, 200.82, 201.92, 201.95, 202.18, 245.57]; +$n = 8; // size of data +$𝛼 = 0.05; // significance level + +// Grubb's test - two sided test +$grubbsStatistic = Outlier::grubbsStatistic($data, Outlier::TWO_SIDED); +$criticalValue = Outlier::grubbsCriticalValue($𝛼, $n, Outlier::TWO_SIDED); + +// Grubbs' test - one sided test of minimum value +$grubbsStatistic = Outlier::grubbsStatistic($data, Outlier::ONE_SIDED_LOWER); +$criticalValue = Outlier::grubbsCriticalValue($𝛼, $n, Outlier::ONE_SIDED); + +// Grubbs' test - one sided test of maximum value +$grubbsStatistic = Outlier::grubbsStatistic($data, Outlier::ONE_SIDED_UPPER); +$criticalValue = Outlier::grubbsCriticalValue($𝛼, $n, Outlier::ONE_SIDED); +``` + +### Statistics - Random Variables +```php +use MathPHP\Statistics\RandomVariable; + +$X = [1, 2, 3, 4]; +$Y = [2, 3, 4, 5]; + +// Central moment (nth moment) +$second_central_moment = RandomVariable::centralMoment($X, 2); +$third_central_moment = RandomVariable::centralMoment($X, 3); + +// Skewness (population, sample, and alternative general method) +$skewness = RandomVariable::skewness($X); // Optional type parameter to choose skewness type calculation. Defaults to sample skewness (similar to Excel's SKEW). +$skewness = RandomVariable::sampleSkewness($X); // Same as RandomVariable::skewness($X, RandomVariable::SAMPLE_SKEWNESS) - Similar to Excel's SKEW, SAS and SPSS, R (e1071) skewness type 2 +$skewness = RandomVariable::populationSkewness($X); // Same as RandomVariable::skewness($X, RandomVariable::POPULATION_SKEWNESS) - Similar to Excel's SKEW.P, classic textbook definition, R (e1071) skewness type 1 +$skewness = RandomVariable::alternativeSkewness($X); // Same as RandomVariable::skewness($X, RandomVariable::ALTERNATIVE_SKEWNESS) - Alternative, classic definition of skewness +$SES = RandomVariable::ses(count($X)); // standard error of skewness + +// Kurtosis (excess) +$kurtosis = RandomVariable::kurtosis($X); // Optional type parameter to choose kurtosis type calculation. Defaults to population kurtosis (similar to Excel's KURT). +$kurtosis = RandomVariable::sampleKurtosis($X); // Same as RandomVariable::kurtosis($X, RandomVariable::SAMPLE_KURTOSIS) - Similar to R (e1071) kurtosis type 1 +$kurtosis = RandomVariable::populationKurtosis($X); // Same as RandomVariable::kurtosis($X, RandomVariable::POPULATION_KURTOSIS) - Similar to Excel's KURT, SAS and SPSS, R (e1071) kurtosis type 2 +$platykurtic = RandomVariable::isPlatykurtic($X); // true if kurtosis is less than zero +$leptokurtic = RandomVariable::isLeptokurtic($X); // true if kurtosis is greater than zero +$mesokurtic = RandomVariable::isMesokurtic($X); // true if kurtosis is zero +$SEK = RandomVariable::sek(count($X)); // standard error of kurtosis + +// Standard error of the mean (SEM) +$sem = RandomVariable::standardErrorOfTheMean($X); // same as sem +$sem = RandomVariable::sem($X); // same as standardErrorOfTheMean + +// Confidence interval +$μ = 90; // sample mean +$n = 9; // sample size +$σ = 36; // standard deviation +$cl = 99; // confidence level +$ci = RandomVariable::confidenceInterval($μ, $n, $σ, $cl); // Array( [ci] => 30.91, [lower_bound] => 59.09, [upper_bound] => 120.91 ) +``` + +### Statistics - Regressions +```php +use MathPHP\Statistics\Regression; + +$points = [[1,2], [2,3], [4,5], [5,7], [6,8]]; + +// Simple linear regression (least squares method) +$regression = new Regression\Linear($points); +$parameters = $regression->getParameters(); // [m => 1.2209302325581, b => 0.6046511627907] +$equation = $regression->getEquation(); // y = 1.2209302325581x + 0.6046511627907 +$y = $regression->evaluate(5); // Evaluate for y at x = 5 using regression equation +$ci = $regression->ci(5, 0.5); // Confidence interval for x = 5 with p-value of 0.5 +$pi = $regression->pi(5, 0.5); // Prediction interval for x = 5 with p-value of 0.5; Optional number of trials parameter. +$Ŷ = $regression->yHat(); +$r = $regression->r(); // same as correlationCoefficient +$r² = $regression->r2(); // same as coefficientOfDetermination +$se = $regression->standardErrors(); // [m => se(m), b => se(b)] +$t = $regression->tValues(); // [m => t, b => t] +$p = $regression->tProbability(); // [m => p, b => p] +$F = $regression->fStatistic(); +$p = $regression->fProbability(); +$h = $regression->leverages(); +$e = $regression->residuals(); +$D = $regression->cooksD(); +$DFFITS = $regression->dffits(); +$SStot = $regression->sumOfSquaresTotal(); +$SSreg = $regression->sumOfSquaresRegression(); +$SSres = $regression->sumOfSquaresResidual(); +$MSR = $regression->meanSquareRegression(); +$MSE = $regression->meanSquareResidual(); +$MSTO = $regression->meanSquareTotal(); +$error = $regression->errorSd(); // Standard error of the residuals +$V = $regression->regressionVariance(); +$n = $regression->getSampleSize(); // 5 +$points = $regression->getPoints(); // [[1,2], [2,3], [4,5], [5,7], [6,8]] +$xs = $regression->getXs(); // [1, 2, 4, 5, 6] +$ys = $regression->getYs(); // [2, 3, 5, 7, 8] +$ν = $regression->degreesOfFreedom(); + +// Linear regression through a fixed point (least squares method) +$force_point = [0,0]; +$regression = new Regression\LinearThroughPoint($points, $force_point); +$parameters = $regression->getParameters(); +$equation = $regression->getEquation(); +$y = $regression->evaluate(5); +$Ŷ = $regression->yHat(); +$r = $regression->r(); +$r² = $regression->r2(); + ⋮ ⋮ + +// Theil–Sen estimator (Sen's slope estimator, Kendall–Theil robust line) +$regression = new Regression\TheilSen($points); +$parameters = $regression->getParameters(); +$equation = $regression->getEquation(); +$y = $regression->evaluate(5); + ⋮ ⋮ + +// Use Lineweaver-Burk linearization to fit data to the Michaelis–Menten model: y = (V * x) / (K + x) +$regression = new Regression\LineweaverBurk($points); +$parameters = $regression->getParameters(); // [V, K] +$equation = $regression->getEquation(); // y = Vx / (K + x) +$y = $regression->evaluate(5); + ⋮ ⋮ + +// Use Hanes-Woolf linearization to fit data to the Michaelis–Menten model: y = (V * x) / (K + x) +$regression = new Regression\HanesWoolf($points); +$parameters = $regression->getParameters(); // [V, K] +$equation = $regression->getEquation(); // y = Vx / (K + x) +$y = $regression->evaluate(5); + ⋮ ⋮ + +// Power law regression - power curve (least squares fitting) +$regression = new Regression\PowerLaw($points); +$parameters = $regression->getParameters(); // [a => 56.483375436574, b => 0.26415375648621] +$equation = $regression->getEquation(); // y = 56.483375436574x^0.26415375648621 +$y = $regression->evaluate(5); + ⋮ ⋮ + +// LOESS - Locally Weighted Scatterplot Smoothing (Local regression) +$α = 1/3; // Smoothness parameter +$λ = 1; // Order of the polynomial fit +$regression = new Regression\LOESS($points, $α, $λ); +$y = $regression->evaluate(5); +$Ŷ = $regression->yHat(); + ⋮ ⋮ +``` + +### Statistics - Significance Testing +```php +use MathPHP\Statistics\Significance; + +// Z test - One sample (z and p values) +$Hₐ = 20; // Alternate hypothesis (M Sample mean) +$n = 200; // Sample size +$H₀ = 19.2; // Null hypothesis (μ Population mean) +$σ = 6; // SD of population (Standard error of the mean) +$z = Significance:zTest($Hₐ, $n, $H₀, $σ); // Same as zTestOneSample +$z = Significance:zTestOneSample($Hₐ, $n, $H₀, $σ); // Same as zTest +/* [ + 'z' => 1.88562, // Z score + 'p1' => 0.02938, // one-tailed p value + 'p2' => 0.0593, // two-tailed p value +] */ + +// Z test - Two samples (z and p values) +$μ₁ = 27; // Sample mean of population 1 +$μ₂ = 33; // Sample mean of population 2 +$n₁ = 75; // Sample size of population 1 +$n₂ = 50; // Sample size of population 2 +$σ₁ = 14.1; // Standard deviation of sample mean 1 +$σ₂ = 9.5; // Standard deviation of sample mean 2 +$z = Significance::zTestTwoSample($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂); +/* [ + 'z' => -2.36868418147285, // z score + 'p1' => 0.00893, // one-tailed p value + 'p2' => 0.0179, // two-tailed p value +] */ + +// Z score +$M = 8; // Sample mean +$μ = 7; // Population mean +$σ = 1; // Population SD +$z = Significance::zScore($M, $μ, $σ); + +// T test - One sample (from sample data) +$a = [3, 4, 4, 5, 5, 5, 6, 6, 7, 8]; // Data set +$H₀ = 300; // Null hypothesis (μ₀ Population mean) +$tTest = Significance::tTest($a, $H₀) +print_r($tTest); +/* Array ( + [t] => 0.42320736951516 // t score + [df] => 9 // degrees of freedom + [p1] => 0.34103867713806 // one-tailed p value + [p2] => 0.68207735427613 // two-tailed p value + [mean] => 5.3 // sample mean + [sd] => 1.4944341180973 // standard deviation +) */ + +// T test - One sample (from summary data) +$Hₐ = 280; // Alternate hypothesis (M Sample mean) +$s = 50; // Standard deviation of sample +$n = 15; // Sample size +$H₀ = 300; // Null hypothesis (μ₀ Population mean) +$tTest = Significance::tTestOneSampleFromSummaryData($Hₐ, $s, $n, $H₀); +print_r($tTest); +/* Array ( + [t] => -1.549193338483 // t score + [df] => 14 // degreees of freedom + [p1] => 0.071820000122611 // one-tailed p value + [p2] => 0.14364000024522 // two-tailed p value + [mean] => 280 // sample mean + [sd] => 50 // standard deviation +) */ + +// T test - Two samples (from sample data) +$x₁ = [27.5, 21.0, 19.0, 23.6, 17.0, 17.9, 16.9, 20.1, 21.9, 22.6, 23.1, 19.6, 19.0, 21.7, 21.4]; +$x₂ = [27.1, 22.0, 20.8, 23.4, 23.4, 23.5, 25.8, 22.0, 24.8, 20.2, 21.9, 22.1, 22.9, 20.5, 24.4]; +$tTest = Significance::tTest($x₁, $x₂); +print_r($tTest); +/* Array ( + [t] => -2.4553600286929 // t score + [df] => 24.988527070145 // degrees of freedom + [p1] => 0.010688914613979 // one-tailed p value + [p2] => 0.021377829227958 // two-tailed p value + [mean1] => 20.82 // mean of sample x₁ + [mean2] => 22.98667 // mean of sample x₂ + [sd1] => 2.804894 // standard deviation of x₁ + [sd2] => 1.952605 // standard deviation of x₂ +) */ + +// T test - Two samples (from summary data) +$μ₁ = 42.14; // Sample mean of population 1 +$μ₂ = 43.23; // Sample mean of population 2 +$n₁ = 10; // Sample size of population 1 +$n₂ = 10; // Sample size of population 2 +$σ₁ = 0.683; // Standard deviation of sample mean 1 +$σ₂ = 0.750; // Standard deviation of sample mean 2 +$tTest = Significance::tTestTwoSampleFromSummaryData($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂); +print_r($tTest); +/* Array ( + [t] => -3.3972305988708 // t score + [df] => 17.847298548027 // degrees of freedom + [p1] => 0.0016211251126198 // one-tailed p value + [p2] => 0.0032422502252396 // two-tailed p value + [mean1] => 42.14 + [mean2] => 43.23 + [sd1] => 0.6834553 + [sd2] => 0.7498889 +] */ + +// T score +$Hₐ = 280; // Alternate hypothesis (M Sample mean) +$s = 50; // SD of sample +$n = 15; // Sample size +$H₀ = 300; // Null hypothesis (μ₀ Population mean) +$t = Significance::tScore($Hₐ, $s, $n, $H); + +// χ² test (chi-squared goodness of fit test) +$observed = [4, 6, 17, 16, 8, 9]; +$expected = [10, 10, 10, 10, 10, 10]; +$χ² = Significance::chiSquaredTest($observed, $expected); +// ['chi-square' => 14.2, 'p' => 0.014388] +``` + +### Trigonometry +```php +use MathPHP\Trigonometry; + +$n = 9; +$points = Trigonometry::unitCircle($n); // Produce n number of points along the unit circle +``` + +Unit Tests +---------- + +Beyond 100% code coverage! + +MathPHP has thousands of unit tests testing individual functions directly with numerous data inputs to achieve 100% test coverage. +MathPHP unit tests also test mathematical axioms which indirectly test the same functions in multiple different ways ensuring that those math properties all work out according to the axioms. + +```bash +$ cd tests +$ phpunit +``` + +[![Coverage Status](https://coveralls.io/repos/github/markrogoyski/math-php/badge.svg?branch=master)](https://coveralls.io/github/markrogoyski/math-php?branch=master) + +Standards +--------- + +MathPHP conforms to the following standards: + + * PSR-1 - Basic coding standard (http://www.php-fig.org/psr/psr-1/) + * PSR-4 - Autoloader (http://www.php-fig.org/psr/psr-4/) + * PSR-12 - Extended coding style guide (http://www.php-fig.org/psr/psr-12/) + +License +------- + +MathPHP is licensed under the MIT License. diff --git a/htdocs/includes/markrogoyski/math-php/composer.json b/htdocs/includes/markrogoyski/math-php/composer.json new file mode 100644 index 00000000000..fb937419c4c --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/composer.json @@ -0,0 +1,41 @@ +{ + "name": "markrogoyski/math-php", + "type": "library", + "description": "Math Library for PHP. Features descriptive statistics and regressions; Continuous and discrete probability distributions; Linear algebra with matrices and vectors, Numerical analysis; special mathematical functions; Algebra", + "keywords": ["math", "mathematics", "probability", "combinatorics", "statistics", "distributions", "regressions", "linear algebra", "matrix", "algebra", "numerical analysis"], + "homepage": "https://github.com/markrogoyski/math-php/", + "require": { + "php": ">=7.2.0", + "ext-json": "*" + }, + "autoload": { + "psr-4": { "MathPHP\\": "src/" } + }, + "require-dev": { + "phpunit/phpunit": "^8.5", + "php-coveralls/php-coveralls": "^2.0", + "squizlabs/php_codesniffer": "3.*", + "phpstan/phpstan": "^1.10", + "phpmd/phpmd": "^2.6", + "phploc/phploc": "*", + "php-parallel-lint/php-parallel-lint": "^1.2" + }, + "authors": [ + { + "name": "Mark Rogoyski", + "role": "Lead developer", + "email": "mark@rogoyski.com", + "homepage": "https://github.com/markrogoyski" + }, + { + "name": "Kevin Nowaczyk", + "role": "Developer", + "homepage": "https://github.com/Beakerboy" + }, + { + "name": "MathPHP Community of Contributors", + "homepage": "https://github.com/markrogoyski/math-php/graphs/contributors" + } + ], + "license": "MIT" +} diff --git a/htdocs/includes/markrogoyski/math-php/src/Exception/BadDataException.php b/htdocs/includes/markrogoyski/math-php/src/Exception/BadDataException.php new file mode 100644 index 00000000000..43fed7fe60d --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/src/Exception/BadDataException.php @@ -0,0 +1,7 @@ + $periods) { + return \NAN; + } + + if ($rate == 0) { + return 0; + } + + if ($beginning && $period == 1) { + return 0.0; + } + + $payment = self::pmt($rate, $periods, $present_value, $future_value, $beginning); + if ($beginning) { + $interest = (self::fv($rate, $period - 2, $payment, $present_value, $beginning) - $payment) * $rate; + } else { + $interest = self::fv($rate, $period - 1, $payment, $present_value, $beginning) * $rate; + } + + return self::checkZero($interest); + } + + /** + * Principle on a financial payment for a loan or annuity with compound interest. + * Determines the principle payment at a particular period of the annuity. For + * a typical loan paid down to zero, the amount of interest and principle paid + * throughout the lifetime of the loan will change, with the principle portion + * of the payment increasing over time as the loan principle decreases. + * + * Same as the =PPMT() function in most spreadsheet software. + * + * See the PMT function for derivation of the formula. + * See the IPMT function for derivation and use of PMT, IPMT, and PPMT. + * + * With derivations for PMT and IPMT, we simply compute: + * + * PPMT = PMT - IPMT + * + * Examples: + * The principle on a payment on a 30-year fixed mortgage note of $265000 at 3.5% interest + * paid at the end of every month, looking at the first payment: + * ppmt(0.035/12, 1, 30*12, 265000, 0, false) + * + * @param float $rate + * @param int $period + * @param int $periods + * @param float $present_value + * @param float $future_value + * @param bool $beginning adjust the payment to the beginning or end of the period + * + * @return float + */ + public static function ppmt(float $rate, int $period, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float + { + $payment = self::pmt($rate, $periods, $present_value, $future_value, $beginning); + $ipmt = self::ipmt($rate, $period, $periods, $present_value, $future_value, $beginning); + + return $payment - $ipmt; + } + + /** + * Number of payment periods of an annuity. + * Solves for the number of periods in the annuity formula. + * + * Same as the =NPER() function in most spreadsheet software. + * + * Solving the basic annuity formula for number of periods: + * log(PMT - FV*r) + * --------------- + * log(PMT + PV*r) + * n = -------------------- + * log(1 + r) + * + * The (1+r*when) factor adjusts the payment to the beginning or end + * of the period. In the common case of a payment at the end of a period, + * the factor is 1 and reduces to the formula above. Setting when=1 computes + * an "annuity due" with an immediate payment. + * + * Examples: + * The number of periods of a $475000 mortgage with interest rate 3.5% and monthly + * payment of $2132.96 paid in full: + * nper(0.035/12, -2132.96, 475000, 0) + * + * @param float $rate + * @param float $payment + * @param float $present_value + * @param float $future_value + * @param bool $beginning adjust the payment to the beginning or end of the period + * + * @return float + */ + public static function periods(float $rate, float $payment, float $present_value, float $future_value, bool $beginning = false): float + { + $when = $beginning ? 1 : 0; + + if ($rate == 0) { + return - ($present_value + $future_value) / $payment; + } + + $initial = $payment * (1.0 + $rate * $when); + return \log(($initial - $future_value * $rate) / ($initial + $present_value * $rate)) / \log(1.0 + $rate); + } + + /** + * Annual Equivalent Rate (AER) of an annual percentage rate (APR). + * The effective yearly rate of an annual percentage rate when the + * annual percentage rate is compounded periodically within the year. + * + * Same as the =EFFECT() function in most spreadsheet software. + * + * The formula: + * https://en.wikipedia.org/wiki/Effective_interest_rate + * + * / i \ ᴺ + * AER = | 1 + - | - 1 + * \ n / + * + * Examples: + * The AER of APR 3.5% interest compounded monthly. + * aer(0.035, 12) + * + * @param float $nominal + * @param int $periods + * + * @return float + */ + public static function aer(float $nominal, int $periods): float + { + if ($periods == 1) { + return $nominal; + } + + return \pow(1 + ($nominal / $periods), $periods) - 1; + } + + /** + * Annual Nominal Rate of an annual effective rate (AER). + * The nominal yearly rate of an annual effective rate when the + * annual effective rate is compounded periodically within the year. + * + * Same as the =NOMINAL() function in most spreadsheet software. + * + * See: + * https://en.wikipedia.org/wiki/Nominal_interest_rate + * + * / 1/N \ + * NOMINAL = | (AER + 1) -1 | * N + * \ / + * + * Examples: + * The nominal rate of AER 3.557% interest compounded monthly. + * nominal(0.03557, 12) + * + * @param float $aer + * @param int $periods + * + * @return float + */ + public static function nominal(float $aer, int $periods): float + { + if ($periods == 1) { + return $aer; + } + + return (\pow($aer + 1, 1 / $periods) - 1) * $periods; + } + + /** + * Future value for a loan or annuity with compound interest. + * + * Same as the =FV() function in most spreadsheet software. + * + * The basic future-value formula derivation: + * https://en.wikipedia.org/wiki/Future_value + * + * PMT*((1+r)ᴺ - 1) + * FV = -PV*(1+r)ᴺ - ---------------- + * r + * + * The (1+r*when) factor adjusts the payment to the beginning or end + * of the period. In the common case of a payment at the end of a period, + * the factor is 1 and reduces to the formula above. Setting when=1 computes + * an "annuity due" with an immediate payment. + * + * Examples: + * The future value in 5 years on a 30-year fixed mortgage note of $265000 + * at 3.5% interest paid at the end of every month. This is how much loan + * principle would be outstanding: + * fv(0.035/12, 5*12, 1189.97, -265000, false) + * + * The present_value is negative indicating money borrowed for the mortgage, + * whereas payment is positive, indicating money that will be paid to the + * mortgage. + * + * @param float $rate + * @param int $periods + * @param float $payment + * @param float $present_value + * @param bool $beginning adjust the payment to the beginning or end of the period + * + * @return float + */ + public static function fv(float $rate, int $periods, float $payment, float $present_value, bool $beginning = false): float + { + $when = $beginning ? 1 : 0; + + if ($rate == 0) { + $fv = -($present_value + ($payment * $periods)); + return self::checkZero($fv); + } + + $initial = 1 + ($rate * $when); + $compound = \pow(1 + $rate, $periods); + $fv = - (($present_value * $compound) + (($payment * $initial * ($compound - 1)) / $rate)); + + return self::checkZero($fv); + } + + /** + * Present value for a loan or annuity with compound interest. + * + * Same as the =PV() function in most spreadsheet software. + * + * The basic present-value formula derivation: + * https://en.wikipedia.org/wiki/Present_value + * + * PMT*((1+r)ᴺ - 1) + * PV = -FV - ---------------- + * r + * --------------------- + * (1 + r)ᴺ + * + * The (1+r*when) factor adjusts the payment to the beginning or end + * of the period. In the common case of a payment at the end of a period, + * the factor is 1 and reduces to the formula above. Setting when=1 computes + * an "annuity due" with an immediate payment. + * + * Examples: + * The present value of a bond's $1000 face value paid in 5 year's time + * with a constant discount rate of 3.5% compounded monthly: + * pv(0.035/12, 5*12, 0, -1000, false) + * + * The present value of a $1000 5-year bond that pays a fixed 7% ($70) + * coupon at the end of each year with a discount rate of 5%: + * pv(0.5, 5, -70, -1000, false) + * + * The payment and future_value is negative indicating money paid out. + * + * @param float $rate + * @param int $periods + * @param float $payment + * @param float $future_value + * @param bool $beginning adjust the payment to the beginning or end of the period + * + * @return float + */ + public static function pv(float $rate, int $periods, float $payment, float $future_value, bool $beginning = false): float + { + $when = $beginning ? 1 : 0; + + if ($rate == 0) { + $pv = -$future_value - ($payment * $periods); + return self::checkZero($pv); + } + + $initial = 1 + ($rate * $when); + $compound = \pow(1 + $rate, $periods); + $pv = (-$future_value - (($payment * $initial * ($compound - 1)) / $rate)) / $compound; + + return self::checkZero($pv); + } + + /** + * Net present value of cash flows. Cash flows are periodic starting + * from an initial time and with a uniform discount rate. + * + * Similar to the =NPV() function in most spreadsheet software, except + * the initial (usually negative) cash flow at time 0 is given as the + * first element of the array rather than subtracted. For example, + * spreadsheet: =NPV(0.01, 100, 200, 300, 400) - 1000 + * is done as + * MathPHP::npv(0.01, [-1000, 100, 200, 300, 400]) + * + * The basic net-present-value formula derivation: + * https://en.wikipedia.org/wiki/Net_present_value + * + * n Rt + * Σ -------- + * t=0 (1 / r)ᵗ + * + * Examples: + * The net present value of 5 yearly cash flows after an initial $1000 + * investment with a 3% discount rate: + * npv(0.03, [-1000, 100, 500, 300, 700, 700]) + * + * @param float $rate + * @param array $values + * + * @return float + */ + public static function npv(float $rate, array $values): float + { + $result = 0.0; + + for ($i = 0; $i < \count($values); ++$i) { + $result += $values[$i] / (1 + $rate) ** $i; + } + + return $result; + } + + /** + * Interest rate per period of an Annuity. + * + * Same as the =RATE() formula in most spreadsheet software. + * + * The basic rate formula derivation is to solve for the future value + * taking into account the present value: + * https://en.wikipedia.org/wiki/Future_value + * + * ((1+r)ᴺ - 1) + * FV + PV*(1+r)ᴺ + PMT * ------------ = 0 + * r + * The (1+r*when) factor adjusts the payment to the beginning or end + * of the period. In the common case of a payment at the end of a period, + * the factor is 1 and reduces to the formula above. Setting when=1 computes + * an "annuity due" with an immediate payment. + * + * Not all solutions for the rate have real-value solutions or converge. + * In these cases, NAN is returned. + * + * @param float $periods + * @param float $payment + * @param float $present_value + * @param float $future_value + * @param bool $beginning + * @param float $initial_guess + * + * @return float + */ + public static function rate(float $periods, float $payment, float $present_value, float $future_value, bool $beginning = false, float $initial_guess = 0.1): float + { + $when = $beginning ? 1 : 0; + + $func = function ($x, $periods, $payment, $present_value, $future_value, $when) { + return $future_value + $present_value * (1 + $x) ** $periods + $payment * (1 + $x * $when) / $x * ((1 + $x) ** $periods - 1); + }; + + return self::checkZero(NumericalAnalysis\RootFinding\NewtonsMethod::solve($func, [$initial_guess, $periods, $payment, $present_value, $future_value, $when], 0, self::EPSILON, 0)); + } + + /** + * Internal rate of return. + * Periodic rate of return that would provide a net-present value (NPV) of 0. + * + * Same as =IRR formula in most spreadsheet software. + * + * Reference: + * https://en.wikipedia.org/wiki/Internal_rate_of_return + * + * Examples: + * The rate of return of an initial investment of $100 with returns + * of $50, $40, and $30: + * irr([-100, 50, 40, 30]) + * + * Solves for NPV=0 using Newton's Method. + * @param array $values + * @param float $initial_guess + * + * @return float + * + * @throws OutOfBoundsException + * + * @todo: Use eigenvalues to find the roots of a characteristic polynomial. + * This will allow finding all solutions and eliminate the need of the initial_guess. + */ + public static function irr(array $values, float $initial_guess = 0.1): float + { + $func = function ($x, $values) { + return Finance::npv($x, $values); + }; + + if (\count($values) <= 1) { + return \NAN; + } + + $root = NumericalAnalysis\RootFinding\NewtonsMethod::solve($func, [$initial_guess, $values], 0, self::EPSILON, 0); + if (!\is_nan($root)) { + return self::CheckZero($root); + } + return self::checkZero(self::alternateIrr($values)); + } + + /** + * Alternate IRR implementation. + * + * A more numerically stable implementation that converges to only one value. + * + * Based off of Better: https://github.com/better/irr + * + * @param array $values + * + * @return float + */ + private static function alternateIrr(array $values): float + { + $rate = 0.0; + for ($iter = 0; $iter < 100; $iter++) { + $m = -1000; + for ($i = 0; $i < \count($values); $i++) { + $m = \max($m, -$rate * $i); + } + $f = []; + for ($i = 0; $i < \count($values); $i++) { + $f[$i] = \exp(-$rate * $i - $m); + } + $t = 0; + for ($i = 0; $i < \count($values); $i++) { + $t += $f[$i] * $values[$i]; + } + if (\abs($t) < (self::EPSILON * \exp($m))) { + break; + } + $u = 0; + for ($i = 0; $i < \count($values); $i++) { + $u += $f[$i] * $i * $values[$i]; + } + if ($u == 0) { + return \NAN; + } + $rate += $t / $u; + } + return \exp($rate) - 1; + } + + /** + * Modified internal rate of return. + * Rate of return that discounts outflows (investments) at the financing rate, + * and reinvests inflows with an expected rate of return. + * + * Same as =MIRR formula in most spreadsheet software. + * + * The formula derivation: + * https://en.wikipedia.org/wiki/Modified_internal_rate_of_return + * + * _____________________________ + * n/ FV(re-invested cash inflows) + * - / ---------------------------- - 1.0 + * \/ PV(discounted cash outflows) + * + * Examples: + * The rate of return of an initial investment of $100 at 5% financing + * with returns of $50, $40, and $30 reinvested at 10%: + * mirr([-100, 50, 40, 30], 0.05, 0.10) + * + * @param array $values + * @param float $finance_rate + * @param float $reinvestment_rate + * + * @return float + */ + public static function mirr(array $values, float $finance_rate, float $reinvestment_rate): float + { + $inflows = array(); + $outflows = array(); + + for ($i = 0; $i < \count($values); $i++) { + if ($values[$i] >= 0) { + $inflows[] = $values[$i]; + $outflows[] = 0; + } else { + $inflows[] = 0; + $outflows[] = $values[$i]; + } + } + + $nonzero = function ($x) { + return $x != 0; + }; + + if (\count(\array_filter($inflows, $nonzero)) == 0 || \count(\array_filter($outflows, $nonzero)) == 0) { + return \NAN; + } + + $root = \count($values) - 1; + $pv_inflows = self::npv($reinvestment_rate, $inflows); + $fv_inflows = self::fv($reinvestment_rate, $root, 0, -$pv_inflows); + $pv_outflows = self::npv($finance_rate, $outflows); + + return self::checkZero(\pow($fv_inflows / -$pv_outflows, 1 / $root) - 1); + } + + /** + * Discounted Payback of an investment. + * The number of periods to recoup cash outlays of an investment. + * + * This is commonly used with discount rate=0 as simple payback period, + * but it is not a real financial measurement when it doesn't consider the + * discount rate. Even with a discount rate, it doesn't consider the cost + * of capital or re-investment of returns. + * + * Avoid this when possible. Consider NPV, MIRR, IRR, and other financial + * functions. + * + * Reference: + * https://en.wikipedia.org/wiki/Payback_period + * + * The result is given assuming cash flows are continous throughout a period. + * To compute payback in terms of whole periods, use ceil() on the result. + * + * An investment could reach its payback period before future cash outlays occur. + * The payback period returned is defined to be the final point at which the + * sum of returns becomes positive. + * + * Examples: + * The payback period of an investment with a $1,000 investment and future returns + * of $100, $200, $300, $400, $500: + * payback([-1000, 100, 200, 300, 400, 500]) + * + * The discounted payback period of an investment with a $1,000 investment, future returns + * of $100, $200, $300, $400, $500, and a discount rate of 0.10: + * payback([-1000, 100, 200, 300, 400, 500], 0.1) + * + * @param array $values + * @param float $rate + * + * @return float + */ + public static function payback(array $values, float $rate = 0.0): float + { + $last_outflow = -1; + for ($i = 0; $i < \count($values); $i++) { + if ($values[$i] < 0) { + $last_outflow = $i; + } + } + + if ($last_outflow < 0) { + return 0.0; + } + + $sum = $values[0]; + $payback_period = -1; + + for ($i = 1; $i < \count($values); $i++) { + $prevsum = $sum; + $discounted_flow = $values[$i] / (1 + $rate) ** $i; + $sum += $discounted_flow; + if ($sum >= 0) { + if ($i > $last_outflow) { + return ($i - 1) + (-$prevsum / $discounted_flow); + } + if ($payback_period == -1) { + $payback_period = ($i - 1) + (-$prevsum / $discounted_flow); + } + } else { + $payback_period = -1; + } + } + if ($sum >= 0) { + return $payback_period; + } + + return \NAN; + } + + /** + * Profitability Index. + * The Profitability Index, also referred to as Profit Investment + * Ratio (PIR) and Value Investment Ratio (VIR), is a comparison of + * discounted cash inflows to discounted cash outflows. It can be + * used as a decision criteria of an investment, using larger than 1 + * to choose an investment, and less than 1 to pass. + * + * The formula derivation: + * https://en.wikipedia.org/wiki/Profitability_index + * + * PV(cash inflows) + * ---------------- + * PV(cash outflows) + * + * The formula is usually stated in terms of the initial investmest, + * but it is generalized here to discount all future outflows. + * + * Examples: + * The profitability index of an initial $100 investment with future + * returns of $50, $50, $50 with a 10% discount rate: + * profitabilityIndex([-100, 50, 50, 50], 0.10) + * + * @param array $values + * @param float $rate + * + * @return float + */ + public static function profitabilityIndex(array $values, float $rate): float + { + $inflows = array(); + $outflows = array(); + + for ($i = 0; $i < \count($values); $i++) { + if ($values[$i] >= 0) { + $inflows[] = $values[$i]; + $outflows[] = 0; + } else { + $inflows[] = 0; + $outflows[] = -$values[$i]; + } + } + + $nonzero = function ($x) { + return $x != 0; + }; + + if (\count(\array_filter($outflows, $nonzero)) == 0) { + return \NAN; + } + + $pv_inflows = self::npv($rate, $inflows); + $pv_outflows = self::npv($rate, $outflows); + + return $pv_inflows / $pv_outflows; + } +} diff --git a/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/NewtonsMethod.php b/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/NewtonsMethod.php new file mode 100644 index 00000000000..77c03ac6eda --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/NewtonsMethod.php @@ -0,0 +1,61 @@ + $args Parameters to pass to callback function. The initial value for the + * parameter of interest must be in this array. + * @param int|float $target Value of f(x) we a trying to solve for + * @param float $tol Tolerance; How close to the actual solution we would like. + * @param int $position Which element in the $args array will be changed; also serves as initial guess + * @param int $iterations + * + * @return int|float + * + * @throws Exception\OutOfBoundsException if the tolerance is not valid + */ + public static function solve(callable $function, array $args, $target, float $tol, int $position = 0, int $iterations = 100) + { + Validation::tolerance($tol); + + // Initialize + $args1 = $args; + $guess = $args[$position]; + $i = 0; + + do { + $args1[$position] = $guess + $tol; // load the initial guess into the arguments + $args[$position] = $guess; // load the initial guess into the arguments + $y = $function(...$args); + $y_at_xplusdelx = $function(...$args1); + $slope = ($y_at_xplusdelx - $y) / $tol; + $del_y = $target - $y; + if (\abs($slope) < $tol) { + return \NAN; + } + $guess = $del_y / $slope + $guess; + $dif = \abs($del_y); + $i++; + } while ($dif > $tol && $i < $iterations); + + if ($dif > $tol) { + return \NAN; + } + return $guess; + } +} diff --git a/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/Validation.php b/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/Validation.php new file mode 100644 index 00000000000..913bd369772 --- /dev/null +++ b/htdocs/includes/markrogoyski/math-php/src/NumericalAnalysis/RootFinding/Validation.php @@ -0,0 +1,40 @@ +