GenericGFPoly.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. /*
  3. * Copyright 2007 ZXing authors
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace Zxing\Common\Reedsolomon;
  18. /**
  19. * <p>Represents a polynomial whose coefficients are elements of a GF.
  20. * Instances of this class are immutable.</p>
  21. *
  22. * <p>Much credit is due to William Rucklidge since portions of this code are an indirect
  23. * port of his C++ Reed-Solomon implementation.</p>
  24. *
  25. * @author Sean Owen
  26. */
  27. final class GenericGFPoly {
  28. private $field;
  29. private $coefficients;
  30. /**
  31. * @param field the {@link GenericGF} instance representing the field to use
  32. * to perform computations
  33. * @param coefficients array coefficients as ints representing elements of GF(size), arranged
  34. * from most significant (highest-power term) coefficient to least significant
  35. * @throws IllegalArgumentException if argument is null or empty,
  36. * or if leading coefficient is 0 and this is not a
  37. * constant polynomial (that is, it is not the monomial "0")
  38. */
  39. function __construct($field, $coefficients) {
  40. if (count($coefficients) == 0) {
  41. throw new \InvalidArgumentException();
  42. }
  43. $this->field = $field;
  44. $coefficientsLength = count($coefficients);
  45. if ($coefficientsLength > 1 && $coefficients[0] == 0) {
  46. // Leading term must be non-zero for anything except the constant polynomial "0"
  47. $firstNonZero = 1;
  48. while ($firstNonZero < $coefficientsLength && $coefficients[$firstNonZero] == 0) {
  49. $firstNonZero++;
  50. }
  51. if ($firstNonZero == $coefficientsLength) {
  52. $this->coefficients = array(0);
  53. } else {
  54. $this->coefficients = fill_array(0,$coefficientsLength - $firstNonZero,0);
  55. $this->coefficients = arraycopy($coefficients,
  56. $firstNonZero,
  57. $this->coefficients,
  58. 0,
  59. count($this->coefficients));
  60. }
  61. } else {
  62. $this->coefficients = $coefficients;
  63. }
  64. }
  65. function getCoefficients() {
  66. return $this->coefficients;
  67. }
  68. /**
  69. * @return degree of this polynomial
  70. */
  71. function getDegree() {
  72. return count($this->coefficients) - 1;
  73. }
  74. /**
  75. * @return true iff this polynomial is the monomial "0"
  76. */
  77. function isZero() {
  78. return $this->coefficients[0] == 0;
  79. }
  80. /**
  81. * @return coefficient of x^degree term in this polynomial
  82. */
  83. function getCoefficient($degree) {
  84. return $this->coefficients[count($this->coefficients) - 1 - $degree];
  85. }
  86. /**
  87. * @return evaluation of this polynomial at a given point
  88. */
  89. function evaluateAt($a) {
  90. if ($a == 0) {
  91. // Just return the x^0 coefficient
  92. return $this->getCoefficient(0);
  93. }
  94. $size = count($this->coefficients);
  95. if ($a == 1) {
  96. // Just the sum of the coefficients
  97. $result = 0;
  98. foreach ($this->coefficients as $coefficient ) {
  99. $result = GenericGF::addOrSubtract($result, $coefficient);
  100. }
  101. return $result;
  102. }
  103. $result = $this->coefficients[0];
  104. for ($i = 1; $i < $size; $i++) {
  105. $result = GenericGF::addOrSubtract($this->field->multiply($a, $result), $this->coefficients[$i]);
  106. }
  107. return $result;
  108. }
  109. function addOrSubtract($other) {
  110. if ($this->field !== $other->field) {
  111. throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
  112. }
  113. if ($this->isZero()) {
  114. return $other;
  115. }
  116. if ($other->isZero()) {
  117. return $this;
  118. }
  119. $smallerCoefficients = $this->coefficients;
  120. $largerCoefficients = $other->coefficients;
  121. if (count($smallerCoefficients) > count($largerCoefficients)) {
  122. $temp = $smallerCoefficients;
  123. $smallerCoefficients = $largerCoefficients;
  124. $largerCoefficients = $temp;
  125. }
  126. $sumDiff = fill_array(0,count($largerCoefficients),0);
  127. $lengthDiff = count($largerCoefficients) - count($smallerCoefficients);
  128. // Copy high-order terms only found in higher-degree polynomial's coefficients
  129. $sumDiff = arraycopy($largerCoefficients, 0, $sumDiff, 0, $lengthDiff);
  130. for ($i = $lengthDiff; $i < count($largerCoefficients); $i++) {
  131. $sumDiff[$i] = GenericGF::addOrSubtract($smallerCoefficients[$i - $lengthDiff], $largerCoefficients[$i]);
  132. }
  133. return new GenericGFPoly($this->field, $sumDiff);
  134. }
  135. function multiply($other) {
  136. if(is_int($other)){
  137. return $this->multiply_($other);
  138. }
  139. if ($this->field !== $other->field) {
  140. throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
  141. }
  142. if ($this->isZero() || $other->isZero()) {
  143. return $this->field->getZero();
  144. }
  145. $aCoefficients = $this->coefficients;
  146. $aLength = count($aCoefficients);
  147. $bCoefficients = $other->coefficients;
  148. $bLength = count($bCoefficients);
  149. $product = fill_array(0,$aLength + $bLength - 1,0);
  150. for ($i = 0; $i < $aLength; $i++) {
  151. $aCoeff = $aCoefficients[$i];
  152. for ($j = 0; $j < $bLength; $j++) {
  153. $product[$i + $j] = GenericGF::addOrSubtract($product[$i + $j],
  154. $this->field->multiply($aCoeff, $bCoefficients[$j]));
  155. }
  156. }
  157. return new GenericGFPoly($this->field, $product);
  158. }
  159. function multiply_($scalar) {
  160. if ($scalar == 0) {
  161. return $this->field->getZero();
  162. }
  163. if ($scalar == 1) {
  164. return $this;
  165. }
  166. $size = count($this->coefficients);
  167. $product = fill_array(0,$size,0);
  168. for ($i = 0; $i < $size; $i++) {
  169. $product[$i] = $this->field->multiply($this->coefficients[$i], $scalar);
  170. }
  171. return new GenericGFPoly($this->field, $product);
  172. }
  173. function multiplyByMonomial($degree, $coefficient) {
  174. if ($degree < 0) {
  175. throw new \InvalidArgumentException();
  176. }
  177. if ($coefficient == 0) {
  178. return $this->field->getZero();
  179. }
  180. $size = count($this->coefficients);
  181. $product = fill_array(0,$size + $degree,0);
  182. for ($i = 0; $i < $size; $i++) {
  183. $product[$i] = $this->field->multiply($this->coefficients[$i], $coefficient);
  184. }
  185. return new GenericGFPoly($this->field, $product);
  186. }
  187. function divide($other) {
  188. if ($this->field !==$other->field) {
  189. throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
  190. }
  191. if ($other->isZero()) {
  192. throw new \InvalidArgumentException("Divide by 0");
  193. }
  194. $quotient = $this->field->getZero();
  195. $remainder = $this;
  196. $denominatorLeadingTerm = $other->getCoefficient($other->getDegree());
  197. $inverseDenominatorLeadingTerm = $this->field->inverse($denominatorLeadingTerm);
  198. while ($remainder->getDegree() >= $other->getDegree() && !$remainder->isZero()) {
  199. $degreeDifference = $remainder->getDegree() - $other->getDegree();
  200. $scale = $this->field->multiply($remainder->getCoefficient($remainder->getDegree()), $inverseDenominatorLeadingTerm);
  201. $term = $other->multiplyByMonomial($degreeDifference, $scale);
  202. $iterationQuotient = $this->field->buildMonomial($degreeDifference, $scale);
  203. $quotient = $quotient->addOrSubtract($iterationQuotient);
  204. $remainder = $remainder->addOrSubtract($term);
  205. }
  206. return array($quotient, $remainder );
  207. }
  208. //@Override
  209. public function toString() {
  210. $result = '';
  211. for ($degree = $this->getDegree(); $degree >= 0; $degree--) {
  212. $coefficient = $this->getCoefficient($degree);
  213. if ($coefficient != 0) {
  214. if ($coefficient < 0) {
  215. $result.=" - ";
  216. $coefficient = -$coefficient;
  217. } else {
  218. if (strlen($result) > 0) {
  219. $result .= " + ";
  220. }
  221. }
  222. if ($degree == 0 || $coefficient != 1) {
  223. $alphaPower = $this->field->log($coefficient);
  224. if ($alphaPower == 0) {
  225. $result.='1';
  226. } else if ($alphaPower == 1) {
  227. $result.='a';
  228. } else {
  229. $result.="a^";
  230. $result.=($alphaPower);
  231. }
  232. }
  233. if ($degree != 0) {
  234. if ($degree == 1) {
  235. $result.='x';
  236. } else {
  237. $result.="x^";
  238. $result.= $degree;
  239. }
  240. }
  241. }
  242. }
  243. return $result;
  244. }
  245. }