/lib/zeta/Graph/src/datasets/average.php

https://gitlab.com/OnBlox/OnBlox-Template · PHP · 375 lines · 151 code · 37 blank · 187 comment · 16 complexity · 83f21448be84c97258cee4ed0afeb2a0 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcGraphDataSetAverage class
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. * @package Graph
  23. * @version //autogentag//
  24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  25. */
  26. /**
  27. * Extension of basic dataset to represent averation.
  28. * Algorithm: http://en.wikipedia.org/wiki/Least_squares
  29. *
  30. * @property int $polynomOrder
  31. * Maximum order of polygon to interpolate from points
  32. * @property int $resolution
  33. * Resolution used to draw line in graph
  34. *
  35. * @version //autogentag//
  36. * @package Graph
  37. * @mainclass
  38. */
  39. class ezcGraphDataSetAveragePolynom extends ezcGraphDataSet
  40. {
  41. /**
  42. * Source dataset to base averation on.
  43. *
  44. * @var ezcGraphDataSet
  45. */
  46. protected $source;
  47. /**
  48. * Calculated averation polynom
  49. *
  50. * @var ezcGraphPolynom
  51. */
  52. protected $polynom = false;
  53. /**
  54. * Minimum key
  55. *
  56. * @var float
  57. */
  58. protected $min = false;
  59. /**
  60. * Maximum key
  61. *
  62. * @var float
  63. */
  64. protected $max = false;
  65. /**
  66. * Position of the data iterator. Depends on the configured resolution.
  67. *
  68. * @var int
  69. */
  70. protected $position = 0;
  71. /**
  72. * Container to hold the properties
  73. *
  74. * @var array(string=>mixed)
  75. */
  76. protected $properties;
  77. /**
  78. * Constructor
  79. *
  80. * @param ezcGraphDataSet $dataset Dataset to interpolate
  81. * @param int $order Maximum order of interpolating polynom
  82. * @return void
  83. * @ignore
  84. */
  85. public function __construct( ezcGraphDataSet $dataset, $order = 3 )
  86. {
  87. parent::__construct();
  88. $this->properties['resolution'] = 100;
  89. $this->properties['polynomOrder'] = (int) $order;
  90. $this->source = $dataset;
  91. }
  92. /**
  93. * Options write access
  94. *
  95. * @throws ezcBasePropertyNotFoundException
  96. * If Option could not be found
  97. * @throws ezcBaseValueException
  98. * If value is out of range
  99. * @param mixed $propertyName Option name
  100. * @param mixed $propertyValue Option value;
  101. * @return mixed
  102. */
  103. public function __set( $propertyName, $propertyValue )
  104. {
  105. switch ( $propertyName ) {
  106. case 'polynomOrder':
  107. if ( !is_numeric( $propertyValue ) ||
  108. ( $propertyValue < 0 ) )
  109. {
  110. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int > 0' );
  111. }
  112. $this->properties['polynomOrder'] = (int) $propertyValue;
  113. $this->polynom = false;
  114. break;
  115. case 'resolution':
  116. if ( !is_numeric( $propertyValue ) ||
  117. ( $propertyValue < 1 ) )
  118. {
  119. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int > 1' );
  120. }
  121. $this->properties['resolution'] = (int) $propertyValue;
  122. break;
  123. default:
  124. parent::__set( $propertyName, $propertyValue );
  125. break;
  126. }
  127. }
  128. /**
  129. * Property get access.
  130. * Simply returns a given option.
  131. *
  132. * @param string $propertyName The name of the option to get.
  133. * @return mixed The option value.
  134. *
  135. * @throws ezcBasePropertyNotFoundException
  136. * If a the value for the property options is not an instance of
  137. */
  138. public function __get( $propertyName )
  139. {
  140. if ( array_key_exists( $propertyName, $this->properties ) )
  141. {
  142. return $this->properties[$propertyName];
  143. }
  144. return parent::__get( $propertyName );
  145. }
  146. /**
  147. * Build the polynom based on the given points.
  148. *
  149. * @return void
  150. */
  151. protected function buildPolynom()
  152. {
  153. $points = array();
  154. foreach ( $this->source as $key => $value )
  155. {
  156. if ( !is_numeric( $key ) )
  157. {
  158. throw new ezcGraphDatasetAverageInvalidKeysException();
  159. }
  160. if ( ( $this->min === false ) || ( $this->min > $key ) )
  161. {
  162. $this->min = (float) $key;
  163. }
  164. if ( ( $this->max === false ) || ( $this->max < $key ) )
  165. {
  166. $this->max = (float) $key;
  167. }
  168. $points[] = new ezcGraphCoordinate( (float) $key, (float) $value );
  169. }
  170. // Build transposed and normal Matrix out of coordiantes
  171. $a = new ezcGraphMatrix( count( $points ), $this->polynomOrder + 1 );
  172. $b = new ezcGraphMatrix( count( $points ), 1 );
  173. for ( $i = 0; $i <= $this->properties['polynomOrder']; ++$i )
  174. {
  175. foreach ( $points as $nr => $point )
  176. {
  177. $a->set( $nr, $i, pow( $point->x, $i ) );
  178. $b->set( $nr, 0, $point->y );
  179. }
  180. }
  181. $at = clone $a;
  182. $at->transpose();
  183. $left = $at->multiply( $a );
  184. $right = $at->multiply( $b );
  185. $this->polynom = $left->solveNonlinearEquatation( $right );
  186. }
  187. /**
  188. * Returns a polynom of the defined order witch matches the datapoints
  189. * using the least squares algorithm.
  190. *
  191. * @return ezcGraphPolynom Polynom
  192. */
  193. public function getPolynom()
  194. {
  195. if ( $this->polynom === false )
  196. {
  197. $this->buildPolynom();
  198. }
  199. return $this->polynom;
  200. }
  201. /**
  202. * Get the x coordinate for the current position
  203. *
  204. * @param int $position Position
  205. * @return float x coordinate
  206. */
  207. protected function getKey()
  208. {
  209. $polynom = $this->getPolynom();
  210. return $this->min +
  211. ( $this->max - $this->min ) / $this->resolution * $this->position;
  212. }
  213. /**
  214. * Returns true if the given datapoint exists
  215. * Allows isset() using ArrayAccess.
  216. *
  217. * @param string $key The key of the datapoint to get.
  218. * @return bool Wether the key exists.
  219. */
  220. public function offsetExists( $key )
  221. {
  222. $polynom = $this->getPolynom();
  223. return ( ( $key >= $this->min ) && ( $key <= $this->max ) );
  224. }
  225. /**
  226. * Returns the value for the given datapoint
  227. * Get an datapoint value by ArrayAccess.
  228. *
  229. * @param string $key The key of the datapoint to get.
  230. * @return float The datapoint value.
  231. */
  232. public function offsetGet( $key )
  233. {
  234. $polynom = $this->getPolynom();
  235. return $polynom->evaluate( $key );
  236. }
  237. /**
  238. * Throws a ezcBasePropertyPermissionException because single datapoints
  239. * cannot be set in average datasets.
  240. *
  241. * @param string $key The kex of a datapoint to set.
  242. * @param float $value The value for the datapoint.
  243. * @throws ezcBasePropertyPermissionException
  244. * Always, because access is readonly.
  245. * @return void
  246. */
  247. public function offsetSet( $key, $value )
  248. {
  249. throw new ezcBasePropertyPermissionException( $key, ezcBasePropertyPermissionException::READ );
  250. }
  251. /**
  252. * Returns the currently selected datapoint.
  253. *
  254. * This method is part of the Iterator interface to allow access to the
  255. * datapoints of this row by iterating over it like an array (e.g. using
  256. * foreach).
  257. *
  258. * @return string The currently selected datapoint.
  259. */
  260. final public function current()
  261. {
  262. $polynom = $this->getPolynom();
  263. return $polynom->evaluate( $this->getKey() );
  264. }
  265. /**
  266. * Returns the next datapoint and selects it or false on the last datapoint.
  267. *
  268. * This method is part of the Iterator interface to allow access to the
  269. * datapoints of this row by iterating over it like an array (e.g. using
  270. * foreach).
  271. *
  272. * @return float datapoint if it exists, or false.
  273. */
  274. final public function next()
  275. {
  276. if ( ++$this->position >= $this->resolution )
  277. {
  278. return false;
  279. }
  280. else
  281. {
  282. return $this->current();
  283. }
  284. }
  285. /**
  286. * Returns the key of the currently selected datapoint.
  287. *
  288. * This method is part of the Iterator interface to allow access to the
  289. * datapoints of this row by iterating over it like an array (e.g. using
  290. * foreach).
  291. *
  292. * @return string The key of the currently selected datapoint.
  293. */
  294. final public function key()
  295. {
  296. return (string) $this->getKey();
  297. }
  298. /**
  299. * Returns if the current datapoint is valid.
  300. *
  301. * This method is part of the Iterator interface to allow access to the
  302. * datapoints of this row by iterating over it like an array (e.g. using
  303. * foreach).
  304. *
  305. * @return bool If the current datapoint is valid
  306. */
  307. final public function valid()
  308. {
  309. $polynom = $this->getPolynom();
  310. if ( $this->min >= $this->max )
  311. {
  312. return false;
  313. }
  314. return ( ( $this->getKey() >= $this->min ) && ( $this->getKey() <= $this->max ) );
  315. }
  316. /**
  317. * Selects the very first datapoint and returns it.
  318. * This method is part of the Iterator interface to allow access to the
  319. * datapoints of this row by iterating over it like an array (e.g. using
  320. * foreach).
  321. *
  322. * @return float The very first datapoint.
  323. */
  324. final public function rewind()
  325. {
  326. $this->position = 0;
  327. }
  328. /**
  329. * Returns the number of elements in this dataset
  330. *
  331. * @return int
  332. */
  333. public function count()
  334. {
  335. return $this->resolution;
  336. }
  337. }
  338. ?>