Javasci: In sparse matrix, add a parameter to constructor to give the ability to...
[scilab.git] / scilab / modules / types / src / java / org / scilab / modules / types / ScilabSparse.java
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011-2011 - DIGITEO - Calixte DENIZET
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.types;
14
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.List;
18
19 /**
20  * This class provides a representation on the Scilab Sparse datatype<br>
21  * <br>
22  * This class is {@link java.io.Serializable} and any modification could
23  * impact load and store of data (Xcos files, Javasci saved data, etc...).<br>
24  * <br>
25  * //TODO Sly : ajouter de la doc
26  * @see org.scilab.modules.javasci.Scilab
27  */
28 public class ScilabSparse implements ScilabType {
29
30     private static final long serialVersionUID = 879625048944109684L;
31     private static final ScilabTypeEnum type = ScilabTypeEnum.sci_sparse;
32
33     private int rows;
34     private int cols;
35     private int nbItem;
36     private int[] nbItemRow;
37     private int[] colPos;
38     private double[] realPart;
39     private double[] imaginaryPart;
40     private String varName;
41
42     /**
43      * Default constructor
44      */
45     public ScilabSparse() { }
46
47     /**
48      * Constructor with a unique value.
49      * @param data the unique value
50      */
51     public ScilabSparse(double data) {
52         if (data != 0) {
53             nbItem = 1;
54             rows = cols = 1;
55             nbItemRow = new int[]{1};
56             colPos = new int[]{0};
57             realPart = new double[]{ data };
58         }
59     }
60
61     /**
62      * Constructor with a unique complex value.
63      *
64      * @param realData the real part
65      * @param imagData the complex part
66      */
67     public ScilabSparse(double realData, double imagData) {
68         if (realData != 0 || imagData != 0) {
69             nbItem = 1;
70             rows = cols = 1;
71             nbItemRow = new int[]{1};
72             colPos = new int[]{0};
73             realPart = new double[]{ realData };
74             imaginaryPart = new double[]{ imagData };
75         }
76     }
77
78     /**
79      * Constructor
80      *
81      * @param rows the number of rows
82      * @param cols the number of cols
83      * @param nbItem the number of non null items
84      * @param nbItemRow contains the number of true in each rows
85      * @param colPos the column position of each non null item
86      * @param data the non null data
87      * @param check if true the parameters validity is checked
88      */
89     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] data, boolean check) throws ScilabSparseException {
90         this(rows, cols, nbItem, nbItemRow, colPos, data);
91         if (check) {
92             checkValidity(rows, cols, nbItem, nbItemRow, colPos);
93
94             if (realPart.length != nbItem) {
95                 throw new ScilabSparseException("Invalid length for the array realPart: its length must be equal to the number of non-null items.");
96             }
97         }
98     }
99
100     /**
101      * Constructor
102      *
103      * @param rows the number of rows
104      * @param cols the number of cols
105      * @param nbItem the number of non null items
106      * @param nbItemRow contains the number of true in each rows
107      * @param colPos the column position of each non null item
108      * @param real the non null real data
109      */
110     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real) {
111         this.rows = rows;
112         this.cols = cols;
113         this.nbItem = nbItem;
114         this.nbItemRow = nbItemRow;
115         this.colPos = colPos;
116         this.realPart = real;
117     }
118
119     /**
120      * Constructor
121      *
122      * @param rows the number of rows
123      * @param cols the number of cols
124      * @param nbItem the number of non null items
125      * @param nbItemRow contains the number of true in each rows
126      * @param colPos the column position of each non null item
127      * @param real the non null real data
128      * @param imag the non null imaginary data
129      * @param check if true the parameters validity is checked
130      */
131     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag, boolean check) throws ScilabSparseException {
132         this(rows, cols, nbItem, nbItemRow, colPos, real, imag);
133         if (check) {
134             checkValidity(rows, cols, nbItem, nbItemRow, colPos);
135
136             if (realPart.length != nbItem) {
137                 throw new ScilabSparseException("Invalid length for the array realPart: its length must be equal to the number of non-null items.");
138             }
139
140             if (imaginaryPart.length != nbItem) {
141                 throw new ScilabSparseException("Invalid length for the array imaginaryPart: its length must be equal to the number of non-null items.");
142             }
143         }
144     }
145
146     /**
147      * Constructor
148      *
149      * @param rows the number of rows
150      * @param cols the number of cols
151      * @param nbItem the number of non null items
152      * @param nbItemRow contains the number of true in each rows
153      * @param colPos the column position of each non null item
154      * @param real the non null real data
155      * @param imag the non null imaginary data
156      */
157     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
158         this(rows, cols, nbItem, nbItemRow, colPos, real);
159         this.imaginaryPart = imag;
160     }
161
162     /**
163      * Constructor
164      *
165      * @param rows the number of rows
166      * @param cols the number of cols
167      * @param nbItem the number of non null items
168      * @param nbItemRow contains the number of true in each rows
169      * @param colPos the column position of each non null item
170      */
171     static final void checkValidity(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos) throws ScilabSparseException {
172         if (nbItem > rows * cols || nbItem < 0) {
173             throw new ScilabSparseException("Invalid number of items: between 0 and " + rows * cols + " expected.");
174         }
175
176         if (nbItemRow.length > rows) {
177             throw new ScilabSparseException("Invalid length for the array nbItemRow: a length between 0 and " + rows + " expected.");
178         }
179
180         int s = 0;
181         for (int i = 0; i < nbItemRow.length; i++) {
182             if (nbItemRow[i] > cols) {
183                 throw new ScilabSparseException("Invalid number of non-null items in nbItemRow at position " + i + ".");
184             }
185             s += nbItemRow[i];
186         }
187
188         if (s != nbItem) {
189             throw new ScilabSparseException("Invalid array nbItemRow: the total sum is not equal to the number of non-null items.");
190         }
191
192         if (colPos.length != nbItem) {
193             throw new ScilabSparseException("Invalid length for the array colPos: its length must be equal to the number of non-null items.");
194         }
195
196         for (int i = 0; i < nbItem; i++) {
197             if (colPos[i] >= cols || colPos[i] < 0) {
198                 throw new ScilabSparseException("Invalid column position at position " + i + ".");
199             }
200         }
201     }
202
203     /**
204      * Constructor with a matrix of real data.
205      *
206      * @param data the data
207      */
208     public ScilabSparse(double[][] data) {
209         if (data.length != 0 && data[0].length != 0) {
210             rows = data.length;
211             cols = data[0].length;
212             nbItemRow = new int[rows];
213             List<Integer> listCol = new ArrayList<Integer>();
214             List<Double> listVal = new ArrayList<Double>();
215
216             for (int i = 0; i < rows; i++) {
217                 for (int j = 0; j < cols; j++) {
218                     if (data[i][j] != 0) {
219                         ++nbItem;
220                         ++nbItemRow[i];
221                         listCol.add(j);
222                         listVal.add(data[i][j]);
223                     }
224                 }
225             }
226
227             colPos = new int[listCol.size()];
228             realPart = new double[colPos.length];
229             int i = 0;
230             for (Integer c : listCol) {
231                 colPos[i++] = c;
232             }
233             i = 0;
234             for (Double x : listVal) {
235                 realPart[i++] = x;
236             }
237         }
238     }
239
240     /**
241      * Constructor with a matrix of complex numbers
242      *
243      * @param realData the real part of the data
244      * @param imagData the imaginary part of the data
245      */
246     public ScilabSparse(double[][] realData, double[][] imagData) {
247         if (realData.length != 0 && realData[0].length != 0) {
248             rows = realData.length;
249             cols = realData[0].length;
250             nbItemRow = new int[rows];
251             List<Integer> listCol = new ArrayList<Integer>();
252             List<Double> listReal = new ArrayList<Double>();
253             List<Double> listImag = new ArrayList<Double>();
254
255             for (int i = 0; i < rows; i++) {
256                 for (int j = 0; j < cols; j++) {
257                     if (realData[i][j] != 0 || imagData[i][j] != 0) {
258                         ++nbItem;
259                         ++nbItemRow[i];
260                         listCol.add(j);
261                         listReal.add(realData[i][j]);
262                         listImag.add(imagData[i][j]);
263                     }
264                 }
265             }
266
267             colPos = new int[listCol.size()];
268             this.realPart = new double[colPos.length];
269             this.imaginaryPart = new double[colPos.length];
270             int i = 0;
271             for (Integer c : listCol) {
272                 colPos[i++] = c;
273             }
274             i = 0;
275             for (Double x : listReal) {
276                 this.realPart[i++] = x;
277             }
278             i = 0;
279             for (Double x : listImag) {
280                 this.imaginaryPart[i++] = x;
281             }
282         }
283     }
284
285     /**
286      * Constructor
287      *
288      * @param varName the variable name
289      * @param rows the number of rows
290      * @param cols the number of cols
291      * @param nbItem the number of non null items
292      * @param nbItemRow contains the number of true in each rows
293      * @param colPos the column position of each non null item
294      * @param real the non null real data
295      * @param imag the non null imaginary data
296      */
297     public ScilabSparse(String varName, int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
298         this(rows, cols, nbItem, nbItemRow, colPos, real, imag);
299         this.varName = varName;
300     }
301
302     /**
303      * Return the type of Scilab
304      * @return the type of Scilab
305      * @since 5.4.0
306      */
307     @Override
308     public ScilabTypeEnum getType() {
309         return type;
310     }
311
312     /**
313      * Check the emptiness of the associated data.
314      * @return true, if the associated data array is empty.
315      */
316     @Override
317     public boolean isEmpty() {
318         return rows == 0 && cols == 0;
319     }
320
321     /**
322      * Check if the current data doesn't have an imaginary part.
323      *
324      * @return true, if the data are real only.
325      */
326     public boolean isReal() {
327         return (imaginaryPart == null);
328     }
329
330     /**
331      * Get the real part of the data.
332      *
333      * @return the real part.
334      */
335     public double[] getRealPart() {
336         return realPart;
337     }
338
339     /**
340      * Set the real part of the data.
341      *
342      * @param realPart the real part.
343      */
344     public void setRealPart(double[] realPart) {
345         this.realPart = realPart;
346     }
347
348     /**
349      * Get the imaginary part of the data.
350      *
351      * @return the imaginary part.
352      */
353     public double[] getImaginaryPart() {
354         return imaginaryPart;
355     }
356
357     /**
358      * Set the imaginary part of the data.
359      *
360      * @param imaginaryPart the imaginary part.
361      */
362     public void setImaginaryPart(double[] imaginaryPart) {
363         this.imaginaryPart = imaginaryPart;
364     }
365
366     /**
367      * Get the number of non null items in the matrix.
368      *
369      * @return the number of non null items.
370      */
371     public int getNbNonNullItems() {
372         return nbItem;
373     }
374
375     /**
376      * Set the number of non null items in the matrix.
377      *
378      * @param the number of non null items.
379      */
380     public void setNbNonNullItems(int nbItem) {
381         this.nbItem = nbItem;
382     }
383
384     /**
385      * Get the number of non null items by row.
386      *
387      * @return an integer array.
388      */
389     public int[] getNbItemRow() {
390         return nbItemRow;
391     }
392
393     /**
394      * Set the number of non null items by row.
395      *
396      * @param an integer array.
397      */
398     public void setNbItemRow(int[] nbItemRow) {
399         this.nbItemRow = nbItemRow;
400     }
401
402     /**
403      * Get the column positions of the non null items.
404      *
405      * @return an integer array.
406      */
407     public int[] getColPos() {
408         return colPos;
409     }
410
411     /**
412      * Set the column positions of the non null items.
413      *
414      * @param an integer array.
415      */
416     public void setColPos(int[] colPos) {
417         this.colPos = colPos;
418     }
419
420     /**
421      * {@inheritDoc}
422      */
423     public String getVarName() {
424         return varName;
425     }
426
427     /**
428      * {@inheritDoc}
429      */
430     public boolean isSwaped() {
431         return false;
432     }
433
434     /**
435      * Get the real part of the full sparse matrix
436      *
437      * @return the full real matrix
438      */
439     public double[][] getFullRealPart() {
440         int prev = 0;
441         int j = 0;
442         double[][] d = new double[rows][cols];
443         for (int i = 0; i < nbItemRow.length; i++) {
444             for (; j < prev + nbItemRow[i]; j++) {
445                 d[i][colPos[j]] = realPart[j];
446             }
447             prev += nbItemRow[i];
448         }
449
450         return d;
451     }
452
453     /**
454      * Get the imaginary part of the full sparse matrix
455      *
456      * @return the full imaginary matrix
457      */
458     public double[][] getFullImaginaryPart() {
459         int prev = 0;
460         int j = 0;
461         double[][] d = new double[rows][cols];
462         for (int i = 0; i < nbItemRow.length; i++) {
463             for (; j < prev + nbItemRow[i]; j++) {
464                 d[i][colPos[j]] = imaginaryPart[j];
465             }
466             prev += nbItemRow[i];
467         }
468
469         return d;
470     }
471
472     /**
473      * Get the full sparse matrix representation as an array 2 x rows x cols
474      * If d = getFullMatrix(), then d[0] contains realpart and d[1] the imaginary one.
475      *
476      * @return the full matrix components
477      */
478     public double[][][] getFullMatrix() {
479         int prev = 0;
480         int j = 0;
481         double[][][] d = new double[2][rows][cols];
482         for (int i = 0; i < nbItemRow.length; i++) {
483             for (; j < prev + nbItemRow[i]; j++) {
484                 d[0][i][colPos[j]] = realPart[j];
485                 d[1][i][colPos[j]] = imaginaryPart[j];
486             }
487             prev += nbItemRow[i];
488         }
489
490         return d;
491     }
492
493     /**
494      * Get complex matrix as a serialized form
495      *
496      * @return the serialized matrix with complex values
497      */
498     // TODO Sly : faire qque chose ici...
499     public double[] getSerializedSparseMatrix() {
500         return new double[0];
501     }
502
503
504     /**
505      * @return the height of the data matrix
506      * @see org.scilab.modules.types.ScilabType#getHeight()
507      */
508     @Override
509     public int getHeight() {
510         return rows;
511     }
512
513     /**
514      * @return the width of the data matrix
515      * @see org.scilab.modules.types.ScilabType#getWidth()
516      */
517     @Override
518     public int getWidth() {
519         return cols;
520     }
521
522     /**
523      * @see org.scilab.modules.types.ScilabType#equals(Object)
524      */
525     @Override
526     public boolean equals(Object obj) {
527         if (obj instanceof ScilabSparse) {
528             ScilabSparse sciSparse = (ScilabSparse) obj;
529             if (this.getNbNonNullItems() == sciSparse.getNbNonNullItems() &&
530                 compareNbItemRow(this.getNbItemRow(), sciSparse.getNbItemRow()) &&
531                 Arrays.equals(this.getColPos(), sciSparse.getColPos())) {
532                 if (this.isReal() && sciSparse.isReal()) {
533                     return Arrays.equals(this.getRealPart(), sciSparse.getRealPart());
534                 } else {
535                     /* Complex */
536                     return Arrays.equals(this.getRealPart(), sciSparse.getRealPart()) && Arrays.equals(this.getImaginaryPart(), sciSparse.getImaginaryPart());
537                 }
538             } else {
539                 return false;
540             }
541         } else {
542             return false;
543         }
544     }
545
546     /**
547      * Compare two arrays containing the number of items by row.
548      * For example {1, 2, 3, 4} is equal to {1, 2, 3, 4, 0, 0, 0, 0}/
549      * @param a an array
550      * @param b an other array
551      * @return true if the arrays are equal
552      */
553     static final boolean compareNbItemRow(final int[] a, final int[] b) {
554         if (Arrays.equals(a, b)) {
555             return true;
556         }
557
558         if (a.length == b.length) {
559             return false;
560         }
561
562         int[] c, d;
563         if (a.length < b.length) {
564             c = a;
565             d = b;
566         } else {
567             c = b;
568             d = a;
569         }
570
571         int i = 0;
572         for (; i < c.length; i++) {
573             if (c[i] != d[i]) {
574                 return false;
575             }
576         }
577
578         for (; i < d.length; i++) {
579             if (d[i] != 0) {
580                 return false;
581             }
582         }
583
584         return true;
585     }
586
587     /**
588      * Display the representation in the Scilab language of the type<br />
589      * Note that the representation can be copied/pasted straight into Scilab
590      *
591      * @return a Scilab-like String representation of the data.
592      * @see java.lang.Object#toString()
593      */
594     @Override
595     public String toString() {
596         StringBuilder result = new StringBuilder();
597
598         if (isEmpty()) {
599             result.append("[]");
600             return result.toString();
601         }
602
603         result.append("sparse([");
604         int j = 0;
605         int prev = 0;
606         for (int i = 0; i < nbItemRow.length; i++) {
607             for (; j < prev + nbItemRow[i]; j++) {
608                 result.append(Integer.toString(i + 1));
609                 result.append(", ");
610                 result.append(Integer.toString(colPos[j] + 1));
611                 if (j < nbItem - 1) {
612                     result.append(" ; ");
613                 }
614             }
615             prev += nbItemRow[i];
616         }
617
618         result.append("], [");
619         for (int i = 0; i < nbItem; i++) {
620             if (isReal()) {
621                 result.append(Double.toString(realPart[i]));
622             } else {
623                 result.append(Double.toString(realPart[i]));
624                 if (imaginaryPart[i] != 0) {
625                     result.append("+");
626                     result.append(Double.toString(imaginaryPart[i]));
627                     result.append("*%i");
628                 }
629             }
630             if (i < nbItem - 1) {
631                 result.append(" ; ");
632             } else {
633                 result.append("]");
634             }
635         }
636
637         result.append(", [");
638         result.append(Integer.toString(rows));
639         result.append(", ");
640         result.append(Integer.toString(cols));
641
642         result.append("])");
643
644         return result.toString();
645     }
646 }