/misc/NeuralNetworkJava/Neural/src/org/retro/neural/Matrix.java

http://jvmnotebook.googlecode.com/ · Java · 1611 lines · 810 code · 282 blank · 519 comment · 156 complexity · 398a7f06b5af6952e69d25ca0992aaff MD5 · raw file

  1. //
  2. // Berlin Brown
  3. //
  4. // $Id: Matrix.java,v 1.1.1.1 2004/04/26 13:27:33 bigbinc Exp $
  5. //
  6. //
  7. // Andreas Keilhauer, Simon D. Levy
  8. //.......................................................
  9. package org.retro.neural;
  10. public class Matrix{
  11. protected int numOfRows;
  12. protected int numOfCols;
  13. protected FieldElement[][] entries;
  14. public Matrix(int numberOfRows, int numberOfCols){
  15. this.numOfRows = numberOfRows;
  16. this.numOfCols = numberOfCols;
  17. this.entries = new FieldElement[numberOfRows][numberOfCols];
  18. }
  19. public Matrix(FieldElement[] theEntries, int numberOfRows)
  20. throws InvalidOperationException{
  21. if (theEntries == null){
  22. throw new InvalidOperationException(
  23. "Tried to construct matrix with a null entry array");
  24. }
  25. if (theEntries.length % numberOfRows != 0){
  26. throw new InvalidOperationException(
  27. "Tried to construct matrix with "+ theEntries.length +
  28. " entries and "+ numberOfRows +" rows");
  29. }
  30. this.numOfRows = numberOfRows;
  31. this.numOfCols = theEntries.length / numberOfRows;
  32. this.entries = new FieldElement[this.numOfRows][this.numOfCols];
  33. for(int i=0; i < this.numOfRows; i++){
  34. for(int j=0; j < this.numOfCols; j++){
  35. entries[i][j] = theEntries[i*this.numOfCols+j];
  36. }
  37. }
  38. }
  39. /**
  40. * Constructs a Matrix out of an array of row vectors.
  41. *
  42. * @param rowVectors as an array of Vectors
  43. * @throws InvalidOperationException if rowVectors is null
  44. * @throws InvalidOperationException if rowVectors contains a null Vector
  45. * @throws InvalidOperationException if rowVectors contains
  46. * Vectors of unequal lengths
  47. */
  48. public Matrix(Vector[] rowVectors) throws InvalidOperationException{
  49. if(rowVectors == null){
  50. throw new InvalidOperationException(
  51. "Tried to construct matrix but array of row vectors was null");
  52. }
  53. for(int i=0; i<rowVectors.length; i++){
  54. if (rowVectors[i] == null){
  55. throw new InvalidOperationException(
  56. "Tried to construct matrix and found null-vector");
  57. }
  58. }
  59. int vectorLength = rowVectors[0].length();
  60. for(int i=0; i < rowVectors.length; i++){
  61. if (rowVectors[i].length() != vectorLength){
  62. throw new InvalidOperationException(
  63. "Tried to construct matrix but not all vectors"+
  64. " had the same length");
  65. }
  66. }
  67. numOfRows = rowVectors.length;
  68. numOfCols = vectorLength;
  69. entries = new FieldElement[numOfRows][numOfCols];
  70. for(int k=0; k<numOfRows; k++){
  71. for(int l=0; l<numOfCols; l++){
  72. entries[k][l] = rowVectors[k].getEntry(l+1);
  73. }
  74. }
  75. }
  76. /**
  77. * Constructs a Matrix out of a two dimensional array of FieldElements.
  78. *
  79. * @param theEntries as a two dimensional FieldElement array.
  80. * @throws InvalidOperationException if theEntries is null
  81. */
  82. public Matrix(FieldElement[][] theEntries)
  83. throws InvalidOperationException {
  84. if(theEntries == null){
  85. throw new InvalidOperationException(
  86. "Tried to construct matrix but entry array was null");
  87. }
  88. int i = 0;
  89. try{
  90. while(true){
  91. FieldElement tmp = theEntries[i][0];
  92. i++;
  93. }
  94. }catch(ArrayIndexOutOfBoundsException a){
  95. this.numOfRows = i;
  96. }
  97. i = 0;
  98. try{
  99. while(true){
  100. FieldElement tmp = theEntries[0][i];
  101. i++;
  102. }
  103. }catch(ArrayIndexOutOfBoundsException a){
  104. this.numOfCols = i;
  105. }
  106. this.entries = theEntries;
  107. }
  108. /**
  109. * Constructs a Matrix out of a two dimensional array of FieldElements.
  110. * But with the dimensions given it is faster than the constructor above
  111. * because it doesnt check any integrity of the entries-array.
  112. *
  113. * @param theEntries
  114. * @param rows
  115. * @param cols
  116. */
  117. public Matrix(FieldElement[][] theEntries, int rows, int cols) {
  118. this.numOfRows = rows;
  119. this.numOfCols = cols;
  120. this.entries = theEntries;
  121. }
  122. /**
  123. * Gets the number of rows of this Matrix.
  124. * @return number of rows
  125. */
  126. public int getRows(){
  127. return numOfRows;
  128. }
  129. /**
  130. * Gets the number of columns of this Matrix.
  131. * @return number of columns
  132. */
  133. public int getCols(){
  134. return numOfCols;
  135. }
  136. /**
  137. * Gets the entry of this Matrix at a certain row - and col index.
  138. *
  139. * @param rowIndex
  140. * @param colIndex
  141. * @return the FieldElement at this row - and column index
  142. */
  143. public FieldElement getEntry(int rowIndex, int colIndex){
  144. return entries[rowIndex-1][colIndex-1];
  145. }
  146. /**
  147. * Sets the entry of this Matrix at a certain row - and col index.
  148. *
  149. * @param rowIndex
  150. * @param colIndex
  151. * @param newEntry
  152. * @throws InvalidOperationException if rowIndex or colIndex is invalid
  153. */
  154. public void setEntry(int rowIndex, int colIndex, FieldElement newEntry)
  155. throws InvalidOperationException {
  156. try{
  157. entries[rowIndex-1][colIndex-1] = newEntry;
  158. }catch(ArrayIndexOutOfBoundsException e){
  159. if(rowIndex > this.numOfRows || rowIndex < 1){
  160. throw new InvalidOperationException(
  161. "Tried row index "+ rowIndex + ". Only row indices from 1 to "+
  162. this.numOfRows +" valid");
  163. }else{
  164. throw new InvalidOperationException(
  165. "Tried column index "+ colIndex + ". Only column indices " +
  166. "from 1 to " + this.numOfCols + " valid");
  167. }
  168. }
  169. }
  170. /**
  171. * Gets the row vector at a certain row index.
  172. *
  173. * @param rowIndex
  174. */
  175. public Vector getRow(int rowIndex){
  176. FieldElement[] rowEntries = new FieldElement[numOfCols];
  177. for(int i=0; i<numOfCols; i++){
  178. rowEntries[i] = entries[rowIndex-1][i];
  179. }
  180. return new Vector(rowEntries);
  181. }
  182. /**
  183. * Gets the column vector at a certain column index.
  184. *
  185. * @param colIndex
  186. */
  187. public Vector getCol(int colIndex){
  188. FieldElement[] colEntries = new FieldElement[numOfRows];
  189. for(int i=0; i<numOfRows; i++){
  190. colEntries[i] = entries[i][colIndex-1];
  191. }
  192. return new Vector(colEntries);
  193. }
  194. /**
  195. * Sets the row vector at a certain index of the matrix.
  196. *
  197. * @param rowIndex
  198. * @param vector
  199. * @throws InvalidOperationException if index out of bounds
  200. */
  201. public void setRow(int rowIndex, Vector vector)
  202. throws InvalidOperationException {
  203. if(this.numOfCols != vector.length()){
  204. throw new InvalidOperationException(
  205. "Tried to set row number "+ rowIndex + "of a matrix with " +
  206. this.numOfCols + " columns with a vector having length "
  207. + vector.length() +" ");
  208. }
  209. for(int i=1; i<=vector.length(); i++){
  210. setEntry(rowIndex, i, vector.getEntry(i));
  211. }
  212. }
  213. /**
  214. * Sets the column vector at a certain column index of the matrix.
  215. *
  216. * @param colIndex
  217. * @param vector
  218. */
  219. public void setCol(int colIndex, Vector vector){
  220. if(this.numOfRows != vector.length()){
  221. throw new InvalidOperationException(
  222. "Tried to set column number "+ colIndex + "of a matrix with " +
  223. this.numOfRows + " rows with a vector having length " +
  224. vector.length() +" ");
  225. }
  226. for(int i=1; i<=vector.length(); i++){
  227. setEntry(i, colIndex, vector.getEntry(i));
  228. }
  229. }
  230. /**
  231. * Returns this Matrix without the row at a certain row index.
  232. *
  233. * @param rowIndex
  234. * @return the matrix without the row at the row index.
  235. */
  236. public Matrix withoutRow(int rowIndex){
  237. //Exception still missing here
  238. Matrix tmp = new Matrix(this.getRows()-1, this.getCols());
  239. int counter = 0;
  240. for(int i=1; i <= this.getRows(); i++){
  241. counter++;
  242. if(i == rowIndex){
  243. counter--;
  244. continue;
  245. }
  246. tmp.setRow(counter, this.getRow(i));
  247. }
  248. return tmp;
  249. }
  250. /**
  251. * Returns this Matrix without the column at a certain column index.
  252. *
  253. * @param colIndex
  254. * @return the matrix without the column at the column index.
  255. */
  256. public Matrix withoutCol(int colIndex){
  257. //Exception still missing here
  258. Matrix tmp = new Matrix(this.getRows(), this.getCols()-1);
  259. int counter = 0;
  260. for(int i=1; i <= this.getCols(); i++){
  261. counter++;
  262. if(i == colIndex){
  263. counter--;
  264. continue;
  265. }
  266. tmp.setCol(counter, this.getCol(i));
  267. }
  268. return tmp;
  269. }
  270. /**
  271. * Returns a Matrix with a Vector inserted at specified index as a
  272. * column. Index 1 will it put at the beginning and index
  273. * numOfCols+1 will attach it to the end.
  274. *
  275. * @param vector
  276. * @param colIndex
  277. * @return matrix with vector inserted.
  278. * @throws InvalidOperationException if index out of bounds
  279. */
  280. public Matrix insertCol(int colIndex, Vector vector)
  281. throws InvalidOperationException {
  282. if(this.getRows() != vector.length()){
  283. throw new InvalidOperationException(
  284. "This vector\n"+ vector + "\n cannot be attached to " +
  285. "the Matrix\n"+ this + " as a column vector. The length does " +
  286. "not match");
  287. }
  288. if(colIndex < 1 || colIndex > this.getCols()+1){
  289. throw new InvalidOperationException(
  290. colIndex + " is not a valid column index for inserting "+
  291. vector + " into\n" + this);
  292. }
  293. Matrix tmp = new Matrix(this.getRows(), this.getCols()+1);
  294. int colOffset = 0;
  295. for(int col = 1; col <= tmp.getCols(); col++){
  296. if(col == colIndex){
  297. tmp.setCol(col, vector);
  298. colOffset = 1;
  299. }else{
  300. tmp.setCol(col, this.getCol(col - colOffset));
  301. }
  302. }
  303. return tmp;
  304. }
  305. /**
  306. * Returns a Matrix with a Vector inserted at specified index as a row.
  307. * Index 1 will put at the beginning and index numOfRows+1 will attach
  308. * it to the end.
  309. *
  310. * @param vector
  311. * @param rowIndex
  312. * @return matrix with vector inserted.
  313. * @throws InvalidOperationException if index out of bounds
  314. */
  315. public Matrix insertRow(int rowIndex, Vector vector)
  316. throws InvalidOperationException {
  317. if(this.getCols() != vector.length()){
  318. throw new InvalidOperationException(
  319. "This vector\n"+ vector +"\n cannot be inserted into the " +
  320. "Matrix\n" + this + " as a row vector");
  321. }
  322. if(rowIndex < 1 || rowIndex > this.getRows()+1){
  323. throw new InvalidOperationException(
  324. rowIndex + " is not a valid row index for inserting "+ vector +
  325. " into\n" + this);
  326. }
  327. Matrix tmp = new Matrix(this.getRows()+1, this.getCols());
  328. int rowOffset = 0;
  329. for(int row = 1; row <= tmp.getRows(); row++){
  330. if(row == rowIndex){
  331. tmp.setRow(row, vector);
  332. rowOffset = 1;
  333. }else{
  334. tmp.setRow(row, this.getRow(row - rowOffset));
  335. }
  336. }
  337. return tmp;
  338. }
  339. /**
  340. * Returns a String representation of this Matrix.
  341. *
  342. * @return String representation
  343. */
  344. public String toString(){
  345. String tempString = "";
  346. for(int i=1; i<numOfRows; i++){
  347. tempString += getRow(i).toString()+"\n";
  348. }
  349. return tempString + getRow(this.getRows()).toString();
  350. }
  351. /**
  352. * Returns the matrix that is the sum of this Matrix and another matrix.
  353. *
  354. * @param anotherMatrix
  355. * @return this + anotherMatrix
  356. * @throws InvalidOperationException if matrices differ in size
  357. */
  358. public Matrix add(Matrix matrix) throws InvalidOperationException {
  359. return operate(this, matrix, new AddOperator(), "sum");
  360. }
  361. /**
  362. * Returns the matrix that is the sum of this Matrix and a scalar.
  363. *
  364. * @param scalar
  365. * @return this + scalar
  366. */
  367. public Matrix add(FieldElement scalar) {
  368. return operate(this, scalar, new AddOperator());
  369. }
  370. /**
  371. * Returns the matrix that is this this Matrix minus another one.
  372. *
  373. * @param anotherMatrix
  374. * @return this - anotherMatrix
  375. * @throws InvalidOperationException if matrices differ in size
  376. */
  377. public Matrix subtract(Matrix matrix) throws InvalidOperationException {
  378. return operate(this, matrix, new SubtractOperator(), "diff");
  379. }
  380. /**
  381. * Returns the matrix that is this this Matrix minus a scalar.
  382. *
  383. * @param scalar
  384. * @return this - scalar
  385. */
  386. public Matrix subtract(FieldElement scalar) {
  387. return operate(this, scalar, new SubtractOperator());
  388. }
  389. /**
  390. * Returns a Matrix that is this Matrix multiplied with a scalar.
  391. *
  392. * @param scalar
  393. * @return multiplied Matrix
  394. */
  395. public Matrix multiply(FieldElement scalar){
  396. return operate(this, scalar, new MultiplyOperator());
  397. }
  398. /**
  399. * Returns a Matrix that is this Matrix divided by a scalar.
  400. *
  401. * @param scalar
  402. * @return divided Matrix
  403. */
  404. public Matrix divide(FieldElement scalar){
  405. return operate(this, scalar, new DivideOperator());
  406. }
  407. /**
  408. * Returns the vector that is the product of this Matrix and a given
  409. * vector.
  410. *
  411. * @param vector
  412. * @return product vector
  413. * @throws InvalidOperationException if number of columns of this matrix
  414. * does not equal number of elements of vector
  415. */
  416. public Vector multiply(Vector vector) throws InvalidOperationException{
  417. if(this.numOfCols != vector.length()) {
  418. String err = "Tried to multiply \n" + this + " and \n" + vector +
  419. "Not correct format!";
  420. throw new InvalidOperationException(err);
  421. }
  422. Vector resultVector = new Vector(this.numOfRows);
  423. for(int i=1; i <= numOfRows; i++){
  424. resultVector.setEntry(i, this.getRow(i).multiply(vector));
  425. }
  426. return resultVector;
  427. }
  428. /**
  429. * Returns the matrix that is the product of this Matrix and
  430. * another matrix.
  431. *
  432. * @param anotherMatrix
  433. * @return product matrix
  434. * @throws InvalidOperationException if number of columns of this matrix
  435. * does not equal number of rows of the other matrix
  436. */
  437. public Matrix multiply(Matrix anotherMatrix)
  438. throws InvalidOperationException {
  439. if(numOfCols != anotherMatrix.getRows()){
  440. throw new InvalidOperationException(
  441. "Tried to multiply \n" + this + " and \n" + anotherMatrix +
  442. "Not correct format!");
  443. }
  444. int resultRows = anotherMatrix.getCols();
  445. int resultCols = this.numOfRows;
  446. Matrix resultMatrix = new Matrix(resultRows, resultCols);
  447. for(int i=1; i <= resultRows; i++){
  448. for(int j=1; j <= resultCols; j++){
  449. resultMatrix.setEntry(i, j,
  450. this.getRow(i).multiply(anotherMatrix.getCol(j)));
  451. }
  452. }
  453. return resultMatrix;
  454. }
  455. /**
  456. * Returns a deep copy of this Matrix.
  457. *
  458. * @return matrix copy
  459. */
  460. public Matrix copy(){
  461. Matrix tmp = new Matrix(this.getRows(), this.getCols());
  462. for(int row = 1; row <= this.getRows(); row++){
  463. for(int col = 1; col <= this.getCols(); col++){
  464. tmp.setEntry(row, col, this.getEntry(row, col));
  465. }
  466. }
  467. return tmp;
  468. }
  469. /**
  470. * Returns the determinant of this Matrix.
  471. *
  472. * @return determinant
  473. * @throws InvalidOperationException if matrix is not square
  474. */
  475. public FieldElement det() throws InvalidOperationException{
  476. if(this.getRows() != this.getCols()){
  477. throw new InvalidOperationException(
  478. "Sqare matrix needed for determinant");
  479. }
  480. return detCalc();
  481. }
  482. private FieldElement detCalc(){
  483. Matrix tmp = this.gausselim();
  484. FieldElement determinant = (tmp.getEntry(1,1).one());
  485. for(int row=1; row<= tmp.getRows(); row++){
  486. determinant = determinant.multiply(tmp.getEntry(row, row));
  487. }
  488. return determinant;
  489. }
  490. /**
  491. * Swaps two rows of this Matrix.
  492. *
  493. * @param rowIndex1 index of first swap partner.
  494. * @param rowIndex2 index of second swap partner.
  495. */
  496. public void swapRows(int rowIndex1, int rowIndex2){
  497. Vector tmp = this.getRow(rowIndex1);
  498. this.setRow(rowIndex1, this.getRow(rowIndex2));
  499. this.setRow(rowIndex2, tmp);
  500. }
  501. /**
  502. * Swaps two columns of this Matrix.
  503. *
  504. * @param colIndex1 index of first swap partner.
  505. * @param colIndex2 index of second swap partner.
  506. */
  507. public void swapCols(int colIndex1, int colIndex2){
  508. Vector tmp = this.getCol(colIndex1);
  509. this.setCol(colIndex1, this.getCol(colIndex2));
  510. this.setCol(colIndex2, tmp);
  511. }
  512. /**
  513. * Returns a matrix that is this Matrix with the Gauss-Jordan
  514. * algorithm executed on. In other words: It returns the reduced
  515. * row echelon form of this Matrix.
  516. *
  517. * @return matrix in reduced row-echelon form
  518. */
  519. public Matrix gaussjord(){
  520. Matrix tmp = this.copy();
  521. int minOfRowsCols = Math.min(tmp.getRows(), tmp.getCols());
  522. int colCounter = 0;
  523. int row = 0;
  524. while(row < minOfRowsCols && colCounter < tmp.getCols()){
  525. row++;
  526. colCounter++;
  527. FieldElement diagonalEntry = tmp.getEntry(row, colCounter);
  528. if(diagonalEntry.isZero()){
  529. //search for non zero entry
  530. boolean found = false;
  531. for(int candidate = row + 1;
  532. candidate <= tmp.getRows();
  533. candidate++){
  534. if(!tmp.getEntry(candidate, colCounter).isZero()){
  535. tmp.swapRows(row, candidate);
  536. found = true;
  537. break;
  538. }
  539. }
  540. if(!found){
  541. if(colCounter == tmp.getCols()){
  542. return tmp;
  543. }
  544. row--;
  545. continue;
  546. }else{
  547. diagonalEntry = tmp.getEntry(row, colCounter);
  548. }
  549. }
  550. for(int j = colCounter; j <= tmp.getCols(); j++){
  551. FieldElement oldEntry = tmp.getEntry(row, j);
  552. tmp.setEntry(row, j, oldEntry.divide(diagonalEntry));
  553. }
  554. for(int j = 1; j <= tmp.getRows(); j++){
  555. FieldElement factor = tmp.getEntry(j, colCounter);
  556. if (row==j || factor.isZero()){
  557. continue;
  558. }
  559. for(int k = colCounter; k <= tmp.getCols(); k++){
  560. FieldElement oldEntry = tmp.getEntry(j, k);
  561. tmp.setEntry(j, k,
  562. oldEntry.subtract(tmp.getEntry(row, k).multiply(factor)));
  563. }
  564. }
  565. }
  566. return tmp;
  567. }
  568. /**
  569. * Returns a matrix that is this Matrix with Gauss-elimination executed on.
  570. * In other words: It returns a row echelon form of this Matrix.
  571. *
  572. * @return matrix in row-echelon form
  573. */
  574. public Matrix gausselim(){
  575. Matrix tmp = this.copy();
  576. int minOfRowsCols = Math.min(tmp.getRows(), tmp.getCols());
  577. int colCounter = 0;
  578. int row = 0;
  579. while(row < minOfRowsCols && colCounter < tmp.getCols()){
  580. row++;
  581. colCounter++;
  582. FieldElement diagonalEntry = tmp.getEntry(row, colCounter);
  583. if(diagonalEntry.isZero()){
  584. //search for non zero entry
  585. boolean found = false;
  586. for(int candidate = row + 1;
  587. candidate <= tmp.getRows();
  588. candidate++){
  589. if(!tmp.getEntry(candidate, colCounter).isZero()){
  590. tmp.swapRows(row, candidate);
  591. found = true;
  592. break;
  593. }
  594. }
  595. if(!found){
  596. if(colCounter == tmp.getCols()){
  597. return tmp;
  598. }
  599. row--;
  600. continue;
  601. }else{
  602. diagonalEntry = tmp.getEntry(row, colCounter);
  603. }
  604. }
  605. for(int j = row; j <= tmp.getRows(); j++){
  606. FieldElement factor =
  607. tmp.getEntry(j, colCounter).divide(diagonalEntry);
  608. if (row==j || factor.isZero()){
  609. continue;
  610. }
  611. for(int k = colCounter; k <= tmp.getCols(); k++){
  612. FieldElement oldEntry = tmp.getEntry(j, k);
  613. tmp.setEntry(j, k,
  614. oldEntry.subtract(factor.multiply(tmp.getEntry(row, k))));
  615. }
  616. }
  617. }
  618. return tmp;
  619. }
  620. /**
  621. * Returns whether the row at the specified row index is a zero row or
  622. * not.
  623. *
  624. * @param rowIndex index of the row to be tested
  625. * @return true if there are only zero elements in the row.
  626. */
  627. public boolean isZeroRow(int rowIndex){
  628. for(int col = 1; col <= this.getCols(); col++){
  629. if(!this.getEntry(rowIndex, col).isZero()){
  630. return false;
  631. }
  632. }
  633. return true;
  634. }
  635. /**
  636. * Returns whether the column at the specified column index is a
  637. * zero column or not.
  638. *
  639. * @param colIndex of the column to be tested
  640. * @return true if there are only zero elements in the column.
  641. */
  642. public boolean isZeroCol(int colIndex){
  643. for(int row = 1; row <= this.getRows(); row++){
  644. if(!this.getEntry(row, colIndex).isZero()){
  645. return false;
  646. }
  647. }
  648. return true;
  649. }
  650. /**
  651. * Returns the rank of this Matrix.
  652. *
  653. * @return rank
  654. */
  655. public int rank(){
  656. Matrix tmp = this.gausselim();
  657. int numberOfZeroRows = 0;
  658. int row = tmp.getRows();
  659. while(tmp.isZeroRow(row) && row > 0){
  660. numberOfZeroRows++;
  661. row--;
  662. }
  663. return tmp.getRows() - numberOfZeroRows;
  664. }
  665. /**
  666. * Returns a matrix that is this Matrix transposed.
  667. *
  668. * @return transposed matrix
  669. */
  670. public Matrix transpose(){
  671. Matrix tmp = new Matrix(this.getCols(), this.getRows());
  672. for(int row = 1; row <= this.getRows(); row++){
  673. for(int col = 1; col <= this.getCols(); col++){
  674. tmp.setEntry(col, row, this.getEntry(row, col));
  675. }
  676. }
  677. return tmp;
  678. }
  679. /**
  680. * Returns a matrix that is this Matrix hermitianly transposed.
  681. * For almost all matrices this method is equivalent to transpose.
  682. * But in case of complex number entries the matrix will be
  683. * transposed and all entries will be conjugated as well.
  684. *
  685. * @return hermitianly transposed matrix
  686. */
  687. public Matrix hermitian(){
  688. Matrix tmp = new Matrix(this.getCols(), this.getRows());
  689. for(int row = 1; row <= this.getRows(); row++){
  690. for(int col = 1; col <= this.getCols(); col++){
  691. FieldElement test = this.getEntry(row, col);
  692. if(test instanceof Complex){
  693. Complex el = (Complex)test;
  694. tmp.setEntry(col, row, el.conjugate());
  695. }else{
  696. tmp.setEntry(col, row, test);
  697. }
  698. }
  699. }
  700. return tmp;
  701. }
  702. /**
  703. * Tests two matrices for equality.
  704. *
  705. * @return true if and only if the two matrices equal in all entries.
  706. * @param anotherMatrix
  707. */
  708. public boolean equals(Matrix anotherMatrix){
  709. if(this.getRows() == anotherMatrix.getRows() &&
  710. this.getCols() == anotherMatrix.getCols()){
  711. for(int row = 1; row <= this.getRows(); row++){
  712. for(int col = 1; col <= this.getCols(); col++){
  713. if(!this.getEntry(row, col).equals(
  714. anotherMatrix.getEntry(row, col))){
  715. return false;
  716. }
  717. }
  718. }
  719. }else{
  720. return false;
  721. }
  722. return true;
  723. }
  724. /**
  725. * Returns the inverse of this Matrix.
  726. *
  727. * @return inverse Matrix
  728. */
  729. public Matrix inverse(){
  730. if(this.getRows() != this.getCols()){
  731. return null;
  732. }
  733. Matrix tmp = this.copy();
  734. FieldElement zero = tmp.getEntry(1,1).zero();
  735. FieldElement one = zero.one();
  736. FieldElement[][] entries2 =
  737. new FieldElement[tmp.getRows()][tmp.getCols()];
  738. for(int i=0; i < tmp.getRows(); i++){
  739. for(int j=0; j < tmp.getCols(); j++){
  740. if(i==j){
  741. entries2[i][j] = one;
  742. }else{
  743. entries2[i][j] = zero;
  744. }
  745. }
  746. }
  747. Matrix tmp2 = new Matrix(entries2);
  748. int minOfRowsCols = Math.min(tmp.getRows(), tmp.getCols());
  749. int colCounter = 0;
  750. int row = 0;
  751. while(row < minOfRowsCols && colCounter < tmp.getCols()){
  752. row++;
  753. colCounter++;
  754. FieldElement diagonalEntry = tmp.getEntry(row, colCounter);
  755. if(diagonalEntry.isZero()){
  756. //search for non zero entry
  757. boolean found = false;
  758. for(int candidate = row + 1;
  759. candidate <= tmp.getRows();
  760. candidate++){
  761. if(!tmp.getEntry(candidate, colCounter).isZero()){
  762. tmp.swapRows(row, candidate);
  763. tmp2.swapRows(row, candidate);
  764. found = true;
  765. break;
  766. }
  767. }
  768. if(!found){
  769. if(colCounter == tmp.getCols()){
  770. return null; // Because there is no inverse of this.
  771. }
  772. row--;
  773. continue;
  774. }else{
  775. diagonalEntry = tmp.getEntry(row, colCounter);
  776. }
  777. }
  778. for(int j = 1; j <= tmp.getCols(); j++){
  779. FieldElement oldEntry = tmp.getEntry(row, j);
  780. FieldElement oldEntry2 = tmp2.getEntry(row, j);
  781. tmp.setEntry(row, j, oldEntry.divide(diagonalEntry));
  782. tmp2.setEntry(row, j, oldEntry2.divide(diagonalEntry));
  783. }
  784. for(int j = 1; j <= tmp.getRows(); j++){
  785. FieldElement factor = tmp.getEntry(j, colCounter);
  786. if (row==j || factor.isZero()){
  787. continue;
  788. }
  789. for(int k = 1; k <= tmp.getCols(); k++){
  790. FieldElement oldEntry = tmp.getEntry(j, k);
  791. FieldElement oldEntry2 = tmp2.getEntry(j, k);
  792. tmp.setEntry(j, k,
  793. oldEntry.subtract(tmp.getEntry(row, k).multiply(factor)));
  794. tmp2.setEntry(j, k,
  795. oldEntry2.subtract(tmp2.getEntry(row,
  796. k).multiply(factor)));
  797. }
  798. }
  799. }
  800. return tmp2;
  801. }
  802. /**
  803. * Divides this Matrix by a scalar.
  804. *
  805. * @param scalar
  806. */
  807. public void divideReplace(FieldElement scalar) {
  808. operate(scalar, new DivideOperator());
  809. }
  810. /**
  811. * Divides this Matrix by another.
  812. * @param another Matrix
  813. * @throws InvalidOperationException if the matrices have different sizes
  814. */
  815. public void divideReplace(Matrix anotherMatrix)
  816. throws InvalidOperationException {
  817. operate(anotherMatrix, new DivideOperator(), "divide");
  818. }
  819. /**
  820. * Multiplies this Matrix by a scalar.
  821. *
  822. * @param scalar
  823. */
  824. public void multiplyReplace(FieldElement scalar){
  825. operate(scalar, new MultiplyOperator());
  826. }
  827. /**
  828. * Multiplies this Matrix element-wise by another.
  829. * @param another Matrix
  830. * @throws InvalidOperationException if the matrices have different sizes
  831. */
  832. public void multiplyReplace(Matrix anotherMatrix)
  833. throws InvalidOperationException {
  834. operate(anotherMatrix, new MultiplyOperator(), "multiply");
  835. }
  836. /**
  837. * Adds a scalar to this Matrix.
  838. *
  839. * @param scalar
  840. */
  841. public void addReplace(FieldElement scalar){
  842. operate(scalar, new AddOperator());
  843. }
  844. /**
  845. * Adds another matrix to this Matrix.
  846. * @param another Matrix
  847. * @throws InvalidOperationException if the matrices have different sizes
  848. */
  849. public void addReplace(Matrix anotherMatrix){
  850. operate(anotherMatrix, new AddOperator(), "add");
  851. }
  852. /**
  853. * Subtracts a scalar from this Matrix.
  854. *
  855. * @param scalar
  856. */
  857. public void subtractReplace(FieldElement scalar){
  858. operate(scalar, new SubtractOperator());
  859. }
  860. /**
  861. * Subtracts another Matrix from this.
  862. * @param another Matrix
  863. * @throws InvalidOperationException if the matrices have different sizes
  864. */
  865. public void subtractReplace(Matrix anotherMatrix){
  866. operate(anotherMatrix, new SubtractOperator(), "subtract");
  867. }
  868. /**
  869. * Returns the logical AND of this Matrix with another. Elements of the
  870. * result are 1 where both matrices are non-zero, and zero elsewhere.
  871. * @param anotherMatrix
  872. * @return Matrix of 1's and 0's
  873. * @throws InvalidOperationException if the matrices have different sizes
  874. */
  875. public Matrix and(Matrix anotherMatrix) {
  876. return operate(this, anotherMatrix, new AndOperator(), "AND");
  877. }
  878. /**
  879. * Returns the logical OR of this Matrix with another. Elements of the
  880. * result are 1 where both matrices are non-zero, and zero elsewhere.
  881. * @param anotherMatrix
  882. * @return Matrix of 1's and 0's
  883. * @throws InvalidOperationException if the matrices have different sizes
  884. */
  885. public Matrix or(Matrix anotherMatrix) {
  886. return operate(this, anotherMatrix, new OrOperator(), "OR");
  887. }
  888. /**
  889. * Returns the logical negation of this Matrix. Elements of the
  890. * result are 1 where the matrix is zero, and one elsewhere.
  891. * @return Matrix of 1's and 0's
  892. */
  893. public Matrix not() {
  894. return this.apply(new NotOperator());
  895. }
  896. /**
  897. * Returns a Matrix containing ones where this Matrix's elements are less
  898. * than those of another Matrices, and zeros elsewhere.
  899. *
  900. * @param anotherMatrix
  901. * @return Matrix of ones and zeros
  902. * @throws InvalidOperationException if the matrices have different sizes
  903. */
  904. public Matrix lt(Matrix anotherMatrix) {
  905. return comparison(anotherMatrix, new LessThanComparator(), "LT");
  906. }
  907. /**
  908. * Returns a Matrix containing ones where this Matrix's elements are less
  909. * than a scalar, and zeros elsewhere.
  910. *
  911. * @param scalar
  912. * @return Matrix of ones and zeros
  913. */
  914. public Matrix lt(FieldElement scalar) {
  915. return comparison(scalar, new LessThanComparator());
  916. }
  917. /**
  918. * Returns a Matrix containing ones where this Matrix's elements are less
  919. * than or equal to those of another Matrices, and zeros elsewhere.
  920. *
  921. * @param anotherMatrix
  922. * @return Matrix of ones and zeros
  923. * @throws InvalidOperationException if the matrices have different sizes
  924. */
  925. public Matrix le(Matrix anotherMatrix) {
  926. return comparison(anotherMatrix, new LessThanOrEqualToComparator(),
  927. "LE");
  928. }
  929. /**
  930. * Returns a Matrix containing ones where this Matrix's elements are less
  931. * than or equal to a scalar, and zeros elsewhere.
  932. *
  933. * @param scalar
  934. * @return Matrix of ones and zeros
  935. */
  936. public Matrix le(FieldElement scalar) {
  937. return comparison(scalar, new LessThanOrEqualToComparator());
  938. }
  939. /**
  940. * Returns a Matrix containing ones where this Matrix's elements
  941. * are greater than those of another Matrices, and zeros elsewhere.
  942. *
  943. * @param anotherMatrix
  944. * @return Matrix of ones and zeros
  945. * @throws InvalidOperationException if the matrices have different sizes
  946. */
  947. public Matrix gt(Matrix anotherMatrix) {
  948. return comparison(anotherMatrix, new GreaterThanComparator(),
  949. "GT");
  950. }
  951. /**
  952. * Returns a Matrix containing ones where this Matrix's elements are
  953. * greater than a scalar, and zeros elsewhere.
  954. *
  955. * @param scalar
  956. * @return Matrix of ones and zeros
  957. */
  958. public Matrix gt(FieldElement scalar) {
  959. return comparison(scalar, new GreaterThanComparator());
  960. }
  961. /**
  962. * Returns a Matrix containing ones where this Matrix's elements
  963. * are greater than or equal to those of another Matrices, and
  964. * zeros elsewhere.
  965. *
  966. * @param anotherMatrix
  967. * @return Matrix of ones and zeros
  968. * @throws InvalidOperationException if the matrices have different sizes
  969. */
  970. public Matrix ge(Matrix anotherMatrix) {
  971. return comparison(anotherMatrix, new GreaterThanOrEqualToComparator(),
  972. "GE");
  973. }
  974. /**
  975. * Returns a Matrix containing ones where this Matrix's elements are
  976. * greater than or equal to a scalar, and zeros elsewhere.
  977. *
  978. * @param scalar
  979. * @return Matrix of ones and zeros
  980. */
  981. public Matrix ge(FieldElement scalar) {
  982. return comparison(scalar, new GreaterThanOrEqualToComparator());
  983. }
  984. /**
  985. * Returns a Matrix containing ones where this Matrix's elements
  986. * are equal to those of another Matrices, and zeros elsewhere.
  987. *
  988. * @param anotherMatrix
  989. * @return Matrix of ones and zeros
  990. * @throws InvalidOperationException if the matrices have different sizes
  991. */
  992. public Matrix eq(Matrix anotherMatrix) {
  993. return comparison(anotherMatrix, new EqualToComparator(), "EQ");
  994. }
  995. /**
  996. * Returns a Matrix containing ones where this Matrix's elements
  997. * are equal to a scalar, and zeros elsewhere.
  998. *
  999. * @param scalar
  1000. * @return Matrix of ones and zeros
  1001. */
  1002. public Matrix eq(FieldElement scalar) {
  1003. return comparison(scalar, new EqualToComparator());
  1004. }
  1005. /**
  1006. * Returns a Matrix containing ones where this Matrix's elements
  1007. * are not equal to those of another Matrices, and zeros elsewhere.
  1008. *
  1009. * @param anotherMatrix
  1010. * @return Matrix of ones and zeros
  1011. * @throws InvalidOperationException if the matrices have different sizes
  1012. */
  1013. public Matrix ne(Matrix anotherMatrix) {
  1014. return comparison(anotherMatrix, new NotEqualToComparator(), "NE");
  1015. }
  1016. /**
  1017. * Returns a Matrix containing ones where this Matrix's elements
  1018. * are not equal to a scalar, and zeros elsewhere.
  1019. *
  1020. * @param scalar
  1021. * @return Matrix of ones and zeros
  1022. */
  1023. public Matrix ne(FieldElement scalar) {
  1024. return comparison(scalar, new NotEqualToComparator());
  1025. }
  1026. /**
  1027. * Sets this Matrix to the result of applying a specified function
  1028. * to every element of this Matrix. New functions can be applied
  1029. * to a Matrix by subclassing the abstract <tt>MonadicOperator</tt>
  1030. * class.
  1031. * @param fun the function to apply
  1032. * @return result of applying <tt>fun</tt> to this Matrix
  1033. */
  1034. public void applyReplace(MonadicOperator fun) {
  1035. for(int i=1; i <= this.getRows(); i++){
  1036. for(int j=1; j <= this.getCols(); j++) {
  1037. this.setEntry(i, j, fun.apply(this.getEntry(i, j)));
  1038. }
  1039. }
  1040. }
  1041. /**
  1042. * Returns the result of applying a specified function to every
  1043. * element of this Matrix. New functions can be applied to a Matrix
  1044. * by subclassing the abstract <tt>MonadicOperator</tt> class.
  1045. * @param matrix the matrix to apply the function to
  1046. * @param fun the function to apply
  1047. * @return result of applying <tt>fun</tt> to this Matrix
  1048. */
  1049. public Matrix apply(MonadicOperator fun) {
  1050. Matrix matrix = new Matrix(this.getRows(), this.getCols());
  1051. for(int i=1; i <= matrix.getRows(); i++){
  1052. for(int j=1; j <= this.getCols(); j++) {
  1053. matrix.setEntry(i, j, fun.apply(this.getEntry(i, j)));
  1054. }
  1055. }
  1056. return matrix;
  1057. }
  1058. /**
  1059. * Sets this Matrix to the result of applying a specified function
  1060. * to elements of this Matrix and another's. New functions can be applied
  1061. * to a Matrix by subclassing the abstract <tt>DyadicOperator</tt>
  1062. * class.
  1063. * @param anotherMatrix
  1064. * @param fun the function to apply
  1065. * @return result of applying <tt>fun</tt> to the two Matrices
  1066. */
  1067. public void applyReplace(Matrix anotherMatrix, DyadicOperator fun) {
  1068. check_sizes(this, anotherMatrix, fun.getClass().getName());
  1069. for(int i=1; i <= this.getRows(); i++){
  1070. for(int j=1; j <= this.getCols(); j++) {
  1071. this.setEntry(i, j, fun.apply(this.getEntry(i, j),
  1072. anotherMatrix.getEntry(i, j)));
  1073. }
  1074. }
  1075. }
  1076. /**
  1077. * Returns the result of applying a specified function to the
  1078. * elements of this Matrix and another. New functions can be
  1079. * applied to a Matrix by subclassing the abstract
  1080. * <tt>DyadicOperator</tt> class.
  1081. * @param anotherMatrix
  1082. * @param fun the function to apply
  1083. * @return result of applying <tt>fun</tt> to the two Matrices
  1084. */
  1085. public Matrix apply(Matrix anotherMatrix, DyadicOperator fun) {
  1086. check_sizes(this, anotherMatrix, fun.getClass().getName());
  1087. Matrix matrix = new Matrix(this.getRows(), this.getCols());
  1088. for(int i=1; i <= matrix.getRows(); i++){
  1089. for(int j=1; j <= this.getCols(); j++) {
  1090. matrix.setEntry(i, j, fun.apply(this.getEntry(i, j),
  1091. anotherMatrix.getEntry(i, j)));
  1092. }
  1093. }
  1094. return matrix;
  1095. }
  1096. /**
  1097. * Sets this Matrix to the result of applying a specified function
  1098. * to elements of this Matrix and a scalar. New functions can be applied
  1099. * to a Matrix by subclassing the abstract <tt>DyadicOperator</tt>
  1100. * class.
  1101. * @param scalar
  1102. * @param fun the function to apply
  1103. * @return result of applying <tt>fun</tt> to this Matrix and the scalar
  1104. */
  1105. public void applyReplace(FieldElement scalar, DyadicOperator fun) {
  1106. for(int i=1; i <= this.getRows(); i++){
  1107. for(int j=1; j <= this.getCols(); j++) {
  1108. this.setEntry(i, j, fun.apply(this.getEntry(i, j), scalar));
  1109. }
  1110. }
  1111. }
  1112. /**
  1113. * Returns the result of applying a specified function to the
  1114. * elements of a this Matrix a scalar. New functions can be
  1115. * applied to a Matrix by subclassing the abstract
  1116. * <tt>DyadicOperator</tt> class.
  1117. * @param scalar
  1118. * @param fun the function to apply
  1119. * @return result of applying <tt>fun</tt> to the Matrix and scalar
  1120. */
  1121. public Matrix apply(FieldElement scalar, DyadicOperator fun) {
  1122. Matrix matrix = new Matrix(this.getRows(), this.getCols());
  1123. for(int i=1; i <= matrix.getRows(); i++){
  1124. for(int j=1; j <= this.getCols(); j++) {
  1125. matrix.setEntry(i, j, fun.apply(this.getEntry(i, j), scalar));
  1126. }
  1127. }
  1128. return matrix;
  1129. }
  1130. /**
  1131. * Returns the element-wise product of this Matrix and another.
  1132. *
  1133. * @param anotherMatrix
  1134. * @return this .* anotherMatrix
  1135. * @throws InvalidOperationException if the matrices have different sizes
  1136. */
  1137. public Matrix arrayMultiply(Matrix anotherMatrix)
  1138. throws InvalidOperationException {
  1139. return operate(this, anotherMatrix, new MultiplyOperator(),
  1140. "arrayMultiply");
  1141. }
  1142. /**
  1143. * Sets all entries to a FieldElement.
  1144. *
  1145. * @param newEntry the FieldElement
  1146. */
  1147. public void setAll(FieldElement newEntry) {
  1148. for (int i=1; i<=this.getRows(); ++i) {
  1149. for (int j=1; j<=this.getCols(); ++j) {
  1150. this.setEntry(i, j, newEntry);
  1151. }
  1152. }
  1153. }
  1154. /**
  1155. * Computes the sum over all elements of this Matrix.
  1156. * @return the sum
  1157. */
  1158. public FieldElement sum() {
  1159. return reduce(new SumReduction());
  1160. }
  1161. /**
  1162. * Computes the mean over all elements of this Matrix.
  1163. * @return the mean
  1164. */
  1165. public FieldElement mean() {
  1166. return sum().divide(instance(getRows() * getCols()));
  1167. }
  1168. /**
  1169. * Computes the smallest value of any element in this Matrix.
  1170. * @return the smallest value
  1171. */
  1172. public FieldElement min() {
  1173. return reduce(new MinReduction());
  1174. }
  1175. /**
  1176. * Computes the largest value of any element in this Matrix.
  1177. * @return the largest value
  1178. */
  1179. public FieldElement max() {
  1180. return reduce(new MaxReduction());
  1181. }
  1182. /**
  1183. * Computes the sum over the rows of this matrix.
  1184. * @return the sum
  1185. */
  1186. public Vector sumRows() {
  1187. Vector sum = getRow(1);
  1188. for (int i=2; i<=getRows(); ++i) {
  1189. sum.addReplace(getRow(i));
  1190. }
  1191. return sum;
  1192. }
  1193. /**
  1194. * Computes the sum over the columns of this matrix.
  1195. * @return the sum
  1196. */
  1197. public Vector sumCols() {
  1198. return this.transpose().sumRows();
  1199. }
  1200. /**
  1201. * Computes the mean over the rows of this Matrix.
  1202. * @return the mean
  1203. */
  1204. public Vector meanRows() {
  1205. return this.sumRows().divide(instance(this.getRows()));
  1206. }
  1207. /**
  1208. * Computes the mean over the columns of this Matrix.
  1209. * @return the mean
  1210. */
  1211. public Vector meanCols() {
  1212. return this.sumCols().divide(instance(this.getCols()));
  1213. }
  1214. /**
  1215. * Returns a new 1xN Vector made from the N elements of this
  1216. * Matrix. Matrix should have 1 row.
  1217. *
  1218. * @return the Matrix
  1219. * @throws InvalidOperationException if number of rows not equal to one
  1220. */
  1221. public Vector toVector() throws InvalidOperationException {
  1222. if (getRows() != 1) {
  1223. String err = "Cannot convert multi-row Matrix to Vector";
  1224. throw new InvalidOperationException(err);
  1225. }
  1226. return getRow(1);
  1227. }
  1228. // return Matrix resulting from operation on two others
  1229. private static Matrix operate(Matrix matrix1, Matrix matrix2,
  1230. DyadicOperator fun, String funName) {
  1231. check_sizes(matrix1, matrix2, funName);
  1232. Matrix matrix3 = new Matrix(matrix1.numOfRows, matrix1.numOfCols);
  1233. for(int i=1; i <= matrix3.getRows(); i++){
  1234. for(int j=1; j <= matrix3.getCols(); j++){
  1235. matrix3.setEntry(i, j,
  1236. fun.apply(matrix1.getEntry(i, j),
  1237. matrix2.getEntry(i, j)));
  1238. }
  1239. }
  1240. return matrix3;
  1241. }
  1242. // return Matrix resulting from operation on Matrix and scalar
  1243. private static Matrix operate(Matrix matrix, FieldElement scalar,
  1244. DyadicOperator fun) {
  1245. Matrix matrix2 = matrix.copy();
  1246. for (int i=1; i<=matrix.getRows(); ++i) {
  1247. for (int j=1; j<=matrix.getCols(); ++j) {
  1248. matrix2.setEntry(i, j, fun.apply(matrix.getEntry(i, j),
  1249. scalar));
  1250. }
  1251. }
  1252. return matrix2;
  1253. }
  1254. // set elements of this Matrix to result of operation on them and another's
  1255. private void operate(Matrix matrix, DyadicOperator fun, String funName) {
  1256. check_sizes(this, matrix, funName);
  1257. for (int i=1; i<=this.getRows(); ++i) {
  1258. for (int j=1; j<=this.getCols(); ++j) {
  1259. this.setEntry(i, j, fun.apply(this.getEntry(i, j),
  1260. matrix.getEntry(i, j)));
  1261. }
  1262. }
  1263. }
  1264. // set elements of this Matrix to result of operation on them and a scalar
  1265. private void operate(FieldElement scalar, DyadicOperator fun) {
  1266. for (int i=1; i<=this.getRows(); ++i) {
  1267. for (int j=1; j<=this.getCols(); ++j) {
  1268. this.setEntry(i, j, fun.apply(this.getEntry(i, j), scalar));
  1269. }
  1270. }
  1271. }
  1272. // return the result of comparing this Matrix with another (ones where
  1273. // comparison succeeds, zeros where it fails)
  1274. private Matrix comparison(Matrix anotherMatrix, FEComparator comp,
  1275. String compName) {
  1276. check_sizes(this, anotherMatrix, compName);
  1277. Matrix a = new Matrix(this.getRows(), this.getCols());
  1278. for (int i=1; i<=this.getRows(); ++i) {
  1279. for (int j=1; j<=this.getCols(); ++j) {
  1280. FieldElement entry = this.getEntry(i, j);
  1281. boolean success = comp.compare(entry,
  1282. anotherMatrix.getEntry(i, j));
  1283. FieldElement result = success ? entry.one() : entry.zero();
  1284. a.setEntry(i, j, result);
  1285. }
  1286. }
  1287. return a;
  1288. }
  1289. // return the result of comparing this Matrix with a scalar (ones where
  1290. // comparison succeeds, zeros where it fails)
  1291. private Matrix comparison(FieldElement scalar, FEComparator comp) {
  1292. Matrix a = new Matrix(this.getRows(), this.getCols());
  1293. for (int i=1; i<=this.getRows(); ++i) {
  1294. for (int j=1; j<=this.getCols(); ++j) {
  1295. FieldElement entry = this.getEntry(i, j);
  1296. boolean success = comp.compare(entry, scalar);
  1297. FieldElement result = success ? entry.one() : entry.zero();
  1298. a.setEntry(i, j, result);
  1299. }
  1300. }
  1301. return a;
  1302. }
  1303. // general size checking for two-matrix operations
  1304. private static void check_sizes(Matrix a, Matrix b, String op)
  1305. throws InvalidOperationException {
  1306. if (a.numOfRows != b.getRows() || a.numOfCols != b.getCols()){
  1307. throw new InvalidOperationException(
  1308. "Tried " + op + "on \n"+ a +"\n and \n"+ b +
  1309. "Not correct format!");
  1310. }
  1311. }
  1312. // generic method for sum, min, max
  1313. private FieldElement reduce(Reduction r) {
  1314. r.init(this.getEntry(1, 1));
  1315. for (int i=1; i<=this.getRows(); i++) {
  1316. for (int j=1; j<=this.getCols(); j++) {
  1317. if (i != 1 || j!= 1) {
  1318. r.track(this.getEntry(i, j));
  1319. }
  1320. }
  1321. }
  1322. return r.reducedValue;
  1323. }
  1324. // return an instance of a value from this matrix
  1325. private FieldElement instance(double n) {
  1326. FieldElement first = this.getEntry(1,1);
  1327. return first.instance(n);
  1328. }
  1329. } // end of the class .........................................