Home | History | Annotate | Download | only in linear
      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  *      http://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 package org.apache.commons.math.linear;
     19 
     20 import java.text.FieldPosition;
     21 import java.text.NumberFormat;
     22 import java.text.ParseException;
     23 import java.text.ParsePosition;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 import java.util.Locale;
     27 
     28 import org.apache.commons.math.MathRuntimeException;
     29 import org.apache.commons.math.exception.util.LocalizedFormats;
     30 import org.apache.commons.math.util.CompositeFormat;
     31 
     32 /**
     33  * Formats a vector in components list format "{v0; v1; ...; vk-1}".
     34  * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
     35  * any user-defined strings. The number format for components can be configured.</p>
     36  * <p>White space is ignored at parse time, even if it is in the prefix, suffix
     37  * or separator specifications. So even if the default separator does include a space
     38  * character that is used at format time, both input string "{1;1;1}" and
     39  * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be
     40  * returned. In the second case, however, the parse position after parsing will be
     41  * just after the closing curly brace, i.e. just before the trailing space.</p>
     42  *
     43  * @version $Revision: 1003886 $ $Date: 2010-10-02 23:04:44 +0200 (sam. 02 oct. 2010) $
     44  * @since 2.0
     45  */
     46 public class RealVectorFormat extends CompositeFormat {
     47 
     48     /** Serializable version identifier */
     49     private static final long serialVersionUID = -708767813036157690L;
     50 
     51     /** The default prefix: "{". */
     52     private static final String DEFAULT_PREFIX = "{";
     53 
     54     /** The default suffix: "}". */
     55     private static final String DEFAULT_SUFFIX = "}";
     56 
     57     /** The default separator: ", ". */
     58     private static final String DEFAULT_SEPARATOR = "; ";
     59 
     60     /** Prefix. */
     61     private final String prefix;
     62 
     63     /** Suffix. */
     64     private final String suffix;
     65 
     66     /** Separator. */
     67     private final String separator;
     68 
     69     /** Trimmed prefix. */
     70     private final String trimmedPrefix;
     71 
     72     /** Trimmed suffix. */
     73     private final String trimmedSuffix;
     74 
     75     /** Trimmed separator. */
     76     private final String trimmedSeparator;
     77 
     78     /** The format used for components. */
     79     private final NumberFormat format;
     80 
     81     /**
     82      * Create an instance with default settings.
     83      * <p>The instance uses the default prefix, suffix and separator:
     84      * "{", "}", and "; " and the default number format for components.</p>
     85      */
     86     public RealVectorFormat() {
     87         this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, getDefaultNumberFormat());
     88     }
     89 
     90     /**
     91      * Create an instance with a custom number format for components.
     92      * @param format the custom format for components.
     93      */
     94     public RealVectorFormat(final NumberFormat format) {
     95         this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
     96     }
     97 
     98     /**
     99      * Create an instance with custom prefix, suffix and separator.
    100      * @param prefix prefix to use instead of the default "{"
    101      * @param suffix suffix to use instead of the default "}"
    102      * @param separator separator to use instead of the default "; "
    103      */
    104     public RealVectorFormat(final String prefix, final String suffix,
    105                             final String separator) {
    106         this(prefix, suffix, separator, getDefaultNumberFormat());
    107     }
    108 
    109     /**
    110      * Create an instance with custom prefix, suffix, separator and format
    111      * for components.
    112      * @param prefix prefix to use instead of the default "{"
    113      * @param suffix suffix to use instead of the default "}"
    114      * @param separator separator to use instead of the default "; "
    115      * @param format the custom format for components.
    116      */
    117     public RealVectorFormat(final String prefix, final String suffix,
    118                             final String separator, final NumberFormat format) {
    119         this.prefix      = prefix;
    120         this.suffix      = suffix;
    121         this.separator   = separator;
    122         trimmedPrefix    = prefix.trim();
    123         trimmedSuffix    = suffix.trim();
    124         trimmedSeparator = separator.trim();
    125         this.format      = format;
    126     }
    127 
    128     /**
    129      * Get the set of locales for which real vectors formats are available.
    130      * <p>This is the same set as the {@link NumberFormat} set.</p>
    131      * @return available real vector format locales.
    132      */
    133     public static Locale[] getAvailableLocales() {
    134         return NumberFormat.getAvailableLocales();
    135     }
    136 
    137     /**
    138      * Get the format prefix.
    139      * @return format prefix.
    140      */
    141     public String getPrefix() {
    142         return prefix;
    143     }
    144 
    145     /**
    146      * Get the format suffix.
    147      * @return format suffix.
    148      */
    149     public String getSuffix() {
    150         return suffix;
    151     }
    152 
    153     /**
    154      * Get the format separator between components.
    155      * @return format separator.
    156      */
    157     public String getSeparator() {
    158         return separator;
    159     }
    160 
    161     /**
    162      * Get the components format.
    163      * @return components format.
    164      */
    165     public NumberFormat getFormat() {
    166         return format;
    167     }
    168 
    169     /**
    170      * Returns the default real vector format for the current locale.
    171      * @return the default real vector format.
    172      */
    173     public static RealVectorFormat getInstance() {
    174         return getInstance(Locale.getDefault());
    175     }
    176 
    177     /**
    178      * Returns the default real vector format for the given locale.
    179      * @param locale the specific locale used by the format.
    180      * @return the real vector format specific to the given locale.
    181      */
    182     public static RealVectorFormat getInstance(final Locale locale) {
    183         return new RealVectorFormat(getDefaultNumberFormat(locale));
    184     }
    185 
    186     /**
    187      * This static method calls {@link #format(Object)} on a default instance of
    188      * RealVectorFormat.
    189      *
    190      * @param v RealVector object to format
    191      * @return A formatted vector
    192      */
    193     public static String formatRealVector(RealVector v) {
    194         return getInstance().format(v);
    195     }
    196 
    197     /**
    198      * Formats a {@link RealVector} object to produce a string.
    199      * @param vector the object to format.
    200      * @param toAppendTo where the text is to be appended
    201      * @param pos On input: an alignment field, if desired. On output: the
    202      *            offsets of the alignment field
    203      * @return the value passed in as toAppendTo.
    204      */
    205     public StringBuffer format(RealVector vector, StringBuffer toAppendTo,
    206                                FieldPosition pos) {
    207 
    208         pos.setBeginIndex(0);
    209         pos.setEndIndex(0);
    210 
    211         // format prefix
    212         toAppendTo.append(prefix);
    213 
    214         // format components
    215         for (int i = 0; i < vector.getDimension(); ++i) {
    216             if (i > 0) {
    217                 toAppendTo.append(separator);
    218             }
    219             formatDouble(vector.getEntry(i), format, toAppendTo, pos);
    220         }
    221 
    222         // format suffix
    223         toAppendTo.append(suffix);
    224 
    225         return toAppendTo;
    226 
    227     }
    228 
    229     /**
    230      * Formats a object to produce a string.
    231      * <p><code>obj</code> must be a  {@link RealVector} object. Any other type of
    232      * object will result in an {@link IllegalArgumentException} being thrown.</p>
    233      * @param obj the object to format.
    234      * @param toAppendTo where the text is to be appended
    235      * @param pos On input: an alignment field, if desired. On output: the
    236      *            offsets of the alignment field
    237      * @return the value passed in as toAppendTo.
    238      * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
    239      * @throws IllegalArgumentException is <code>obj</code> is not a valid type.
    240      */
    241     @Override
    242     public StringBuffer format(Object obj, StringBuffer toAppendTo,
    243                                FieldPosition pos) {
    244 
    245         if (obj instanceof RealVector) {
    246             return format( (RealVector)obj, toAppendTo, pos);
    247         }
    248 
    249         throw MathRuntimeException.createIllegalArgumentException(
    250               LocalizedFormats.CANNOT_FORMAT_INSTANCE_AS_REAL_VECTOR,
    251               obj.getClass().getName());
    252 
    253     }
    254 
    255     /**
    256      * Parses a string to produce a {@link RealVector} object.
    257      * @param source the string to parse
    258      * @return the parsed {@link RealVector} object.
    259      * @exception ParseException if the beginning of the specified string
    260      *            cannot be parsed.
    261      */
    262     public ArrayRealVector parse(String source) throws ParseException {
    263         ParsePosition parsePosition = new ParsePosition(0);
    264         ArrayRealVector result = parse(source, parsePosition);
    265         if (parsePosition.getIndex() == 0) {
    266             throw MathRuntimeException.createParseException(
    267                     parsePosition.getErrorIndex(),
    268                     LocalizedFormats.UNPARSEABLE_REAL_VECTOR, source);
    269         }
    270         return result;
    271     }
    272 
    273     /**
    274      * Parses a string to produce a {@link RealVector} object.
    275      * @param source the string to parse
    276      * @param pos input/ouput parsing parameter.
    277      * @return the parsed {@link RealVector} object.
    278      */
    279     public ArrayRealVector parse(String source, ParsePosition pos) {
    280         int initialIndex = pos.getIndex();
    281 
    282         // parse prefix
    283         parseAndIgnoreWhitespace(source, pos);
    284         if (!parseFixedstring(source, trimmedPrefix, pos)) {
    285             return null;
    286         }
    287 
    288         // parse components
    289         List<Number> components = new ArrayList<Number>();
    290         for (boolean loop = true; loop;){
    291 
    292             if (!components.isEmpty()) {
    293                 parseAndIgnoreWhitespace(source, pos);
    294                 if (!parseFixedstring(source, trimmedSeparator, pos)) {
    295                     loop = false;
    296                 }
    297             }
    298 
    299             if (loop) {
    300                 parseAndIgnoreWhitespace(source, pos);
    301                 Number component = parseNumber(source, format, pos);
    302                 if (component != null) {
    303                     components.add(component);
    304                 } else {
    305                     // invalid component
    306                     // set index back to initial, error index should already be set
    307                     pos.setIndex(initialIndex);
    308                     return null;
    309                 }
    310             }
    311 
    312         }
    313 
    314         // parse suffix
    315         parseAndIgnoreWhitespace(source, pos);
    316         if (!parseFixedstring(source, trimmedSuffix, pos)) {
    317             return null;
    318         }
    319 
    320         // build vector
    321         double[] data = new double[components.size()];
    322         for (int i = 0; i < data.length; ++i) {
    323             data[i] = components.get(i).doubleValue();
    324         }
    325         return new ArrayRealVector(data, false);
    326 
    327     }
    328 
    329     /**
    330      * Parses a string to produce a object.
    331      * @param source the string to parse
    332      * @param pos input/ouput parsing parameter.
    333      * @return the parsed object.
    334      * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
    335      */
    336     @Override
    337     public Object parseObject(String source, ParsePosition pos) {
    338         return parse(source, pos);
    339     }
    340 
    341 }
    342