Javasci: slightly simplify the way to create a sparse or a boolean sparse matrix
[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      */
88     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] data) {
89         this.rows = rows;
90         this.cols = cols;
91         this.nbItem = nbItem;
92         this.nbItemRow = nbItemRow;
93         this.colPos = colPos;
94         this.realPart = data;
95     }
96
97     /**
98      * Constructor
99      *
100      * @param rows the number of rows
101      * @param cols the number of cols
102      * @param nbItem the number of non null items
103      * @param nbItemRow contains the number of true in each rows
104      * @param colPos the column position of each non null item
105      * @param real the non null real data
106      * @param imag the non null imaginary data
107      */
108     public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
109         this(rows, cols, nbItem, nbItemRow, colPos, real);
110         this.imaginaryPart = imag;
111     }
112
113     /**
114      * Constructor with a matrix of real data.
115      *
116      * @param data the data
117      */
118     public ScilabSparse(double[][] data) {
119         if (data.length != 0 && data[0].length != 0) {
120             rows = data.length;
121             cols = data[0].length;
122             nbItemRow = new int[rows];
123             List<Integer> listCol = new ArrayList<Integer>();
124             List<Double> listVal = new ArrayList<Double>();
125
126             for (int i = 0; i < rows; i++) {
127                 for (int j = 0; j < cols; j++) {
128                     if (data[i][j] != 0) {
129                         ++nbItem;
130                         ++nbItemRow[i];
131                         listCol.add(j);
132                         listVal.add(data[i][j]);
133                     }
134                 }
135             }
136
137             colPos = new int[listCol.size()];
138             realPart = new double[colPos.length];
139             int i = 0;
140             for (Integer c : listCol) {
141                 colPos[i++] = c;
142             }
143             i = 0;
144             for (Double x : listVal) {
145                 realPart[i++] = x;
146             }
147         }
148     }
149
150     /**
151      * Constructor with a matrix of complex numbers
152      *
153      * @param realData the real part of the data
154      * @param imagData the imaginary part of the data
155      */
156     public ScilabSparse(double[][] realData, double[][] imagData) {
157         if (realData.length != 0 && realData[0].length != 0) {
158             rows = realData.length;
159             cols = realData[0].length;
160             nbItemRow = new int[rows];
161             List<Integer> listCol = new ArrayList<Integer>();
162             List<Double> listReal = new ArrayList<Double>();
163             List<Double> listImag = new ArrayList<Double>();
164
165             for (int i = 0; i < rows; i++) {
166                 for (int j = 0; j < cols; j++) {
167                     if (realData[i][j] != 0 || imagData[i][j] != 0) {
168                         ++nbItem;
169                         ++nbItemRow[i];
170                         listCol.add(j);
171                         listReal.add(realData[i][j]);
172                         listImag.add(imagData[i][j]);
173                     }
174                 }
175             }
176
177             colPos = new int[listCol.size()];
178             this.realPart = new double[colPos.length];
179             this.imaginaryPart = new double[colPos.length];
180             int i = 0;
181             for (Integer c : listCol) {
182                 colPos[i++] = c;
183             }
184             i = 0;
185             for (Double x : listReal) {
186                 this.realPart[i++] = x;
187             }
188             i = 0;
189             for (Double x : listImag) {
190                 this.imaginaryPart[i++] = x;
191             }
192         }
193     }
194
195     /**
196      * Constructor
197      *
198      * @param varName the variable name
199      * @param rows the number of rows
200      * @param cols the number of cols
201      * @param nbItem the number of non null items
202      * @param nbItemRow contains the number of true in each rows
203      * @param colPos the column position of each non null item
204      * @param real the non null real data
205      * @param imag the non null imaginary data
206      */
207     public ScilabSparse(String varName, int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
208         this(rows, cols, nbItem, nbItemRow, colPos, real, imag);
209         this.varName = varName;
210     }
211
212     /**
213      * Return the type of Scilab
214      * @return the type of Scilab
215      * @since 5.4.0
216      */
217     @Override
218     public ScilabTypeEnum getType() {
219         return type;
220     }
221
222     /**
223      * Check the emptiness of the associated data.
224      * @return true, if the associated data array is empty.
225      */
226     @Override
227     public boolean isEmpty() {
228         return rows == 0 && cols == 0;
229     }
230
231     /**
232      * Check if the current data doesn't have an imaginary part.
233      *
234      * @return true, if the data are real only.
235      */
236     public boolean isReal() {
237         return (imaginaryPart == null);
238     }
239
240     /**
241      * Get the real part of the data.
242      *
243      * @return the real part.
244      */
245     public double[] getRealPart() {
246         return realPart;
247     }
248
249     /**
250      * Set the real part of the data.
251      *
252      * @param realPart the real part.
253      */
254     public void setRealPart(double[] realPart) {
255         this.realPart = realPart;
256     }
257
258     /**
259      * Get the imaginary part of the data.
260      *
261      * @return the imaginary part.
262      */
263     public double[] getImaginaryPart() {
264         return imaginaryPart;
265     }
266
267     /**
268      * Set the imaginary part of the data.
269      *
270      * @param imaginaryPart the imaginary part.
271      */
272     public void setImaginaryPart(double[] imaginaryPart) {
273         this.imaginaryPart = imaginaryPart;
274     }
275
276     /**
277      * Get the number of non null items in the matrix.
278      *
279      * @return the number of non null items.
280      */
281     public int getNbNonNullItems() {
282         return nbItem;
283     }
284
285     /**
286      * Set the number of non null items in the matrix.
287      *
288      * @param the number of non null items.
289      */
290     public void setNbNonNullItems(int nbItem) {
291         this.nbItem = nbItem;
292     }
293
294     /**
295      * Get the number of non null items by row.
296      *
297      * @return an integer array.
298      */
299     public int[] getNbItemRow() {
300         return nbItemRow;
301     }
302
303     /**
304      * Set the number of non null items by row.
305      *
306      * @param an integer array.
307      */
308     public void setNbItemRow(int[] nbItemRow) {
309         this.nbItemRow = nbItemRow;
310     }
311
312     /**
313      * Get the column positions of the non null items.
314      *
315      * @return an integer array.
316      */
317     public int[] getColPos() {
318         return colPos;
319     }
320
321     /**
322      * Set the column positions of the non null items.
323      *
324      * @param an integer array.
325      */
326     public void setColPos(int[] colPos) {
327         this.colPos = colPos;
328     }
329
330     /**
331      * {@inheritDoc}
332      */
333     public String getVarName() {
334         return varName;
335     }
336
337     /**
338      * {@inheritDoc}
339      */
340     public boolean isSwaped() {
341         return false;
342     }
343
344     /**
345      * Get the real part of the full sparse matrix
346      *
347      * @return the full real matrix
348      */
349     public double[][] getFullRealPart() {
350         int prev = 0;
351         int j = 0;
352         double[][] d = new double[rows][cols];
353         for (int i = 0; i < nbItemRow.length; i++) {
354             for (; j < prev + nbItemRow[i]; j++) {
355                 d[i][colPos[j]] = realPart[j];
356             }
357             prev += nbItemRow[i];
358         }
359
360         return d;
361     }
362
363     /**
364      * Get the imaginary part of the full sparse matrix
365      *
366      * @return the full imaginary matrix
367      */
368     public double[][] getFullImaginaryPart() {
369         int prev = 0;
370         int j = 0;
371         double[][] d = new double[rows][cols];
372         for (int i = 0; i < nbItemRow.length; i++) {
373             for (; j < prev + nbItemRow[i]; j++) {
374                 d[i][colPos[j]] = imaginaryPart[j];
375             }
376             prev += nbItemRow[i];
377         }
378
379         return d;
380     }
381
382     /**
383      * Get the full sparse matrix representation as an array 2 x rows x cols
384      * If d = getFullMatrix(), then d[0] contains realpart and d[1] the imaginary one.
385      *
386      * @return the full matrix components
387      */
388     public double[][][] getFullMatrix() {
389         int prev = 0;
390         int j = 0;
391         double[][][] d = new double[2][rows][cols];
392         for (int i = 0; i < nbItemRow.length; i++) {
393             for (; j < prev + nbItemRow[i]; j++) {
394                 d[0][i][colPos[j]] = realPart[j];
395                 d[1][i][colPos[j]] = imaginaryPart[j];
396             }
397             prev += nbItemRow[i];
398         }
399
400         return d;
401     }
402
403     /**
404      * Get complex matrix as a serialized form
405      *
406      * @return the serialized matrix with complex values
407      */
408     // TODO Sly : faire qque chose ici...
409     public double[] getSerializedSparseMatrix() {
410         return new double[0];
411     }
412
413
414     /**
415      * @return the height of the data matrix
416      * @see org.scilab.modules.types.ScilabType#getHeight()
417      */
418     @Override
419     public int getHeight() {
420         return rows;
421     }
422
423     /**
424      * @return the width of the data matrix
425      * @see org.scilab.modules.types.ScilabType#getWidth()
426      */
427     @Override
428     public int getWidth() {
429         return cols;
430     }
431
432     /**
433      * @see org.scilab.modules.types.ScilabType#equals(Object)
434      */
435     @Override
436     public boolean equals(Object obj) {
437         if (obj instanceof ScilabSparse) {
438             ScilabSparse sciSparse = (ScilabSparse) obj;
439             if (this.getNbNonNullItems() == sciSparse.getNbNonNullItems() &&
440                 compareNbItemRow(this.getNbItemRow(), sciSparse.getNbItemRow()) &&
441                 Arrays.equals(this.getColPos(), sciSparse.getColPos())) {
442                 if (this.isReal() && sciSparse.isReal()) {
443                     return Arrays.equals(this.getRealPart(), sciSparse.getRealPart());
444                 } else {
445                     /* Complex */
446                     return Arrays.equals(this.getRealPart(), sciSparse.getRealPart()) && Arrays.equals(this.getImaginaryPart(), sciSparse.getImaginaryPart());
447                 }
448             } else {
449                 return false;
450             }
451         } else {
452             return false;
453         }
454     }
455
456     /**
457      * Compare two arrays containing the number of items by row.
458      * For example {1, 2, 3, 4} is equal to {1, 2, 3, 4, 0, 0, 0, 0}/
459      * @param a an array
460      * @param b an other array
461      * @return true if the arrays are equal
462      */
463     static final boolean compareNbItemRow(final int[] a, final int[] b) {
464         if (Arrays.equals(a, b)) {
465             return true;
466         }
467
468         if (a.length == b.length) {
469             return false;
470         }
471
472         int[] c, d;
473         if (a.length < b.length) {
474             c = a;
475             d = b;
476         } else {
477             c = b;
478             d = a;
479         }
480
481         int i = 0;
482         for (; i < c.length; i++) {
483             if (c[i] != d[i]) {
484                 return false;
485             }
486         }
487
488         for (; i < d.length; i++) {
489             if (d[i] != 0) {
490                 return false;
491             }
492         }
493
494         return true;
495     }
496
497     /**
498      * Display the representation in the Scilab language of the type<br />
499      * Note that the representation can be copied/pasted straight into Scilab
500      *
501      * @return a Scilab-like String representation of the data.
502      * @see java.lang.Object#toString()
503      */
504     @Override
505     public String toString() {
506         StringBuilder result = new StringBuilder();
507
508         if (isEmpty()) {
509             result.append("[]");
510             return result.toString();
511         }
512
513         result.append("sparse([");
514         int j = 0;
515         int prev = 0;
516         for (int i = 0; i < nbItemRow.length; i++) {
517             for (; j < prev + nbItemRow[i]; j++) {
518                 result.append(Integer.toString(i + 1));
519                 result.append(", ");
520                 result.append(Integer.toString(colPos[j] + 1));
521                 if (j < nbItem - 1) {
522                     result.append(" ; ");
523                 }
524             }
525             prev += nbItemRow[i];
526         }
527
528         result.append("], [");
529         for (int i = 0; i < nbItem; i++) {
530             if (isReal()) {
531                 result.append(Double.toString(realPart[i]));
532             } else {
533                 result.append(Double.toString(realPart[i]));
534                 if (imaginaryPart[i] != 0) {
535                     result.append("+");
536                     result.append(Double.toString(imaginaryPart[i]));
537                     result.append("*%i");
538                 }
539             }
540             if (i < nbItem - 1) {
541                 result.append(" ; ");
542             } else {
543                 result.append("]");
544             }
545         }
546
547         result.append(", [");
548         result.append(Integer.toString(rows));
549         result.append(", ");
550         result.append(Integer.toString(cols));
551
552         result.append("])");
553
554         return result.toString();
555     }
556 }