New Controllers added. Added Charts

This commit is contained in:
2017-09-19 22:01:00 +02:00
parent ccc5b07ddf
commit 930311b550
400 changed files with 30686 additions and 8 deletions

View File

@@ -0,0 +1,86 @@
<?php
/**
* Created by: Jon Lawrence on 2015-07-13 8:42 AM
*/
namespace jlawrence\eos;
class AdvancedFunctions
{
/**
* Create a list for the parser of 'expressiveFunction' => 'class::function'
*
* @return array
*/
public static function map()
{
$ret = array(
'sum' => __NAMESPACE__ .'\AdvancedFunctions::sum',
'log' => __NAMESPACE__ .'\AdvancedFunctions::log'
);
return $ret;
}
/**
* Summation function
*
* Will take an equation and run it through a summation algorithm. All parts
* of the input can be in equation form, so the start and stops can have
* equations to determine what they should be using the globally inputted
* variables from the user.
*
* @param string $input String in the form of "equation, start, stop"
* @param array $vars Array of variables used for solving the current equation.
* @return float The summation of the equation
*/
public static function sum($input, $vars)
{
//remove whitespace
$input = preg_replace("/\s/", "", $input);
//split in to parts
list($eq, $start, $stop) = explode(",", $input);
$ret = 0;
//make sure there's a variable, or return equation as-is
if((Parser::solveIF($eq,0)) == preg_replace("/[\(\)]/", "", $eq)) {
return $eq;
}
$start = Parser::solveIF($start, $vars);
$stop = Parser::solveIF($stop, $vars);
for($i=$start; $i <= $stop; $i++) {
$ret += Parser::solveIF($eq, $i);
}
return $ret;
}
/**
* Log function for all non-natural logs. Defaults to base 10
*
* @param $input
* @param array $vars Variable replacement
* @return float
* @throws \Exception
*/
public static function log($input, $vars)
{
$base = 10;
if(stripos($input, ",")) {
list($eq, $base) = explode(",", $input);
} else {
$eq = $input;
}
//Make sure no functions or operators are hidden inside
$sc = Parser::solveIF($eq, $vars);
if(10 != $base) {
$base = Parser::solveIF($base, $vars);
}
$ans = log($sc, $base);
if(is_nan($ans) || is_infinite($ans)) {
throw new \Exception("Result of 'log({$eq}, {$base}) = {$ans}' is either infinite or a non-number in ". Parser::$inFix, Math::E_NAN);
}
return $ans;
}
}

View File

@@ -0,0 +1,281 @@
<?php
namespace jlawrence\eos;
// fun class that requires the GD libraries to give visual output to the user
/**
* Equation Graph
*
* Fun class that requires the GD libraries to give visual output of an
* equation to the user. Extends the Parser class.
*
* @author Jon Lawrence <jlawrence11@gmail.com>
* @copyright Copyright ©2005-2013 Jon Lawrence
* @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
* @package Math
* @subpackage EOS
* @version 3.x
*/
class Graph
{
private static $width = 640;
private static $height = 480;
/**
* @var resource
*/
private static $image;
public static $labelAxis = true;
public static $backgroundColor = array(255, 255, 255);
public static $gridColor = array(150, 150, 150);
public static $axisColor = array(0, 0, 0);
public static $lineColor = array(0, 0, 0);
/**
* Initializer
*
* Sets up the Graph class with an image width and height defaults to
* 640x480
*
* @param int $width Image width
* @param int $height Image height
*/
public static function init($width = 640, $height = 480)
{
// default width and height equal to that of a poor monitor (in early 2000s)
self::$width = $width;
self::$height = $height;
// initialize main class
Parser::init();
//can't really mess this up, return true
return true;
}
/**
* Create GD Graph Image
*
* Creates a GD image based on the equation given with the parameters that are set
*
* @param string $eq Equation to use. Needs variable in equation to create graph, all variables are interpreted as 'x'
* @param integer $xLow Lower x-bound for graph
* @param integer $xHigh Upper x-bound for graph
* @param float $xStep Stepping points while solving, the lower, the better precision. Slow if lower than .01
* @param bool $xyGrid Draw grid-lines?
* @param bool $yGuess Guess the upper/lower yBounds?
* @param int $yLow Lower y-bound
* @param int $yHigh Upper y-bound
* @return null
*/
public static function graph($eq, $xLow, $xHigh, $xStep = null, $xyGrid = false, $yGuess = true, $yLow = null, $yHigh = null)
{
//create our image and allocate the two colors
$img = ImageCreate(self::$width, self::$height);
//The following noinspection needed because the first color allocated is the background, but not used for anything else.
/** @noinspection PhpUnusedLocalVariableInspection */
$bgColor = ImageColorAllocate($img, self::$backgroundColor[0], self::$backgroundColor[1], self::$backgroundColor[2]);
$aColor = ImageColorAllocate($img, self::$axisColor[0], self::$axisColor[1], self::$axisColor[2]);
$lColor = ImageColorAllocate($img, self::$lineColor[0], self::$lineColor[1], self::$lineColor[2]);
$gColor = ImageColorAllocate($img, self::$gridColor[0], self::$gridColor[1], self::$gridColor[2]);
//$black = ImageColorAllocate($img, 0, 0, 0);
//$grey = ImageColorAllocate($img, 150, 150, 150);
//$darkGrey = ImageColorAllocate($img, 50, 50, 50);
if ($xLow > $xHigh)
list($xLow, $xHigh) = array($xHigh, $xLow); //swap function
//Smart xStep calc
if ($xStep == false) {
$xStep = ($xHigh - $xLow) / self::$width;
}
$xStep = abs($xStep);
$hand = null;
$xVars = array();
//If yGuess is true, make sure yLow and yHigh are not set
if ($yGuess) {
$yLow = null;
$yHigh = null;
}
//We want to limit the number of lines/ticks/etc so graph remains readable, set max now
$xMaxLines = 30;
$yMaxLines = 30;
//DEVELOPER, UNCOMMENT NEXT LINE IF WANTING TO PREVENT SLOW GRAPHS
//$xStep = ($xStep < .01) ? $xStep : 0.01;
$xScale = self::$width / ($xHigh - $xLow);
$counter = 0;
// @codeCoverageIgnoreStart
if (Math::$DEBUG) {
$hand = fopen("Graph.txt", "w");
fwrite($hand, "$eq\n");
}
// @codeCoverageIgnoreEnd
for ($i = $xLow; $i <= $xHigh; $i += $xStep) {
$tester = sprintf("%10.3f", $i);
if ($tester == "-0.000") $i = 0;
$y = Parser::solve($eq, $i);
//eval('$y='. str_replace('&x', $i, $eq).";"); /* used to debug my Parser class results */
// @codeCoverageIgnoreStart
if (Math::$DEBUG) {
$tmp1 = sprintf("y(%5.3f) = %10.3f\n", $i, $y);
fwrite($hand, $tmp1);
}
// @codeCoverageIgnoreEnd
// If developer asked us to find the upper and lower bounds for y...
if ($yGuess == true) {
$yLow = ($yLow === null || ($y < $yLow)) ? $y : $yLow;
$yHigh = ($yHigh === null || $y > $yHigh) ? $y : $yHigh;
}
$xVars[$counter] = $y;
$counter++;
}
//Now that we have all the variables stored...find the yScale
$yScale = self::$height / (($yHigh) - ($yLow));
// @codeCoverageIgnoreStart
//Calculate the stepping points for lines now
if ($yHigh - $yLow > $yMaxLines) {
$yJump = ceil(($yHigh - $yLow) / $yMaxLines);
} else {
$yJump = 1;
}
if ($xHigh - $xLow > $xMaxLines) {
$xJump = ceil(($xHigh - $xLow) / $xMaxLines);
} else {
$xJump = 1;
}
// @codeCoverageIgnoreEnd
// add 0.01 to each side so that if y is from 1 to 5, the lines at 1 and 5 are seen
$yLow -= 0.01;
$yHigh += 0.01;
// @codeCoverageIgnoreStart
if (Math::$DEBUG) {
fwrite($hand, $yLow . " -- " . $yHigh . "\n");
}
// @codeCoverageIgnoreEnd
// if developer wanted a grid on the graph, add it now
if ($xyGrid == true) {
// @codeCoverageIgnoreStart
if (Math::$DEBUG) {
fwrite($hand, "Drawing Grid\n");
}
// @codeCoverageIgnoreEnd
for ($i = ceil($yLow); $i <= floor($yHigh); $i += $yJump) {
$i0 = abs($yHigh - $i);
ImageLine($img, 0, $i0 * $yScale, self::$width, $i0 * $yScale, $gColor);
imagestring($img, 1, 2, $i0 * $yScale + 2, $i, $gColor);
}
for ($i = ceil($xLow); $i <= floor($xHigh); $i += $xJump) {
$i0 = abs($xLow - $i);
ImageLine($img, $i0 * $xScale, 0, $i0 * $xScale, self::$height, $gColor);
imagestring($img, 1, $i0 * $xScale + 2, 2, $i, $gColor);
}
}
//Now that we have the scales, let's see if we can draw an x/y-axis
if ($xLow <= 0 && $xHigh >= 0) {
//the y-axis is within our range - draw it.
$x0 = abs($xLow) * $xScale;
ImageLine($img, $x0, 0, $x0, self::$height, $aColor);
for ($i = ceil($yLow); $i <= floor($yHigh); $i += $yJump) {
$i0 = abs($yHigh - $i);
ImageLine($img, $x0 - 3, $i0 * $yScale, $x0 + 3, $i0 * $yScale, $aColor);
//If we want the axis labeled... (call in the allies?)
if (self::$labelAxis) {
imagestring($img, 1, $x0 + 2, $i0 * $yScale + 1, $i, $aColor);
}
}
}
if ($yLow <= 0 && $yHigh >= 0) {
//the x-axis is within our range - draw it.
$y0 = abs($yHigh) * $yScale;
ImageLine($img, 0, $y0, self::$width, $y0, $aColor);
//Create ticks for y
for ($i = ceil($xLow); $i <= floor($xHigh); $i += $xJump) {
$i0 = abs($xLow - $i);
ImageLine($img, $i0 * $xScale, $y0 - 3, $i0 * $xScale, $y0 + 3, $aColor);
//If we want the axis labeled....
if (self::$labelAxis) {
imagestring($img, 1, $i0 * $xScale + 2, $y0 + 1, $i, $aColor);
}
}
}
$counter = 1;
//now graph it all ;]
for ($i = $xLow + $xStep; $i <= $xHigh; $i += $xStep) {
$x1 = (abs($xLow - ($i - $xStep))) * $xScale;
$y1 = (($xVars[$counter - 1] < $yLow) || ($xVars[$counter - 1] > $yHigh)) ? -1 : (abs($yHigh - $xVars[$counter - 1])) * $yScale;
$x2 = (abs($xLow - $i)) * $xScale;
$y2 = (($xVars[$counter] < $yLow) || ($xVars[$counter] > $yHigh)) ? -1 : (abs($yHigh - $xVars[$counter])) * $yScale;
// if any of the y values were found to be off of the y-bounds, don't graph those connecting lines
if ($y1 != -1 && $y2 != -1)
ImageLine($img, $x1, $y1, $x2, $y2, $lColor);
$counter++;
}
// @codeCoverageIgnoreStart
if (Math::$DEBUG) {
fclose($hand);
}
// @codeCoverageIgnoreEnd
self::$image = $img;
}
/**
* Sends JPG to browser
*
* Sends a JPG image with proper header to output
*
* @codeCoverageIgnore
*/
public static function outJPG()
{
header("Content-type: image/jpeg");
ImageJpeg(self::$image);
}
/**
* Sends PNG to browser
*
* Sends a PNG image with proper header to output
*
* @codeCoverageIgnore
*/
public static function outPNG()
{
header("Content-type: image/png");
ImagePng(self::$image);
}
/**
* Output GD Image
*
* Will give the developer the GD resource for the graph that
* can be used to store the graph to the FS or other media
*
* @return Resource GD Image Resource
*/
public static function getImage()
{
return self::$image;
}
/**
* Output GD Image
*
* Alias for eqGraph::getImage()
*
* @return Resource GD Image resource
*/
public static function outGD()
{
return self::getImage();
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Created by: Jon Lawrence on 2015-07-02 2:49 PM
*/
namespace jlawrence\eos;
/**
* Class Math
* @package jlawrence\eos
*
* Will be a holder for constants, variables, and other things commonly needed by the
* rest of the package.
*/
class Math
{
/**
* No matching open/close pair in equation
*/
const E_NO_SET = 5500;
/**
* Division by zero
*/
const E_DIV_ZERO = 5501;
/**
* No equation present
*/
const E_NO_EQ = 5502;
/**
* No variable replacements available
*/
const E_NO_VAR = 5503;
/**
* Not A Number (NAN)
*/
const E_NAN = 5504;
/**
* @var bool Use debug features
*/
public static $DEBUG = false;
}

View File

@@ -0,0 +1,656 @@
<?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 <20>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;
}
}
?>

View File

@@ -0,0 +1,593 @@
<?php
/**
* Equation Operating System Classes.
*
* This class was created for the safe parsing of mathematical equations
* in PHP. There is a need for a way to successfully parse equations
* in PHP that do NOT require the use of `eval`. `eval` at its core
* opens the system using it to so many security vulnerabilities it is oft
* suggested /never/ to use it, and for good reason. This class set will
* successfully take an equation, parse it, and provide solutions to the
* developer. It is a safe way to evaluate expressions without putting
* the system at risk.
*
*
* @author Jon Lawrence <jlawrence11@gmail.com>
* @copyright Copyright ©2005-2015, Jon Lawrence
* @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
* @version 3.0.0
*/
namespace jlawrence\eos;
/**
* Equation Operating System (EOS) Parser
*
* A class that can safely parse mathematical equations. Re-written portions
* from version 2.x to be extend-able with custom functions.
*
* @author Jon Lawrence <jlawrence11@gmail.com>
* @copyright Copyright ©2005-2015, Jon Lawrence
* @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
* @version 3.0.0
*/
class Parser {
/**
* @var string Infix equation
* Public so advanced/user-defined/etc can access it when throwing exceptions.
*/
public static $inFix;
/**
* @var array Opening and closing selectors
*/
protected static $SEP = array(
'open' => array('(', '['),
'close' => array(')', ']')
);
// Top precedence following operator - not in use
protected static $SGL = array('!');
// Order of operations arrays follow
protected static $ST = array('^', '!');
protected static $ST1 = array('/', '*', '%');
protected static $ST2 = array('+', '-');
/**
* @var array Allowed functions
*/
protected static $FNC = array(
'sin', 'cos', 'tan',
'csc', 'sec', 'cot',
'abs', 'ln', 'sqrt'
);
/**
* @var array Advanced functions container
*/
protected static $AFNC = array();
/**
* Initialize
*/
public static function init() {
if (empty(self::$AFNC)) {
//No advanced functions yet, so this function has not run, do so now.
self::$AFNC = AdvancedFunctions::map();
}
}
/**
* Add Advanced Function Class
*
* Adds a function class to the parser for user/programmer defined
* functions that can be parsed with the parser. For example
* class structure see jlawrence\eos\AdvancedFunctions.
* Class must be static, and must have a function named 'map'
*
* @param string $class Fully Qualified String to class (must include namespace)
* @return bool True on success
* @throws \Exception When the added class doesn't have the 'map' function or doesn't exist.
*
* @codeCoverageIgnore
*/
public static function addFunctionClass($class)
{
self::init();
if(is_callable("{$class}::map")) {
$a = call_user_func($class.'::map');
self::$AFNC = array_merge($a, self::$AFNC);
} else {
throw new \Exception("{$class}::map() is not callable");
}
return true;
}
/**
* Check Infix for opening closing pair matches.
*
* This function is meant to solely check to make sure every opening
* statement has a matching closing one, and throws an exception if
* it doesn't.
*
* @param string $infix Equation to check
* @throws \Exception if malformed.
* @return Bool true if passes - throws an exception if not.
*/
private static function checkInfix($infix) {
self::init();
if(trim($infix) == "") {
throw new \Exception("No Equation given", Math::E_NO_EQ);
}
//Make sure we have the same number of '(' as we do ')'
// and the same # of '[' as we do ']'
if(substr_count($infix, '(') != substr_count($infix, ')')) {
throw new \Exception("Mismatched parenthesis in ". self::$inFix, Math::E_NO_SET);
} elseif(substr_count($infix, '[') != substr_count($infix, ']')) {
throw new \Exception("Mismatched brackets in '". self::$inFix, Math::E_NO_SET);
}
return true;
}
/**
* Infix to Postfix
*
* Converts an infix (standard) equation to postfix (RPN) notation.
* Sets the internal variable $this->postFix for the Parser::solvePF()
* function to use.
*
* @link http://en.wikipedia.org/wiki/Infix_notation Infix Notation
* @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish Notation
* @param string $infix A standard notation equation
* @throws \Exception When parenthesis are mismatched
* @return array Fully formed RPN Stack
*/
public static function in2post($infix) {
// if an equation was not passed, use the one that was passed in the constructor
//$infix = (isset($infix)) ? $infix : $this->inFix;
//check to make sure 'valid' equation
self::checkInfix($infix);
$pf = array();
$ops = new Stack();
//$vars = new Stack();
// remove all white-space
$infix = preg_replace("/\s/", "", $infix);
// Create postfix array index
$pfIndex = 0;
//what was the last character? (useful for discerning between a sign for negation and subtraction)
$lChar = '';
//loop through all the characters and start doing stuff ^^
for($i=0;$i<strlen($infix);$i++) {
// pull out 1 character from the string
$chr = substr($infix, $i, 1);
// if the character is numerical
if(preg_match('/[0-9.]/i', $chr)) {
// if the previous character was not a '-' or a number
if((!preg_match('/[0-9.]/i', $lChar) && ($lChar != "")) && (isset($pf[$pfIndex]) && ($pf[$pfIndex]!="-")))
$pfIndex++; // increase the index so as not to overlap anything
// Add the number character to the array
if(isset($pf[$pfIndex])) {
$pf[$pfIndex] .= $chr;
} else {
$pf[$pfIndex] = $chr;
}
}
// If the character opens a set e.g. '(' or '['
elseif(in_array($chr, self::$SEP['open'])) {
// if the last character was a number, place an assumed '*' on the stack
if(preg_match('/[0-9.]/i', $lChar))
$ops->push('*');
$ops->push($chr);
}
// if the character closes a set e.g. ')' or ']'
elseif(in_array($chr, self::$SEP['close'])) {
// find what set it was i.e. matches ')' with '(' or ']' with '['
$key = array_search($chr, self::$SEP['close']);
// while the operator on the stack isn't the matching pair...pop it off
while($ops->peek() != self::$SEP['open'][$key]) {
$nchr = $ops->pop();
if($nchr)
$pf[++$pfIndex] = $nchr;
else {
//Should NEVER get here...
// @codeCoverageIgnoreStart
throw new \Exception("Error while searching for '". self::$SEP['open'][$key] ."' in ". self::$inFix, Math::E_NO_SET);
// @codeCoverageIgnoreEnd
}
}
$ops->pop();
}
// If a special operator that has precedence over everything else
elseif(in_array($chr, self::$ST)) {
while(in_array($ops->peek(), self::$ST))
$pf[++$pfIndex] = $ops->pop();
$ops->push($chr);
$pfIndex++;
}
// Any other operator other than '+' and '-'
elseif(in_array($chr, self::$ST1)) {
while(in_array($ops->peek(), self::$ST1) || in_array($ops->peek(), self::$ST))
$pf[++$pfIndex] = $ops->pop();
$ops->push($chr);
$pfIndex++;
}
// if a '+' or '-'
elseif(in_array($chr, self::$ST2)) {
// if it is a '-' and the character before it was an operator or nothingness (e.g. it negates a number)
if((in_array($lChar, array_merge(self::$ST1, self::$ST2, self::$ST, self::$SEP['open'])) || $lChar=="") && $chr=="-") {
// increase the index because there is no reason that it shouldn't..
$pfIndex++;
$pf[$pfIndex] = $chr;
}
// Otherwise it will function like a normal operator
else {
while(in_array($ops->peek(), array_merge(self::$ST1, self::$ST2, self::$ST)))
$pf[++$pfIndex] = $ops->pop();
$ops->push($chr);
$pfIndex++;
}
}
// make sure we record this character to be referred to by the next one
$lChar = $chr;
}
// if there is anything on the stack after we are done...add it to the back of the RPN array
while(($tmp = $ops->pop()) !== false)
$pf[++$pfIndex] = $tmp;
// re-index the array at 0
$pf = array_values($pf);
// set the private variable for later use if needed
//self::$postFix = $pf;
// return the RPN array in case developer wants to use it for some insane reason (bug testing ;] )
// Also... because we pass it right in to the RPN solver. So I guess there's that too.
return $pf;
}
/**
* Solve Postfix (RPN)
*
* This function will solve a RPN array. Default action is to solve
* the RPN array stored in the class from Parser::in2post(), can take
* an array input to solve as well, though default action is preferred.
*
* @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Postix Notation
* @param array $pfArray RPN formatted array. Optional.
* @throws \Exception on division by 0
* @return float Result of the operation.
*/
public static function solvePF($pfArray) {
$pf = $pfArray;
// create our temporary function variables
$temp = array();
//$tot = 0;
$hold = 0;
// Loop through each number/operator
for($i=0;$i<count($pf); $i++) {
// If the string isn't an operator, add it to the temp var as a holding place
if(!in_array($pf[$i], array_merge(self::$ST, self::$ST1, self::$ST2))) {
$temp[$hold++] = $pf[$i];
}
// ...Otherwise perform the operator on the last two numbers
else {
switch ($pf[$i]) {
case '+':
$temp[$hold-2] = $temp[$hold-2] + $temp[$hold-1];
break;
case '-':
$temp[$hold-2] = $temp[$hold-2] - $temp[$hold-1];
break;
case '*':
$temp[$hold-2] = $temp[$hold-2] * $temp[$hold-1];
break;
case '/':
if($temp[$hold-1] == 0) {
throw new \Exception("Division by 0 on: '{$temp[$hold-2]} / {$temp[$hold-1]}' in ". self::$inFix, Math::E_DIV_ZERO);
}
$temp[$hold-2] = $temp[$hold-2] / $temp[$hold-1];
break;
case '^':
$temp[$hold-2] = pow($temp[$hold-2], $temp[$hold-1]);
break;
case '!':
$temp[$hold-1] = self::factorial($temp[$hold-1]);
$hold++;
break;
case '%':
if($temp[$hold-1] == 0) {
throw new \Exception("Division by 0 on: '{$temp[$hold-2]} % {$temp[$hold-1]}' in ". self::$inFix, Math::E_DIV_ZERO);
}
$temp[$hold-2] = bcmod($temp[$hold-2], $temp[$hold-1]);
break;
}
// Decrease the hold var to one above where the last number is
$hold = $hold-1;
}
}
// return the last number in the array
return $temp[$hold-1];
}
/**
* Solve
*
* This function is called by the user to solve an equation within the parser system
* No internal functions or added advanced functions should ever call this. Sets
* the internal $infix variable for use in thrown exceptions. The variable array must
* be in the format of 'variable' => value. If variable array is scalar (ie 5), all
* variables will be replaced with it.
*
* @param string $equation Equation to Solve
* @param array|double $values variable values
* @return float Answer to the equation
*/
public static function solve($equation, $values = null) {
if(is_array($equation)) {
return self::solvePF($equation);
} else {
self::$inFix = $equation;
return self::solveIF($equation, $values);
}
}
/**
* Solve Infix (Standard) Notation Equation
*
* Will take a standard equation with optional variables and solve it.
* This function is the one for programmers making modules for this
* package should call as it does not set the internal variable for
* the equation. This should not be used by the programmer/user that
* is using this package to solve equations.
*
* @param string $infix Standard Equation to solve
* @param string|array $vArray Variable replacement
* @throws \Exception On division by zero or NaN
* @return float Solved equation
*/
public static function solveIF($infix, $vArray = null) {
//Check to make sure a 'valid' expression
self::checkInfix($infix);
//$ops = new Stack();
//$vars = new Stack();
$hand = null;
//remove all white-space
$infix = preg_replace("/\s/", "", $infix);
$infix = self::checkAdvancedInput($infix,$vArray);
// Finds all the 'functions' within the equation and calculates them
//Nested parenthesis are now a go!
while((preg_match("/(". implode("|", self::$FNC) . ")\(((?:[^()]|\((?2)\))*+)\)/", $infix, $match)) != 0) {
$func = self::solveIF($match[2], $vArray);
switch($match[1]) {
case "cos":
$ans = Trig::cos($func);
break;
case "sin":
$ans = Trig::sin($func);
break;
case "tan":
$ans = Trig::tan($func);
break;
case "sec":
$ans = Trig::sec($func);
break;
case "csc":
$ans = Trig::csc($func);
break;
case "cot":
$ans = Trig::cot($func);
break;
case "abs":
$ans = abs($func);
break;
case "ln":
$ans = log($func);
if(is_nan($ans) || is_infinite($ans)) {
throw new \Exception("Result of 'ln({$func}) = {$ans}' is either infinite or a non-number in ". self::$inFix, Math::E_NAN);
}
break;
case "sqrt":
if($func < 0) {
throw new \Exception("Result of 'sqrt({$func}) = i' in ". self::$inFix .". We can't handle imaginary numbers", Math::E_NAN);
}
$ans = sqrt($func);
break;
// @codeCoverageIgnoreStart
default:
$ans = 0;
break;
// @codeCoverageIgnoreEnd
}
$infix = str_replace($match[0], "({$ans})", $infix);
}
//replace scientific notation with normal notation (2e-9 to 2*10^-9)
$infix = preg_replace('/([\d])([eE])(-?\d)/', '$1*10^$3', $infix);
$infix = self::replaceVars($infix, $vArray);
return self::solvePF(self::in2post($infix));
}
/**
* checkAdvancedInput
*
* Will take the input from `Parser::solveIF()` and solve all the advanced functions
* that exist within it, returning it to the function when done for further
* processing.
*
* @param string $input Check for advanced functions, recursively go through them.
* @param array|int|null $vArray Variables from user-input
* @return string The input with all advanced functions solved for.
*/
protected static function checkAdvancedInput($input, $vArray)
{
$infix = $input;
//Advanced/User-defined functions
while((preg_match("/(". implode("|", array_keys(self::$AFNC)) . ")\(((?:[^()]|\((?2)\))*+)\)/", $infix, $match)) != 0) {
$method = self::$AFNC[$match[1]];
if(stripos($match[2], '(') !== false) {
$match[2] = self::checkAdvancedInput($match[2], $vArray);
}
$ans = call_user_func($method, $match[2], $vArray);
$infix = str_replace($match[0], "({$ans})", $infix);
}
return $infix;
}
/**
* @param string $infix
* @param array $vArray
* @return string
* @throws \Exception
*/
protected static function replaceVars($infix, $vArray)
{
//Remove old '$' and '&' signis so the regex works properly.
$infix = preg_replace('/[$&]/', "", $infix);
//Find all the variables that were passed and replaces them
while((preg_match('/([^a-zA-Z]){0,1}([a-zA-Z]+)([^a-zA-Z]){0,1}/', $infix, $match)) != 0) {
//remove notices by defining if undefined.
if(!isset($match[3])) {
$match[3] = "";
}
// Ensure that the variable has an operator or something of that sort in front and back - if it doesn't, add an implied '*'
if((!in_array($match[1], array_merge(self::$ST, self::$ST1, self::$ST2, self::$SEP['open'])) && $match[1] != "") || is_numeric($match[1])) //$this->SEP['close'] removed
$front = "*";
else
$front = "";
if((!in_array($match[3], array_merge(self::$ST, self::$ST1, self::$ST2, self::$SEP['close'])) && $match[3] != "") || is_numeric($match[3])) //$this->SEP['open'] removed
$back = "*";
else
$back = "";
//Make sure that the variable does have a replacement
//First check for pi and e variables that wll automatically be replaced
if(in_array(strtolower($match[2]), array('pi', 'e'))) {
$t = (strtolower($match[2])=='pi') ? pi() : exp(1);
$infix = str_replace($match[0], $match[1] . $front. $t. $back . $match[3], $infix);
} elseif(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && !is_numeric($vArray) && 0 !== $vArray)) {
throw new \Exception("Variable replacement does not exist for '". $match[2] ."' in ". self::$inFix .".", Math::E_NO_VAR);
} elseif(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && is_numeric($vArray))) {
$infix = str_replace($match[0], $match[1] . $front. $vArray. $back . $match[3], $infix);
} elseif(isset($vArray[$match[2]])) {
$infix = str_replace($match[0], $match[1] . $front. $vArray[$match[2]]. $back . $match[3], $infix);
}
}
return $infix;
}
/**
* Solve factorial (!)
*
* Will take an integer and solve for it's factorial. Eg.
* `5!` will become `1*2*3*4*5` = `120`
* DONE:
* Solve for non-integer factorials 2015/07/02
*
* @param float $num Non-negative real number to get factorial of
* @throws \Exception if number is at or less than 0
* @return float Solved factorial
*/
protected static function factorial($num) {
if($num < 0) {
throw new \Exception("Factorial Error: Factorials don't exist for numbers < 0 in ". self::$inFix, Math::E_NAN);
}
//A non-integer! Gamma that sucker up!
if(intval($num) != $num) {
return self::gamma($num + 1);
}
$tot = 1;
for($i=1;$i<=$num;$i++) {
$tot *= $i;
}
return $tot;
}
/**
* Gamma Function
*
* Because we can. This function exists as a catch-all for different
* numerical approx. of gamma if I decide to add any past Lanczos'.
*
* @param $z Number to compute gamma from
* @return float The gamma (hopefully, I'll test it after writing the code)
*/
public static function gamma($z)
{
return self::laGamma($z);
}
/**
* Lanczos Approximation
*
* The Lanczos Approximation method of finding gamma values
*
* @link http://www.rskey.org/CMS/index.php/the-library/11
* @link http://algolist.manual.ru/maths/count_fast/gamma_function.php
* @link https://en.wikipedia.org/wiki/Lanczos_approximation
* @param $z Number to obtain the gamma of
* @return float Answer
*/
protected static function laGamma($z)
{
// Set up coefficients
$p = array(
0 => 1.000000000190015,
1 => 76.18009172947146,
2 => -86.50532032941677,
3 => 24.01409824083091,
4 => -1.231739572450155,
5 => 1.208650973866179E-3,
6 => -5.395239384953E-6
);
// Formula:
// ((sqrt(2pi)/z)(p[0]+sum(p[n]/(z+n), 1, 6)))(z+5.5)^(z+0.5)*e^(-(z+5.5))
// Break it down now...
$g1 = sqrt(2*pi())/$z;
// Next comes our summation
$g2 =0;
for($n=1;$n<=6;$n++) {
$g2 += $p[$n]/($z+$n);
}
// Don't forget to add p[0] to it...
$g2 += $p[0];
$g3 = pow($z+5.5, $z + .5);
$g4 = exp(-($z+5.5));
//now just multiply them all together
$gamma = $g1 * $g2 * $g3 * $g4;
return $gamma;
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace jlawrence\eos;
/**
* Basic Stack Class.
*
* Created for use with eqEOS. May eventually be replaced with native
* PHP functions `array_pop()`, `array_push()`, and `end()`
*
* @author Jon Lawrence <jlawrence11@gmail.com>
* @copyright Copyright ©2005-2015 Jon Lawrence
* @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
* @package Math
* @version 0.1
*/
class Stack {
private $index;
private $locArray;
/**
* Constructor
*
* Initializes the stack
*/
public function __construct() {
//define the private vars
$this->locArray = array();
$this->index = -1;
}
/**
* Peek
*
* Will view the last element of the stack without removing it
*
* @return mixed An element of the array or false if none exist
*/
public function peek() {
if($this->index > -1)
return $this->locArray[$this->index];
else
return false;
}
/**
* Poke
*
* Will add an element to the end of the stack
*
* @param mixed $data Element to add
*/
public function poke($data) {
$this->locArray[++$this->index] = $data;
}
/**
* Push
*
* Alias of {@see Stack::poke()}
* Adds element to the stack
*
* @param mixed $data Element to add
*/
public function push($data) {
//alias for 'poke'
$this->poke($data);
}
/**
* Pop
*
* Retrieves an element from the end of the stack, and removes it from
* the stack at the same time. If no elements, returns boolean false
*
* @return mixed Element at end of stack or false if none exist
*/
public function pop() {
if($this->index > -1)
{
$this->index--;
return $this->locArray[$this->index+1];
}
else
return false;
}
/**
* Clear
*
* Clears the stack to be reused.
*/
public function clear() {
$this->index = -1;
$this->locArray = array();
}
/**
* Get Stack
*
* Returns the array of stack elements, keeping all, indexed at 0
*
* @return mixed Array of stack elements or false if none exist.
*/
public function getStack() {
if($this->index > -1)
{
return array_values($this->locArray);
}
else
return false;
}
}
?>

View File

@@ -0,0 +1,75 @@
<?php
/**
* Created by: Jon Lawrence on 2015-07-02 3:10 PM
*/
namespace jlawrence\eos;
/**
* Class Trig
* @package jlawrence\Math
*
* Trig functions, primarily because there's a difference when dealing with
* radians and degrees, and this class will help with that - defaulting
* to radians, but allowing the default to be set to degrees for the
* project. Thus simplifying the amount of calculations the user
* of this project needs to do.
*/
class Trig
{
/**
* @var bool Whether or not to convert to radians before calculation
* (Meaning input is in degree form)
*/
public static $DEGREES = false;
protected static function getRadDeg($x)
{
if(self::$DEGREES == true) {
return deg2rad($x);
}
return $x;
}
public static function cos($x)
{
return cos(self::getRadDeg($x));
}
public static function sin($x)
{
return sin(self::getRadDeg($x));
}
public static function tan($x)
{
return tan(self::getRadDeg($x));
}
public static function sec($x)
{
$tmp = self::cos($x);
if($tmp == 0)
throw new \Exception("Division by 0 on: 'sec({$x}) = 1/cos({$x})' in ". Parser::$inFix, Math::E_DIV_ZERO);
return 1/$tmp;
}
public static function csc($x)
{
$tmp = self::sin($x);
if($tmp == 0)
throw new \Exception("Division by 0 on: 'csc({$x})) = 1/sin({$x})' in ". Parser::$inFix, Math::E_DIV_ZERO);
return 1/$tmp;
}
public static function cot($x)
{
$tmp = self::tan($x);
if($tmp == 0)
throw new \Exception("Division by 0 on: 'cot({$x})) = 1/tan({$x})' in ". Parser::$inFix, Math::E_DIV_ZERO);
return 1/$tmp;
}
}