branch develop updated (35279a2 -> 12386cb)
This is an automated email from the git hooks/post-receive script. New change to branch develop in repository nuiton-matrix. See https://gitlab.nuiton.org/nuiton/nuiton-matrix.git from 35279a2 fixes #4138: Expose exportCSVND in public MatrixND api new 12386cb fixes #4139: add on MatrixFactory create with reader or File in argument The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 12386cb2f8a9ab7acd32ef50e9ffd9107cdba984 Author: Benjamin POUSSIN <poussin@codelutin.com> Date: Thu Jan 19 18:47:49 2017 +0100 fixes #4139: add on MatrixFactory create with reader or File in argument Summary of changes: .../org/nuiton/math/matrix/AbstractMatrixND.java | 152 +-------------- .../java/org/nuiton/math/matrix/MatrixFactory.java | 206 +++++++++++++++++++++ .../main/java/org/nuiton/math/matrix/MatrixND.java | 1 + .../nuiton/math/matrix/ImportExportMatrixTest.java | 3 +- 4 files changed, 213 insertions(+), 149 deletions(-) -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository nuiton-matrix. See https://gitlab.nuiton.org/nuiton/nuiton-matrix.git commit 12386cb2f8a9ab7acd32ef50e9ffd9107cdba984 Author: Benjamin POUSSIN <poussin@codelutin.com> Date: Thu Jan 19 18:47:49 2017 +0100 fixes #4139: add on MatrixFactory create with reader or File in argument --- .../org/nuiton/math/matrix/AbstractMatrixND.java | 152 +-------------- .../java/org/nuiton/math/matrix/MatrixFactory.java | 206 +++++++++++++++++++++ .../main/java/org/nuiton/math/matrix/MatrixND.java | 1 + .../nuiton/math/matrix/ImportExportMatrixTest.java | 3 +- 4 files changed, 213 insertions(+), 149 deletions(-) diff --git a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/AbstractMatrixND.java b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/AbstractMatrixND.java index c5e7bb9..6781db8 100644 --- a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/AbstractMatrixND.java +++ b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/AbstractMatrixND.java @@ -36,8 +36,6 @@ import java.util.List; import java.util.regex.Pattern; import org.apache.commons.collections.primitives.ArrayIntList; -import org.apache.commons.collections.primitives.IntList; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.logging.Log; @@ -87,8 +85,9 @@ public abstract class AbstractMatrixND implements MatrixND { // AbstractMatrixND */ public static final char CSV_SEPARATOR = ';'; - protected static final Pattern NUMBER = Pattern - .compile(" *[+-]?[0-9]*\\.?[0-9]+([eE][+-]?[0-9]+)? *"); + protected static final String NUMBER_REGEX = + " *[+-]?[0-9]*\\.?[0-9]+([eE][+-]?[0-9]+)? *"; + protected static final Pattern NUMBER = Pattern.compile(NUMBER_REGEX); protected void init(int[] dim) { this.dim = new int[dim.length]; @@ -1309,6 +1308,7 @@ public abstract class AbstractMatrixND implements MatrixND { // AbstractMatrixND * @param origin le point à partir duquel il faut faire l'importation * @throws IOException */ + @Override public void importCSV(File file, int[] origin) throws IOException { Reader reader = null; try { @@ -1339,154 +1339,12 @@ public abstract class AbstractMatrixND implements MatrixND { // AbstractMatrixND * @throws IOException */ protected void importCSVND(Reader reader, int[] origin) throws IOException { - - int c = -1; - StringBuffer number = new StringBuffer(20); - IntList coordinates = new ArrayIntList(); - - // read dimension - reader.read(); // skip [ - while ((c = reader.read()) != -1) { - if (c == ' ') { - // skip space - } else if (c == ',' || c == ']') { - if (NUMBER.matcher(number.toString()).matches()) { - int coord = Integer.parseInt(number.toString()); - coordinates.add(coord); - } - number.setLength(0); - - if (c == ']') { - break; - } - } else { - number.append((char) c); - } - } - int[] dimensions = coordinates.toArray(); - coordinates.clear(); - // / read dimension - - // read defaut value - while ((c = reader.read()) != -1) { - if (c == ',' || c == ' ' || c == '\r') { - // skip - } - else if (c == '\n') { - break; - } - else { - number.append((char) c); - } - } - double defaultValue = 0.0; - if (NUMBER.matcher(number.toString()).matches()) { - defaultValue = Double.parseDouble(number.toString()); - MatrixHelper.fill(this, defaultValue); - } - number.setLength(0); - // / read default value - - List[] semantics = new List[dimensions.length]; - for (int indexDim = 0 ; indexDim < dimensions.length ; indexDim++) { - List dimension = importCSVNDReadDimension(reader); - if (dimension != null && dimension.size() != dimensions[indexDim]) { - throw new MatrixException(String.format("Semantics %d count not equals to semantics dimension, excepted %d, got %d", - indexDim, dimensions[indexDim], dimension.size())); - } - semantics[indexDim] = dimension; - } - - if (ArrayUtils.contains(semantics, null)) { - throw new MatrixException("Wrong semantics definition : " + Arrays.toString(semantics)); - } - MatrixND matrix = MatrixFactory.getInstance().create(semantics); - MatrixHelper.fill(matrix, defaultValue); - do { - c = reader.read(); - if (c == ' ') { - // skip space - } else if (c == CSV_SEPARATOR) { - if (NUMBER.matcher(number.toString()).matches()) { - int coord = Integer.parseInt(number.toString()); - coordinates.add(coord); - } - number.setLength(0); - } else if (c == -1 || c == '\n' || c == '\r' || c == -1) { - // 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* - Double val = null; - if (NUMBER.matcher(number.toString()).matches()) { - val = Double.valueOf(number.toString()); - } - number.setLength(0); - - if (!coordinates.isEmpty()) { - int[] coords = coordinates.toArray(); - matrix.setValue(coords, val); - coordinates.clear(); - } - } else { - number.append((char) c); - } - } while (c != -1); - + MatrixND matrix = MatrixFactory.getInstance().create(reader); // finally paste loaded matrix into this pasteSemantics(matrix); } /** - * Read a line and convert line to semantic value. - * - * Use: - * - mapper to convert semantics values - * - return null if line is empty - * - * @param reader reader to read - * @return semantics for readed line - * @throws IOException - */ - protected List importCSVNDReadDimension(Reader reader) throws IOException { - - StringBuffer buffer = new StringBuffer(); - int c = -1; - while ((c = reader.read()) != -1) { - if (c == '\n') { - break; - } - else { - buffer.append((char)c); - } - } - - // read must be in form: - // type : PK1, PK2, PK3... - List sems = null; - if (buffer.length() > 0) { - sems = new ArrayList(); - // get type - int twodIndex = buffer.indexOf(":"); - if (twodIndex == -1) { - throw new MatrixException("Can't parse semantics line as 'Type: ids'"); - } - String type = buffer.substring(0, twodIndex).trim(); - Class typeClass = MatrixFactory.getSemanticMapper().getType(type); - - // get semantics value - String semanticsStrings = buffer.substring(twodIndex +1).trim(); - String[] semanticsPKs = semanticsStrings.split("\\s*,\\s*"); - for (String semanticsPK : semanticsPKs) { - Object value = MatrixFactory.getSemanticMapper().getValue(typeClass, semanticsPK); - sems.add(value); - } - } - return sems; - } - - /** * Export dans un writer au format CSV de la matrice * * @param writer le writer ou copier la matrice diff --git a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixFactory.java b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixFactory.java index f79d30d..2680163 100644 --- a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixFactory.java +++ b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixFactory.java @@ -22,7 +22,17 @@ package org.nuiton.math.matrix; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; + /** * Cette classe permet de creer des matrices, toutes les creations de matrice @@ -39,6 +49,21 @@ import java.util.List; */ public class MatrixFactory { // MatrixFactory + + final static private Pattern DIM_AND_DEFAULT_LINE = Pattern.compile( + // match [1,2,3] + // match [1,2,3] 3.14 + "^\\s*\\[((?:\\s*[0-9]+\\s*,?)+)\\]\\s*,?\\s*(" + AbstractMatrixND.NUMBER_REGEX + ")?\\s*$"); + + final static private Pattern SEMANTICS_LINE = Pattern.compile( + // match: <Class name>:value1, value2, value3, ... + "^\\s*([^:]+)\\s*:\\s*(.+)\\s*$"); + + final static private Pattern DATA_LINE = Pattern.compile( + // match: x;y;z;...;<value> + "^(.*)" + AbstractMatrixND.CSV_SEPARATOR + "(.*)$" + ); + /** * If true, createVector return all time LazyVector to prevent memory * allocation when not necessary. LazyVector init real vector only when @@ -189,6 +214,187 @@ public class MatrixFactory { // MatrixFactory matrixFactoryThreadLocal.remove(); } + /** + * Create new Matrix from file. + * File contains data as describe for export/import CSV ND + * + * @param file + * @return + * @throws IOException + * @since 2.5.2 + */ + public MatrixND create(File file) throws IOException { + Reader in = new BufferedReader(new FileReader(file)); + try { + String matrixName = file.getName(); + int extPos = matrixName.lastIndexOf('.'); + if (extPos != -1) { // remove extension + matrixName = matrixName.substring(0, extPos); + } + + MatrixND result = create(in); + result.setName(matrixName); + return result; + } finally { + in.close(); + } + } + + /** + * Create new Matrix from file. + * File contains data as describe for export/import CSV ND + * @param reader + * @return + * @throws IOException + * @since 2.5.2 + */ + public MatrixND create(Reader reader) throws IOException { + BufferedReader in = new BufferedReader(reader); + + String line = readLine(in); + + if (line == null) { + throw new MatrixException("Bad file format, file is not Matrix"); + } + + // read metadata + int[] dimensions = readDimensions(line); + double defaultValue = readDefaultValue(line); + List[] semantics = readSemantics(dimensions, in); + + MatrixND matrix = this.create(semantics); + MatrixHelper.fill(matrix, defaultValue); + + // read data + line = readLine(in); + while (line != null) { + Matcher m = DATA_LINE.matcher(line); + if (m.matches()) { + int[] coords = readCoordinates(m.group(1)); + double val = readDouble(m.group(2)); + matrix.setValue(coords, val); + } else { + throw new MatrixException("Bad file format, can't read data"); + } + line = readLine(in); + } + + return matrix; + } + + private String readLine(BufferedReader in) throws IOException { + String line = in.readLine(); + while (line != null && StringUtils.isBlank(line)) { + line = in.readLine(); + } + return line; + } + + private int[] readDimensions(String line) throws IOException { + int[] dimensions; + + Matcher m = DIM_AND_DEFAULT_LINE.matcher(line); + + if (m.matches()) { + String dimString = m.group(1); + try { + String[] dimArrayString = dimString.split("\\s*,\\s*"); + dimensions = new int[dimArrayString.length]; + int i = 0; + for (String d : dimArrayString) { + dimensions[i++] = Integer.parseInt(d); + } + } catch (Exception eee) { + throw new MatrixException("Can't parse dimension value: " + dimString, eee); + } + } else { + throw new MatrixException("Line doesn't match dimension and default value information:" + line); + } + + return dimensions; + } + + private double readDefaultValue(String line) throws IOException { + double defaultValue = 0.0; + + Matcher m = DIM_AND_DEFAULT_LINE.matcher(line); + + if (m.matches()) { + String defaultValueString = m.group(2); + if (StringUtils.isNoneBlank(defaultValueString)) { + try { + defaultValue = Double.parseDouble(defaultValueString); + } catch (Exception eee) { + throw new MatrixException("Can't parse default value: " + defaultValueString, eee); + } + } + } else { + throw new MatrixException("Line doesn't match dimension and default value information:" + line); + } + return defaultValue; + } + + /** + * Read a line and convert line to semantic value. + * + * Use: + * - mapper to convert semantics values + */ + private List[] readSemantics(int[] dimensions, BufferedReader in) throws IOException { + List[] semantics = new List[dimensions.length]; + + for (int indexDim = 0 ; indexDim < dimensions.length ; indexDim++) { + String line = readLine(in); + if (line == null) { + throw new MatrixException("Bad file format, file is not Matrix (semantics missing)"); + } + Matcher m = SEMANTICS_LINE.matcher(line); + if (m.matches()) { + String type = m.group(1).trim(); + String[] semString = m.group(2).split("\\s*,\\s*"); + + List sems = new ArrayList(); + Class typeClass = MatrixFactory.getSemanticMapper().getType(type); + for (String s : semString) { + Object value = MatrixFactory.getSemanticMapper().getValue(typeClass, s); + sems.add(value); + } + if (sems.size() != dimensions[indexDim]) { + throw new MatrixException(String.format("Semantics %d count not equals to semantics dimension, excepted %d, got %d", + indexDim, dimensions[indexDim], sems.size())); + } + semantics[indexDim] = sems; + } else { + throw new MatrixException("Bad file format, line is not a semantics declaration: " + line); + } + } + + return semantics; + } + + private int[] readCoordinates(String s) { + String[] coords = s.split("\\s*" + AbstractMatrixND.CSV_SEPARATOR + "\\s*"); + int[] result = new int[coords.length]; + for (int i = 0, max = coords.length; i < max; i++) { + try { + result[i] = Integer.parseInt(coords[i]); + } catch (Exception eee) { + throw new MatrixException("Can't parse coordinate value: " + s, eee); + } + } + return result; + } + + private double readDouble(String s) { + try { + double result = Double.parseDouble(s); + return result; + } catch (Exception eee) { + throw new MatrixException("Can't parse value: " + s, eee); + } + } + + public MatrixND create(int[] dim) { return new MatrixNDImpl(this, dim); } diff --git a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixND.java b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixND.java index f73cc5f..e47ceca 100644 --- a/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixND.java +++ b/nuiton-matrix/src/main/java/org/nuiton/math/matrix/MatrixND.java @@ -940,6 +940,7 @@ public interface MatrixND extends Serializable, Cloneable { // MatrixND * @param writer le writer ou copier la matrice * @param withSemantics export ou pas des semantiques de la matrice dans le * writer + * @throws java.io.IOException */ public void exportCSVND(Writer writer, boolean withSemantics) throws IOException; diff --git a/nuiton-matrix/src/test/java/org/nuiton/math/matrix/ImportExportMatrixTest.java b/nuiton-matrix/src/test/java/org/nuiton/math/matrix/ImportExportMatrixTest.java index 3930b14..ef56a02 100644 --- a/nuiton-matrix/src/test/java/org/nuiton/math/matrix/ImportExportMatrixTest.java +++ b/nuiton-matrix/src/test/java/org/nuiton/math/matrix/ImportExportMatrixTest.java @@ -266,8 +266,7 @@ public class ImportExportMatrixTest { "1;1;0;4.0\n" + "1;1;1;42.0"; - MatrixND m = MatrixFactory.getInstance().create(new int[]{2, 2, 2}); - m.importCSV(new StringReader(matrix3D), null); + MatrixND m = MatrixFactory.getInstance().create(new StringReader(matrix3D)); // default value Assert.assertEquals(Math.PI, m.getValue(0, 1, 0), 0.00001); } -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
participants (1)
-
nuiton.org scm