Index: lutinmatrix/src/java/org/codelutin/math/matrix/AbstractMatrixND.java diff -u lutinmatrix/src/java/org/codelutin/math/matrix/AbstractMatrixND.java:1.14 lutinmatrix/src/java/org/codelutin/math/matrix/AbstractMatrixND.java:1.15 --- lutinmatrix/src/java/org/codelutin/math/matrix/AbstractMatrixND.java:1.14 Fri Aug 11 09:29:48 2006 +++ lutinmatrix/src/java/org/codelutin/math/matrix/AbstractMatrixND.java Mon Aug 28 11:41:20 2006 @@ -23,9 +23,9 @@ * Created: 29 oct. 2004 * * @author Benjamin Poussin - * @version $Revision: 1.14 $ + * @version $Revision: 1.15 $ * - * Mise a jour: $Date: 2006/08/11 09:29:48 $ + * Mise a jour: $Date: 2006/08/28 11:41:20 $ * par : $Author: bpoussin $ */ @@ -39,6 +39,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import org.apache.commons.collections.primitives.ArrayIntList; import org.apache.commons.lang.math.NumberUtils; @@ -624,7 +625,7 @@ /** * Separateur CSV par défaut la virgule */ - public static String CSV_SEPARATOR = ";"; + public static char CSV_SEPARATOR = ';'; /** * Determine si la matrice supporte l'import et l'export CSV @@ -634,6 +635,8 @@ return getNbDim() <= 2; } + Pattern NUMBER = Pattern.compile(" *[+-]?[0-9]*\\.?[0-9]+([eE][+-]?[0-9]+)? *"); + /** * Import depuis un reader au format CSV des données dans la matrice * @param reader le reader à importer @@ -641,20 +644,33 @@ */ public void importCSV(Reader reader, int[] origin) throws IOException { int rowsCount = 0; - StreamTokenizer tokenizer; List row = new ArrayList(); + StringBuffer number = new StringBuffer(20); boolean stop = false; - tokenizer = new StreamTokenizer(reader); - tokenizer.eolIsSignificant(true); - - while(!stop) { - tokenizer.nextToken(); - - switch (tokenizer.ttype) { - case StreamTokenizer.TT_EOF: + for (int c=reader.read(); !stop; c=reader.read()){ + if (c == -1) { stop = true; - case StreamTokenizer.TT_EOL: + } + if (c == ' ') { + // skip space + } else if (c == CSV_SEPARATOR) { + if (NUMBER.matcher(number.toString()).matches()) { + Double val = Double.valueOf(number.toString()); + row.add(val); + } + number.setLength(0); + } else if (c == -1 || c == '\n' || c == '\r') { + // is line return or equivalent char because space is already skiped + // or end of stream + + // at end of line, we must see if the leave number + if (NUMBER.matcher(number.toString()).matches()) { + Double val = Double.valueOf(number.toString()); + row.add(val); + } + number.setLength(0); + if(!row.isEmpty()) { MatrixND matrix = getFactory().create(new int[]{1, row.size()}); int columnNumber = 0; @@ -665,17 +681,52 @@ paste(new int[]{origin[0] + rowsCount, origin[1]}, matrix); rowsCount ++; row.clear(); - } - break; - case StreamTokenizer.TT_NUMBER: - row.add(tokenizer.nval); - break; - case StreamTokenizer.TT_WORD: - break; - default: - break; + } + } else { + number.append((char)c); } } + + // cette implatation avec StreamTokenizer ne fonctionne pas + // car il ne sait pas reconnaitre tous les nombres: 5.0E-7 +// int rowsCount = 0; +// StreamTokenizer tokenizer; +// List row = new ArrayList(); +// boolean stop = false; +// +// tokenizer = new StreamTokenizer(reader); +// tokenizer.eolIsSignificant(true); +// +// while(!stop) { +// tokenizer.nextToken(); +// +// switch (tokenizer.ttype) { +// case StreamTokenizer.TT_EOF: +// stop = true; // no break we do next case too +// case StreamTokenizer.TT_EOL: +// if(!row.isEmpty()) { +// MatrixND matrix = getFactory().create(new int[]{1, row.size()}); +// int columnNumber = 0; +// for (Double value : row) { +// matrix.setValue(new int[]{0, columnNumber}, value); +// columnNumber++; +// } +// paste(new int[]{origin[0] + rowsCount, origin[1]}, matrix); +// rowsCount ++; +// row.clear(); +// } +// break; +// case StreamTokenizer.TT_NUMBER: +// System.out.println("+++++++++ " + tokenizer.nval); +// row.add(tokenizer.nval); +// break; +// case StreamTokenizer.TT_WORD: +// System.out.println("--------- " + tokenizer.nval); +// break; +// default: +// break; +// } +// } } /** @@ -716,7 +767,7 @@ /* Calcul des coordonnees */ coordinates = dimsCount == 1 ? new int[]{columnNb} : new int[]{rowNb, columnNb}; - writer.append(getValue(coordinates) + CSV_SEPARATOR); + writer.append(getValue(coordinates) + "" + CSV_SEPARATOR); } writer.append("\n"); } Index: lutinmatrix/src/java/org/codelutin/math/matrix/MatrixHelper.java diff -u lutinmatrix/src/java/org/codelutin/math/matrix/MatrixHelper.java:1.9 lutinmatrix/src/java/org/codelutin/math/matrix/MatrixHelper.java:1.10 --- lutinmatrix/src/java/org/codelutin/math/matrix/MatrixHelper.java:1.9 Fri Aug 11 09:29:48 2006 +++ lutinmatrix/src/java/org/codelutin/math/matrix/MatrixHelper.java Mon Aug 28 11:41:20 2006 @@ -23,9 +23,9 @@ * Created: 28 oct. 2004 * * @author Benjamin Poussin - * @version $Revision: 1.9 $ + * @version $Revision: 1.10 $ * - * Mise a jour: $Date: 2006/08/11 09:29:48 $ + * Mise a jour: $Date: 2006/08/28 11:41:20 $ * par : $Author: bpoussin $ */ @@ -43,6 +43,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.codelutin.util.StringUtil; import org.codelutin.xml.XMLEncoderDecoder; public class MatrixHelper { @@ -76,38 +77,61 @@ } return mat; } - + /** * Permet de relire une chaine du type [[[1, 2], [3, 4]],[[3, 5], [1, 4]]] + *

+ * Remarque: une premiere implatantion avait ete faite en utilisant + * {@link StreamTokenizer} mais en fait il y a un bug dedans, il ne + * sait pas parser les chiffres avec un exposant: 5.0E-7 par exemple + * est lu comme 5.0 :( + *

+ * Remarque: une autre implantation de remplacement a ete faite en + * utilisant le {@link org.codelutin.util.StrintUtil#split(String, String)} + * mais elle etait moins performante (x2) + * * @param s la chaine representant les listes de liste * @return une liste de liste ... de Double - */ + */ static public List convertStringToList(String s) { List result = null; Stack stack = new Stack(); - double value = 0; - StreamTokenizer tok = new StreamTokenizer(new StringReader(s)); - try { - int v = tok.nextToken(); - while (v != StreamTokenizer.TT_EOF) { - if (v == '[') { - stack.push(new ArrayList()); - } else if (v == ']'){ - List current = stack.pop(); - if (stack.empty()) { - result = current; - } else { - stack.peek().add(current); - } - } else if (v == StreamTokenizer.TT_NUMBER) { - value = tok.nval; + StringBuffer number = new StringBuffer(20); // initial to 20 char + + for (int i=0; i + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2006/08/28 11:41:20 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.math.matrix; + +import java.util.Arrays; + +import org.apache.commons.collections.primitives.ArrayDoubleList; +import org.apache.commons.collections.primitives.ArrayFloatList; + +/** +* Permet de stocker des données à une position lineair et de la redemander +* Cette classe ne gére que les données lineaire. +* L'avantage de cette classe est de ne conserver que les elements differents +* de la valeur par defaut, ce qui minimize la taille du tableau necessaire +* a conserver les données. +*/ +public class DoubleVector implements Vector { // FloatVector + + /** maximum number of element, maximum pos value */ + protected int capacity = 0; + + /** la valeur par defaut */ + protected double defaultValue = 0; + + /** contient la position de l'element, le tableau est trie */ + protected int [] position; + protected int positionSize = 0; + + /** contient la valeur de l'element */ + protected ArrayDoubleList data = new ArrayDoubleList(); + + public DoubleVector(int capacity) { + this.capacity = capacity; + position = new int[8]; + Arrays.fill(position, Integer.MAX_VALUE); + } + + public DoubleVector(int capacity, double defaultValue){ + this(capacity); + this.defaultValue = defaultValue; + } + + public int size() { + return capacity; + } + + // poussin 20060827 TODO: verifier l'implantation, il semble quelle soit fausse et ne puisse pas recherche le nombre max correctement + public double getMaxOccurence() { + double result = defaultValue; + + double [] tmp = data.toArray(); + + // si potentiellement il y a plus d'element identique dans data + // que de valeur par defaut, on recherche la valeur possible + if (this.capacity < 2*tmp.length) { + Arrays.sort(tmp); + + // le nombre de fois que l'on a rencontrer la valeur la plus nombreuse + int max = 1; + // le nombre de fois que l'on a rencontrer la valeur courante + int count = 1; + // la valeur la plus rencontrer + result = tmp[0]; + // la valeur que l'on vient de traiter précédement + double old = tmp[0]; + // la valeur courante lu dans le tableaux + double current = tmp[0]; + // tant que l'on peut encore trouve un element plus nombreux dans le + // tableau on le parcours + for(int i=1; max max){ + max = count; + result = old; + } + count = 1; + old = current; + } + } + if(count > max){ + max = count; + result = current; + } + + if(max <= capacity - tmp.length) { + // en fin de compte, il n'y a pas plus d'element identique + // dans data que de defaultValue + result = defaultValue; + } + } + + return result; + } + + protected void checkPos(int pos){ + if(pos < 0 || pos >= capacity) { + throw new IllegalArgumentException("pos " + pos + " is not in [0, "+capacity+"]"); + } + } + + public double getValue(int pos) { + checkPos(pos); + + double result = defaultValue; + int index = findIndex(pos); + if (index >= 0) { + result = data.get(index); + } + return result; + } + + /** + * On ajoute dans l'o + */ + public void setValue(int pos, double value) { + checkPos(pos); + + int index = findIndex(pos); + if (index >= 0) { + if (value == defaultValue) { + // il etait present, on supprime l'element + removeElementAt(index); + data.removeElementAt(index); + } else { + // il etait deja present, on modifie la valeur + data.set(index, value); + } + } else { + // il n'etait pas present + if (value != defaultValue) { + // il faut ajouter dans position et dans data + index = -index -1; + + addElementAt(index, pos); + data.add(index, value); + } + } + } + + public boolean equals(Object o) { + boolean result = false; + if (o instanceof DoubleVector) { + DoubleVector other = (DoubleVector)o; + result = Arrays.equals(this.position, other.position) && data.equals(other.data); + } else if (o instanceof Vector) { + Vector other = (Vector)o; + result = true; + for(int i=0; i position.length) { + int newcap = (position.length * 3) / 2 + 1; + int olddata[] = position; + position = new int[newcap >= mincap ? newcap : mincap]; + System.arraycopy(olddata, 0, position, 0, positionSize); + for(int i=positionSize; i 0) { + System.arraycopy(position, index + 1, position, index, numtomove); + } + positionSize--; + position[positionSize] = Integer.MAX_VALUE; + return oldval; + } + + + public boolean isImplementedPaste(Vector v) { + return v instanceof DoubleVector; + } + public boolean isImplementedAdd(Vector v) { + // FIXME une fois la methode implanter supprimer le false + return false && v instanceof DoubleVector; + } + public boolean isImplementedMinus(Vector v) { + // FIXME une fois la methode implanter supprimer le false + return false && v instanceof DoubleVector; + } + public boolean isImplementedMap() { + return true; + } + + /** + * On recopie tous les attributs pour que le vector ressemble exactement + * a celui passé en argument + */ + public void paste(Vector v) { + DoubleVector fbv = (DoubleVector)v; + this.capacity = fbv.capacity; + this.defaultValue = fbv.defaultValue; + this.positionSize = fbv.positionSize; + this.position = new int[fbv.position.length]; + System.arraycopy(fbv.position, 0, this.position, 0, this.position.length); + this.data.clear(); + this.data.addAll(fbv.data); + } + + // poussin 20060827 FIXME a refaire car v.data et date n'ont pas forcement leur element qui se correspondent, cette implatation est donc fausse + public void add(Vector v) { + DoubleVector fbv = (DoubleVector)v; + for(int i=0; i=0; i--) { + double value = f.apply(data.get(i)); + if (value == defaultValue) { + // il etait present, on supprime l'element + removeElementAt(i); + data.removeElementAt(i); + } else { + // il etait deja present, on modifie la valeur + data.set(i, value); + } + } + } +} // FloatVector +