diff options
author | Kore Nordmann <github@kore-nordmann.de> | 2006-08-16 12:59:26 +0000 |
---|---|---|
committer | Kore Nordmann <github@kore-nordmann.de> | 2006-08-16 12:59:26 +0000 |
commit | bb028918891c1840d200530a0cb458db9a07cf95 (patch) | |
tree | 7f98afbf839f41a2e4ad27bb1fb9179f4ce96ee2 | |
parent | ae311d59bf94eb135dfaa1c09dd93e1ebea4ee05 (diff) | |
download | zetacomponents-graph-bb028918891c1840d200530a0cb458db9a07cf95.zip zetacomponents-graph-bb028918891c1840d200530a0cb458db9a07cf95.tar.gz |
- Added matrix and polynom classes for future use in statistical datasets
-rw-r--r-- | src/exceptions/invalid_dimensions.php | 25 | ||||
-rw-r--r-- | src/exceptions/out_of_boundings.php | 25 | ||||
-rw-r--r-- | src/graph_autoload.php | 5 | ||||
-rw-r--r-- | src/math/matrix.php | 266 | ||||
-rw-r--r-- | src/math/polynom.php | 167 | ||||
-rw-r--r-- | tests/matrix_test.php | 263 | ||||
-rw-r--r-- | tests/polynom_test.php | 122 | ||||
-rw-r--r-- | tests/suite.php | 4 |
8 files changed, 877 insertions, 0 deletions
diff --git a/src/exceptions/invalid_dimensions.php b/src/exceptions/invalid_dimensions.php new file mode 100644 index 0000000..e3d98bd --- /dev/null +++ b/src/exceptions/invalid_dimensions.php @@ -0,0 +1,25 @@ +<?php +/** + * File containing the ezcGraphMatrixInvalidDimensionsException class + * + * @package Graph + * @version //autogen// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Exception thrown when an operation i not possible because of incompatible + * matrix dimensions. + * + * @package Graph + * @version //autogen// + */ +class ezcGraphMatrixInvalidDimensionsException extends ezcGraphException +{ + public function __construct( $rows, $columns, $dRows, $dColumns ) + { + parent::__construct( "Matrix <{$dRows}, {$dColumns}> is incompatible with matrix <{$rows}, {$columns}> for requested operation." ); + } +} + +?> diff --git a/src/exceptions/out_of_boundings.php b/src/exceptions/out_of_boundings.php new file mode 100644 index 0000000..8fe5848 --- /dev/null +++ b/src/exceptions/out_of_boundings.php @@ -0,0 +1,25 @@ +<?php +/** + * File containing the ezcGraphMatrixOutOfBoundingsException class + * + * @package Graph + * @version //autogen// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Exception thrown when a rrequested matrix value is out of the boundings of + * the matrix. + * + * @package Graph + * @version //autogen// + */ +class ezcGraphMatrixOutOfBoundingsException extends ezcGraphException +{ + public function __construct( $rows, $columns, $rPos, $cPos ) + { + parent::__construct( "Position <{$rPos}, {$cPos}> is out of the matrix boundings <{$rows}, {$columns}>." ); + } +} + +?> diff --git a/src/graph_autoload.php b/src/graph_autoload.php index 7c8a9f7..297832c 100644 --- a/src/graph_autoload.php +++ b/src/graph_autoload.php @@ -85,6 +85,11 @@ return array( 'ezcGraphUnknownDataSetSourceException' => 'Graph/exceptions/unknown_dataset_source.php', 'ezcGraphInvalidDisplayTypeException' => 'Graph/exceptions/invalid_display_type.php', + 'ezcGraphMatrix' => 'Graph/math/matrix.php', + 'ezcGraphMatrixInvalidDimensionsException' => 'Graph/exceptions/invalid_dimensions.php', + 'ezcGraphMatrixOutOfBoundingsException' => 'Graph/exceptions/out_of_boundings.php', + 'ezcGraphPolynom' => 'Graph/math/polynom.php', + 'ezcGraphBoundings' => 'Graph/structs/boundings.php', 'ezcGraphCoordinate' => 'Graph/structs/coordinate.php', ); diff --git a/src/math/matrix.php b/src/math/matrix.php new file mode 100644 index 0000000..dae2f64 --- /dev/null +++ b/src/math/matrix.php @@ -0,0 +1,266 @@ +<?php +/** + * File containing the abstract ezcGraphMatrix class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Provides a genereic matrix class with basic math operations + * + * @package Graph + */ +class ezcGraphMatrix +{ + + protected $columns; + + protected $rows; + + protected $matrix; + + /** + * Constructor + * + * Creates a matrix with given dimensions. Optionally accepts an array to + * define the initial matrix values. If no array is given an identity + * matrix is created. + * + * @param int $columns Number of columns + * @param int $rows Number of rows + * @param array $values Array with values + * @return void + */ + public function __construct( $columns = 3, $rows = 3, array $values = null ) + { + $this->columns = max( 2, (int) $columns ); + $this->rows = max( 2, (int) $rows ); + + if ( $values !== null ) + { + $this->fromArray( $values ); + } + else + { + $this->init(); + } + } + + /** + * Create matrix from array + * + * Use the array values to set matrix values + * + * @param array $values Array with values + * @return ezcGraphMatrix Modified matrix + */ + public function fromArray( array $values ) + { + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $this->rows; ++$j ) + { + $this->matrix[$i][$j] = + ( isset( $values[$i][$j] ) + ? (float) $values[$i][$j] + : 0 ); + } + } + + return $this; + } + + /** + * Init matrix + * + * Sets matrix to identity matrix + * + * @return ezcGraphMatrix Modified matrix + */ + public function init() + { + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $this->rows; ++$j ) + { + $this->matrix[$i][$j] = ( $i === $j ? 1 : 0 ); + } + } + + return $this; + } + + /** + * Returns number of columns + * + * @return int Number of columns + */ + public function columns() + { + return $this->columns; + } + + /** + * Returns number of rows + * + * @return int Number of rows + */ + public function rows() + { + return $this->rows; + } + + /** + * Get a single matrix value + * + * Returns the value of the matrix at the given position + * + * @param int $i Row + * @param int $j Column + * @return float Matrix value + */ + public function get( $i, $j ) + { + if ( !isset( $this->matrix[$i][$j] ) ) + { + throw new ezcGraphMatrixOutOfBoundingsException( $this->columns, $this->rows, $i, $j ); + } + + return $this->matrix[$i][$j]; + } + + /** + * Set a single matrix value + * + * Sets the value of the matrix at the given position + * + * @param int $i Row + * @param int $j Column + * @param float $value Value + * @return ezcGraphMatrix Updated matrix + */ + public function set( $i, $j, $value ) + { + if ( !isset( $this->matrix[$i][$j] ) ) + { + throw new ezcGraphMatrixOutOfBoundingsException( $this->columns, $this->rows, $i, $j ); + } + + $this->matrix[$i][$j] = $value; + + return $this; + } + + /** + * Adds one matrix to the current one + * + * Calculate the sum of two matrices and returns the resulting matrix. + * + * @param ezcGraphMatrix $matrix Matrix to sum with + * @return ezcGraphMatrix Result matrix + */ + public function add( ezcGraphMatrix $matrix ) + { + if ( ( $this->columns !== $matrix->columns() ) || + ( $this->rows !== $matrix->rows() ) ) + { + throw new ezcGraphMatrixInvalidDimensionsException( $this->columns, $this->rows, $matrix->columns(), $matrix->rows() ); + } + + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $this->rows; ++$j ) + { + $this->matrix[$i][$j] += $matrix->get( $i, $j ); + } + } + + return $this; + } + + /** + * Subtracts matrix from current one + * + * Calculate the diffenrence of two matices and returns the result matrix. + * + * @param ezcGraphMatrix $matrix subtrahend + * @return ezcGraphMatrix Result matrix + */ + public function diff( ezcGraphMatrix $matrix ) + { + if ( ( $this->columns !== $matrix->columns() ) || + ( $this->rows !== $matrix->rows() ) ) + { + throw new ezcGraphMatrixInvalidDimensionsException( $this->columns, $this->rows, $matrix->columns(), $matrix->rows() ); + } + + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $this->rows; ++$j ) + { + $this->matrix[$i][$j] -= $matrix->get( $i, $j ); + } + } + + return $this; + } + + /** + * Scalar multiplication + * + * Multiplies matrix with the given scalar and returns the result matrix + * + * @param float $scalar Scalar + * @return ezcGraphMatrix Result matrix + */ + public function scalar( $scalar ) + { + $scalar = (float) $scalar; + + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $this->rows; ++$j ) + { + $this->matrix[$i][$j] *= $scalar; + } + } + } + + /** + * Multiplies two matrices + * + * Multiply current matrix with another matrix and returns the result + * matrix. + * + * @param ezcGraphMatrix $matrix Second factor + * @returns ezcGraphMatrix Result matrix + */ + public function multiply( ezcGraphMatrix $matrix ) + { + $mColumns = $matrix->columns(); + if ( $this->columns !== ( $mRows = $matrix->rows() ) ) + { + throw new ezcGraphMatrixInvalidDimensionsException( $this->columns, $this->rows, $mColumns, $mRows ); + } + + $result = new ezcGraphMatrix( $mRows, $mRows ); + + for ( $i = 0; $i < $this->columns; ++$i ) + { + for ( $j = 0; $j < $mRows; ++$j ) + { + $sum = 0; + for ( $k = 0; $k < $mColumns; ++$k ) { + $sum += $this->matrix[$i][$k] * $matrix->get( $k, $j ); + } + + $result->set( $i, $j, $sum ); + } + } + + return $result; + } +} +?> diff --git a/src/math/polynom.php b/src/math/polynom.php new file mode 100644 index 0000000..779c4f1 --- /dev/null +++ b/src/math/polynom.php @@ -0,0 +1,167 @@ +<?php +/** + * File containing the abstract ezcGraphPolynom class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Provides a class for generic operations on polynoms + * + * @package Graph + */ +class ezcGraphPolynom +{ + protected $values; + + /** + * Constructor + * + * Constructs a polynom object from given array, where the key is the + * exponent and the value the factor. + * An example: + * Polynom: + * 2 * x^3 + .5 * x - 3 + * Array: + * array ( + * 3 => 2, + * 1 => .5, + * 0 => -3, + * ) + * + * @param int $columns Number of columns + * @param int $rows Number of rows + * @param array $values Array with values + * @return void + */ + public function __construct( array $values = array() ) + { + foreach ( $values as $exponent => $factor ) + { + $this->values[(int) $exponent] = (float) $factor; + } + } + + /** + * Initialise a polygon + * + * Initialise a polygon of the given order. Sets all factors to 0. + * + * @param int $order Order of polygon + * @return ezcGraphPolynom Created polynom + */ + public function init( $order ) + { + for ( $i = 0; $i <= $order; ++$i ) + { + $this->values[$i] = 0; + } + + return $this; + } + + /** + * Return factor for one exponent + * + * @param int $exponent Exponent + * @return float Factor + */ + public function get( $exponent ) + { + if ( !isset( $this->values[$exponent] ) ) + { + return 0; + } + else + { + return $this->values[$exponent]; + } + } + + /** + * Set the factor for one exponent + * + * @param int $exponent Exponent + * @param float $factor Factor + * @return ezcGraphPolynom Modified polynom + */ + public function set( $exponent, $factor ) + { + $this->values[(int) $exponent] = (float) $factor; + + return $this; + } + + /** + * Returns the order of the polynom + * + * @return int Polynom order + */ + public function getOrder() + { + return max( array_keys( $this->values ) ); + } + + /** + * Adds polynom to current polynom + * + * @param ezcGraphPolynom $polynom Polynom to add + * @return ezcGraphPolynom Modified polynom + */ + public function add( ezcGraphPolynom $polynom ) + { + $order = max( + $this->getOrder(), + $polynom->getOrder() + ); + + for ( $i = 0; $i <= $order; ++$i ) + { + $this->set( $i, $this->get( $i ) + $polynom->get( $i ) ); + } + + return $this; + } + + /** + * Evaluate Polynom with a given value + * + * @param float $x Value + * @return float Result + */ + public function evaluate( $x ) + { + $value = 0; + foreach( $this->values as $exponent => $factor ) + { + $value += $factor * pow( $x, $exponent ); + } + + return $value; + } + + /** + * Returns a string represenation of the polynom + * + * @return string String representation of polynom + */ + public function __to_string() + { + krsort( $this->values ); + $string = ''; + + foreach ( $this->values as $exponent => $factor ) + { + $string .= + ( $factor != 1 ? sprintf( '%.2f * ', $factor ) : '' ) . + ( $exponent > 1 ? sprintf( 'x^%d + ', $exponent ) : + ( $exponent === 1 ? 'x + ' : '' ) + ); + } + + return substr( $string, 0, -3 ); + } +} +?> diff --git a/tests/matrix_test.php b/tests/matrix_test.php new file mode 100644 index 0000000..0afd631 --- /dev/null +++ b/tests/matrix_test.php @@ -0,0 +1,263 @@ +<?php +/** + * ezcGraphMatrixTest + * + * @package Graph + * @version //autogen// + * @subpackage Tests + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ + +/** + * Tests for ezcGraph class. + * + * @package ImageAnalysis + * @subpackage Tests + */ +class ezcGraphMatrixTest extends ezcTestCase +{ + + public static function suite() + { + return new ezcTestSuite( "ezcGraphMatrixTest" ); + } + + /** + * setUp + * + * @access public + */ + public function setUp() + { + } + + /** + * tearDown + * + * @access public + */ + public function tearDown() + { + } + + public function testCreateIdentityMatrix() + { + $matrix = new ezcGraphMatrix(); + + $this->assertEquals( + array( + array( 1, 0, 0 ), + array( 0, 1, 0 ), + array( 0, 0, 1 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testCreateCustomIdentityMatrix() + { + $matrix = new ezcGraphMatrix( 2, 4 ); + + $this->assertEquals( + array( + array( 1, 0, 0, 0 ), + array( 0, 1, 0, 0 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testCreateCustomMatrix() + { + $matrix = new ezcGraphMatrix( 2, 4, array( array( 1, 0, 5 ), array( 6, -1, -3, .5 ) ) ); + + $this->assertEquals( + array( + array( 1, 0, 5, 0 ), + array( 6, -1, -3, .5 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testGetMatrixValue() + { + $matrix = new ezcGraphMatrix( ); + + $this->assertEquals( + 1, + $matrix->get( 1, 1 ) + ); + } + + public function testSetMatrixValue() + { + $matrix = new ezcGraphMatrix( ); + + $matrix->set( 1, 2, .45 ); + + $this->assertEquals( + .45, + $matrix->get( 1, 2 ) + ); + } + + public function testSetInvalidMatrixValue() + { + $matrix = new ezcGraphMatrix( ); + + try + { + $matrix->set( 1, 32, .45 ); + } + catch ( ezcGraphMatrixOutOfBoundingsException $e ) + { + return true; + } + + $this->fail( 'Expected ezcGraphMatrixOutOfBoundingsException.' ); + } + + public function testGetInvalidMatrixValue() + { + $matrix = new ezcGraphMatrix( ); + + try + { + $matrix->get( 1, 32 ); + } + catch ( ezcGraphMatrixOutOfBoundingsException $e ) + { + return true; + } + + $this->fail( 'Expected ezcGraphMatrixOutOfBoundingsException.' ); + } + + public function testAddMatrices() + { + $matrix = new ezcGraphMatrix(); + $matrix->add( new ezcGraphMatrix() ); + + $this->assertEquals( + array( + array( 2, 0, 0 ), + array( 0, 2, 0 ), + array( 0, 0, 2 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testDiffMatrices() + { + $matrix = new ezcGraphMatrix(); + $matrix->diff( new ezcGraphMatrix() ); + + $this->assertEquals( + array( + array( 0, 0, 0 ), + array( 0, 0, 0 ), + array( 0, 0, 0 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testAddIncompatibleMatrices() + { + $matrix = new ezcGraphMatrix(); + + try + { + $matrix->add( new ezcGraphMatrix( 4, 4 ) ); + } + catch ( ezcGraphMatrixInvalidDimensionsException $e ) + { + return true; + } + + $this->fail( 'Expected ezcGraphMatrixInvalidDimensionsException.' ); + } + + public function testDiffIncompatibleMatrices() + { + $matrix = new ezcGraphMatrix(); + + try + { + $matrix->add( new ezcGraphMatrix( 4, 4 ) ); + } + catch ( ezcGraphMatrixInvalidDimensionsException $e ) + { + return true; + } + + $this->fail( 'Expected ezcGraphMatrixInvalidDimensionsException.' ); + } + + public function testScalarMultiplication() + { + $matrix = new ezcGraphMatrix(); + $matrix->scalar( -.5 ); + + $this->assertEquals( + array( + array( -.5, 0, 0 ), + array( 0, -.5, 0 ), + array( 0, 0, -.5 ), + ), + $this->getAttribute( $matrix, 'matrix' ) + ); + } + + public function testMatrixMultiplication() + { + $a = new ezcGraphMatrix( 2, 3, array( + array( 1, 2, 3 ), + array( 4, 5, 6 ), + ) ); + $b = new ezcGraphMatrix( 3, 2, array( + array( 6, -1 ), + array( 3, 2 ), + array( 0, -3 ), + ) ); + + $c = $a->multiply( $b ); + + $this->assertEquals( + array( + array( 12, -6 ), + array( 39, -12 ), + ), + $this->getAttribute( $c, 'matrix' ) + ); + } + + public function testMatrixMultiplication2() + { + $a = new ezcGraphMatrix( 2, 3, array( + array( 1, 2, 3 ), + array( 4, 5, 6 ), + ) ); + $b = new ezcGraphMatrix( 3, 3, array( + array( 6, -1 ), + array( 3, 2 ), + array( 0, -3 ), + ) ); + + try + { + $a->multiply( $b ); + } + catch( ezcGraphMatrixInvalidDimensionsException $e ) + { + return true; + } + + $this->fail( 'Expected ezcGraphMatrixInvalidDimensionsException.' ); + } +} + +?> diff --git a/tests/polynom_test.php b/tests/polynom_test.php new file mode 100644 index 0000000..c46d8c5 --- /dev/null +++ b/tests/polynom_test.php @@ -0,0 +1,122 @@ +<?php +/** + * ezcGraphPolynomTest + * + * @package Graph + * @version //autogen// + * @subpackage Tests + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ + +/** + * Tests for ezcGraph class. + * + * @package ImageAnalysis + * @subpackage Tests + */ +class ezcGraphPolynomTest extends ezcTestCase +{ + + public static function suite() + { + return new ezcTestSuite( "ezcGraphPolynomTest" ); + } + + /** + * setUp + * + * @access public + */ + public function setUp() + { + } + + /** + * tearDown + * + * @access public + */ + public function tearDown() + { + } + + public function testCreatePolynom() + { + $polynom = new ezcGraphPolynom( array( 2 => 1 ) ); + + $this->assertEquals( + 'x^2', + $polynom->__to_string() + ); + } + + public function testCreatePolynom2() + { + $polynom = new ezcGraphPolynom( array( 2 => .5, 1 => 3, 0 => -4.5 ) ); + + $this->assertEquals( + '0.50 * x^2 + 3.00 * x + -4.50', + $polynom->__to_string() + ); + } + + public function testPolynomGetOrder() + { + $polynom = new ezcGraphPolynom( array( 2 => .5, 1 => 3, 0 => -4.5 ) ); + + $this->assertEquals( + 2, + $polynom->getOrder() + ); + } + + public function testAddPolynom() + { + $polynom = new ezcGraphPolynom( array( 2 => .5, 1 => 3, 0 => -4.5 ) ); + $polynom->add( new ezcGraphPolynom( array( 2 => 1 ) ) ); + + $this->assertEquals( + '1.50 * x^2 + 3.00 * x + -4.50', + $polynom->__to_string() + ); + } + + public function testEvaluatePolynom() + { + $polynom = new ezcGraphPolynom( array( 2 => 1 ) ); + + $this->assertEquals( + 4., + $polynom->evaluate( 2 ), + 'Calculated wrong value', + .1 + ); + } + + public function testEvaluatePolynomNegativeValue() + { + $polynom = new ezcGraphPolynom( array( 2 => 1 ) ); + + $this->assertEquals( + 4., + $polynom->evaluate( -2 ), + 'Calculated wrong value', + .1 + ); + } + + public function testEvaluateComplexPolynom() + { + $polynom = new ezcGraphPolynom( array( 2 => .5, 1 => 3, 0 => -4.5 ) ); + + $this->assertEquals( + 9., + $polynom->evaluate( 3 ), + 'Calculated wrong value', + .1 + ); + } +} + +?> diff --git a/tests/suite.php b/tests/suite.php index 71c4aca..2237fdd 100644 --- a/tests/suite.php +++ b/tests/suite.php @@ -30,6 +30,8 @@ require_once 'driver_gd_test.php'; require_once 'driver_svg_test.php'; require_once 'font_test.php'; require_once 'palette_test.php'; +require_once 'matrix_test.php'; +require_once 'polynom_test.php'; /** * Test suite for ImageAnalysis package. @@ -62,6 +64,8 @@ class ezcGraphSuite extends ezcTestSuite $this->addTest( ezcGraphFontTest::suite() ); $this->addTest( ezcGraphTextTest::suite() ); $this->addTest( ezcGraphPaletteTest::suite() ); + $this->addTest( ezcGraphMatrixTest::suite() ); + $this->addTest( ezcGraphPolynomTest::suite() ); } public static function suite() |