NEW : Library including math and financial functions (#25035)

This commit is contained in:
ATM-Nicolas 2023-10-12 18:01:16 +02:00 committed by GitHub
parent 9274f7f507
commit 9ef5d4ae2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 4714 additions and 0 deletions

View File

@ -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

View File

@ -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 BoxMuller 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

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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"
}

View File

@ -0,0 +1,7 @@
<?php
namespace MathPHP\Exception;
class BadDataException extends MathException
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace MathPHP\Exception;
class OutOfBoundsException extends MathException
{
}

View File

@ -0,0 +1,780 @@
<?php
namespace MathPHP;
use MathPHP\Exception\OutOfBoundsException;
/**
* General references on financial functions and formulas:
* - Open Document Format for Office Applications (OpenDocument) Version 1.2 Part 2:
* Recalculated Formula (OpenFormula) Format. 29 September 2011. OASIS Standard.
* http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part2.html#__RefHeading__1018228_715980110
* - https://wiki.openoffice.org/wiki/Documentation/How_Tos/Calc:_Derivation_of_Financial_Formulas#Loans_and_Annuities
*/
class Finance
{
/**
* Floating-point range near zero to consider insignificant.
*/
public const EPSILON = 1e-6;
/**
* Consider any floating-point value less than epsilon from zero as zero,
* ie any value in the range [-epsilon < 0 < epsilon] is considered zero.
* Also used to convert -0.0 to 0.0.
*
* @param float $value
* @param float $epsilon
*
* @return float
*/
private static function checkZero(float $value, float $epsilon = self::EPSILON): float
{
return \abs($value) < $epsilon ? 0.0 : $value;
}
/**
* Financial payment for a loan or annuity with compound interest.
* Determines the periodic payment amount for a given interest rate,
* principal, targeted payment goal, life of the annuity as number
* of payments, and whether the payments are made at the start or end
* of each payment period.
*
* Same as the =PMT() function in most spreadsheet software.
*
* The basic monthly payment formula derivation:
* https://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula
*
* rP(1+r)
* PMT = --------
* (1+r)-1
*
* The formula is adjusted to allow targeting any future value rather than 0.
* The 1/(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 payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
* paid at the end of every month.
* pmt(0.035/12, 30*12, 265000, 0, false)
*
* The payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
* needed to half the principal in half in 5 years:
* pmt(0.035/12, 5*12, 265000, 265000/2, false)
*
* The weekly payment into a savings account with 1% interest rate and current
* balance of $1500 needed to reach $10000 after 3 years:
* pmt(0.01/52, 3*52, -1500, 10000, false)
* The present_value is negative indicating money put into the savings account,
* whereas future_value is positive, indicating money that will be withdrawn from
* the account. Similarly, the payment value is negative
*
* How much money can be withdrawn at the end of every quarter from an account
* with $1000000 earning 4% so the money lasts 20 years:
* pmt(0.04/4, 20*4, 1000000, 0, false)
*
* @param float $rate
* @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 pmt(float $rate, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float
{
$when = $beginning ? 1 : 0;
if ($rate == 0) {
return - ($future_value + $present_value) / $periods;
}
return - ($future_value + ($present_value * \pow(1 + $rate, $periods)))
/
((1 + $rate * $when) / $rate * (\pow(1 + $rate, $periods) - 1));
}
/**
* Interest on a financial payment for a loan or annuity with compound interest.
* Determines the interest 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 interest portion
* of the payment decreasing over time as the loan principle decreases.
*
* Same as the =IPMT() function in most spreadsheet software.
*
* See the PMT function for derivation of the formula. For IPMT, we have
* the payment equal to the interest portion and principle portion of the payment:
*
* PMT = IPMT + PPMT
*
* The interest portion IPMT on a regular annuity can be calculated by computing
* the future value of the annuity for the prior period and computing the compound
* interest for one period:
*
* IPMT = FV(p=n-1) * rate
*
* For an "annuity due" where payment is at the start of the period, period=1 has
* no interest portion of the payment because no time has elapsed for compounding.
* To compute the interest portion of the payment, the future value of 2 periods
* back needs to be computed, as the definition of a period is different, giving:
*
* IPMT = (FV(p=n-2) - PMT) * rate
*
* By thinking of the future value at period 0 instead of the present value, the
* given formulas are computed.
*
* Example of regular annuity and annuity due for a loan of $10.00 paid back in 3 periods.
* Although the principle payments are equal, the total payment and interest portion are
* lower with the annuity due because a principle payment is made immediately.
*
* Regular Annuity | Annuity Due
* Period FV PMT IPMT PPMT | PMT IPMT PPMT
* 0 -10.00 |
* 1 -6.83 -3.67 -0.50 -3.17 | -3.50 0.00 -3.50
* 2 -3.50 -3.67 -0.34 -3.33 | -3.50 -0.33 -3.17
* 3 0.00 -3.67 -0.17 -3.50 | -3.50 -0.17 -3.33
* -----------------------|----------------------
* SUM -11.01 -1.01 -10.00 | -10.50 -0.50 -10.00
*
* Examples:
* The interest 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:
* ipmt(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 ipmt(float $rate, int $period, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float
{
if ($period < 1 || $period > $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<float> $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<float> $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<float> $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<float> $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<float> $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<float> $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;
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace MathPHP\NumericalAnalysis\RootFinding;
use MathPHP\Exception;
/**
* Newton's Method (also known as the NewtonRaphson method)
*
* In numerical analysis, Newton's method is a method for finding successively better
* approximations to the roots (or zeroes) of a real-valued function.
*/
class NewtonsMethod
{
/**
* Use Newton's Method to find the x which produces $target = $function(x) value
* $args is an array of parameters to pass to $function, but having the element that
* will be changed and serve as the initial guess in position $position.
*
* @param callable $function f(x) callback function
* @param array<mixed> $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;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace MathPHP\NumericalAnalysis\RootFinding;
use MathPHP\Exception;
/**
* Common validation methods for root finding techniques
*/
class Validation
{
/**
* Throw an exception if the tolerance is negative.
*
* @param int|float $tol Tolerance; How close to the actual solution we would like.
*
* @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative
*/
public static function tolerance($tol): void
{
if ($tol < 0) {
throw new Exception\OutOfBoundsException('Tolerance must be greater than zero.');
}
}
/**
* Verify that the start and end of of an interval are distinct numbers.
*
* @param int|float $a The start of the interval
* @param int|float $b The end of the interval
*
* @throws Exception\BadDataException if $a = $b
*/
public static function interval($a, $b): void
{
if ($a === $b) {
throw new Exception\BadDataException('Start point and end point of interval cannot be the same.');
}
}
}