From b19f70ba00cd9d81745127ffa17ce0753c0236ee Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Sun, 22 Jul 2012 19:38:36 +0000 Subject: [PATCH] [MATH-831] Add a RealMatrixFormat class to (de-)serialize a RealMatrix from its string representation. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1364405 13f79535-47bb-0310-9956-ffa450edef68 --- .../math3/linear/RealMatrixFormat.java | 351 +++++++++++++++++ .../linear/RealMatrixFormatAbstractTest.java | 361 ++++++++++++++++++ .../math3/linear/RealMatrixFormatTest.java | 34 ++ 3 files changed, 746 insertions(+) create mode 100644 src/main/java/org/apache/commons/math3/linear/RealMatrixFormat.java create mode 100644 src/test/java/org/apache/commons/math3/linear/RealMatrixFormatAbstractTest.java create mode 100644 src/test/java/org/apache/commons/math3/linear/RealMatrixFormatTest.java diff --git a/src/main/java/org/apache/commons/math3/linear/RealMatrixFormat.java b/src/main/java/org/apache/commons/math3/linear/RealMatrixFormat.java new file mode 100644 index 000000000..e44ab7f52 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/linear/RealMatrixFormat.java @@ -0,0 +1,351 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math3.linear; + +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.math3.exception.MathParseException; +import org.apache.commons.math3.util.CompositeFormat; + +/** + * Formats a {@code nxm} matrix in components list format + * "[a00, a01, ..., + * a0m-1; a10, + * a11, ..., a1m-1; ...; + * an-10, an-11, ..., + * an-1m-1}". + *

The prefix and suffix "[" and "]", the row separator "; " and the column + * separator ", " can be replaced by any user-defined strings. The number format + * for components can be configured.

+ * + *

White space is ignored at parse time, even if it is in the prefix, suffix + * or separator specifications. So even if the default separator does include a space + * character that is used at format time, both input string "[1,1,1]" and + * " [ 1 , 1 , 1 ] " will be parsed without error and the same vector will be + * returned. In the second case, however, the parse position after parsing will be + * just after the closing curly brace, i.e. just before the trailing space.

+ * + *

Note: the grouping functionality of the used {@link NumberFormat} is + * disabled to prevent problems when parsing (e.g. 1,345.34 would be a valid number + * but conflicts with the default column separator).

+ * + * @since 3.1 + * @version $Id$ + */ +public class RealMatrixFormat { + + /** The default prefix: "{". */ + private static final String DEFAULT_PREFIX = "["; + /** The default suffix: "}". */ + private static final String DEFAULT_SUFFIX = "]"; + /** The default row separator: ";". */ + private static final String DEFAULT_ROW_SEPARATOR = "; "; + /** The default column separator: ", ". */ + private static final String DEFAULT_COLUMN_SEPARATOR = ", "; + /** Prefix. */ + private final String prefix; + /** Suffix. */ + private final String suffix; + /** Row separator. */ + private final String rowSeparator; + /** Column separator. */ + private final String columnSeparator; + /** Trimmed prefix. */ + private final String trimmedPrefix; + /** Trimmed suffix. */ + private final String trimmedSuffix; + /** Trimmed row separator. */ + private final String trimmedRowSeparator; + /** Trimmed column separator. */ + private final String trimmedColumnSeparator; + /** The format used for components. */ + private final NumberFormat format; + + /** + * Create an instance with default settings. + *

The instance uses the default prefix, suffix and row/column separator: + * "[", "]", ";" and ", " and the default number format for components.

+ */ + public RealMatrixFormat() { + this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ROW_SEPARATOR, DEFAULT_COLUMN_SEPARATOR, + CompositeFormat.getDefaultNumberFormat()); + } + + /** + * Create an instance with a custom number format for components. + * @param format the custom format for components. + */ + public RealMatrixFormat(final NumberFormat format) { + this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ROW_SEPARATOR, DEFAULT_COLUMN_SEPARATOR, format); + } + + /** + * Create an instance with custom prefix, suffix and separator. + * @param prefix prefix to use instead of the default "{" + * @param suffix suffix to use instead of the default "}" + * @param rowSeparator tow separator to use instead of the default ";" + * @param columnSeparator column separator to use instead of the default ", " + */ + public RealMatrixFormat(final String prefix, final String suffix, + final String rowSeparator, final String columnSeparator) { + this(prefix, suffix, rowSeparator, columnSeparator, CompositeFormat.getDefaultNumberFormat()); + } + + /** + * Create an instance with custom prefix, suffix, separator and format + * for components. + * @param prefix prefix to use instead of the default "{" + * @param suffix suffix to use instead of the default "}" + * @param rowSeparator tow separator to use instead of the default ";" + * @param columnSeparator column separator to use instead of the default ", " + * @param format the custom format for components. + */ + public RealMatrixFormat(final String prefix, final String suffix, + final String rowSeparator, final String columnSeparator, + final NumberFormat format) { + this.prefix = prefix; + this.suffix = suffix; + this.rowSeparator = rowSeparator; + this.columnSeparator = columnSeparator; + trimmedPrefix = prefix.trim(); + trimmedSuffix = suffix.trim(); + trimmedRowSeparator = rowSeparator.trim(); + trimmedColumnSeparator = columnSeparator.trim(); + this.format = format; + // disable grouping to prevent parsing problems + this.format.setGroupingUsed(false); + } + + /** + * Get the set of locales for which real vectors formats are available. + *

This is the same set as the {@link NumberFormat} set.

+ * @return available real vector format locales. + */ + public static Locale[] getAvailableLocales() { + return NumberFormat.getAvailableLocales(); + } + + /** + * Get the format prefix. + * @return format prefix. + */ + public String getPrefix() { + return prefix; + } + + /** + * Get the format suffix. + * @return format suffix. + */ + public String getSuffix() { + return suffix; + } + + /** + * Get the format separator between rows of the matrix. + * @return format separator for rows. + */ + public String getRowSeparator() { + return rowSeparator; + } + + /** + * Get the format separator between components. + * @return format separator between components. + */ + public String getColumnSeparator() { + return columnSeparator; + } + + /** + * Get the components format. + * @return components format. + */ + public NumberFormat getFormat() { + return format; + } + + /** + * Returns the default real vector format for the current locale. + * @return the default real vector format. + */ + public static RealMatrixFormat getInstance() { + return getInstance(Locale.getDefault()); + } + + /** + * Returns the default real vector format for the given locale. + * @param locale the specific locale used by the format. + * @return the real vector format specific to the given locale. + */ + public static RealMatrixFormat getInstance(final Locale locale) { + return new RealMatrixFormat(CompositeFormat.getDefaultNumberFormat(locale)); + } + + /** + * This method calls {@link #format(RealMatrix,StringBuffer,FieldPosition)}. + * + * @param m RealMatrix object to format. + * @return a formatted matrix. + */ + public String format(RealMatrix m) { + return format(m, new StringBuffer(), new FieldPosition(0)).toString(); + } + + /** + * Formats a {@link RealMatrix} object to produce a string. + * @param matrix the object to format. + * @param toAppendTo where the text is to be appended + * @param pos On input: an alignment field, if desired. On output: the + * offsets of the alignment field + * @return the value passed in as toAppendTo. + */ + public StringBuffer format(RealMatrix matrix, StringBuffer toAppendTo, + FieldPosition pos) { + + pos.setBeginIndex(0); + pos.setEndIndex(0); + + // format prefix + toAppendTo.append(prefix); + + // format rows + final int rows = matrix.getRowDimension(); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < matrix.getColumnDimension(); ++j) { + if (j > 0) { + toAppendTo.append(columnSeparator); + } + CompositeFormat.formatDouble(matrix.getEntry(i, j), format, toAppendTo, pos); + } + if (i < rows - 1) { + toAppendTo.append(rowSeparator); + } + } + + // format suffix + toAppendTo.append(suffix); + + return toAppendTo; + } + + /** + * Parse a string to produce a {@link RealMatrix} object. + * + * @param source String to parse. + * @return the parsed {@link RealMatrix} object. + * @throws MathParseException if the beginning of the specified string + * cannot be parsed. + */ + public RealMatrix parse(String source) { + final ParsePosition parsePosition = new ParsePosition(0); + final RealMatrix result = parse(source, parsePosition); + if (parsePosition.getIndex() == 0) { + throw new MathParseException(source, + parsePosition.getErrorIndex(), + Array2DRowRealMatrix.class); + } + return result; + } + + /** + * Parse a string to produce a {@link RealMatrix} object. + * + * @param source String to parse. + * @param pos input/ouput parsing parameter. + * @return the parsed {@link RealMatrix} object. + */ + public RealMatrix parse(String source, ParsePosition pos) { + int initialIndex = pos.getIndex(); + + // parse prefix + CompositeFormat.parseAndIgnoreWhitespace(source, pos); + if (!CompositeFormat.parseFixedstring(source, trimmedPrefix, pos)) { + return null; + } + + // parse components + List> matrix = new ArrayList>(); + List rowComponents = new ArrayList(); + for (boolean loop = true; loop;){ + + if (!rowComponents.isEmpty()) { + CompositeFormat.parseAndIgnoreWhitespace(source, pos); + if (!CompositeFormat.parseFixedstring(source, trimmedColumnSeparator, pos)) { + if (CompositeFormat.parseFixedstring(source, trimmedRowSeparator, pos)) { + matrix.add(rowComponents); + rowComponents = new ArrayList(); + } else { + loop = false; + } + } + } + + if (loop) { + CompositeFormat.parseAndIgnoreWhitespace(source, pos); + Number component = CompositeFormat.parseNumber(source, format, pos); + if (component != null) { + rowComponents.add(component); + } else { + if (rowComponents.isEmpty()) { + loop = false; + } else { + // invalid component + // set index back to initial, error index should already be set + pos.setIndex(initialIndex); + return null; + } + } + } + + } + + if (!rowComponents.isEmpty()) { + matrix.add(rowComponents); + } + + // parse suffix + CompositeFormat.parseAndIgnoreWhitespace(source, pos); + if (!CompositeFormat.parseFixedstring(source, trimmedSuffix, pos)) { + return null; + } + + // do not allow an empty matrix + if (matrix.isEmpty()) { + pos.setIndex(initialIndex); + return null; + } + + // build vector + double[][] data = new double[matrix.size()][]; + int row = 0; + for (List rowList : matrix) { + data[row] = new double[rowList.size()]; + for (int i = 0; i < rowList.size(); i++) { + data[row][i] = rowList.get(i).doubleValue(); + } + row++; + } + return MatrixUtils.createRealMatrix(data); + } +} diff --git a/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatAbstractTest.java b/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatAbstractTest.java new file mode 100644 index 000000000..930ffda9e --- /dev/null +++ b/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatAbstractTest.java @@ -0,0 +1,361 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math3.linear; + +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +import org.junit.Test; +import org.junit.Assert; + +import org.apache.commons.math3.exception.MathParseException; + +public abstract class RealMatrixFormatAbstractTest { + + RealMatrixFormat realMatrixFormat = null; + RealMatrixFormat realMatrixFormatOther = null; + + protected abstract Locale getLocale(); + + protected abstract char getDecimalCharacter(); + + public RealMatrixFormatAbstractTest() { + realMatrixFormat = RealMatrixFormat.getInstance(getLocale()); + final NumberFormat nf = NumberFormat.getInstance(getLocale()); + nf.setMaximumFractionDigits(2); + realMatrixFormatOther = new RealMatrixFormat("{", "}", ", ", " : ", nf); + } + + @Test + public void testSimpleNoDecimals() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1, 1, 1}, {1, 1, 1}}); + String expected = "[1, 1, 1; 1, 1, 1]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testSimpleWithDecimals() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1.23, 1.43, 1.63}, {2.46, 2.46, 2.66}}); + String expected = + "[1" + getDecimalCharacter() + + "23, 1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63; 2" + getDecimalCharacter() + + "46, 2" + getDecimalCharacter() + + "46, 2" + getDecimalCharacter() + + "66]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testSimpleWithDecimalsTrunc() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1.2323, 1.4343, 1.6333}, + {2.4666, 2.4666, 2.6666}}); + String expected = + "[1" + getDecimalCharacter() + + "23, 1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63; 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "67]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testNegativeX() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{-1.2323, 1.4343, 1.6333}, + {2.4666, 2.4666, 2.6666}}); + String expected = + "[-1" + getDecimalCharacter() + + "23, 1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63; 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "67]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testNegativeY() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1.2323, -1.4343, 1.6333}, + {2.4666, 2.4666, 2.6666}}); + String expected = + "[1" + getDecimalCharacter() + + "23, -1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63; 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "67]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testNegativeSecondRow() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1.2323, 1.4343, 1.6333}, + {-2.4666, 2.4666, 2.6666}}); + String expected = + "[1" + getDecimalCharacter() + + "23, 1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63; -2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "47, 2" + getDecimalCharacter() + + "67]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testNonDefaultSetting() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{1, 1, 1}, {1, 1, 1}}); + String expected = "{1 : 1 : 1, 1 : 1 : 1}"; + String actual = realMatrixFormatOther.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testDefaultFormatRealVectorImpl() { + Locale defaultLocal = Locale.getDefault(); + Locale.setDefault(getLocale()); + + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{232.222, -342.33, 432.444}}); + String expected = + "[232" + getDecimalCharacter() + + "22, -342" + getDecimalCharacter() + + "33, 432" + getDecimalCharacter() + + "44]"; + String actual = (new RealMatrixFormat()).format(m); + Assert.assertEquals(expected, actual); + + Locale.setDefault(defaultLocal); + } + + @Test + public void testNan() { + RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {{Double.NaN, Double.NaN, Double.NaN}}); + String expected = "[(NaN), (NaN), (NaN)]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testPositiveInfinity() { + RealMatrix m = MatrixUtils.createRealMatrix( + new double[][] {{Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY}}); + String expected = "[(Infinity), (Infinity), (Infinity)]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void tesNegativeInfinity() { + RealMatrix m = MatrixUtils.createRealMatrix( + new double[][] {{Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY}}); + String expected = "[(-Infinity), (-Infinity), (-Infinity)]"; + String actual = realMatrixFormat.format(m); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseSimpleNoDecimals() { + String source = "[1, 1, 1; 1, 1, 1]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1, 1, 1}, {1, 1, 1}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseSimpleWithClosingRowSeparator() { + String source = "[1, 1, 1; 1, 1, 1 ;]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1, 1, 1}, {1, 1, 1}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseIgnoredWhitespace() { + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1, 1, 1}, {1, 1, 1}}); + ParsePosition pos1 = new ParsePosition(0); + String source1 = "[1,1,1;1,1,1]"; + Assert.assertEquals(expected, realMatrixFormat.parse(source1, pos1)); + Assert.assertEquals(source1.length(), pos1.getIndex()); + ParsePosition pos2 = new ParsePosition(0); + String source2 = " [ 1 , 1 , 1 ; 1 , 1 , 1 ] "; + Assert.assertEquals(expected, realMatrixFormat.parse(source2, pos2)); + Assert.assertEquals(source2.length() - 1, pos2.getIndex()); + } + + @Test + public void testParseSimpleWithDecimals() { + String source = + "[1" + getDecimalCharacter() + + "23, 1" + getDecimalCharacter() + + "43, 1" + getDecimalCharacter() + + "63]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1.23, 1.43, 1.63}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseSimpleWithDecimalsTrunc() { + String source = + "[1" + getDecimalCharacter() + + "2323, 1" + getDecimalCharacter() + + "4343, 1" + getDecimalCharacter() + + "6333]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1.2323, 1.4343, 1.6333}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNegativeComponent() { + String source = + "[-1" + getDecimalCharacter() + + "2323, 1" + getDecimalCharacter() + + "4343, 1" + getDecimalCharacter() + + "6333]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{-1.2323, 1.4343, 1.6333}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNegativeAll() { + String source = + "[-1" + getDecimalCharacter() + + "2323, -1" + getDecimalCharacter() + + "4343, -1" + getDecimalCharacter() + + "6333]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{-1.2323, -1.4343, -1.6333}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseZeroComponent() { + String source = + "[0" + getDecimalCharacter() + + "0, -1" + getDecimalCharacter() + + "4343, 1" + getDecimalCharacter() + + "6333]"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{0.0, -1.4343, 1.6333}}); + RealMatrix actual = realMatrixFormat.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNonDefaultSetting() { + String source = + "{1" + getDecimalCharacter() + + "2323 : 1" + getDecimalCharacter() + + "4343 : 1" + getDecimalCharacter() + + "6333}"; + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{1.2323, 1.4343, 1.6333}}); + RealMatrix actual = realMatrixFormatOther.parse(source); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNan() { + String source = "[(NaN), (NaN), (NaN)]"; + RealMatrix actual = realMatrixFormat.parse(source); + RealMatrix expected = MatrixUtils.createRealMatrix(new double[][] {{Double.NaN, Double.NaN, Double.NaN}}); + for (int i = 0; i < expected.getRowDimension(); i++) { + for (int j = 0; j < expected.getColumnDimension(); j++) { + Assert.assertTrue(Double.isNaN(actual.getEntry(i, j))); + } + } + } + + @Test + public void testParsePositiveInfinity() { + String source = "[(Infinity), (Infinity), (Infinity)]"; + RealMatrix actual = realMatrixFormat.parse(source); + RealMatrix expected = MatrixUtils.createRealMatrix( + new double[][] {{Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY}}); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNegativeInfinity() { + String source = "[(-Infinity), (-Infinity), (-Infinity)]"; + RealMatrix actual = realMatrixFormat.parse(source); + RealMatrix expected = MatrixUtils.createRealMatrix( + new double[][] {{Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY}}); + Assert.assertEquals(expected, actual); + } + + @Test + public void testParseNoComponents() { + try { + realMatrixFormat.parse("[ ]"); + Assert.fail("Expecting MathParseException"); + } catch (MathParseException pe) { + // expected behavior + } + } + + @Test + public void testParseManyComponents() { + RealMatrix parsed = realMatrixFormat.parse("[0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0]"); + Assert.assertEquals(24, parsed.getRowDimension()); + } + + @Test + public void testConstructorSingleFormat() { + NumberFormat nf = NumberFormat.getInstance(); + RealMatrixFormat mf = new RealMatrixFormat(nf); + Assert.assertNotNull(mf); + Assert.assertEquals(nf, mf.getFormat()); + } + + @Test + public void testForgottenPrefix() { + ParsePosition pos = new ParsePosition(0); + final String source = "1; 1; 1]"; + Assert.assertNull("Should not parse <"+source+">", new RealMatrixFormat().parse(source, pos)); + Assert.assertEquals(0, pos.getErrorIndex()); + } + + @Test + public void testForgottenSeparator() { + ParsePosition pos = new ParsePosition(0); + final String source = "[1; 1 1]"; + Assert.assertNull("Should not parse <"+source+">", new RealMatrixFormat().parse(source, pos)); + Assert.assertEquals(6, pos.getErrorIndex()); + } + + @Test + public void testForgottenSuffix() { + ParsePosition pos = new ParsePosition(0); + final String source = "[1; 1; 1 "; + Assert.assertNull("Should not parse <"+source+">", new RealMatrixFormat().parse(source, pos)); + Assert.assertEquals(8, pos.getErrorIndex()); + } +} diff --git a/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatTest.java b/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatTest.java new file mode 100644 index 000000000..86a1e283a --- /dev/null +++ b/src/test/java/org/apache/commons/math3/linear/RealMatrixFormatTest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math3.linear; + +import java.util.Locale; + + +public class RealMatrixFormatTest extends RealMatrixFormatAbstractTest { + + @Override + protected char getDecimalCharacter() { + return '.'; + } + + @Override + protected Locale getLocale() { + return Locale.US; + } +}