RealVectorFormat.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.linear;

  22. import java.text.FieldPosition;
  23. import java.text.NumberFormat;
  24. import java.text.ParsePosition;
  25. import java.util.ArrayList;
  26. import java.util.List;
  27. import java.util.Locale;

  28. import org.hipparchus.exception.LocalizedCoreFormats;
  29. import org.hipparchus.exception.MathIllegalStateException;
  30. import org.hipparchus.util.CompositeFormat;

  31. /**
  32.  * Formats a vector in components list format "{v0; v1; ...; vk-1}".
  33.  * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
  34.  * any user-defined strings. The number format for components can be configured.</p>
  35.  * <p>White space is ignored at parse time, even if it is in the prefix, suffix
  36.  * or separator specifications. So even if the default separator does include a space
  37.  * character that is used at format time, both input string "{1;1;1}" and
  38.  * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be
  39.  * returned. In the second case, however, the parse position after parsing will be
  40.  * just after the closing curly brace, i.e. just before the trailing space.</p>
  41.  *
  42.  */
  43. public class RealVectorFormat {

  44.     /** The default prefix: "{". */
  45.     private static final String DEFAULT_PREFIX = "{";
  46.     /** The default suffix: "}". */
  47.     private static final String DEFAULT_SUFFIX = "}";
  48.     /** The default separator: ", ". */
  49.     private static final String DEFAULT_SEPARATOR = "; ";
  50.     /** Prefix. */
  51.     private final String prefix;
  52.     /** Suffix. */
  53.     private final String suffix;
  54.     /** Separator. */
  55.     private final String separator;
  56.     /** Trimmed prefix. */
  57.     private final String trimmedPrefix;
  58.     /** Trimmed suffix. */
  59.     private final String trimmedSuffix;
  60.     /** Trimmed separator. */
  61.     private final String trimmedSeparator;
  62.     /** The format used for components. */
  63.     private final NumberFormat format;

  64.     /**
  65.      * Create an instance with default settings.
  66.      * <p>The instance uses the default prefix, suffix and separator:
  67.      * "{", "}", and "; " and the default number format for components.</p>
  68.      */
  69.     public RealVectorFormat() {
  70.         this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR,
  71.              CompositeFormat.getDefaultNumberFormat());
  72.     }

  73.     /**
  74.      * Create an instance with a custom number format for components.
  75.      * @param format the custom format for components.
  76.      */
  77.     public RealVectorFormat(final NumberFormat format) {
  78.         this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
  79.     }

  80.     /**
  81.      * Create an instance with custom prefix, suffix and separator.
  82.      * @param prefix prefix to use instead of the default "{"
  83.      * @param suffix suffix to use instead of the default "}"
  84.      * @param separator separator to use instead of the default "; "
  85.      */
  86.     public RealVectorFormat(final String prefix, final String suffix,
  87.                             final String separator) {
  88.         this(prefix, suffix, separator,
  89.              CompositeFormat.getDefaultNumberFormat());
  90.     }

  91.     /**
  92.      * Create an instance with custom prefix, suffix, separator and format
  93.      * for components.
  94.      * @param prefix prefix to use instead of the default "{"
  95.      * @param suffix suffix to use instead of the default "}"
  96.      * @param separator separator to use instead of the default "; "
  97.      * @param format the custom format for components.
  98.      */
  99.     public RealVectorFormat(final String prefix, final String suffix,
  100.                             final String separator, final NumberFormat format) {
  101.         this.prefix      = prefix;
  102.         this.suffix      = suffix;
  103.         this.separator   = separator;
  104.         trimmedPrefix    = prefix.trim();
  105.         trimmedSuffix    = suffix.trim();
  106.         trimmedSeparator = separator.trim();
  107.         this.format      = format;
  108.     }

  109.     /**
  110.      * Get the set of locales for which real vectors formats are available.
  111.      * <p>This is the same set as the {@link NumberFormat} set.</p>
  112.      * @return available real vector format locales.
  113.      */
  114.     public static Locale[] getAvailableLocales() {
  115.         return NumberFormat.getAvailableLocales();
  116.     }

  117.     /**
  118.      * Get the format prefix.
  119.      * @return format prefix.
  120.      */
  121.     public String getPrefix() {
  122.         return prefix;
  123.     }

  124.     /**
  125.      * Get the format suffix.
  126.      * @return format suffix.
  127.      */
  128.     public String getSuffix() {
  129.         return suffix;
  130.     }

  131.     /**
  132.      * Get the format separator between components.
  133.      * @return format separator.
  134.      */
  135.     public String getSeparator() {
  136.         return separator;
  137.     }

  138.     /**
  139.      * Get the components format.
  140.      * @return components format.
  141.      */
  142.     public NumberFormat getFormat() {
  143.         return format;
  144.     }

  145.     /**
  146.      * Returns the default real vector format for the current locale.
  147.      * @return the default real vector format.
  148.      * @since 1.4
  149.      */
  150.     public static RealVectorFormat getRealVectorFormat() {
  151.         return getRealVectorFormat(Locale.getDefault());
  152.     }

  153.     /**
  154.      * Returns the default real vector format for the given locale.
  155.      * @param locale the specific locale used by the format.
  156.      * @return the real vector format specific to the given locale.
  157.      * @since 1.4
  158.      */
  159.     public static RealVectorFormat getRealVectorFormat(final Locale locale) {
  160.         return new RealVectorFormat(CompositeFormat.getDefaultNumberFormat(locale));
  161.     }

  162.     /**
  163.      * This method calls {@link #format(RealVector,StringBuffer,FieldPosition)}.
  164.      *
  165.      * @param v RealVector object to format.
  166.      * @return a formatted vector.
  167.      */
  168.     public String format(RealVector v) {
  169.         return format(v, new StringBuffer(), new FieldPosition(0)).toString();
  170.     }

  171.     /**
  172.      * Formats a {@link RealVector} object to produce a string.
  173.      * @param vector the object to format.
  174.      * @param toAppendTo where the text is to be appended
  175.      * @param pos On input: an alignment field, if desired. On output: the
  176.      *            offsets of the alignment field
  177.      * @return the value passed in as toAppendTo.
  178.      */
  179.     public StringBuffer format(RealVector vector, StringBuffer toAppendTo,
  180.                                FieldPosition pos) {

  181.         pos.setBeginIndex(0);
  182.         pos.setEndIndex(0);

  183.         // format prefix
  184.         toAppendTo.append(prefix);

  185.         // format components
  186.         for (int i = 0; i < vector.getDimension(); ++i) {
  187.             if (i > 0) {
  188.                 toAppendTo.append(separator);
  189.             }
  190.             CompositeFormat.formatDouble(vector.getEntry(i), format, toAppendTo, pos);
  191.         }

  192.         // format suffix
  193.         toAppendTo.append(suffix);

  194.         return toAppendTo;
  195.     }

  196.     /**
  197.      * Parse a string to produce a {@link RealVector} object.
  198.      *
  199.      * @param source String to parse.
  200.      * @return the parsed {@link RealVector} object.
  201.      * @throws MathIllegalStateException if the beginning of the specified string
  202.      * cannot be parsed.
  203.      */
  204.     public ArrayRealVector parse(String source) {
  205.         final ParsePosition parsePosition = new ParsePosition(0);
  206.         final ArrayRealVector result = parse(source, parsePosition);
  207.         if (parsePosition.getIndex() == 0) {
  208.             throw new MathIllegalStateException(LocalizedCoreFormats.CANNOT_PARSE_AS_TYPE,
  209.                                                 source,
  210.                                                 parsePosition.getErrorIndex(),
  211.                                                 ArrayRealVector.class);
  212.         }
  213.         return result;
  214.     }

  215.     /**
  216.      * Parse a string to produce a {@link RealVector} object.
  217.      *
  218.      * @param source String to parse.
  219.      * @param pos input/ouput parsing parameter.
  220.      * @return the parsed {@link RealVector} object.
  221.      */
  222.     public ArrayRealVector parse(String source, ParsePosition pos) {
  223.         int initialIndex = pos.getIndex();

  224.         // parse prefix
  225.         CompositeFormat.parseAndIgnoreWhitespace(source, pos);
  226.         if (!CompositeFormat.parseFixedstring(source, trimmedPrefix, pos)) {
  227.             return null;
  228.         }

  229.         // parse components
  230.         List<Number> components = new ArrayList<>();
  231.         for (boolean loop = true; loop;){

  232.             if (!components.isEmpty()) {
  233.                 CompositeFormat.parseAndIgnoreWhitespace(source, pos);
  234.                 if (!CompositeFormat.parseFixedstring(source, trimmedSeparator, pos)) {
  235.                     loop = false;
  236.                 }
  237.             }

  238.             if (loop) {
  239.                 CompositeFormat.parseAndIgnoreWhitespace(source, pos);
  240.                 Number component = CompositeFormat.parseNumber(source, format, pos);
  241.                 if (component != null) {
  242.                     components.add(component);
  243.                 } else {
  244.                     // invalid component
  245.                     // set index back to initial, error index should already be set
  246.                     pos.setIndex(initialIndex);
  247.                     return null;
  248.                 }
  249.             }

  250.         }

  251.         // parse suffix
  252.         CompositeFormat.parseAndIgnoreWhitespace(source, pos);
  253.         if (!CompositeFormat.parseFixedstring(source, trimmedSuffix, pos)) {
  254.             return null;
  255.         }

  256.         // build vector
  257.         double[] data = new double[components.size()];
  258.         for (int i = 0; i < data.length; ++i) {
  259.             data[i] = components.get(i).doubleValue();
  260.         }
  261.         return new ArrayRealVector(data, false);
  262.     }
  263. }