2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2011-2011 - DIGITEO - Calixte DENIZET
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
7 * This file is hereby licensed under the terms of the GNU GPL v2.0,
8 * pursuant to article 5.3.4 of the CeCILL v.2.1.
9 * This file was originally licensed under the terms of the CeCILL v2.1,
10 * and continues to be available under such terms.
11 * For more information, see the COPYING file which you should have received
12 * along with this program.
16 package org.scilab.modules.types;
18 import java.io.IOException;
19 import java.io.ObjectInput;
20 import java.io.ObjectOutput;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
26 * This class provides a representation on the Scilab Sparse datatype<br>
28 * This class is {@link java.io.Serializable} and any modification could impact
29 * load and store of data (Xcos files, Javasci saved data, etc...).<br>
32 * @see org.scilab.modules.javasci.Scilab
34 public class ScilabSparse implements ScilabType {
36 private static final long serialVersionUID = 879625048944109684L;
38 private static final int VERSION = 0;
43 protected int[] nbItemRow;
44 protected int[] colPos;
45 protected double[] realPart;
46 protected double[] imaginaryPart;
47 protected String varName;
48 protected boolean byref;
53 public ScilabSparse() {
57 * Constructor with a unique value.
62 public ScilabSparse(double data) {
66 nbItemRow = new int[] { 1 };
67 colPos = new int[] { 0 };
68 realPart = new double[] { data };
73 * Constructor with a unique complex value.
80 public ScilabSparse(double realData, double imagData) {
81 if (realData != 0 || imagData != 0) {
84 nbItemRow = new int[] { 1 };
85 colPos = new int[] { 0 };
86 realPart = new double[] { realData };
87 imaginaryPart = new double[] { imagData };
99 * the number of non null items
101 * contains the number of true in each rows
103 * the column position of each non null item
107 * if true the parameters validity is checked
108 * @throws ScilabSparseException if the passed arguments are not a valid sparse representation
110 public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] data, boolean check) throws ScilabSparseException {
111 this(rows, cols, nbItem, nbItemRow, colPos, data);
113 checkValidity(rows, cols, nbItem, nbItemRow, colPos);
115 if (realPart.length != nbItem) {
116 throw new ScilabSparseException("Invalid length for the array realPart: its length must be equal to the number of non-null items.");
129 * the number of non null items
131 * contains the number of true in each rows
133 * the column position of each non null item
135 * the non null real data
137 public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real) {
140 this.nbItem = nbItem;
141 this.nbItemRow = nbItemRow;
142 this.colPos = colPos;
143 this.realPart = real;
154 * the number of non null items
156 * contains the number of true in each rows
158 * the column position of each non null item
160 * the non null real data
162 * the non null imaginary data
164 * if true the parameters validity is checked
165 * @throws ScilabSparseException if the passed arguments are not a valid sparse representation
167 public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag, boolean check)
168 throws ScilabSparseException {
169 this(rows, cols, nbItem, nbItemRow, colPos, real, imag);
171 checkValidity(rows, cols, nbItem, nbItemRow, colPos);
173 if (realPart.length != nbItem) {
174 throw new ScilabSparseException("Invalid length for the array realPart: its length must be equal to the number of non-null items.");
177 if (imaginaryPart.length != nbItem) {
178 throw new ScilabSparseException("Invalid length for the array imaginaryPart: its length must be equal to the number of non-null items.");
191 * the number of non null items
193 * contains the number of true in each rows
195 * the column position of each non null item
197 * the non null real data
199 * the non null imaginary data
201 public ScilabSparse(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
202 this(rows, cols, nbItem, nbItemRow, colPos, real);
203 this.imaginaryPart = imag;
214 * the number of non null items
216 * contains the number of true in each rows
218 * the column position of each non null item
220 static final void checkValidity(int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos) throws ScilabSparseException {
221 if (nbItem > rows * cols || nbItem < 0) {
222 throw new ScilabSparseException("Invalid number of items: between 0 and " + rows * cols + " expected.");
225 if (nbItemRow.length > rows) {
226 throw new ScilabSparseException("Invalid length for the array nbItemRow: a length between 0 and " + rows + " expected.");
230 for (int i = 0; i < nbItemRow.length; i++) {
231 if (nbItemRow[i] > cols) {
232 throw new ScilabSparseException("Invalid number of non-null items in nbItemRow at position " + i + ".");
238 throw new ScilabSparseException("Invalid array nbItemRow: the total sum is not equal to the number of non-null items.");
241 if (colPos.length != nbItem) {
242 throw new ScilabSparseException("Invalid length for the array colPos: its length must be equal to the number of non-null items.");
245 for (int i = 0; i < nbItem; i++) {
246 if (colPos[i] >= cols || colPos[i] < 0) {
247 throw new ScilabSparseException("Invalid column position at position " + i + ".");
253 * Constructor with a matrix of real data.
258 public ScilabSparse(double[][] data) {
259 if (data.length != 0 && data[0].length != 0) {
261 cols = data[0].length;
262 nbItemRow = new int[rows];
263 List<Integer> listCol = new ArrayList<Integer>();
264 List<Double> listVal = new ArrayList<Double>();
266 for (int i = 0; i < rows; i++) {
267 for (int j = 0; j < cols; j++) {
268 if (data[i][j] != 0) {
272 listVal.add(data[i][j]);
277 colPos = new int[listCol.size()];
278 realPart = new double[colPos.length];
280 for (Integer c : listCol) {
284 for (Double x : listVal) {
291 * Constructor with a matrix of complex numbers
294 * the real part of the data
296 * the imaginary part of the data
298 public ScilabSparse(double[][] realData, double[][] imagData) {
299 if (realData.length != 0 && realData[0].length != 0) {
300 rows = realData.length;
301 cols = realData[0].length;
302 nbItemRow = new int[rows];
303 List<Integer> listCol = new ArrayList<Integer>();
304 List<Double> listReal = new ArrayList<Double>();
305 List<Double> listImag = new ArrayList<Double>();
307 for (int i = 0; i < rows; i++) {
308 for (int j = 0; j < cols; j++) {
309 if (realData[i][j] != 0 || imagData[i][j] != 0) {
313 listReal.add(realData[i][j]);
314 listImag.add(imagData[i][j]);
319 colPos = new int[listCol.size()];
320 this.realPart = new double[colPos.length];
321 this.imaginaryPart = new double[colPos.length];
323 for (Integer c : listCol) {
327 for (Double x : listReal) {
328 this.realPart[i++] = x;
331 for (Double x : listImag) {
332 this.imaginaryPart[i++] = x;
347 * the number of non null items
349 * contains the number of true in each rows
351 * the column position of each non null item
353 * the non null real data
355 * the non null imaginary data
357 public ScilabSparse(String varName, int rows, int cols, int nbItem, int[] nbItemRow, int[] colPos, double[] real, double[] imag) {
358 this(rows, cols, nbItem, nbItemRow, colPos, real, imag);
359 this.varName = varName;
366 public boolean isReference() {
371 * Return the type of Scilab
373 * @return the type of Scilab
377 public ScilabTypeEnum getType() {
378 return ScilabTypeEnum.sci_sparse;
382 * Check the emptiness of the associated data.
384 * @return true, if the associated data array is empty.
387 public boolean isEmpty() {
388 return rows == 0 && cols == 0;
392 * Check if the current data doesn't have an imaginary part.
394 * @return true, if the data are real only.
396 public boolean isReal() {
397 return imaginaryPart == null;
401 * Get the element in column position
402 * @param i the position
403 * @return the column position
405 public int getColPosElement(final int i) {
410 * Set the element in column position
411 * @param i the position
412 * @param x the column position
414 public void setColPosElement(final int i, final int x) {
419 * Get the number of non-null item in row i
421 * @return the number of non-null items
423 public int getNbItemElement(final int i) {
428 * Set the number of non-null item in row i
430 * @param x the number of non-null items
432 public void setNbItemElement(final int i, final int x) {
437 * Get the real element at position i
438 * @param i the position
441 public double getRealElement(final int i) {
446 * Get the real element at position (i, j) in the sparse matrix
447 * @param i the row index
448 * @param j the column index
451 public double getRealElement(final int i, final int j) {
452 if (getNbItemElement(i) == 0) {
457 for (int k = 0; k < i; k++) {
458 prev += getNbItemElement(k);
461 for (int k = prev; k < prev + getNbItemElement(i); k++) {
462 if (getColPosElement(k) == j) {
463 return getRealElement(k);
471 * Get the imaginary element at position i
472 * @param i the position
475 public double getImaginaryElement(final int i) {
476 return imaginaryPart[i];
480 * Get the imanginary element at position (i, j) in the sparse matrix
481 * @param i the row index
482 * @param j the column index
485 public double getImaginaryElement(final int i, final int j) {
486 if (getNbItemElement(i) == 0) {
491 for (int k = 0; k < i; k++) {
492 prev += getNbItemElement(k);
495 for (int k = prev; k < prev + getNbItemElement(i); k++) {
496 if (getColPosElement(k) == j) {
497 return getImaginaryElement(k);
505 * Get the real and imaginary elements at position i
506 * @param i the position
507 * @return a 2-array containing real and imaginary part
509 public double[] getElement(final int i) {
511 return new double[] {realPart[i], 0};
513 return new double[] {realPart[i], imaginaryPart[i]};
518 * Get the real and imanginary element at position (i, j) in the sparse matrix
519 * @param i the row index
520 * @param j the column index
521 * @return a 2-array containing real and imaginary parts
523 public double[] getElement(final int i, final int j) {
525 return new double[] {getRealElement(i, j), 0};
527 if (getNbItemElement(i) == 0) {
528 return new double[] {0, 0};
532 for (int k = 0; k < i; k++) {
533 prev += getNbItemElement(k);
536 for (int k = prev; k < prev + getNbItemElement(i); k++) {
537 if (getColPosElement(k) == j) {
538 return new double[] {getRealElement(k), getImaginaryElement(k)};
542 return new double[] {0, 0};
547 * Set the real element at position i
548 * @param i the position
549 * @param x the value to set
551 public void setRealElement(final int i, final double x) {
556 * Set the real element at position (i, j) in sparse matrix
557 * Take care only an already non-null element can be set
558 * @param i the row index
559 * @param j the column index
560 * @param x the value to set
562 public void setRealElement(final int i, final int j, final double x) {
563 if (getNbItemElement(i) == 0) {
568 for (int k = 0; k < i; k++) {
569 prev += getNbItemElement(k);
572 for (int k = prev; k < prev + getNbItemElement(i); k++) {
573 if (getColPosElement(k) == j) {
574 setRealElement(k, x);
581 * Set the imaginary element at position i
582 * @param i the position
583 * @param x the value to set
585 public void setImaginaryElement(final int i, final double x) {
586 imaginaryPart[i] = x;
590 * Set the imaginary element at position (i, j) in sparse matrix
591 * Take care only an already non-null element can be set
592 * @param i the row index
593 * @param j the column index
594 * @param x the value to set
596 public void setImaginaryElement(final int i, final int j, final double x) {
597 if (getNbItemElement(i) == 0) {
602 for (int k = 0; k < i; k++) {
603 prev += getNbItemElement(k);
606 for (int k = prev; k < prev + getNbItemElement(i); k++) {
607 if (getColPosElement(k) == j) {
608 setImaginaryElement(k, x);
615 * Set the real and imaginary elements at position i
616 * @param i the position
617 * @param x the real part to set
618 * @param y the imaginary part to set
620 public void setElement(final int i, final double x, final double y) {
621 setRealElement(i, x);
622 setImaginaryElement(i, y);
626 * Get the real part of the data.
628 * @return the real part.
630 public double[] getRealPart() {
635 * Set the real part of the data.
640 public void setRealPart(double[] realPart) {
641 this.realPart = realPart;
645 * Get the imaginary part of the data.
647 * @return the imaginary part.
649 public double[] getImaginaryPart() {
650 return imaginaryPart;
654 * Set the imaginary part of the data.
656 * @param imaginaryPart
657 * the imaginary part.
659 public void setImaginaryPart(double[] imaginaryPart) {
660 this.imaginaryPart = imaginaryPart;
664 * Get the number of non null items in the matrix.
666 * @return the number of non null items.
668 public int getNbNonNullItems() {
673 * Set the number of non null items in the matrix.
676 * the number of non null items.
678 public void setNbNonNullItems(int nbItem) {
679 this.nbItem = nbItem;
683 * Get the number of non null items by row.
685 * @return an integer array.
687 public int[] getNbItemRow() {
692 * Set the number of non null items by row.
697 public void setNbItemRow(int[] nbItemRow) {
698 this.nbItemRow = nbItemRow;
702 * Get the column positions of the non null items.
704 * @return an integer array.
706 public int[] getScilabColPos() {
707 int[] cp = new int[colPos.length];
708 for (int i = 0; i < colPos.length; i++) {
709 cp[i] = colPos[i] + 1;
715 * Get the column positions of the non null items.
717 * @return an integer array.
719 public int[] getColPos() {
724 * Set the column positions of the non null items.
729 public void setColPos(int[] colPos) {
730 this.colPos = colPos;
737 public String getVarName() {
745 public boolean isSwaped() {
750 * Get the real part of the full sparse matrix
752 * @return the full real matrix
754 public double[][] getFullRealPart() {
757 double[][] d = new double[rows][cols];
758 for (int i = 0; i < nbItemRow.length; i++) {
759 for (; j < prev + nbItemRow[i]; j++) {
760 d[i][colPos[j]] = realPart[j];
762 prev += nbItemRow[i];
769 * Get the imaginary part of the full sparse matrix
771 * @return the full imaginary matrix
773 public double[][] getFullImaginaryPart() {
776 double[][] d = new double[rows][cols];
777 for (int i = 0; i < nbItemRow.length; i++) {
778 for (; j < prev + nbItemRow[i]; j++) {
779 d[i][colPos[j]] = imaginaryPart[j];
781 prev += nbItemRow[i];
788 * Get the full sparse matrix representation as an array 2 x rows x cols If
789 * d = getFullMatrix(), then d[0] contains realpart and d[1] the imaginary
792 * @return the full matrix components
794 public double[][][] getFullMatrix() {
797 double[][][] d = new double[2][rows][cols];
798 for (int i = 0; i < nbItemRow.length; i++) {
799 for (; j < prev + nbItemRow[i]; j++) {
800 d[0][i][colPos[j]] = realPart[j];
801 d[1][i][colPos[j]] = imaginaryPart[j];
803 prev += nbItemRow[i];
810 * Get complex matrix as a serialized form
812 * @return the serialized matrix with complex values
814 // TODO Sly : faire qque chose ici...
815 public double[] getSerializedSparseMatrix() {
816 return new double[0];
820 * @return the height of the data matrix
821 * @see org.scilab.modules.types.ScilabType#getHeight()
824 public int getHeight() {
829 * @return the width of the data matrix
830 * @see org.scilab.modules.types.ScilabType#getWidth()
833 public int getWidth() {
838 public int hashCode() {
839 final int prime = 31;
841 result = prime * result + Arrays.hashCode(colPos);
842 result = prime * result + cols;
843 result = prime * result + Arrays.hashCode(imaginaryPart);
844 result = prime * result + nbItem;
845 result = prime * result + Arrays.hashCode(nbItemRow);
846 result = prime * result + Arrays.hashCode(realPart);
847 result = prime * result + rows;
852 * @see org.scilab.modules.types.ScilabType#equals(Object)
855 public boolean equals(Object obj) {
856 if (obj instanceof ScilabSparse) {
857 ScilabSparse sciSparse = (ScilabSparse) obj;
858 if (isEmpty() && sciSparse.isEmpty()) {
862 if (this.getWidth() != sciSparse.getWidth() || this.getHeight() != sciSparse.getHeight()) {
866 if (this.getNbNonNullItems() == sciSparse.getNbNonNullItems() && compareNbItemRow(this.getNbItemRow(), sciSparse.getNbItemRow())
867 && Arrays.equals(this.getColPos(), sciSparse.getColPos())) {
868 if (this.isReal() && sciSparse.isReal()) {
869 return Arrays.equals(this.getRealPart(), sciSparse.getRealPart());
872 return Arrays.equals(this.getRealPart(), sciSparse.getRealPart()) && Arrays.equals(this.getImaginaryPart(), sciSparse.getImaginaryPart());
883 * Compare two arrays containing the number of items by row. For example {1,
884 * 2, 3, 4} is equal to {1, 2, 3, 4, 0, 0, 0, 0}/
890 * @return true if the arrays are equal
892 static final boolean compareNbItemRow(final int[] a, final int[] b) {
893 if (Arrays.equals(a, b)) {
897 if (a.length == b.length) {
902 if (a.length < b.length) {
911 for (; i < c.length; i++) {
917 for (; i < d.length; i++) {
930 public Object getSerializedObject() {
932 return new Object[] { new int[] { getHeight(), getWidth() }, getNbItemRow(), getScilabColPos(), getRealPart() };
934 return new Object[] { new int[] { getHeight(), getWidth() }, getNbItemRow(), getScilabColPos(), getRealPart(), getImaginaryPart() };
939 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
940 int version = in.readInt();
945 nbItem = in.readInt();
946 nbItemRow = (int[]) in.readObject();
947 colPos = (int[]) in.readObject();
948 realPart = (double[]) in.readObject();
949 imaginaryPart = (double[]) in.readObject();
950 varName = (String) in.readObject();
953 throw new ClassNotFoundException("A class ScilabSparse with a version " + version + " does not exists");
958 public void writeExternal(ObjectOutput out) throws IOException {
959 out.writeInt(VERSION);
962 out.writeInt(nbItem);
963 out.writeObject(nbItemRow);
964 out.writeObject(colPos);
965 out.writeObject(realPart);
966 out.writeObject(imaginaryPart);
967 out.writeObject(varName);
971 * Display the representation in the Scilab language of the type<BR>
972 * Note that the representation can be copied/pasted straight into Scilab
974 * @return a Scilab-like String representation of the data.
975 * @see java.lang.Object#toString()
978 public String toString() {
979 StringBuilder result = new StringBuilder();
985 result.append("sparse([");
988 int[] nbItemRow = getNbItemRow();
989 int[] colPos = getColPos();
990 for (int i = 0; i < nbItemRow.length; i++) {
991 for (; j < prev + nbItemRow[i]; j++) {
992 result.append(Integer.toString(i + 1));
994 result.append(Integer.toString(colPos[j] + 1));
995 if (j < nbItem - 1) {
996 result.append(" ; ");
999 prev += nbItemRow[i];
1002 result.append("], [");
1003 boolean real = isReal();
1004 for (int i = 0; i < nbItem; i++) {
1005 result.append(Double.toString(getRealElement(i)));
1007 final double y = getImaginaryElement(i);
1012 result.append(Double.toString(y));
1013 result.append("*%i");
1016 if (i < nbItem - 1) {
1017 result.append(" ; ");
1023 result.append(", [");
1024 result.append(Integer.toString(rows));
1025 result.append(", ");
1026 result.append(Integer.toString(cols));
1028 result.append("])");
1030 return result.toString();