001/*
002*   ParameterVector -- A n-dimensional vector of Parameter objects.
003*
004*   Copyright (C) 2009-2025, by Joseph A. Huwaldt. All rights reserved.
005*   
006*   This library is free software; you can redistribute it and/or
007*   modify it under the terms of the GNU Lesser General Public
008*   License as published by the Free Software Foundation; either
009*   version 2 of the License, or (at your option) any later version.
010*   
011*   This library is distributed in the hope that it will be useful,
012*   but WITHOUT ANY WARRANTY; without even the implied warranty of
013*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014*   Lesser General Public License for more details.
015*
016*   You should have received a copy of the GNU Lesser General Public License
017*   along with this program; if not, write to the Free Software
018*   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
019*   Or visit:  http://www.gnu.org/licenses/lgpl.html
020 */
021package jahuwaldt.js.param;
022
023import java.util.List;
024import javax.measure.converter.ConversionException;
025import javax.measure.converter.UnitConverter;
026import javax.measure.quantity.Dimensionless;
027import javax.measure.quantity.Length;
028import javax.measure.quantity.Quantity;
029import javax.measure.unit.NonSI;
030import javax.measure.unit.SI;
031import javax.measure.unit.Unit;
032import javolution.context.ObjectFactory;
033import javolution.context.StackContext;
034import javolution.lang.MathLib;
035import javolution.lang.ValueType;
036import javolution.util.FastTable;
037import javolution.xml.XMLFormat;
038import javolution.xml.XMLSerializable;
039import javolution.xml.stream.XMLStreamException;
040import org.jscience.mathematics.number.Float64;
041import org.jscience.mathematics.vector.DimensionException;
042import org.jscience.mathematics.vector.Float64Vector;
043import org.jscience.mathematics.vector.Vector;
044
045/**
046 * <p>
047 * This class represents an n-dimensional {@link Vector vector} of {@link Parameter}
048 * elements sharing the same units.</p>
049 *
050 * <p> Modified by: Joseph A. Huwaldt   </p>
051 *
052 * @author Joseph A. Huwaldt Date: March 27, 2009
053 * @version February 23, 2025
054 */
055public class ParameterVector<Q extends Quantity> extends AbstractParamVector<Q, ParameterVector<Q>>
056        implements ValueType, XMLSerializable {
057
058    private static final long serialVersionUID = -1026285730707259617L;
059
060    /**
061     * Constant used to identify the X (0) coordinate in the vector.
062     */
063    public static final int X = 0;
064
065    /**
066     * Constant used to identify the Y (1) coordinate in the vector.
067     */
068    public static final int Y = 1;
069
070    /**
071     * Constant used to identify the Z (2) coordinate in the vector.
072     */
073    public static final int Z = 2;
074
075    /**
076     * The coordinates are stored in this vector. Serialization is handled by this class
077     * since Float64Vector is not Serializable.
078     */
079    protected transient Float64Vector _data;
080
081    /**
082     * Holds the unit of the coordinates.
083     */
084    protected Unit<Q> _unit;
085
086    /**
087     * Returns a 2D {@link ParameterVector} instance holding the specified
088     * <code>double</code> values stated in the specified units.
089     *
090     * @param x    the x value stated in the specified unit.
091     * @param y    the y value stated in the specified unit.
092     * @param unit the unit in which the coordinates are stated.
093     * @param <Q>  the quantity or type of the specified unit.
094     * @return the vector having the specified values.
095     */
096    public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, Unit<Q> unit) {
097        ParameterVector<Q> V = newInstance(unit);
098
099        V._data = Float64Vector.valueOf(x, y);
100
101        return V;
102    }
103
104    /**
105     * Returns a {@link ParameterVector} instance holding the specified
106     * <code>double</code> values stated in the specified units.
107     *
108     * @param x    the x value stated in the specified unit.
109     * @param y    the y value stated in the specified unit.
110     * @param z    the z value stated in the specified unit.
111     * @param unit the unit in which the coordinates are stated.
112     * @param <Q>  the quantity or type of the specified unit.
113     * @return the vector having the specified values.
114     */
115    public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, double z, Unit<Q> unit) {
116        ParameterVector<Q> V = newInstance(unit);
117
118        V._data = Float64Vector.valueOf(x, y, z);
119
120        return V;
121    }
122
123    /**
124     * Returns a {@link ParameterVector} instance holding the specified
125     * <code>double</code> values stated in the specified units.
126     *
127     * @param unit   the unit in which the coordinates are stated.
128     * @param values A list of values to store in the vector.
129     * @param <Q>    the quantity or type of the specified unit.
130     * @return the vector having the specified values.
131     */
132    public static <Q extends Quantity> ParameterVector<Q> valueOf(Unit<Q> unit, double... values) {
133        ParameterVector<Q> V = newInstance(unit);
134
135        V._data = Float64Vector.valueOf(values);
136
137        return V;
138    }
139
140    /**
141     * Returns a {@link ParameterVector} instance holding the specified
142     * <code>Parameter</code> values. All the values are converted to the same units as
143     * the x value.
144     *
145     * @param x   the x value.
146     * @param y   the y value.
147     * @param z   the z value.
148     * @param <Q> the quantity or type of the specified unit.
149     * @return the vector having the specified values in the units of x.
150     */
151    public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q> x, Parameter<Q> y, Parameter<Q> z) {
152
153        Unit<Q> unit = x.getUnit();
154        ParameterVector<Q> V = newInstance(unit);
155        V._data = Float64Vector.valueOf(x.getValue(), y.getValue(unit), z.getValue(unit));
156
157        return V;
158    }
159
160    /**
161     * Returns a {@link ParameterVector} instance holding the specified
162     * <code>Parameter</code> values. All the values are converted to the same units as
163     * the first value.
164     *
165     * @param values A list of values to store in the vector.
166     * @param <Q>    the quantity or type of the specified unit.
167     * @return the vector having the specified values in the units of x.
168     */
169    public static <Q extends Quantity> ParameterVector<Q> valueOf(List<Parameter<Q>> values) {
170        FastTable<Float64> valueList = FastTable.newInstance();
171
172        Unit<Q> unit = values.get(0).getUnit();
173        int size = values.size();
174        for (int i = 0; i < size; ++i) {
175            Parameter<Q> param = values.get(i);
176            Float64 value = Float64.valueOf(param.getValue(unit));
177            valueList.add(value);
178        }
179
180        ParameterVector<Q> V = newInstance(unit);
181        V._data = Float64Vector.valueOf(valueList);
182
183        FastTable.recycle(valueList);
184
185        return V;
186    }
187
188    /**
189     * Returns a {@link ParameterVector} instance holding the specified
190     * <code>Parameter</code> values. All the values are converted to the same units as
191     * the first value.
192     *
193     * @param values A list of values to store in the vector.
194     * @param <Q>    the quantity or type of the specified unit.
195     * @return the vector having the specified values in the units of x.
196     */
197    public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q>... values) {
198        FastTable<Float64> valueList = FastTable.newInstance();
199
200        Unit<Q> unit = values[0].getUnit();
201        int size = values.length;
202        for (int i = 0; i < size; ++i) {
203            Parameter<Q> param = values[i];
204            Float64 value = Float64.valueOf(param.getValue(unit));
205            valueList.add(value);
206        }
207
208        ParameterVector<Q> V = newInstance(unit);
209        V._data = Float64Vector.valueOf(valueList);
210
211        FastTable.recycle(valueList);
212
213        return V;
214    }
215
216    /**
217     * Returns a {@link ParameterVector} instance containing the specified vector of
218     * Float64 values stated in the specified units.
219     *
220     * @param vector the vector of Float64 values stated in the specified unit.
221     * @param unit   the unit in which the coordinates are stated.
222     * @param <Q>    the quantity or type of the specified unit.
223     * @return the vector having the specified values.
224     */
225    public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Float64> vector, Unit<Q> unit) {
226
227        ParameterVector<Q> V = newInstance(unit);
228        V._data = Float64Vector.valueOf(vector);
229
230        return V;
231    }
232
233    /**
234     * Returns a {@link ParameterVector} instance containing the specified vector of
235     * Parameter values with compatible units. All the values are converted to the same
236     * units as the 1st value.
237     *
238     * @param vector the vector of Parameter values stated in the specified unit.
239     * @param <Q>    the quantity or type of the specified unit.
240     * @return the vector having the specified values.
241     */
242    public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Parameter<Q>> vector) {
243        if (vector instanceof ParameterVector)
244            return (ParameterVector<Q>) vector;
245
246        Unit<Q> unit = vector.get(0).getUnit();
247        FastTable<Float64> valueList = FastTable.newInstance();
248
249        int size = vector.getDimension();
250        for (int i = 0; i < size; ++i) {
251            Parameter<Q> param = vector.get(i);
252            Float64 value = Float64.valueOf(param.getValue(unit));
253            valueList.add(value);
254        }
255
256        ParameterVector<Q> V = newInstance(unit);
257        V._data = Float64Vector.valueOf(valueList);
258
259        FastTable.recycle(valueList);
260
261        return V;
262    }
263
264    /**
265     * Returns a Vector3D representation of this vector if possible.
266     *
267     * @return A Vector3D that is equivalent to this vector
268     * @throws DimensionException if this vector has any number of dimensions other than
269     * 3.
270     */
271    @Override
272    public Vector3D<Q> toVector3D() {
273        if (getDimension() != 3)
274            throw new DimensionException(RESOURCES.getString("pvNumElementsErr"));
275        return (Vector3D<Q>) Vector3D.valueOf(this);
276    }
277
278    /**
279     * Return the specified {@link Vector3D} object as a <code>ParameterVector</code>
280     * instance.
281     *
282     * @param vector The <code>Vector3D</code> object to be converted to a
283     *               <code>ParameterVector</code>.
284     * @return A <code>ParameterVector</code> instance that is equivalent to the supplied
285     * <code>Vector3D</code> object.
286     */
287    @Override
288    public ParameterVector<Q> fromVector3D(Vector3D<Q> vector) {
289        return (ParameterVector<Q>) ParameterVector.valueOf(vector);
290    }
291
292    /**
293     * Returns the number of elements held by this vector.
294     *
295     * @return this vector dimension.
296     */
297    @Override
298    public int getDimension() {
299        return _data.getDimension();
300    }
301
302    /**
303     * Returns the value of a Parameter from this vector.
304     *
305     * @param i the dimension index.
306     * @return the value of the parameter at <code>i</code>.
307     * @throws IndexOutOfBoundsException <code>(i < 0) || (i &ge; dimension())</code>
308     */
309    @Override
310    public Parameter<Q> get(int i) {
311        return Parameter.valueOf(getValue(i), getUnit());
312    }
313
314    /**
315     * Returns the value of the Parameter in this vector as a <code>double</code>, stated
316     * in this vector's {@link #getUnit unit}.
317     *
318     * @param i the dimension index.
319     * @return the value of the Parameter at <code>i</code>.
320     * @throws IndexOutOfBoundsException <code>(i < 0) || (i &ge; dimension())</code>
321     */
322    @Override
323    public double getValue(int i) {
324        return _data.getValue(i);
325    }
326
327    /**
328     * Returns the {@link #norm}, magnitude, or length value of this vector.
329     *
330     * @return <code>this.norm().doubleValue()</code>.
331     */
332    @Override
333    public double normValue() {
334        return _data.normValue();
335    }
336
337    /**
338     * Returns the negation of this vector.
339     *
340     * @return <code>-this</code>.
341     */
342    @Override
343    public ParameterVector<Q> opposite() {
344        ParameterVector<Q> V = newInstance(this._unit);
345        V._data = this._data.opposite();
346        return V;
347    }
348
349    /**
350     * Returns the sum of this vector with the one specified. The unit of the output
351     * vector will be the units of this vector.
352     *
353     * @param that the vector to be added.
354     * @return  <code>this + that</code>.
355     * @throws DimensionException if vector dimensions are different.
356     * @throws ConversionException if the input vector is not in units consistent with
357     * this vector.
358     */
359    @Override
360    public ParameterVector<Q> plus(Vector<Parameter<Q>> that) {
361
362        if (that.getDimension() != this.getDimension())
363            throw new DimensionException();
364
365        //      Convert input vector to a Float64Vector (with unit conversion if necessary).
366        Float64Vector thatData = toFloat64Vector(that, this._unit);
367
368        ParameterVector<Q> V = newInstance(this._unit);
369        V._data = this._data.plus(thatData);
370
371        return V;
372    }
373
374    /**
375     * Returns the sum of this vector with the parameter specified. The input parameter is
376     * added to each component of this vector. The unit of the output vector will be the
377     * units of this vector.
378     *
379     * @param that the parameter to be added to each element of this vector.
380     * @return  <code>this + that</code>.
381     */
382    @Override
383    public ParameterVector<Q> plus(Parameter<Q> that) {
384
385        //      Convert input parameter to the units of this vector.
386        double thatValue = that.getValue(this._unit);
387
388        StackContext.enter();
389        try {
390            FastTable<Float64> valueList = FastTable.newInstance();
391            int numDims = _data.getDimension();
392            for (int i = 0; i < numDims; ++i) {
393                double value = this._data.getValue(i) + thatValue;
394                valueList.add(Float64.valueOf(value));
395            }
396            ParameterVector<Q> V = newInstance(this._unit);
397            V._data = Float64Vector.valueOf(valueList);
398
399            return StackContext.outerCopy(V);
400        } finally {
401            StackContext.exit();
402        }
403    }
404
405    /**
406     * Returns the difference between this vector and the one specified. The unit of the
407     * output vector will be the units of this vector.
408     *
409     * @param that the vector to be subtracted.
410     * @return <code>this - that</code>.
411     * @throws DimensionException if vector dimensions are different.
412     * @throws ConversionException if the input vector is not in units consistent with
413     * this vector.
414     */
415    @Override
416    public ParameterVector<Q> minus(Vector<Parameter<Q>> that) {
417
418        if (that.getDimension() != this.getDimension())
419            throw new DimensionException();
420
421        //      Convert input vector to a Float64Vector (with unit conversion if necessary).
422        Float64Vector thatData = toFloat64Vector(that, this._unit);
423
424        ParameterVector<Q> V = newInstance(this._unit);
425        V._data = this._data.minus(thatData);
426
427        return V;
428    }
429
430    /**
431     * Subtracts the supplied Parameter from each element of this vector and returns the
432     * result. The unit of the output vector will be the units of this vector.
433     *
434     * @param that the Parameter to be subtracted from each element of this vector.
435     * @return <code>this - that</code>.
436     */
437    @Override
438    public ParameterVector<Q> minus(Parameter<Q> that) {
439
440        //      Convert input parameter to the units of this vector.
441        double thatValue = that.getValue(this._unit);
442
443        StackContext.enter();
444        try {
445            FastTable<Float64> valueList = FastTable.newInstance();
446            int numDims = _data.getDimension();
447            for (int i = 0; i < numDims; ++i) {
448                double value = this._data.getValue(i) - thatValue;
449                valueList.add(Float64.valueOf(value));
450            }
451            ParameterVector<Q> V = newInstance(this._unit);
452            V._data = Float64Vector.valueOf(valueList);
453
454            return StackContext.outerCopy(V);
455        } finally {
456            StackContext.exit();
457        }
458    }
459
460    /**
461     * Returns the product of this vector with the specified coefficient.
462     *
463     * @param k the coefficient multiplier.
464     * @return <code>this times k</code>
465     */
466    @Override
467    @SuppressWarnings({"unchecked", "rawtypes"})
468    public ParameterVector times(Parameter k) {
469        ParameterVector V = FACTORY.object();
470
471        V._unit = Parameter.productOf(this.getUnit(), k.getUnit());
472        V._data = this._data.times(k.getValue());
473
474        return V;
475    }
476
477    /**
478     * Returns the product of this vector with the specified coefficient.
479     *
480     * @param k the coefficient multiplier.
481     * @return <code>this times k</code>
482     */
483    @Override
484    public ParameterVector<Q> times(double k) {
485        ParameterVector<Q> V = newInstance(this._unit);
486        V._data = _data.times(k);
487        return V;
488    }
489
490    /**
491     * Returns the dot product of this vector with the one specified.
492     *
493     * @param that the vector multiplier.
494     * @return <code>this times that</code>
495     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
496     * @see <a href="http://en.wikipedia.org/wiki/Dot_product">
497     * Wikipedia: Dot Product</a>
498     */
499    @SuppressWarnings("rawtypes")
500    @Override
501    public Parameter times(Vector that) {
502
503        if (that.getDimension() != this.getDimension())
504            throw new DimensionException();
505
506        //      Convert input vector to a Float64Vector.
507        @SuppressWarnings("unchecked")
508        Float64Vector thatData = toFloat64Vector(that, null);
509
510        Float64 f = this._data.times(thatData);
511        Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit());
512
513        return Parameter.valueOf(f.doubleValue(), unit);
514    }
515
516    /**
517     * Returns the element-by-element product of this vector with the one specified.
518     *
519     * @param that the vector multiplier.
520     * @return <code>this .* that</code>
521     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
522     */
523    @SuppressWarnings("rawtypes")
524    public ParameterVector timesEBE(Vector that) {
525
526        if (that.getDimension() != this.getDimension())
527            throw new DimensionException();
528
529        StackContext.enter();
530        try {
531            //  Convert input vector to a Float64Vector.
532            @SuppressWarnings("unchecked")
533            Float64Vector thatData = toFloat64Vector(that, null);
534
535            Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit());
536
537            //  Carry out the multiplication.
538            FastTable<Float64> valueList = FastTable.newInstance();
539            int size = getDimension();
540            for (int i = 0; i < size; ++i) {
541                double value = this._data.getValue(i) * thatData.getValue(i);
542                valueList.add(Float64.valueOf(value));
543            }
544
545            ParameterVector<?> V = newInstance(unit);
546            V._data = Float64Vector.valueOf(valueList);
547
548            return StackContext.outerCopy(V);
549        } finally {
550            StackContext.exit();
551        }
552    }
553
554    /**
555     * Returns the cross product of two vectors.
556     *
557     * @param that the vector multiplier.
558     * @return <code>this x that</code>
559     * @throws DimensionException if
560     * <code>(that.getDimension() != this.getDimension())</code>
561     * @see <a href="http://en.wikipedia.org/wiki/Cross_product">
562     * Wikipedia: Cross Product</a>
563     */
564    @SuppressWarnings({"unchecked", "rawtypes"})
565    @Override
566    public ParameterVector cross(Vector that) {
567
568        if (that.getDimension() != this.getDimension())
569            throw new DimensionException();
570
571        //      Convert input vector to a Float64Vector.
572        Float64Vector thatData = toFloat64Vector(that, null);
573
574        Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit());
575
576        ParameterVector V = newInstance(unit);
577        V._data = this._data.cross(thatData);
578
579        return V;
580    }
581
582    /**
583     * Returns this vector with each element divided by the specified divisor.
584     *
585     * @param that the divisor.
586     * @return <code>this / that</code>.
587     */
588    public ParameterVector<?> divide(Parameter<?> that) {
589        return times(that.inverse());
590    }
591
592    /**
593     * Returns this vector converted to a unit vector by dividing all the vector's
594     * elements by the length ({@link #norm}) of this vector.
595     *
596     * @return This vector converted to a unit vector by dividing all the vector's
597     * elements by the length of this vector.
598     */
599    @SuppressWarnings("unchecked")
600    public ParameterVector<Dimensionless> toUnitVector() {
601        double magnitude = this.normValue();
602        if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude - 1) <= Parameter.EPS)
603            return (ParameterVector<Dimensionless>) this;
604        ParameterVector<Dimensionless> V = newInstance(Dimensionless.UNIT);
605        V._data = this._data.times(1.0 / magnitude);
606        return V;
607    }
608
609    /**
610     * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated}
611     * by the calling thread (possibly on the stack).
612     *
613     * @return an identical and independent copy of this vector.
614     */
615    @Override
616    public ParameterVector<Q> copy() {
617        return copyOf(this);
618    }
619
620    /**
621     * Returns the unit in which the {@link #getValue values} in this vector are stated
622     * in.
623     */
624    @Override
625    public Unit<Q> getUnit() {
626        return _unit;
627    }
628
629    /**
630     * Returns the equivalent to this vector but stated in the specified unit.
631     *
632     * @param unit the unit of the vector to be returned.
633     * @return a vector equivalent to this vector but stated in the specified unit.
634     * @throws ConversionException if the current model does not allows for conversion to
635     * the specified unit.
636     */
637    @SuppressWarnings("unchecked")
638    @Override
639    public <R extends Quantity> ParameterVector<R> to(Unit<R> unit) {
640        if ((_unit == unit) || this._unit.equals(unit))
641            return (ParameterVector<R>) this;
642
643        StackContext.enter();
644        try {
645            UnitConverter cvtr = Parameter.converterOf(_unit, unit);
646            if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
647                ParameterVector<R> result = (ParameterVector<R>) copyOf(this);
648                result._unit = unit;
649                return StackContext.outerCopy((ParameterVector<R>) result);
650            }
651
652            FastTable<Float64> valueList = FastTable.newInstance();
653            int size = _data.getDimension();
654            for (int i = 0; i < size; ++i) {
655                double value = cvtr.convert(_data.getValue(i));
656                valueList.add(Float64.valueOf(value));
657            }
658
659            ParameterVector<R> result = newInstance(unit);
660            result._data = Float64Vector.valueOf(valueList);
661
662            return StackContext.outerCopy(result);
663        } finally {
664            StackContext.exit();
665        }
666    }
667
668    /**
669     * Casts this ParameterVector to a parameterized unit of specified nature or throw a
670     * <code>ClassCastException</code> if the dimension of the specified quantity and this
671     * parameter's unit dimension do not match.
672     *
673     * @param type the quantity class identifying the nature of the unit.
674     * @param <T>  The quantity or type of the new unit
675     * @return this ParameterVector parameterized with the specified type.
676     * @throws ClassCastException if the dimension of this parameter's unit is different
677     * from the specified quantity dimension.
678     * @throws UnsupportedOperationException if the specified quantity class does not have
679     * a public static field named "UNIT" holding the standard unit for the quantity.
680     */
681    @SuppressWarnings("unchecked")
682    public <T extends Quantity> ParameterVector<T> asType(Class<T> type) throws ClassCastException {
683        @SuppressWarnings("unused")
684        Unit<T> u = _unit.asType(type); //      If no exception is thrown, the cast is valid.
685        return (ParameterVector<T>) this;
686    }
687
688    /**
689     * Returns the values stored in this vector, stated in this vector's
690     * {@link #getUnit unit}, as a Float64Vector.
691     *
692     * @return The values stored in this vector, stated in this vector's unit.
693     */
694    public Float64Vector toFloat64Vector() {
695        return _data;
696    }
697
698    /**
699     * Compares this ParameterVector against the specified object for strict equality
700     * (same values and same units).
701     *
702     * @param obj the object to compare with.
703     * @return <code>true</code> if this vector is identical to that vector;
704     * <code>false</code> otherwise.
705     */
706    @Override
707    public boolean equals(Object obj) {
708        if (this == obj)
709            return true;
710        if ((obj == null) || (obj.getClass() != this.getClass()))
711            return false;
712
713        ParameterVector<?> that = (ParameterVector<?>) obj;
714        if (!this._data.equals(that._data))
715            return false;
716
717        return this._unit.equals(that._unit);
718    }
719
720    /**
721     * Returns the hash code for this parameter.
722     *
723     * @return the hash code value.
724     */
725    @Override
726    public int hashCode() {
727        int hash = 7;
728
729        int var_code = _unit.hashCode();
730        hash = hash * 31 + var_code;
731
732        var_code = _data.hashCode();
733        hash = hash * 31 + var_code;
734
735        return hash;
736    }
737
738    /**
739     * Convert a vector of Parameter objects to a Float64Vector stated in the specified
740     * units. If the units are null, no conversion occurs.
741     */
742    private static <Q extends Quantity> Float64Vector toFloat64Vector(Vector<Parameter<Q>> that, Unit<Q> unit) {
743
744        StackContext.enter();
745        try {
746            Float64Vector thatData;
747            Unit<?> oldUnit;
748            if (that instanceof ParameterVector) {
749                ParameterVector<Q> V = ((ParameterVector<Q>) that);
750                thatData = V.toFloat64Vector();
751                oldUnit = V.getUnit();
752
753            } else if (that instanceof Coordinate3D) {
754                Vector3D<Q> T = ((Coordinate3D<Q>) that).toVector3D();
755                if (!Length.UNIT.isCompatible(T.getUnit()))
756                    throw new ConversionException(RESOURCES.getString("incompatibleUnits").
757                            replace("<NAME/>", "input vector").replace("<TYPE/>", "length"));
758                oldUnit = T.getUnit();
759                thatData = T.toFloat64Vector();
760
761            } else {
762                ParameterVector<Q> V = valueOf(that);
763                thatData = V.toFloat64Vector();
764                oldUnit = V.getUnit();
765            }
766
767            //  Convert that vector's units to the specified units if necessary.
768            if (unit != null) {
769                if (!unit.equals(oldUnit)) {
770                    UnitConverter cvtr = Parameter.converterOf(oldUnit, unit);
771                    if (cvtr != UnitConverter.IDENTITY) {
772                        FastTable<Float64> valueList = FastTable.newInstance();
773                        int size = thatData.getDimension();
774                        for (int i = 0; i < size; ++i) {
775                            double value = cvtr.convert(thatData.getValue(i));
776                            valueList.add(Float64.valueOf(value));
777                        }
778                        thatData = Float64Vector.valueOf(valueList);
779                    }
780                }
781            }
782
783            return StackContext.outerCopy(thatData);
784        } finally {
785            StackContext.exit();
786        }
787    }
788
789    /**
790     * During serialization, this will write out the Float64Vector as a simple series of
791     * <code>double</code> values. This method is ONLY called by the Java Serialization
792     * mechanism and should not otherwise be used.
793     *
794     * @param out The output stream to serialized this object to.
795     * @throws java.io.IOException if the output stream could not be written to.
796     */
797    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
798
799        // Call the default write object method.
800        out.defaultWriteObject();
801
802        //      Write out the number of elements.
803        int size = _data.getDimension();
804        out.writeInt(size);
805
806        //      Write out the coordinate values.
807        for (int i = 0; i < size; ++i)
808            out.writeDouble(_data.getValue(i));
809
810    }
811
812    /**
813     * During de-serialization, this will handle the reconstruction of the Float64Vector.
814     * This method is ONLY called by the Java Serialization mechanism and should not
815     * otherwise be used.
816     *
817     * @param in The input stream to be de-serialized
818     * @throws java.io.IOException if there is a problem reading from the input stream.
819     * @throws ClassNotFoundException if the class could not be constructed.
820     */
821    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
822
823        // Call the default read object method.
824        in.defaultReadObject();
825
826        //      Read in the number of elements.
827        int size = in.readInt();
828
829        //      Read in the coordinate values.
830        FastTable<Float64> valueList = FastTable.newInstance();
831        for (int i = 0; i < size; ++i) {
832            double value = in.readDouble();
833            valueList.add(Float64.valueOf(value));
834        }
835
836        _data = Float64Vector.valueOf(valueList);
837
838        FastTable.recycle(valueList);
839    }
840
841    /**
842     * Holds the default XML representation. For example:
843     * <pre>
844     *  &lt;ParameterVector unit = "m"&gt;
845     *          &lt;Float64 value="1.0" /&gt;
846     *          &lt;Float64 value="0.0" /&gt;
847     *          &lt;Float64 value="2.0" /&gt;
848     *  &lt;/ParameterVector&gt;
849     * </pre>
850     */
851    @SuppressWarnings("rawtypes")
852    protected static final XMLFormat<ParameterVector> XML = new XMLFormat<ParameterVector>(ParameterVector.class) {
853
854        @Override
855        public ParameterVector<?> newInstance(Class<ParameterVector> cls, InputElement xml) throws XMLStreamException {
856
857            Unit<?> unit = Unit.valueOf(xml.getAttribute("unit"));
858            ParameterVector<?> V = ParameterVector.newInstance(unit);
859
860            FastTable<Float64> valueList = FastTable.newInstance();
861            while (xml.hasNext()) {
862                Float64 value = xml.getNext();
863                valueList.add(value);
864            }
865            V._data = Float64Vector.valueOf(valueList);
866
867            FastTable.recycle(valueList);
868
869            return V;
870        }
871
872        @Override
873        public void read(InputElement xml, ParameterVector V) throws XMLStreamException {
874            //  Nothing to do.
875        }
876
877        @Override
878        public void write(ParameterVector V, OutputElement xml) throws XMLStreamException {
879
880            xml.setAttribute("unit", V._unit.toString());
881            int size = V._data.getDimension();
882            for (int i = 0; i < size; ++i)
883                xml.add(V._data.get(i));
884
885        }
886    };
887
888    ///////////////////////
889    // Factory creation. //
890    ///////////////////////
891    protected ParameterVector() {
892    }
893
894    @SuppressWarnings("rawtypes")
895    private static final ObjectFactory<ParameterVector> FACTORY = new ObjectFactory<ParameterVector>() {
896        @Override
897        protected ParameterVector create() {
898            return new ParameterVector();
899        }
900    };
901
902    /**
903     * Return a new instance of the ParameterVector class with the specified unit. The
904     * <code>_data</code> value will be undefined and must be set before using the
905     * returned object for anything.
906     */
907    @SuppressWarnings("unchecked")
908    protected static <Q extends Quantity> ParameterVector<Q> newInstance(Unit<Q> unit) {
909        if (unit == null)
910            throw new NullPointerException("Unit can not be null.");
911        ParameterVector<Q> measure = FACTORY.object();
912        measure._unit = unit;
913        return measure;
914    }
915
916    @SuppressWarnings("unchecked")
917    private static <Q extends Quantity> ParameterVector<Q> copyOf(ParameterVector<Q> original) {
918        ParameterVector<Q> measure = FACTORY.object();
919        measure._unit = original._unit;
920        measure._data = original._data.copy();
921        return measure;
922    }
923
924    /**
925     * Tests the methods in this class.
926     *
927     * @param args the command-line arguments
928     */
929    public static void main(String args[]) {
930        System.out.println("Testing ParameterVector:  test = result [correct result]");
931
932        ParameterVector<Length> v1 = ParameterVector.valueOf(1, 2, 3, NonSI.FOOT);
933        System.out.println("v1 = " + v1);
934        System.out.println("  converted to m       = " + v1.to(SI.METER) + " [{0.3048 m, 0.6096 m, 0.9144 m}]");
935        System.out.println("  v1.norm()            = " + v1.norm() + " [3.74165738677394 ft]");
936        System.out.println("  v1.opposite()        = " + v1.opposite() + " [{-1.0 ft, -2.0 ft, -3.0 ft}]");
937        System.out.println("  v1.toUnitVector()    = " + v1.toUnitVector() + " [{0.267261241912424 , 0.534522483824849 , 0.801783725737273 }]");
938
939        Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH);
940        System.out.println("point = " + point);
941        System.out.println("  v1 + point           = " + v1.plus(point) + " [{3.0 ft, 4.0 ft, 5.0 ft}]");
942        System.out.println("  v1 - point           = " + v1.minus(point) + " [{-1.0 ft, 0.0 ft, 1.0 ft}]");
943        System.out.println("  v1 * 2               = " + v1.times(2) + " [{2.0 ft, 4.0 ft, 6.0 ft}]");
944
945        ParameterVector<?> areaVector = (ParameterVector<?>) v1.times(point);
946        System.out.println("  v1 * point           = " + areaVector);
947        System.out.println("  converted to ft²     = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 4.0 ft², 6.0 ft²}]");
948
949        ParameterVector<Length> v2 = ParameterVector.valueOf(1, 1, 1, SI.METER);
950        ParameterVector<?> v1xv2 = (ParameterVector<?>) v1.cross(v2);
951        System.out.println("v2 = " + v2);
952        System.out.println("  v1 + v2 = " + v1.plus(v2) + " [{4.28083989501312 ft, 5.28083989501312 ft, 6.28083989501312 ft}]");
953        System.out.println("  v1 - v2 = " + v1.minus(v2) + " [{-2.28083989501312 ft, -1.28083989501312 ft, -0.280839895013123 ft}]");
954        System.out.println("  v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [19.6850393700787 ft²]");
955        System.out.println("  v1.cross(v2) = " + v1xv2.to(NonSI.FOOT.pow(2)) + " [{-3.28083989501312 ft^2, 6.56167979002625 ft^2, -3.28083989501312 ft^2}]");
956        System.out.println("  v1.angle(v2) = " + v1.angle(v2).to(NonSI.DEGREE_ANGLE) + " [73.6090476746643 deg]");
957
958        //      Write out XML data.
959        try {
960            System.out.println();
961
962            // Creates some useful aliases for class names.
963            javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding();
964            binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64");
965
966            javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out);
967            writer.setIndentation("    ");
968            writer.setBinding(binding);
969            writer.write(v1, "ParameterVector", ParameterVector.class);
970            writer.flush();
971
972            System.out.println();
973        } catch (Exception e) {
974            e.printStackTrace();
975        }
976    }
977}