Current Path : /var/www/html/soar-backup/wp-content/plugins/formcraft3/lib/eos/ |
Current File : /var/www/html/soar-backup/wp-content/plugins/formcraft3/lib/eos/Matrix.php |
<?php /** * matrix.class.php * * Will set up the defines for error checking as well as provide * the Matrix class for include. As this is made to be modular, * only the class (and possibly helper classes) along with their * defines will be found in this file. * @package Math * @subpackage Matrix */ namespace jlawrence\eos; /** * Matrix Class * * This class will allow you to create and use Matrices * as well as providing common Matrix operations. It * uses PHP5 for OOP and Error Throwing and is commented * for the PHPDoc Parser for documentation creation. * * @version $Id: matrix.class.php 10 2012-08-06 23:41:36Z jlawrence11 $ * @author Jon Lawrence <JLawrence11@gmail.com> * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License * @copyright Copyright �2012, Jon Lawrence * @package Math * @subpackage Matrix */ class Matrix { /** * Invalid String input type */ const E_INVALID_INPUT = 5001; /** * Matrix needed to be a square matrix for the operation */ const E_NOT_SQUARE = 5002; /** * Matrix was undefined */ const E_NO_MATRIX = 5003; /** * Matrix had varying column lengths */ const E_INVALID_MATRIX = 5004; /** * Matrix operation required rows/cols to be even, they were not */ const E_NOT_EQUAL = 5005; /** * Determinate was '0' while preforming another operation */ const E_NO_INVERSE = 5006; private $matrix; /** * Construct method * * For format of input string, see the see tag below * * @see Matrix::_assign() * @param string $mText Matrix text input */ public function __construct($mText="") { if ($mText) $this->_assign($mText); } /** * Create a matrix based on string input similar to the TI Calculators * input string "[1,2,3;4,5,6;7,8,9]" is the equivalent of the matrix: * <pre> * | 1 2 3 | * | 4 5 6 | * | 7 8 9 | * </pre> * * @param String $mText The matrix in string format to assign to the current object * @return Boolean True if is passes verification after being converted * @throws \Exception If the input text is not in a valid format */ public function _assign($mText) { if(trim($mText)=="") return false; $mText = preg_replace("/\s/", "", $mText); if(!preg_match("/^\[(([\-]*[0-9\. ]+[,]{0,1})+[;]{0,1})*\]$/", $mText)) { throw new \Exception("'{$mText}' is not a valid input", Matrix::E_INVALID_INPUT); } $mText = preg_replace("/(\[|\])/", "", $mText); $rows = explode(";", $mText); $i=0;$j=0; foreach($rows as $row) { $cols = explode(",", $row); foreach($cols as $value) { $this->matrix[$i][$j] = $value; $j++; } $i++; $j = 0; } return $this->_verify(); } /** * Private function that will verify all the columns have the same * number of items, ensuring it is a valid matrix * * @access private * @param array|bool $mArray * @return bool True if it passes, false if not a valid matrix */ private function _verify($mArray = false) { if(!$mArray) $mArray = $this->matrix; $nSet = false; if(is_array($mArray)) { foreach($mArray as $row) { $cols = count($row); if($nSet===false) { $nSet = $cols; } if($cols != $nSet) { return false; } } } else { return false; } return true; } /** * Is it a valid matrix? * * Public function to tell the class user whether or not the passed * array is valid, if no array is passed, it will tell the user whether * the matrix of the current instance is valid. Valid is denoted by all * rows have the same number of columns. * * @param array|bool $mArray Array to be used, if not assigned will default to $this->matrix * @return bool True/False depending on if array is a valid matrix */ public function isValid($mArray = false) { if(!$mArray) $mArray = $this->matrix; return $this->_verify($mArray); } /** * Is it a square Matrix? * * Will determine whether or not the matrix is valid, and if it * is, will determine if the matrix is a square matrix (n by n). * * @param array|bool $mArray Matrix array, if not assigned will use $this->matrix * @return bool True/False depending on whether or not the matrix is square */ public function isSquare($mArray = false) { if(!$mArray) $mArray = $this->matrix; if(!$this->_verify($mArray)) { return false; } $rows = count($mArray); $cols = count($mArray[0]); return ($rows == $cols); } /** * Get 'n' from a square (n by n) Matrix * * Will check to see if a matrix is square, if so, will return 'n', which * is the number of rows==columns in the matrix * * @param array|bool $mArray Matrix array, uses $this->matrix if not assigned * @return int The 'n' of a square matrix, or false if not square * @throws \Exception If not a square matrix, throws an exception */ public function _getN($mArray = false) { if(!$mArray) $mArray = $this->matrix; if($this->isSquare($mArray)) { return count($mArray); } else { $m = $this->toString($mArray); throw new \Exception("'{$m}' is not a square matrix", Matrix::E_NOT_SQUARE); } } /** * Create an Identity Matrix * * Creates an Identity Matrix of size 'n'. * * @link http://en.wikipedia.org/wiki/Identity_matrix * @param int $n The rows/cols of identity matrix * @param bool $useInternal If true will set $this->matrix * @return Matrix|bool Return an identity matrix if $useInternal is false, otherwise 'true' */ public function createIdentity($n, $useInternal = true) { $mArray = array(); for($rows=0;$rows<$n;$rows++) { for($cols=0;$cols<$n;$cols++) { if($rows==$cols) { $mArray[$rows][$cols] = 1; } else { $mArray[$rows][$cols] = 0; } } } if($useInternal == true) { $this->matrix = $mArray; return true; } else { $nMatrix = new Matrix($this->toString($mArray)); return $nMatrix; } } /** * Convert current Matrix to string format * * Convert an array to the string format used by this class. * * @see Matrix::_assign() * @param array|bool $mArray if not assigned will use this instance's matrix. * @throws \Exception If matrix is not an array * @return string The array broken down in to string format */ public function toString($mArray = false) { if(!$mArray) $mArray = $this->matrix; $rows=array(); if(is_array($mArray)) { foreach($mArray as $cols){ $rows[] = implode(",", $cols); } $retString = sprintf("[%s]", implode($rows, ";")); return $retString; } else { throw new \Exception("No matrix to convert", Matrix::E_NO_MATRIX); } } /** * Overload PHP's class __toString() method * * PHP magic method for "echoing" this object without a specific method called * Will use {@link Matrix::toString()} with no parameters for it's return. * * @return string Returns the $matrix value in string format */ public function __toString() { return $this->toString(); } /** * Get Matrix Array * * Will return the matrix array of the current instance. * * @return array The matrix array of the current instance */ public function getArray() { return $this->matrix; } /** * Formatted Matrix output for use in console * * Will output the matrix in 'pretty' format, if used with 'echo' and * HTML, surround it by the '<<pre>>' and '<</pre>>' tags to display properly * * @param int $width The width of printing space to use * @param array|bool $mArray Matrix array, defaults to $this->matrix * @return string "Pretty-Printed" matrix in ASCII format */ public function prettyPrint($width=80, $mArray=false) { if(!$mArray) $mArray = $this->matrix; if(!$this->_verify($mArray)) return false; $out = ""; $aCount = count($mArray[0]); $space = floor(($width-4)/$aCount); $space_2 = floor($space/2); foreach($mArray as $row) { $out .= sprintf("| %{$space_2}.2f", $row[0]); for($i=1;$i<$aCount;$i++) { $out .= sprintf("%{$space}.2f", $row[$i]); } $out .= sprintf("%{$space_2}s |\n", " "); } return $out; } /** * Adds two matrices together * * Will add the inputted Matrix to the current instance, and return * the result as Matrix class. * * @link http://en.wikipedia.org/wiki/Matrix_addition * @param Matrix $nMatrix Matrix class to be added to current instance * @return Matrix The result of the addition * @throws \Exception $msg of exception explains problem */ public function addMatrix(Matrix $nMatrix) { if(!$this->_verify() || !$nMatrix->_verify()) throw new \Exception("Matrices have varying column sizes", Matrix::E_INVALID_MATRIX); $matrix1 = $this->getArray(); $matrix2 = $nMatrix->getArray(); if((count($matrix1)!=count($matrix2)) || (count($matrix1[0])!=count($matrix2[0]))) { $m1 = $this->toString($matrix1); $m2 = $this->toString($matrix2); throw new \Exception("The rows and/or columns '{$m1}' and '{$m2}' are not the same", Matrix::E_NOT_EQUAL); } $rArray = array(); for($row=0;$row<count($matrix1);$row++) { for($col=0;$col<count($matrix1[0]);$col++) { $rArray[$row][$col] = $matrix1[$row][$col] + $matrix2[$row][$col]; } } $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } /** * Subtract Matrices * * Will subtract the inputted Matrix from the current instance, and return * the result as Matrix class. * * @link http://en.wikipedia.org/wiki/Matrix_subtraction * @param Matrix $nMatrix Matrix class to be subtracted from current instance * @return Matrix The result of the subtraction * @throws \Exception $msg of exception explains problem */ public function subMatrix(Matrix $nMatrix) { if(!$this->_verify() || !$nMatrix->_verify()) throw new \Exception("Matrices have varying column sizes", Matrix::E_INVALID_MATRIX); $matrix1 = $this->getArray(); $matrix2 = $nMatrix->getArray(); if((count($matrix1)!=count($matrix2)) || (count($matrix1[0])!=count($matrix2[0]))) { $m1 = $this->toString($matrix1); $m2 = $this->toString($matrix2); throw new \Exception("The rows and/or columns '{$m1}' and '{$m2}' are not the same", Matrix::E_NOT_EQUAL); } $rArray = array(); for($row=0;$row<count($matrix1);$row++) { for($col=0;$col<count($matrix1[0]);$col++) { $rArray[$row][$col] = $matrix1[$row][$col] - $matrix2[$row][$col]; } } $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } /** * Multiply current matrix by a scalar value * * Multiplies a matrix by a scalar value (int/float/etc) (constant, ie '2') * * @link http://en.wikipedia.org/wiki/Scalar_multiplication * @param float $k The value to multiply the matrix by * @return Matrix Returns a new Matrix instance with the result * @throws \Exception if the instance matrix is not valid */ public function mpScalar($k) { //we'll verify a true matrix to ... help the user if(!$this->_verify()) throw new \Exception("Matrix '{$this}' has varying column sizes", Matrix::E_INVALID_MATRIX); $cArray = $this->getArray(); $rArray = array(); $rows = count($cArray); $cols = count($cArray[0]); for($i=0;$i<$rows;$i++) { for($j=0;$j<$cols;$j++) { $rArray[$i][$j] = $cArray[$i][$j] * $k; } } $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } /** * Get the Matrix Determinant * * Finds the determinant of the square matrix, user should not use * the parameter, as that is meant to allow recursive calling * of this function from within itself. * * @link http://en.wikipedia.org/wiki/Matrix_determinant * @param array|bool $mArray The array to find a determinate of * @return float The Determinate of the square matrix * @throws \Exception If matrix is 1,1 or is not square */ public function getDeterminant($mArray = false) { if(!$mArray) $mArray = $this->matrix; //print_r($mArray); if(!$this->isSquare($mArray)) throw new \Exception("'{$this}' is not a square matrix", Matrix::E_NOT_SQUARE); $n = $this->_getN($mArray); if($n < 1){ // @codeCoverageIgnoreStart // Should never get this far throw new \Exception("No Matrix", Matrix::E_NO_MATRIX); // @codeCoverageIgnoreEnd } elseif ($n == 1) { $det = $mArray[0][0]; } elseif ($n == 2) { $det = $mArray[0][0]*$mArray[1][1] - $mArray[1][0]*$mArray[0][1]; } else { $det = 0; $nArray = array(); for($j1=0;$j1<$n;$j1++) { for($i=1;$i<$n;$i++) { $j2 = 0; for($j=0;$j<$n;$j++) { if($j==$j1) { continue; } $nArray[$i-1][$j2] = $mArray[$i][$j]; $j2++; } } $det += pow(-1,2+$j1)*$mArray[0][$j1]*$this->getDeterminant($nArray); } } return $det; } /** * coFactor Matrix * * Will return a Matrix of coFactors for the matrix provided, or an array * of the matrix as is the default. * * @link http://en.wikipedia.org/wiki/Matrix_cofactors * @param array|bool $cArray A matrix in array format (or $this->matrix by default) * @param bool $asArray When set to true, will return an array, when false a Matrix Object * @return Matrix|array A matrix of coFactors for the array provided (or current matrix) * @throws \Exception if the matrix is not square */ public function coFactor($cArray=false,$asArray=true) { if(!$cArray) $cArray = $this->matrix; if(!$this->isSquare($cArray)) throw new \Exception("'{$this}' is not a square matrix", Matrix::E_NOT_SQUARE); $n = $this->_getN($cArray); $minor = array(); $rArray = array(); for($j=0;$j<$n;$j++){ for($i=0;$i<$n;$i++) { //Form the adjugate $i1 = 0; for($ii=0;$ii<$n;$ii++) { if($ii==$i) { continue; } $j1=0; for($jj=0;$jj<$n;$jj++) { if($jj==$j) { continue; } $minor[$i1][$j1] = $cArray[$ii][$jj]; $j1++; } $i1++; } $det = $this->getDeterminant($minor); $rArray[$i][$j] = pow(-1,$i+$j+2)*$det; } } if($asArray==false){ $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } else { return $rArray; } } /** * Will transpose the current matrix or array provided * * Transposes the current matrix, or the array provided * * @link http://en.wikipedia.org/wiki/Matrix_transpose * @param array|bool $cArray the array to transpose (defaults to $this->matrix) * @param bool $asArray whether to return an array or Matrix object * @return array|Matrix Defaults to returning an array of the transposed matrix * @throws \Exception if the matrix is not square */ public function transpose($cArray=false,$asArray=true) { if(!$cArray) $cArray = $this->matrix; if(!$this->isSquare($cArray)) throw new \Exception("'{$this}' is not a square matrix", Matrix::E_NOT_SQUARE); $n = $this->_getN(); $nArray = array(); for($i=0;$i<$n;$i++) { for($j=0;$j<$n;$j++) { $nArray[$j][$i] = $cArray[$i][$j]; } } if($asArray==true) { return $nArray; } else { $nMatrix = new Matrix($this->toString($nArray)); return $nMatrix; } } /** * Adjugate Matrix * * Will return the Adjugate matrix of the array provided * or the current matrix instance if not provided. * * @link http://en.wikipedia.org/wiki/Adjugate_matrix * @param array|bool $cArray Defaults to $this->matrix if not provided * @param bool $asArray Whether to return an array or Matrix object * @return array|Matrix Defaults to return the array of the Adjugate matrix */ public function adjugate($cArray=false,$asArray=true) { if(!$cArray) $cArray = $this->matrix; $rArray = $this->transpose($this->coFactor($cArray)); if($asArray==true) return $rArray; $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } /** * Inverse of current matrix * * Will give the inverse of the array provided or the current matrix * Matrix returned denoted by A^-1 * * @link http://en.wikipedia.org/wiki/Inverse_matrix * @param array|bool $cArray Array to invert (defaults to $this->matrix) * @return Matrix By default returns a new instance of Matrix * @throws \Exception for any number of reasons that would make the inverse not available */ public function inverse($cArray = false) { if(!$cArray) $cArray = $this->matrix; $det = $this->getDeterminant($cArray); if($det == 0) throw new \Exception("Determinant of {$this} is 0, No Inverse found", Matrix::E_NO_INVERSE); $scalar = 1/$det; $adj = $this->adjugate($cArray, false); $iMatrix = $adj->mpScalar($scalar); return $iMatrix; } /** * Multiply Matrices * * This function will multiply the current matrix with the matrix provided. * If current Matrix is denoted by 'A' and the inputted is denoted by 'B', * When written, this will return AB. * * @link http://en.wikipedia.org/wiki/Matrix_multiplication * @param Matrix $bMatrix The matrix to multiply with the current * @return Matrix The result of multiplication. * @throws \Exception $msg explains why operation failed */ public function mpMatrix(Matrix $bMatrix) { if(!$this->_verify() || !$bMatrix->_verify()) { // @codeCoverageIgnoreStart // Should never get this far $eM1 = $this->toString(); $eM2 = $bMatrix->toString(); throw new \Exception("Either '{$eM1}' and/or '{$eM2}' is not a valid Matrix", Matrix::E_INVALID_MATRIX); // @codeCoverageIgnoreEnd } $aArray = $this->matrix; $bArray = $bMatrix->getArray(); //The number of columns in A must match the number of rows in B if(count($aArray[0]) != count($bArray)) { $mA = $this->toString(); $mB = $bMatrix->toString(); throw new \Exception("Columns in '{$mA}' don't match Rows of '{$mB}'", Matrix::E_NOT_EQUAL); } $rArray = array(); //Loop through rows of Matrix A for($i=0;$i<count($aArray);$i++) { //Loop through the columns of Matrix B for($j=0;$j<count($bArray[0]);$j++) { $value = 0; //loop through the rows of Matrix B for($k=0;$k<count($bArray);$k++) { $value += $aArray[$i][$k] * $bArray[$k][$j]; } $rArray[$i][$j] = $value; } } $rMatrix = new Matrix($this->toString($rArray)); return $rMatrix; } } ?>