View Javadoc
1   package org.djunits.value;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.fail;
5   
6   import java.lang.reflect.Array;
7   import java.lang.reflect.Constructor;
8   import java.lang.reflect.Field;
9   import java.lang.reflect.InvocationTargetException;
10  import java.lang.reflect.Method;
11  import java.util.ArrayList;
12  import java.util.Arrays;
13  import java.util.List;
14  import java.util.SortedMap;
15  import java.util.TreeMap;
16  
17  import org.djunits.unit.UNITS;
18  import org.djunits.unit.Unit;
19  import org.djunits.unit.unitsystem.UnitSystem;
20  import org.djunits.util.ClassUtil;
21  import org.djunits.value.vdouble.scalar.AbstractDoubleScalar;
22  import org.djunits.value.vdouble.scalar.Area;
23  import org.djunits.value.vdouble.scalar.DoubleScalar;
24  import org.djunits.value.vdouble.scalar.Length;
25  import org.djunits.value.vdouble.vector.AbstractDoubleVector;
26  import org.djunits.value.vdouble.vector.DoubleVectorInterface;
27  import org.djunits.value.vdouble.vector.MutableDoubleVectorInterface;
28  import org.djunits.value.vfloat.scalar.AbstractFloatScalar;
29  import org.djunits.value.vfloat.scalar.FloatScalar;
30  import org.djunits.value.vfloat.vector.AbstractFloatVector;
31  import org.djunits.value.vfloat.vector.FloatVectorInterface;
32  import org.djunits.value.vfloat.vector.MutableFloatVectorInterface;
33  import org.junit.Assert;
34  import org.junit.Test;
35  
36  /**
37   * Find all various methods and prove their correctness.
38   * <p>
39   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
40   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
41   * </p>
42   * $LastChangedDate: 2015-10-04 13:58:23 +0200 (Sun, 04 Oct 2015) $, @version $Revision: 84 $, by $Author: averbraeck $, initial
43   * version Sep 14, 2015 <br>
44   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
45   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
46   * @param <TypedDoubleVectorAbs> Type of the object to perform the test on
47   */
48  public class VectorOperationsTest<TypedDoubleVectorAbs> implements UNITS
49  {
50      /** The classes that are absolute (name = class name). */
51      public static final String[] CLASSNAMES_ABS = new String[] { "AbsoluteTemperature", "Direction", "Position", "Time" };
52  
53      /** The relative classes that mirror the absolute ones (name = class name). */
54      public static final String[] CLASSNAMES_ABS_REL = new String[] { "Temperature", "Angle", "Length", "Duration" };
55  
56      /** The classes that are just relative (name = class name). */
57      public static final String[] CLASSNAMES_REL = new String[] { "Angle", "Acceleration", "AngleSolid", "Area", "Density",
58              "Dimensionless", "Duration", "ElectricalCharge", "ElectricalCurrent", "ElectricalPotential", "ElectricalResistance",
59              "Energy", "FlowMass", "FlowVolume", "Force", "Frequency", "Length", "LinearDensity", "Mass", "Power", "Pressure",
60              "Speed", "Temperature", "Torque", "Volume" };
61  
62      /** The money classes that are just relative (name = class name); these classes don't have an si field. */
63      public static final String[] CLASSNAMES_MONEY = new String[] { "Money", "MoneyPerArea", "MoneyPerEnergy", "MoneyPerLength",
64              "MoneyPerMass", "MoneyPerDuration", "MoneyPerVolume" };
65  
66      /**
67       * Perform many tests on the double and float vector types.
68       * @throws IllegalAccessException on class or method resolving error
69       * @throws InstantiationException on class or method resolving error
70       * @throws NoSuchMethodException on class or method resolving error
71       * @throws InvocationTargetException on class or method resolving error
72       * @throws NoSuchFieldException on class or method resolving error
73       * @throws ClassNotFoundException on reflection error
74       * @throws IllegalArgumentException on reflection error
75       * @throws SecurityException on reflection error
76       * @throws ValueException when index out of range
77       */
78      @SuppressWarnings("static-method")
79      @Test
80      public final void vectorOperationsTest()
81              throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
82              NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException, ValueException
83      {
84          doubleOrFloatScalarOperationsTest(true); // Double precision versions
85          doubleOrFloatScalarOperationsTest(false); // Float versions
86      }
87  
88      /**
89       * Perform many tests on vector types.
90       * @param doubleType boolean; if true; perform tests on DoubleScalar types; if false; perform tests on FloatScalar types
91       * @throws NoSuchFieldException on class or method resolving error
92       * @throws InvocationTargetException on class or method resolving error
93       * @throws IllegalAccessException on class or method resolving error
94       * @throws InstantiationException on class or method resolving error
95       * @throws NoSuchMethodException on class or method resolving error
96       * @throws ClassNotFoundException on reflection error
97       * @throws IllegalArgumentException on reflection error
98       * @throws SecurityException on reflection error
99       * @throws ValueException when index out of range
100      */
101     private void doubleOrFloatScalarOperationsTest(final boolean doubleType)
102             throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
103             NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException, ValueException
104     {
105         final String upperVectorType = "Vector";
106         final String floatPrefix = doubleType ? "" : "Float";
107         String doubleOrFloat = doubleType ? "double" : "float";
108         for (boolean mutable : new boolean[] { false, true })
109         {
110             for (StorageType storageType : StorageType.values())
111             {
112                 // get the interfaces such as org.djunits.value.vdouble.vector.Time
113                 for (int i = 0; i < CLASSNAMES_ABS.length; i++)
114                 {
115                     String vectorNameAbs = CLASSNAMES_ABS[i];
116                     Class<?> vectorClassAbs = null;
117                     String classNameAbs = "org.djunits.value.v" + doubleOrFloat + ".vector." + (mutable ? "Mutable" : "")
118                             + floatPrefix + vectorNameAbs + upperVectorType;
119                     System.out.println("Looking up class " + classNameAbs);
120                     vectorClassAbs = Class.forName(classNameAbs);
121                     Class<?> vectorClassRel = null;
122 
123                     String vectorNameRel = CLASSNAMES_ABS_REL[i];
124                     String classNameRel = "org.djunits.value.v" + doubleOrFloat + ".vector." + (mutable ? "Mutable" : "")
125                             + floatPrefix + vectorNameRel + upperVectorType;
126                     vectorClassRel = Class.forName(classNameRel);
127 
128                     testMethods(vectorClassAbs, true, doubleType, storageType, mutable);
129                     testMethods(vectorClassRel, false, doubleType, storageType, mutable);
130                     // testAbsRelConversion(vectorClass, true, doubleType, StorageType.DENSE);
131                     // testAbsRelConversion(vectorClass, true, doubleType, StorageType.SPARSE);
132                 }
133                 // get the interfaces such as org.djunits.value.vXXXX.vector.Area
134                 for (String vectorName : CLASSNAMES_REL)
135                 {
136                     String vectorClassName = (doubleType ? "" : "Float") + vectorName;
137                     String fullClassName = "org.djunits.value.v" + doubleOrFloat + ".vector." + (mutable ? "Mutable" : "")
138                             + vectorClassName + "Vector";
139                     Class<?> vectorClass = null;
140                     vectorClass = Class.forName(fullClassName);
141                     testMethods(vectorClass, false, doubleType, storageType, mutable);
142                 }
143                 // get the interfaces such as org.djunits.value.vXXXX.scalar.MoneyPerArea
144                 for (String vectorName : CLASSNAMES_MONEY)
145                 {
146                     String vectorClassName = doubleType ? vectorName : "Float" + vectorName;
147                     String fullClassName = "org.djunits.value.v" + doubleOrFloat + ".vector." + (mutable ? "Mutable" : "")
148                             + vectorClassName + "Vector";
149                     Class<?> vectorClass = null;
150                     vectorClass = Class.forName(fullClassName);
151                     testMethods(vectorClass, false, doubleType, storageType, mutable);
152                 }
153             }
154         }
155     }
156 
157     /**
158      * Find the methods defined in the class itself (not in a superclass) called multiplyBy or divideBy and test the method.
159      * Also test the Unary methods of the class.
160      * @param vectorClassAbsRel class to test
161      * @param isAbs boolean; if true; the scalarClassAbsRel must be aAsolute; if false; the scalarClassAbsRel must be Relative
162      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false perform tests on FloatScalar
163      * @param storageType StorageType; DENSE or SPARSE
164      * @param mutable boolean; if true; the vectorClass should be mutable; if false; the vectorClass should not be mutable
165      * @throws InvocationTargetException on class or method resolving error
166      * @throws IllegalAccessException on class or method resolving error
167      * @throws InstantiationException on class or method resolving error
168      * @throws NoSuchMethodException on class or method resolving error
169      * @throws NoSuchFieldException on class or method resolving error
170      * @throws ClassNotFoundException on reflection error
171      * @throws ValueException whhen index out of range
172      */
173     private void testMethods(final Class<?> vectorClassAbsRel, final boolean isAbs, final boolean doubleType,
174             final StorageType storageType, final boolean mutable) throws NoSuchMethodException, InstantiationException,
175             IllegalAccessException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException, ValueException
176     {
177         // System.out.print(listMethods(vectorClassAbsRel, "multiplyBy", "\t"));
178         for (Method method : vectorClassAbsRel.getMethods())
179         {
180             // System.out.println("Method name is " + method.getName());
181             if (method.getName().equals("multiplyBy"))
182             {
183                 testMultiplyByOrDivideByMethod(vectorClassAbsRel, method, true, doubleType, isAbs, storageType);
184             }
185             else if (method.getName().equals("divideBy"))
186             {
187                 testMultiplyByOrDivideByMethod(vectorClassAbsRel, method, false, doubleType, isAbs, storageType);
188             }
189         }
190         testConstructors(vectorClassAbsRel, isAbs, doubleType, mutable, storageType);
191         testGet(vectorClassAbsRel, isAbs, doubleType, mutable, storageType);
192         testUnaryMethods(vectorClassAbsRel, isAbs, doubleType, mutable, storageType);
193         testInterpolateMethod(vectorClassAbsRel, isAbs, doubleType, storageType);
194     }
195 
196     /**
197      * Test a multiplication method for a Relative vector. Note: filter out the method that multiplies by a constant...
198      * @param vectorClass Class&lt;?&gt;; the Relative class for the multiplication, e.g. Length
199      * @param method the method 'multiplyBy' for that class
200      * @param multiply boolean; if true; test a multiplyBy method; if false; test a divideBy method
201      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false; perform tests on FloatScalar
202      * @param abs boolean; if true; the vector class is absolute; if false; the vector class is relative
203      * @param storageType StorageType; DENSE or SPARSE
204      * @throws NoSuchMethodException on class or method resolving error
205      * @throws InvocationTargetException on class or method resolving error
206      * @throws IllegalAccessException on class or method resolving error
207      * @throws InstantiationException on class or method resolving error
208      * @throws NoSuchFieldException on class or method resolving error
209      * @throws ClassNotFoundException on reflection error
210      * @throws ValueException on reflection error
211      * @throws IllegalArgumentException on reflection error
212      * @throws SecurityException when index out of range
213      */
214     private void testMultiplyByOrDivideByMethod(final Class<?> vectorClass, final Method method, final boolean multiply,
215             final boolean doubleType, final boolean abs, final StorageType storageType)
216             throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
217             NoSuchFieldException, ClassNotFoundException, SecurityException, IllegalArgumentException, ValueException
218     {
219         // System.out.println(method.getName() + paramsToString(method.getParameterTypes()));
220         Class<?>[] parTypes = method.getParameterTypes();
221         if (parTypes.length != 1)
222         {
223             fail("DoubleScalar class " + vectorClass.getName() + "." + method.getName() + "() has " + parTypes.length
224                     + " parameters, <> 1");
225         }
226         Class<?> parameterClass = parTypes[0];
227         if (parameterClass.toString().equals("double") || parameterClass.toString().equals("float"))
228         {
229             // Tested elsewhere.
230             return;
231         }
232         // FIXME: multiplyBy and divideBy are currently only available for a non mutable argument.
233         // Next if statement is always taken.
234         // It is quite possible that multiplyBy will be restricted to Dimensionless vector arguments.
235         if (!vectorClass.isAssignableFrom(parameterClass))
236         {
237             return;
238         }
239 
240         Class<?> returnClass = method.getReturnType();
241         if (!vectorClass.isAssignableFrom(returnClass))
242         {
243             Assert.fail("DoubleScalar class " + vectorClass.getName()
244                     + ".multiplyBy() has return type with incompatible class: " + returnClass.getName());
245         }
246 
247         // get the SI coefficients of the unit classes, scalar type, parameter type and return type
248         String returnSI = getCoefficients(getUnitClass(returnClass));
249         String scalarSI = getCoefficients(getUnitClass(vectorClass));
250         String paramSI = getCoefficients(getUnitClass(parameterClass));
251         // print what we just have found
252         System.out.println(vectorClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + "."
253                 + (multiply ? "multiplyBy" : "divideBy") + "("
254                 + parameterClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + ") => "
255                 + returnClass.getName().replaceFirst("org.djunits.value.vdouble.scalar.", "") + ": " + scalarSI
256                 + (multiply ? " * " : " : ") + paramSI + " => " + returnSI);
257 
258         Constructor<?> constructor = vectorClass.getConstructor(double.class, getUnitClass(vectorClass));
259         if (doubleType)
260         {
261             DoubleScalar.Rel<?> left =
262                     (DoubleScalar.Rel<?>) constructor.newInstance(123d, getSIUnitInstance(getUnitClass(vectorClass)));
263             // System.out.println("constructed left: " + left);
264             constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
265             DoubleScalar.Rel<?> right =
266                     (DoubleScalar.Rel<?>) constructor.newInstance(456d, getSIUnitInstance(getUnitClass(parameterClass)));
267             // System.out.println("constructed right: " + right);
268             double expectedValue = multiply ? 123d * 456 : 123d / 456;
269 
270             if (multiply)
271             {
272                 Method multiplyMethod = vectorClass.getDeclaredMethod("multiplyBy", new Class[] { parameterClass });
273                 Object result = multiplyMethod.invoke(left, right);
274                 double resultSI = ((DoubleScalar.Rel<?>) result).si;
275                 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
276             }
277             else
278             {
279                 Method divideMethod = vectorClass.getDeclaredMethod("divideBy", new Class[] { parameterClass });
280                 Object result = divideMethod.invoke(left, right);
281                 double resultSI = ((DoubleScalar.Rel<?>) result).si;
282                 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
283             }
284             DoubleScalar.Rel<?> result = multiply ? DoubleScalar.multiply(left, right) : DoubleScalar.divide(left, right);
285             // System.out.println("result is " + result);
286             String resultCoefficients = result.getUnit().getSICoefficientsString();
287             assertEquals("SI coefficients of result should match expected SI coefficients", resultCoefficients, returnSI);
288         }
289         else
290         {
291             FloatScalar.Rel<?> left =
292                     (FloatScalar.Rel<?>) constructor.newInstance(123f, getSIUnitInstance(getUnitClass(vectorClass)));
293             // System.out.println("constructed left: " + left);
294             constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
295             FloatScalar.Rel<?> right =
296                     (FloatScalar.Rel<?>) constructor.newInstance(456f, getSIUnitInstance(getUnitClass(parameterClass)));
297             // System.out.println("constructed right: " + right);
298             float expectedValue = multiply ? 123f * 456 : 123f / 456;
299 
300             if (multiply)
301             {
302                 Method multiplyMethod = vectorClass.getDeclaredMethod("multiplyBy", new Class[] { parameterClass });
303                 Object result = multiplyMethod.invoke(left, right);
304                 double resultSI = ((FloatScalar.Rel<?>) result).si;
305                 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
306             }
307             else
308             {
309                 Method divideMethod = vectorClass.getDeclaredMethod("divideBy", new Class[] { parameterClass });
310                 Object result = divideMethod.invoke(left, right);
311                 float resultSI = ((FloatScalar.Rel<?>) result).si;
312                 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
313             }
314             FloatScalar.Rel<?> result = multiply ? FloatScalar.multiply(left, right) : FloatScalar.divide(left, right);
315             // System.out.println("result is " + result);
316             String resultCoefficients = result.getUnit().getSICoefficientsString();
317             assertEquals("SI coefficients of result should match expected SI coefficients", resultCoefficients, returnSI);
318         }
319     }
320 
321     /**
322      * Obtain the SI coefficient string of a DJUNITS class.
323      * @param clas Class&lt;?&gt;; the DJUNITS class
324      * @return String
325      * @throws IllegalAccessException on class or method resolving error
326      * @throws NoSuchFieldException on class or method resolving error
327      */
328     private String getCoefficients(final Class<?> clas) throws IllegalAccessException, NoSuchFieldException
329     {
330         if (clas.getName().contains("Money"))
331         {
332             // get any static field of the type itself
333             for (Field field : clas.getDeclaredFields())
334             {
335                 if (field.getType().equals(clas))
336                 {
337                     return ((Unit<?>) field.get(clas)).getSICoefficientsString();
338                 }
339             }
340             return "1";
341         }
342         Field si = clas.getField("SI");
343         Unit<?> u = ((Unit<?>) si.get(clas));
344         String r = u.getSICoefficientsString();
345         return r;
346         // return ((Unit<?>) si.get(clas)).getSICoefficientsString();
347     }
348 
349     /**
350      * Obtain the SI coefficient string of a DJUNITS class.
351      * @param clas Class&lt;?&gt;; the DJUNITS class
352      * @return String
353      * @throws NoSuchFieldException on class or method resolving error
354      * @throws IllegalAccessException on class or method resolving error
355      */
356     private Unit<?> getSIUnitInstance(final Class<?> clas) throws NoSuchFieldException, IllegalAccessException
357     {
358         if (clas.getName().contains("Money"))
359         {
360             // get any static field of the type itself
361             for (Field field : clas.getDeclaredFields())
362             {
363                 if (field.getType().equals(clas))
364                 {
365                     return ((Unit<?>) field.get(clas));
366                 }
367             }
368             return null;
369         }
370         // TODO: Check for BASE field in absolutes, SI field in relatives
371         Field si = null;
372         try
373         {
374             si = clas.getField("SI");
375         }
376         catch (NoSuchFieldException nsfe)
377         {
378             si = clas.getField("BASE");
379         }
380         return ((Unit<?>) si.get(clas));
381     }
382 
383     /**
384      * Get the unit of a Scalar class by looking at the constructor with two arguments -- the second argument is the unit type.
385      * @param vectorClass the class to find the unit for
386      * @return the unit class for this scalar class
387      */
388     private Class<?> getUnitClass(final Class<?> vectorClass)
389     {
390         Constructor<?>[] constructors = vectorClass.getConstructors();
391         for (Constructor<?> constructor : constructors)
392         {
393             Class<?>[] parTypes = constructor.getParameterTypes();
394             // System.out.print("Found constructor " + vectorClass + "(");
395             // String separator = "";
396             // for (Class<?> parType : parTypes)
397             // {
398             // System.out.print(separator + parType);
399             // separator = ", ";
400             // }
401             // System.out.println(")");
402             if (parTypes.length >= 2 && Unit.class.isAssignableFrom(parTypes[1]))
403             {
404                 return parTypes[1];
405             }
406         }
407         Assert.fail("Could not find constructor with a unit as 2nd argument for Vector class " + vectorClass.getName());
408         return null;
409     }
410 
411     /**
412      * Verify the Absoluteness, Relativeness, and SI values of a DoubleVector or FloatVector.
413      * @param abs boolean; expected Absolute- or Relative-ness
414      * @param doubleType boolean; if true; double is expected; if false; float is expected
415      * @param storageType StorageType; DENSE or SPARSE
416      * @param got the (DoubleVector?) object
417      * @param expected double[] or float[] with expected values
418      * @param precision double; maximum error of the results
419      * @throws ValueException when index out of range
420      */
421     private void verifyAbsRelPrecisionAndValues(final boolean abs, final boolean doubleType, final StorageType storageType,
422             final Object got, final Object expected, final double precision) throws ValueException
423     {
424         int size = doubleType ? ((double[]) expected).length : ((float[]) expected).length;
425         int refSize = doubleType ? ((double[]) expected).length : ((float[]) expected).length;
426         assertEquals("size of resulting array", refSize, size);
427         for (int i = 0; i < size; i++)
428         {
429             double result = verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, got, i);
430             assertEquals("value check", doubleType ? ((double[]) expected)[i] : ((float[]) expected)[i], result, precision);
431         }
432     }
433 
434     /**
435      * Verify the Absoluteness or Relativeness of a DoubleScalar and return the SI value.
436      * @param abs boolean; expected Absolute- or Relativeness
437      * @param doubleType boolean; if true; double is expected; if false; float is expected
438      * @param storageType StorageType; the expected StorageType (DENSE or SPARSE)
439      * @param o the (DoubleScalar?) object
440      * @param index int; the index of the value to return
441      * @return double; the SI value
442      * @throws ValueException when index out of range
443      */
444     private double verifyAbsRelPrecisionAndExtractSI(final boolean abs, final boolean doubleType, final StorageType storageType,
445             final Object o, final int index) throws ValueException
446     {
447         double result = Double.NaN;
448         if (doubleType)
449         {
450             if (!(o instanceof DoubleVectorInterface))
451             {
452                 fail("object is not a DoubleVector");
453             }
454             AbstractDoubleVector<?, ?> dv = (AbstractDoubleVector<?, ?>) o;
455             result = dv.getSI(index);
456             assertEquals("StorageType", storageType, dv.getStorageType());
457         }
458         else
459         {
460             if (!(o instanceof FloatVectorInterface))
461             {
462                 fail("object is not a FloatVector");
463             }
464             AbstractFloatVector<?, ?> fv = (AbstractFloatVector<?, ?>) o;
465             result = fv.getSI(index);
466             assertEquals("StorageType", storageType, fv.getStorageType());
467         }
468         if (o instanceof Absolute)
469         {
470             if (!abs)
471             {
472                 fail("Result should have been Absolute");
473             }
474         }
475         else if (o instanceof Relative)
476         {
477             if (abs)
478             {
479                 fail("Result should have been Relative");
480             }
481         }
482         else
483         {
484             fail("Result is neither Absolute, nor Relative");
485         }
486         return result;
487     }
488 
489     /**
490      * @param vectorClass the class to test
491      * @param abs boolean; if true; the absolute version is tested; if false; the relative version is tested
492      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false; perform tests on FloatScalar
493      * @param mutable boolean; if true; perform test for mutable version; if false; perform test for non-mutable version
494      * @param storageType StorageType; Dense or Sparse
495      * @throws NoSuchMethodException on class or method resolving error
496      * @throws InstantiationException on class or method resolving error
497      * @throws IllegalAccessException on class or method resolving error
498      * @throws InvocationTargetException on class or method resolving error
499      * @throws NoSuchFieldException on class or method resolving error
500      * @throws ClassNotFoundException on class or method resolving error
501      * @throws ValueException when index out of range
502      */
503     private void testConstructors(final Class<?> vectorClass, final boolean abs, final boolean doubleType,
504             final boolean mutable, final StorageType storageType) throws NoSuchMethodException, InstantiationException,
505             IllegalAccessException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException, ValueException
506     {
507         double[] doubleValue = { 1.23456, 2.34567, 3.45678 };
508         float[] floatValue = { 1.23456f, 2.34567f, 3.45678f };
509         Object value = doubleType ? doubleValue : floatValue;
510         findAndTestConstructor(vectorClass, new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType },
511                 abs, doubleType, storageType, value);
512         // What is the corresponding Scalar type?
513         String scalarClassName = vectorClass.getName();
514         // System.out.println("name is " + scalarClassName);
515         scalarClassName = scalarClassName.replaceFirst("Vector", "");
516         // System.out.println("name is " + scalarClassName);
517         scalarClassName = scalarClassName.replaceFirst("vector", "scalar");
518         // System.out.println("name is " + scalarClassName);
519         scalarClassName = scalarClassName.replaceFirst("Mutable", "");
520         // System.out.println("name is " + scalarClassName);
521         Class<?> scalarClassAbsRel = Class.forName(scalarClassName);
522         // System.out.println("class is " + scalarClassAbsRel);
523         if (doubleType)
524         {
525             List<Double> list = new ArrayList<Double>();
526             for (int i = 0; i < doubleValue.length; i++)
527             {
528                 list.add(doubleValue[i]);
529             }
530             findAndTestConstructor(vectorClass,
531                     new Object[] { list, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, abs, doubleType,
532                     storageType, value);
533             // Construct a list of scalar objects
534             Constructor<?> constructor =
535                     scalarClassAbsRel.getConstructor(new Class<?>[] { double.class, getUnitClass(vectorClass) });
536             List<Object> objectList = new ArrayList<Object>();
537             for (Double d : list)
538             {
539                 objectList.add(constructor.newInstance(d, getSIUnitInstance(getUnitClass(vectorClass))));
540             }
541             findAndTestConstructor(vectorClass, new Object[] { objectList, storageType }, abs, doubleType, storageType, value);
542             // Construct an array of the correct scalar objects
543             Object[] objectArray = (Object[]) Array.newInstance(scalarClassAbsRel, objectList.size());
544             for (int i = 0; i < objectList.size(); i++)
545             {
546                 objectArray[i] = objectList.get(i);
547             }
548             findAndTestConstructor(vectorClass, new Object[] { objectArray, storageType }, abs, doubleType, storageType, value);
549             SortedMap<Integer, Object> map = new TreeMap<Integer, Object>();
550             for (int i = 0; i < objectList.size(); i++)
551             {
552                 map.put(i, objectList.get(i));
553             }
554             // System.out.println("int is assignable from Integer ? " + int.class.isAssignableFrom(Integer.class));
555             findAndTestConstructor(vectorClass, new Object[] { map, objectList.size(), storageType }, abs, doubleType,
556                     storageType, value);
557             map.clear();
558             for (int i = 0; i < doubleValue.length; i++)
559             {
560                 map.put(i, doubleValue[i]);
561             }
562             findAndTestConstructor(vectorClass,
563                     new Object[] { map, getSIUnitInstance(getUnitClass(vectorClass)), doubleValue.length, storageType }, abs,
564                     doubleType, storageType, value);
565         }
566         else
567         {
568             List<Float> list = new ArrayList<Float>();
569             for (int i = 0; i < floatValue.length; i++)
570             {
571                 list.add(floatValue[i]);
572             }
573             findAndTestConstructor(vectorClass,
574                     new Object[] { list, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, abs, doubleType,
575                     storageType, value);
576             // Construct a list of scalar objects
577             Constructor<?> constructor =
578                     scalarClassAbsRel.getConstructor(new Class<?>[] { double.class, getUnitClass(vectorClass) });
579             List<Object> objectList = new ArrayList<Object>();
580             for (Float f : list)
581             {
582                 objectList.add(constructor.newInstance(f, getSIUnitInstance(getUnitClass(vectorClass))));
583             }
584             findAndTestConstructor(vectorClass, new Object[] { objectList, storageType }, abs, doubleType, storageType, value);
585             // Construct an array of the correct scalar objects
586             Object[] objectArray = (Object[]) Array.newInstance(scalarClassAbsRel, objectList.size());
587             for (int i = 0; i < objectList.size(); i++)
588             {
589                 objectArray[i] = objectList.get(i);
590             }
591             findAndTestConstructor(vectorClass, new Object[] { objectArray, storageType }, abs, doubleType, storageType, value);
592             SortedMap<Integer, Object> map = new TreeMap<Integer, Object>();
593             for (int i = 0; i < objectList.size(); i++)
594             {
595                 map.put(i, objectList.get(i));
596             }
597             // System.out.println("int is assignable from Integer ? " + int.class.isAssignableFrom(Integer.class));
598             findAndTestConstructor(vectorClass, new Object[] { map, objectList.size(), storageType }, abs, doubleType,
599                     storageType, value);
600             map.clear();
601             for (int i = 0; i < floatValue.length; i++)
602             {
603                 map.put(i, floatValue[i]);
604             }
605             findAndTestConstructor(vectorClass,
606                     new Object[] { map, getSIUnitInstance(getUnitClass(vectorClass)), floatValue.length, storageType }, abs,
607                     doubleType, storageType, value);
608         }
609     }
610 
611     /**
612      * Return a string with the types of all types of a class array.
613      * @param params Class&lt;?&gt;[]; the class array
614      * @return String
615      */
616     private String paramsToString(final Class<?>[] params)
617     {
618         StringBuilder result = new StringBuilder();
619         result.append("(");
620         String separator = "";
621         for (Class<?> parType : params)
622         {
623             result.append(separator + parType);
624             separator = ", ";
625         }
626         result.append(")");
627         return result.toString();
628     }
629 
630     /**
631      * Find and execute a constructor and return the result.
632      * @param vectorClass Class&lt;?&gt;; the class to which the constructor belongs
633      * @param args Object[]; arguments to provide to the constructor
634      * @param doubleType boolean; if true; the args argument is array of double; of false; the args argument is array of float
635      * @return constructed object
636      * @throws NoSuchMethodException on reflection error
637      * @throws SecurityException on reflection error
638      * @throws InstantiationException on reflection error
639      * @throws IllegalAccessException on reflection error
640      * @throws IllegalArgumentException on reflection error
641      * @throws InvocationTargetException on reflection error
642      * @throws ValueException when index out of range
643      */
644     private Object findAndExecuteConstructor(final Class<?> vectorClass, final Object[] args, final boolean doubleType)
645             throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
646             IllegalArgumentException, InvocationTargetException, ValueException
647     {
648         Class<?>[] parameterTypes = new Class<?>[args.length];
649         for (int i = 0; i < args.length; i++)
650         {
651             Class<?> c = args[i].getClass();
652             if (c.isAssignableFrom(double[].class))
653             {
654                 c = double[].class;
655             }
656             else if (c.isAssignableFrom(float[].class))
657             {
658                 c = float[].class;
659             }
660             parameterTypes[i] = c;
661             // System.out.println("parameter type[" + i + "] is " + c);
662         }
663         Constructor<?> constructor = null;
664         for (Constructor<?> c : vectorClass.getConstructors())
665         {
666             // System.out.println("Found constructor for " + vectorClass + " " + paramsToString(c.getParameterTypes()));
667             Class<?>[] parTypes = c.getParameterTypes();
668             boolean compatible = parTypes.length == args.length;
669             for (int i = 0; i < parTypes.length; i++)
670             {
671                 Class<?> parType = parTypes[i];
672                 if (compatible && !parType.isAssignableFrom(parameterTypes[i])
673                         && (!(parType == int.class && parameterTypes[i] == Integer.class)))
674                 {
675                     compatible = false;
676                 }
677             }
678             if (compatible)
679             {
680                 // System.out.println(" MATCH");
681                 constructor = c;
682             }
683         }
684         // Constructor<?> constructor = vectorClass.getConstructor(parameterTypes);
685         if (null == constructor)
686         {
687             System.out.println("No suitable constructor for " + vectorClass + ":");
688             for (int i = 0; i < args.length; i++)
689             {
690                 System.out.println("\tparameter type[" + i + "] is " + args[i].getClass());
691             }
692             fail("Cannot find suitable constructor");
693         }
694         return constructor.newInstance(args);
695     }
696 
697     /**
698      * Find and execute a constructor and check the result.
699      * @param vectorClass Class&lt;?&gt;; the class to which the constructor belongs
700      * @param args Object[]; arguments to provide to the constructor
701      * @param abs boolean; if true; the result of the constructor is expected to be Absolute; if false; the result of the
702      *            constructor is expected to be relative
703      * @param doubleType boolean; if true; the args argument is array of double; of false; the args argument is array of float
704      * @param expectedStorageType StorageType; the expected Storage type (DENSE or SPARSE)
705      * @param expectedResult Object; either array of double, or array of float
706      * @throws NoSuchMethodException on class or method resolving error
707      * @throws SecurityException on class or method resolving error
708      * @throws InstantiationException on class or method resolving error
709      * @throws IllegalAccessException on class or method resolving error
710      * @throws IllegalArgumentException on class or method resolving error
711      * @throws InvocationTargetException on class or method resolving error
712      * @throws ValueException when index out of range
713      */
714     private void findAndTestConstructor(final Class<?> vectorClass, final Object[] args, final boolean abs,
715             final boolean doubleType, final StorageType expectedStorageType, final Object expectedResult)
716             throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
717             IllegalArgumentException, InvocationTargetException, ValueException
718     {
719         verifyAbsRelPrecisionAndValues(abs, doubleType, expectedStorageType,
720                 findAndExecuteConstructor(vectorClass, args, doubleType), expectedResult, 0.0001);
721     }
722 
723     /**
724      * Test the get method.
725      * @param vectorClass the class to test
726      * @param abs boolean; if true; the absolute version is tested; if false; the relative version is tested
727      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false; perform tests on FloatScalar
728      * @param mutable boolean; if true; perform test for mutable version; if false; perform test for non-mutable version
729      * @param storageType StorageType; Dense or Sparse
730      * @throws NoSuchMethodException on class or method resolving error
731      * @throws InstantiationException on class or method resolving error
732      * @throws IllegalAccessException on class or method resolving error
733      * @throws InvocationTargetException on class or method resolving error
734      * @throws NoSuchFieldException on class or method resolving error
735      * @throws ClassNotFoundException on class or method resolving error
736      * @throws ValueException when index out of range
737      */
738     private void testGet(final Class<?> vectorClass, final boolean abs, final boolean doubleType, final boolean mutable,
739             final StorageType storageType) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
740             InvocationTargetException, NoSuchFieldException, ClassNotFoundException, ValueException
741     {
742         double[] doubleValue = { 1.23456, 2.34567, 3.45678 };
743         float[] floatValue = { 1.23456f, 2.34567f, 3.45678f };
744         Object value = doubleType ? doubleValue : floatValue;
745         Object vector = findAndExecuteConstructor(vectorClass,
746                 new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
747         if (doubleType)
748         {
749             AbstractDoubleVector<?, ?> dv = (AbstractDoubleVector<?, ?>) vector;
750             for (int i = 0; i < doubleValue.length; i++)
751             {
752                 AbstractDoubleScalar<?, ?> ds = dv.get(i);
753                 double got = ds.getSI();
754                 assertEquals("get returns expected value", doubleValue[i], got, 0.0001);
755             }
756         }
757         else
758         {
759             AbstractFloatVector<?, ?> fv = (AbstractFloatVector<?, ?>) vector;
760             for (int i = 0; i < doubleValue.length; i++)
761             {
762                 AbstractFloatScalar<?, ?> fs = fv.get(i);
763                 float got = fs.getSI();
764                 assertEquals("get returns expected value", doubleValue[i], got, 0.0001);
765             }
766         }
767     }
768 
769     /**
770      * @param vectorClass the class to test
771      * @param abs abs or rel class
772      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false; perform tests on FloatScalar
773      * @param mutable boolean; if true; perform test for mutable version; if false; perform test for non-mutable version
774      * @param storageType StorageType; Dense or Sparse
775      * @throws NoSuchMethodException on class or method resolving error
776      * @throws InstantiationException on class or method resolving error
777      * @throws IllegalAccessException on class or method resolving error
778      * @throws InvocationTargetException on class or method resolving error
779      * @throws NoSuchFieldException on class or method resolving error
780      * @throws ClassNotFoundException on class or method resolving error
781      * @throws ValueException when index out of range
782      */
783     private void testUnaryMethods(final Class<?> vectorClass, final boolean abs, final boolean doubleType,
784             final boolean mutable, final StorageType storageType) throws NoSuchMethodException, InstantiationException,
785             IllegalAccessException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException, ValueException
786     {
787         double[] doubleValue = { 1.23456, -2.34567, 3.45678 };
788         float[] floatValue = { 1.23456f, -2.34567f, 3.45678f };
789         Object value = doubleType ? doubleValue : floatValue;
790         Object left = findAndExecuteConstructor(vectorClass,
791                 new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
792         Object result;
793         if (doubleType)
794         {
795             result = ((DoubleVectorInterface<?>) left).toSparse();
796             verifyAbsRelPrecisionAndValues(abs, doubleType, StorageType.SPARSE, result, value, 0.0001);
797             result = ((DoubleVectorInterface<?>) left).toDense();
798             verifyAbsRelPrecisionAndValues(abs, doubleType, StorageType.DENSE, result, value, 0.0001);
799             result = ((DoubleVectorInterface<?>) left).mutable();
800             verifyAbsRelPrecisionAndValues(abs, doubleType, storageType, result, value, 0.0001);
801             result = ((MutableDoubleVectorInterface<?>) result).immutable();
802             verifyAbsRelPrecisionAndValues(abs, doubleType, storageType, result, value, 0.0001);
803             if (abs)
804             {
805                 double[] thirdValue = new double[doubleValue.length];
806                 double[] twoThirdValue = new double[doubleValue.length];
807                 for (int i = 0; i < thirdValue.length; i++)
808                 {
809                     thirdValue[i] = doubleValue[i] / 3;
810                     twoThirdValue[i] = 2 * thirdValue[i];
811                 }
812                 // FIXME - Peter does not know how to write this with generics...
813                 // Does not work yet because mixed mutable immutable minus does not exist yet
814                 // Object right =
815                 // findAndExecuteConstructor(vectorClass, new Object[] { thirdValue,
816                 // getSIUnitInstance(getUnitClass(vectorClass)), storageType }, abs, doubleType);
817                 // System.out.println("left : " + left.getClass() + " right : " + right.getClass());
818                 // System.out.println(Arrays.toString(left.getClass().ClassUtil.resolveMethod(left.getClass(),
819                 // s()).replaceAll(" org", "\norg"));
820                 // System.out.println("super class " + right.getClass().getSuperclass());
821                 // Method minus = left.getClass().getMethod("minus", new Class<?>[] { right.getClass().getSuperclass() });
822                 // result = minus.invoke(left, right);
823                 // result = left.minus(right);
824                 // verifyAbsRelPrecisionAndValues(false, doubleType, storageType, result, twoThirdValue, 0.0001);
825             }
826         }
827         else
828         {
829             result = ((FloatVectorInterface<?>) left).toSparse();
830             verifyAbsRelPrecisionAndValues(abs, doubleType, StorageType.SPARSE, result, value, 0.0001);
831             result = ((FloatVectorInterface<?>) left).toDense();
832             verifyAbsRelPrecisionAndValues(abs, doubleType, StorageType.DENSE, result, value, 0.0001);
833             result = ((FloatVectorInterface<?>) left).mutable();
834             verifyAbsRelPrecisionAndValues(abs, doubleType, storageType, result, value, 0.0001);
835             result = ((MutableFloatVectorInterface<?>) result).immutable();
836             verifyAbsRelPrecisionAndValues(abs, doubleType, storageType, result, value, 0.0001);
837             if (abs)
838             {
839                 double[] thirdValue = new double[floatValue.length];
840                 double[] twoThirdValue = new double[floatValue.length];
841                 for (int i = 0; i < thirdValue.length; i++)
842                 {
843                     thirdValue[i] = floatValue[i] / 3;
844                     twoThirdValue[i] = 2 * thirdValue[i];
845                 }
846                 // FIXME - Peter does not know how to write this with generics...
847                 // Does not work yet because mixed mutable immutable minus does not exist yet
848                 // Object right =
849                 // findAndExecuteConstructor(vectorClass, new Object[] { thirdValue,
850                 // getSIUnitInstance(getUnitClass(vectorClass)), storageType }, abs, doubleType);
851                 // System.out.println("left : " + left.getClass() + " right : " + right.getClass());
852                 // System.out.println(Arrays.toString(left.getClass().getMethods()).replaceAll(" org", "\norg"));
853                 // System.out.println("super class " + right.getClass().getSuperclass());
854                 // Method minus = ClassUtil.resolveMethod(left.getClass(), "minus", new Class<?>[] {
855                 // right.getClass().getSuperclass() });
856                 // result = minus.invoke(left, right);
857                 // result = left.minus(right);
858                 // verifyAbsRelPrecisionAndValues(false, doubleType, storageType, result, twoThirdValue, 0.0001);
859             }
860         }
861 
862         if (mutable)
863         {
864             double doubleDifference = 42.42;
865             float floatDifference = 42.42f;
866             Class<?> argumentClass = doubleType ? double.class : float.class;
867             Method incrementBy = ClassUtil.resolveMethod(vectorClass, "incrementBy", new Class<?>[] { argumentClass });
868             incrementBy = ClassUtil.resolveMethod(vectorClass, "incrementBy", new Class<?>[] { argumentClass });
869             incrementBy.setAccessible(true);
870             // System.out.print(paramsToString(incrementBy.getParameterTypes()));
871             // System.out.println("type of value is " + value.getClass());
872             // System.out.println("type of difference is " + difference.getClass());
873             if (doubleType)
874             {
875                 result = incrementBy.invoke(left, new Object[] { doubleDifference });
876             }
877             else
878             {
879                 result = incrementBy.invoke(left, new Object[] { floatDifference });
880             }
881             for (int i = 0; i < doubleValue.length; i++)
882             {
883                 double resultElement = verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i);
884                 assertEquals("value check result",
885                         doubleType ? (doubleValue[i] + doubleDifference) : (floatValue[i] + floatDifference), resultElement,
886                         0.00001);
887                 // Check that original is also modified
888                 double originalElement = verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i);
889                 assertEquals("value check original",
890                         doubleType ? (doubleValue[i] + doubleDifference) : (floatValue[i] + floatDifference), originalElement,
891                         0.00001);
892             }
893             left = findAndExecuteConstructor(vectorClass,
894                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
895             Method decrementBy = ClassUtil.resolveMethod(vectorClass, "decrementBy", new Class<?>[] { argumentClass });
896             decrementBy.setAccessible(true);
897             if (doubleType)
898             {
899                 result = decrementBy.invoke(left, new Object[] { doubleDifference });
900             }
901             else
902             {
903                 result = decrementBy.invoke(left, new Object[] { floatDifference });
904             }
905             for (int i = 0; i < doubleValue.length; i++)
906             {
907                 double resultElement = verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i);
908                 assertEquals("value check",
909                         doubleType ? (doubleValue[i] - doubleDifference) : (floatValue[i] - floatDifference), resultElement,
910                         0.00001);
911                 // Check that original is also modified
912                 double originalElement = verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i);
913                 assertEquals("value check original",
914                         doubleType ? (doubleValue[i] - doubleDifference) : (floatValue[i] - floatDifference), originalElement,
915                         0.00001);
916             }
917 
918             left = findAndExecuteConstructor(vectorClass,
919                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
920             Method mathMethod = ClassUtil.resolveMethod(vectorClass, "ceil", new Class[] {});
921             mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
922             result = mathMethod.invoke(left);
923             for (int i = 0; i < doubleValue.length; i++)
924             {
925                 assertEquals("Result of operation",
926                         doubleType ? Math.ceil(doubleValue[i]) : ((float) Math.ceil(doubleValue[i])),
927                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
928                 // Check that original is also modified
929                 assertEquals("Result of operation",
930                         doubleType ? Math.ceil(doubleValue[i]) : ((float) Math.ceil(doubleValue[i])),
931                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
932             }
933 
934             left = findAndExecuteConstructor(vectorClass,
935                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
936             mathMethod = ClassUtil.resolveMethod(vectorClass, "floor", new Class[] {});
937             mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
938             result = mathMethod.invoke(left);
939             for (int i = 0; i < doubleValue.length; i++)
940             {
941                 assertEquals("Result of operation",
942                         doubleType ? Math.floor(doubleValue[i]) : ((float) Math.floor(doubleValue[i])),
943                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
944                 // Check that original is also modified
945                 assertEquals("Result of operation",
946                         doubleType ? Math.floor(doubleValue[i]) : ((float) Math.floor(doubleValue[i])),
947                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
948             }
949 
950             left = findAndExecuteConstructor(vectorClass,
951                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
952             mathMethod = ClassUtil.resolveMethod(vectorClass, "rint", new Class[] {});
953             mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
954             result = mathMethod.invoke(left);
955             for (int i = 0; i < doubleValue.length; i++)
956             {
957                 assertEquals("Result of operation",
958                         doubleType ? Math.rint(doubleValue[i]) : ((float) Math.rint(doubleValue[i])),
959                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
960                 // Check that original is also modified
961                 assertEquals("Result of operation",
962                         doubleType ? Math.rint(doubleValue[i]) : ((float) Math.rint(doubleValue[i])),
963                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
964             }
965 
966             left = findAndExecuteConstructor(vectorClass,
967                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
968             mathMethod = ClassUtil.resolveMethod(vectorClass, "round", new Class[] {});
969             mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
970             result = mathMethod.invoke(left);
971             for (int i = 0; i < doubleValue.length; i++)
972             {
973                 assertEquals("Result of operation",
974                         doubleType ? Math.round(doubleValue[i]) : ((float) Math.round(doubleValue[i])),
975                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
976                 // Check that original is also modified
977                 assertEquals("Result of operation",
978                         doubleType ? Math.round(doubleValue[i]) : ((float) Math.round(doubleValue[i])),
979                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
980             }
981 
982             if (!abs)
983             {
984                 left = findAndExecuteConstructor(vectorClass,
985                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
986                 mathMethod = ClassUtil.resolveMethod(vectorClass, "abs", new Class[] {});
987                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
988                 result = mathMethod.invoke(left);
989                 for (int i = 0; i < doubleValue.length; i++)
990                 {
991                     assertEquals("Result of operation",
992                             doubleType ? Math.abs(doubleValue[i]) : ((float) Math.abs(doubleValue[i])),
993                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
994                     // Check that original is also modified
995                     assertEquals("Result of operation",
996                             doubleType ? Math.abs(doubleValue[i]) : ((float) Math.abs(doubleValue[i])),
997                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
998                 }
999             }
1000 
1001             if (vectorClass.getName().contains("Dimensionless"))
1002             {
1003                 left = findAndExecuteConstructor(vectorClass,
1004                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1005                 mathMethod = ClassUtil.resolveMethod(vectorClass, "acos", new Class[] {});
1006                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1007                 result = mathMethod.invoke(left);
1008                 for (int i = 0; i < doubleValue.length; i++)
1009                 {
1010                     assertEquals("Result of operation",
1011                             doubleType ? Math.acos(doubleValue[i]) : ((float) Math.acos(doubleValue[i])),
1012                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1013                     // Check that original is also modified
1014                     assertEquals("Result of operation",
1015                             doubleType ? Math.acos(doubleValue[i]) : ((float) Math.acos(doubleValue[i])),
1016                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1017                 }
1018 
1019                 left = findAndExecuteConstructor(vectorClass,
1020                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1021                 mathMethod = ClassUtil.resolveMethod(vectorClass, "asin", new Class[] {});
1022                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1023                 result = mathMethod.invoke(left);
1024                 for (int i = 0; i < doubleValue.length; i++)
1025                 {
1026                     assertEquals("Result of operation",
1027                             doubleType ? Math.asin(doubleValue[i]) : ((float) Math.asin(doubleValue[i])),
1028                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1029                     // Check that original is also modified
1030                     assertEquals("Result of operation",
1031                             doubleType ? Math.asin(doubleValue[i]) : ((float) Math.asin(doubleValue[i])),
1032                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1033                 }
1034 
1035                 left = findAndExecuteConstructor(vectorClass,
1036                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1037                 mathMethod = ClassUtil.resolveMethod(vectorClass, "atan", new Class[] {});
1038                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1039                 result = mathMethod.invoke(left);
1040                 for (int i = 0; i < doubleValue.length; i++)
1041                 {
1042                     assertEquals("Result of operation",
1043                             doubleType ? Math.atan(doubleValue[i]) : ((float) Math.atan(doubleValue[i])),
1044                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1045                     // Check that original is also modified
1046                     assertEquals("Result of operation",
1047                             doubleType ? Math.atan(doubleValue[i]) : ((float) Math.atan(doubleValue[i])),
1048                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1049                 }
1050 
1051                 left = findAndExecuteConstructor(vectorClass,
1052                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1053                 mathMethod = ClassUtil.resolveMethod(vectorClass, "cbrt", new Class[] {});
1054                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1055                 result = mathMethod.invoke(left);
1056                 for (int i = 0; i < doubleValue.length; i++)
1057                 {
1058                     assertEquals("Result of operation",
1059                             doubleType ? Math.cbrt(doubleValue[i]) : ((float) Math.cbrt(doubleValue[i])),
1060                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1061                     // Check that original is also modified
1062                     assertEquals("Result of operation",
1063                             doubleType ? Math.cbrt(doubleValue[i]) : ((float) Math.cbrt(doubleValue[i])),
1064                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1065                 }
1066 
1067                 left = findAndExecuteConstructor(vectorClass,
1068                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1069                 mathMethod = ClassUtil.resolveMethod(vectorClass, "cos", new Class[] {});
1070                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1071                 result = mathMethod.invoke(left);
1072                 for (int i = 0; i < doubleValue.length; i++)
1073                 {
1074                     assertEquals("Result of operation",
1075                             doubleType ? Math.cos(doubleValue[i]) : ((float) Math.cos(doubleValue[i])),
1076                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1077                     // Check that original is also modified
1078                     assertEquals("Result of operation",
1079                             doubleType ? Math.cos(doubleValue[i]) : ((float) Math.cos(doubleValue[i])),
1080                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1081                 }
1082 
1083                 left = findAndExecuteConstructor(vectorClass,
1084                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1085                 mathMethod = ClassUtil.resolveMethod(vectorClass, "cosh", new Class[] {});
1086                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1087                 result = mathMethod.invoke(left);
1088                 for (int i = 0; i < doubleValue.length; i++)
1089                 {
1090                     assertEquals("Result of operation",
1091                             doubleType ? Math.cosh(doubleValue[i]) : ((float) Math.cosh(doubleValue[i])),
1092                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1093                     // Check that original is also modified
1094                     assertEquals("Result of operation",
1095                             doubleType ? Math.cosh(doubleValue[i]) : ((float) Math.cosh(doubleValue[i])),
1096                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1097                 }
1098 
1099                 left = findAndExecuteConstructor(vectorClass,
1100                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1101                 mathMethod = ClassUtil.resolveMethod(vectorClass, "exp", new Class[] {});
1102                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1103                 result = mathMethod.invoke(left);
1104                 for (int i = 0; i < doubleValue.length; i++)
1105                 {
1106                     assertEquals("Result of operation",
1107                             doubleType ? Math.exp(doubleValue[i]) : ((float) Math.exp(doubleValue[i])),
1108                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1109                     // Check that original is also modified
1110                     assertEquals("Result of operation",
1111                             doubleType ? Math.exp(doubleValue[i]) : ((float) Math.exp(doubleValue[i])),
1112                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1113                 }
1114 
1115                 left = findAndExecuteConstructor(vectorClass,
1116                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1117                 mathMethod = ClassUtil.resolveMethod(vectorClass, "expm1", new Class[] {});
1118                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1119                 result = mathMethod.invoke(left);
1120                 for (int i = 0; i < doubleValue.length; i++)
1121                 {
1122                     assertEquals("Result of operation",
1123                             doubleType ? Math.expm1(doubleValue[i]) : ((float) Math.expm1(doubleValue[i])),
1124                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1125                     // Check that original is also modified
1126                     assertEquals("Result of operation",
1127                             doubleType ? Math.expm1(doubleValue[i]) : ((float) Math.expm1(doubleValue[i])),
1128                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1129                 }
1130 
1131                 left = findAndExecuteConstructor(vectorClass,
1132                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1133                 mathMethod = ClassUtil.resolveMethod(vectorClass, "log", new Class[] {});
1134                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1135                 result = mathMethod.invoke(left);
1136                 for (int i = 0; i < doubleValue.length; i++)
1137                 {
1138                     assertEquals("Result of operation",
1139                             doubleType ? Math.log(doubleValue[i]) : ((float) Math.log(doubleValue[i])),
1140                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1141                     // Check that original is also modified
1142                     assertEquals("Result of operation",
1143                             doubleType ? Math.log(doubleValue[i]) : ((float) Math.log(doubleValue[i])),
1144                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1145                 }
1146 
1147                 left = findAndExecuteConstructor(vectorClass,
1148                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1149                 mathMethod = ClassUtil.resolveMethod(vectorClass, "log10", new Class[] {});
1150                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1151                 result = mathMethod.invoke(left);
1152                 for (int i = 0; i < doubleValue.length; i++)
1153                 {
1154                     assertEquals("Result of operation",
1155                             doubleType ? Math.log10(doubleValue[i]) : ((float) Math.log10(doubleValue[i])),
1156                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1157                     // Check that original is also modified
1158                     assertEquals("Result of operation",
1159                             doubleType ? Math.log10(doubleValue[i]) : ((float) Math.log10(doubleValue[i])),
1160                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1161                 }
1162 
1163                 left = findAndExecuteConstructor(vectorClass,
1164                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1165                 mathMethod = ClassUtil.resolveMethod(vectorClass, "log1p", new Class[] {});
1166                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1167                 result = mathMethod.invoke(left);
1168                 for (int i = 0; i < doubleValue.length; i++)
1169                 {
1170                     assertEquals("Result of operation",
1171                             doubleType ? Math.log1p(doubleValue[i]) : ((float) Math.log1p(doubleValue[i])),
1172                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1173                     // Check that original is also modified
1174                     assertEquals("Result of operation",
1175                             doubleType ? Math.log1p(doubleValue[i]) : ((float) Math.log1p(doubleValue[i])),
1176                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1177                 }
1178 
1179                 left = findAndExecuteConstructor(vectorClass,
1180                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1181                 mathMethod = ClassUtil.resolveMethod(vectorClass, "signum", new Class[] {});
1182                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1183                 result = mathMethod.invoke(left);
1184                 for (int i = 0; i < doubleValue.length; i++)
1185                 {
1186                     assertEquals("Result of operation",
1187                             doubleType ? Math.signum(doubleValue[i]) : ((float) Math.signum(doubleValue[i])),
1188                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1189                     // Check that original is also modified
1190                     assertEquals("Result of operation",
1191                             doubleType ? Math.signum(doubleValue[i]) : ((float) Math.signum(doubleValue[i])),
1192                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1193                 }
1194 
1195                 left = findAndExecuteConstructor(vectorClass,
1196                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1197                 mathMethod = ClassUtil.resolveMethod(vectorClass, "sin", new Class[] {});
1198                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1199                 result = mathMethod.invoke(left);
1200                 for (int i = 0; i < doubleValue.length; i++)
1201                 {
1202                     assertEquals("Result of operation",
1203                             doubleType ? Math.sin(doubleValue[i]) : ((float) Math.sin(doubleValue[i])),
1204                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1205                     // Check that original is also modified
1206                     assertEquals("Result of operation",
1207                             doubleType ? Math.sin(doubleValue[i]) : ((float) Math.sin(doubleValue[i])),
1208                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1209                 }
1210 
1211                 left = findAndExecuteConstructor(vectorClass,
1212                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1213                 mathMethod = ClassUtil.resolveMethod(vectorClass, "sinh", new Class[] {});
1214                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1215                 result = mathMethod.invoke(left);
1216                 for (int i = 0; i < doubleValue.length; i++)
1217                 {
1218                     assertEquals("Result of operation",
1219                             doubleType ? Math.sinh(doubleValue[i]) : ((float) Math.sinh(doubleValue[i])),
1220                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1221                     // Check that original is also modified
1222                     assertEquals("Result of operation",
1223                             doubleType ? Math.sinh(doubleValue[i]) : ((float) Math.sinh(doubleValue[i])),
1224                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1225                 }
1226 
1227                 left = findAndExecuteConstructor(vectorClass,
1228                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1229                 mathMethod = ClassUtil.resolveMethod(vectorClass, "sqrt", new Class[] {});
1230                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1231                 result = mathMethod.invoke(left);
1232                 for (int i = 0; i < doubleValue.length; i++)
1233                 {
1234                     assertEquals("Result of operation",
1235                             doubleType ? Math.sqrt(doubleValue[i]) : ((float) Math.sqrt(doubleValue[i])),
1236                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1237                     // Check that original is also modified
1238                     assertEquals("Result of operation",
1239                             doubleType ? Math.sqrt(doubleValue[i]) : ((float) Math.sqrt(doubleValue[i])),
1240                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1241                 }
1242 
1243                 left = findAndExecuteConstructor(vectorClass,
1244                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1245                 mathMethod = ClassUtil.resolveMethod(vectorClass, "tan", new Class[] {});
1246                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1247                 result = mathMethod.invoke(left);
1248                 for (int i = 0; i < doubleValue.length; i++)
1249                 {
1250                     assertEquals("Result of operation",
1251                             doubleType ? Math.tan(doubleValue[i]) : ((float) Math.tan(doubleValue[i])),
1252                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1253                     // Check that original is also modified
1254                     assertEquals("Result of operation",
1255                             doubleType ? Math.tan(doubleValue[i]) : ((float) Math.tan(doubleValue[i])),
1256                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1257                 }
1258 
1259                 left = findAndExecuteConstructor(vectorClass,
1260                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1261                 mathMethod = ClassUtil.resolveMethod(vectorClass, "tanh", new Class[] {});
1262                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1263                 result = mathMethod.invoke(left);
1264                 for (int i = 0; i < doubleValue.length; i++)
1265                 {
1266                     assertEquals("Result of operation",
1267                             doubleType ? Math.tanh(doubleValue[i]) : ((float) Math.tanh(doubleValue[i])),
1268                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1269                     // Check that original is also modified
1270                     assertEquals("Result of operation",
1271                             doubleType ? Math.tanh(doubleValue[i]) : ((float) Math.tanh(doubleValue[i])),
1272                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1273                 }
1274 
1275                 left = findAndExecuteConstructor(vectorClass,
1276                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1277                 mathMethod = ClassUtil.resolveMethod(vectorClass, "inv", new Class[] {});
1278                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1279                 result = mathMethod.invoke(left);
1280                 for (int i = 0; i < doubleValue.length; i++)
1281                 {
1282                     assertEquals("Result of operation", doubleType ? (1.0 / doubleValue[i]) : ((float) (1.0 / doubleValue[i])),
1283                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1284                     // Check that original is also modified
1285                     assertEquals("Result of operation", doubleType ? (1.0 / doubleValue[i]) : ((float) (1.0 / doubleValue[i])),
1286                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1287                 }
1288 
1289                 for (double power : new double[] { -3, -Math.PI, -1, -0.5, 0, 0.5, 1, Math.PI, 3 })
1290                 {
1291                     left = findAndExecuteConstructor(vectorClass,
1292                             new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1293                     mathMethod = ClassUtil.resolveMethod(vectorClass, "pow", new Class[] { double.class });
1294                     mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1295                     result = mathMethod.invoke(left, power);
1296                     for (int i = 0; i < doubleValue.length; i++)
1297                     {
1298                         assertEquals("Result of operation",
1299                                 doubleType ? Math.pow(doubleValue[i], power) : ((float) Math.pow(doubleValue[i], power)),
1300                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1301                         // Check that original is also modified
1302                         assertEquals("Result of operation",
1303                                 doubleType ? Math.pow(doubleValue[i], power) : ((float) Math.pow(doubleValue[i], power)),
1304                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1305                     }
1306                 }
1307 
1308                 left = findAndExecuteConstructor(vectorClass,
1309                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1310                 mathMethod = ClassUtil.resolveMethod(vectorClass, "normalize", new Class[] {});
1311                 mathMethod.setAccessible(true); // because MutableTyped classes are package protected...
1312                 mathMethod.invoke(left);
1313                 double sum = 0;
1314                 for (double v : doubleValue)
1315                 {
1316                     sum += v;
1317                 }
1318                 for (int i = 0; i < doubleValue.length; i++)
1319                 {
1320                     assertEquals("Result of operation", doubleType ? (doubleValue[i] / sum) : ((float) (doubleValue[i] / sum)),
1321                             verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1322                 }
1323 
1324                 double[] doubleZeroZSum = { -4, 4, -1, 1, 0 };
1325                 float[] floatZeroZSum = { -4, 4, -1, 1, 0 };
1326                 Object zeroZSumValue = doubleType ? doubleZeroZSum : floatZeroZSum;
1327                 left = findAndExecuteConstructor(vectorClass,
1328                         new Object[] { zeroZSumValue, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1329                 try
1330                 {
1331                     mathMethod.invoke(left);
1332                     fail("normalize should have thrown a ValueException because zSum is 0");
1333                 }
1334                 catch (Exception ve)
1335                 {
1336                     if (!(ve.getCause() instanceof ValueException))
1337                     {
1338                         fail("Thrown exception should have been a ValueException");
1339                     }
1340                     // ignore expected exception
1341                 }
1342 
1343             }
1344         }
1345 
1346         left = findAndExecuteConstructor(vectorClass,
1347                 new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1348         if (mutable)
1349         {
1350             Method multiplyBy =
1351                     ClassUtil.resolveMethod(vectorClass, "multiplyBy", new Class[] { doubleType ? double.class : float.class });
1352             multiplyBy.setAccessible(true); // FIXME this should not be necessary
1353             if (doubleType)
1354             {
1355                 result = multiplyBy.invoke(left, Math.PI);
1356             }
1357             else
1358             {
1359                 result = multiplyBy.invoke(left, (float) Math.PI);
1360             }
1361             for (int i = 0; i < doubleValue.length; i++)
1362             {
1363                 assertEquals("Result of operation", doubleValue[i] * Math.PI,
1364                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1365                 // Check that original is also modified
1366                 assertEquals("Result of operation", doubleValue[i] * Math.PI,
1367                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1368             }
1369             left = findAndExecuteConstructor(vectorClass,
1370                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1371             Method divideBy =
1372                     ClassUtil.resolveMethod(vectorClass, "divideBy", new Class[] { doubleType ? double.class : float.class });
1373             divideBy.setAccessible(true); // FIXME this should not be necessary
1374             if (doubleType)
1375             {
1376                 result = divideBy.invoke(left, Math.PI);
1377             }
1378             else
1379             {
1380                 result = divideBy.invoke(left, (float) Math.PI);
1381             }
1382             for (int i = 0; i < doubleValue.length; i++)
1383             {
1384                 assertEquals("Result of operation", doubleValue[i] / Math.PI,
1385                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1386                 // Check that original is also modified
1387                 assertEquals("Result of operation", doubleValue[i] / Math.PI,
1388                         verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1389             }
1390             double[] zDoubleValues = { 0, 0, 0, 0, 0, 0, 0 };
1391             float[] zFloatValues = { 0, 0, 0, 0, 0, 0, 0 };
1392             Object zValues = doubleType ? zDoubleValues : zFloatValues;
1393             Method set = ClassUtil.resolveMethod(vectorClass, "setSI",
1394                     new Class[] { int.class, doubleType ? double.class : float.class });
1395             set.setAccessible(true);
1396             for (int pivot2 = 0; pivot2 < zDoubleValues.length; pivot2++)
1397             {
1398                 for (int pivot = 0; pivot < zDoubleValues.length; pivot++)
1399                 {
1400                     if (pivot == pivot2)
1401                     {
1402                         continue;
1403                     }
1404                     left = findAndExecuteConstructor(vectorClass,
1405                             new Object[] { zValues, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1406                     // System.out.println("initial " + pivot + ", " + pivot2 + " " + left);
1407                     if (doubleType)
1408                     {
1409                         set.invoke(left, new Object[] { pivot, Math.PI * (pivot + 1) });
1410                     }
1411                     else
1412                     {
1413                         set.invoke(left, new Object[] { pivot, (float) (Math.PI * (pivot + 1)) });
1414                     }
1415                     // System.out.println("after one set " + left);
1416                     for (int i = 0; i < zDoubleValues.length; i++)
1417                     {
1418                         assertEquals("after one set, i=" + i, i == pivot ? Math.PI * (pivot + 1) : 0,
1419                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1420                     }
1421                     if (doubleType)
1422                     {
1423                         set.invoke(left, new Object[] { pivot2, Math.PI * (pivot2 + 20) });
1424                     }
1425                     else
1426                     {
1427                         set.invoke(left, new Object[] { pivot2, (float) (Math.PI * (pivot2 + 20)) });
1428                     }
1429                     // System.out.println("after second set " + left);
1430                     for (int i = 0; i < zDoubleValues.length; i++)
1431                     {
1432                         assertEquals("after second set, i=" + i,
1433                                 i == pivot ? Math.PI * (pivot + 1) : i == pivot2 ? Math.PI * (pivot2 + 20) : 0,
1434                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1435                     }
1436                     for (int i = 0; i < zDoubleValues.length; i++)
1437                     {
1438                         if (i == pivot || i == pivot2)
1439                         {
1440                             continue;
1441                         }
1442                         if (doubleType)
1443                         {
1444                             set.invoke(left, new Object[] { i, (double) (i + 1) });
1445                         }
1446                         else
1447                         {
1448                             set.invoke(left, new Object[] { i, (float) (i + 1) });
1449                         }
1450                     }
1451                     // System.out.println("after fill " + left);
1452                     for (int i = 0; i < zDoubleValues.length; i++)
1453                     {
1454                         assertEquals("after all set i=" + i + " pivot=" + pivot + ", pivot2=" + pivot2,
1455                                 i == pivot ? Math.PI * (pivot + 1) : i == pivot2 ? Math.PI * (pivot2 + 20) : i + 1,
1456                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, left, i), 0.01);
1457                     }
1458                 }
1459             }
1460         }
1461         Object compatibleRight = null;
1462         Object compatibleRel = null;
1463         // TODO: Probably we exclude too much here for the tests...
1464         if (!vectorClass.getName().contains("Money") && !vectorClass.getName().contains("Dimensionless")
1465                 && !vectorClass.getName().contains("Temperature") && !vectorClass.getName().contains("Position")
1466                 && !vectorClass.getName().contains("Time") && !vectorClass.getName().contains("Direction"))
1467         {
1468             // Construct a new unit to test mixed unit plus and minus
1469             Class<?> unitClass = getUnitClass(vectorClass);
1470             UnitSystem unitSystem = UnitSystem.SI_DERIVED;
1471             Unit<?> referenceUnit;
1472             // Call the getUnit method of left
1473             Method getUnitMethod = ClassUtil.resolveMethod(vectorClass, "getUnit");
1474             referenceUnit = (Unit<?>) getUnitMethod.invoke(left);
1475             Constructor<?> unitConstructor =
1476                     unitClass.getConstructor(String.class, String.class, UnitSystem.class, unitClass, double.class);
1477             Object newUnit = unitConstructor.newInstance("7fullName", "7abbr", unitSystem, referenceUnit, 7d);
1478             // System.out.println("new unit prints like " + newUnit);
1479             compatibleRight = findAndExecuteConstructor(vectorClass, new Object[] { value, newUnit, storageType }, doubleType);
1480             // System.out.println("compatibleRight prints like \"" + compatibleRight + "\"");
1481             if (abs)
1482             {
1483                 String className = vectorClass.getName();
1484                 for (int i = 0; i < CLASSNAMES_ABS.length; i++)
1485                 {
1486                     className = className.replaceAll(CLASSNAMES_ABS[i], CLASSNAMES_ABS_REL[i]);
1487                 }
1488                 Class<?> relClass = Class.forName(className);
1489                 compatibleRel = findAndExecuteConstructor(relClass, new Object[] { value, newUnit, storageType }, doubleType);
1490                 // System.out.println("compatibleRel prints like \"" + compatibleRight + "\"");
1491             }
1492         }
1493         if (null != compatibleRight)
1494         {
1495             left = findAndExecuteConstructor(vectorClass,
1496                     new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1497             // System.out.print(listMethods(vectorClass, "plus", "\t"));
1498             // System.out.println("Mutable is " + mutable);
1499             if (!mutable)
1500             { // FIXME: should also work for mutable and mix of mutable and immutable
1501               // System.out.println("Type of right is " + compatibleRight.getClass());
1502                 if (!abs)
1503                 {
1504                     Method plus = ClassUtil.resolveMethod(vectorClass, "plus",
1505                             new Class<?>[] { compatibleRight.getClass().getSuperclass() });
1506                     plus.setAccessible(true);
1507                     result = plus.invoke(left, compatibleRight);
1508                     for (int i = 0; i < doubleValue.length; i++)
1509                     {
1510                         assertEquals("Result of mixed operation", 8 * doubleValue[i],
1511                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1512                     }
1513                 }
1514                 if (null != compatibleRel)
1515                 {
1516                     // System.out.print(listMethods(vectorClass, "plus", "\t"));
1517                     // System.out.println("Type of rel is " + compatibleRel.getClass());
1518                     Method plus = ClassUtil.resolveMethod(vectorClass, "plus",
1519                             new Class<?>[] { compatibleRel.getClass().getSuperclass() });
1520                     plus.setAccessible(true);
1521                     result = plus.invoke(left, compatibleRel);
1522                     for (int i = 0; i < doubleValue.length; i++)
1523                     {
1524                         assertEquals("Result of mixed operation", 8 * doubleValue[i],
1525                                 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, storageType, result, i), 0.01);
1526                     }
1527                 }
1528             }
1529         }
1530         left = findAndExecuteConstructor(vectorClass,
1531                 new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1532         if (!mutable)
1533         {
1534             // System.out.print(listMethods(vectorClass, "minus", "\t"));
1535             Method minus = ClassUtil.resolveMethod(vectorClass, "minus", new Class[] { vectorClass.getSuperclass() });
1536             minus.setAccessible(true);
1537             result = minus.invoke(left, left);
1538             for (int i = 0; i < doubleValue.length; i++)
1539             {
1540                 assertEquals("Result of minus", 0, verifyAbsRelPrecisionAndExtractSI(false, doubleType, storageType, result, i),
1541                         0.01);
1542             }
1543             if (null != compatibleRight)
1544             {
1545                 left = findAndExecuteConstructor(vectorClass,
1546                         new Object[] { value, getSIUnitInstance(getUnitClass(vectorClass)), storageType }, doubleType);
1547                 result = minus.invoke(left, compatibleRight);
1548                 for (int i = 0; i < doubleValue.length; i++)
1549                 {
1550                     assertEquals("Result of minus with compatible arg", -6 * doubleValue[i],
1551                             verifyAbsRelPrecisionAndExtractSI(false, doubleType, storageType, result, i), 0.01);
1552                 }
1553             }
1554         }
1555     }
1556 
1557     /**
1558      * List all methods matching the given name.
1559      * @param theClass Class&lt;?&gt;; the class
1560      * @param name String; the name of the method, or null to list all methods in the class
1561      * @param prefix String; prefix for each line in the result;
1562      * @return String
1563      */
1564     public final String listMethods(final Class<?> theClass, final String name, final String prefix)
1565     {
1566         StringBuilder result = new StringBuilder();
1567         for (Method m : theClass.getMethods())
1568         {
1569             if (null == name || name.equals(m.getName()))
1570             {
1571                 result.append(
1572                         prefix + m.getName() + paramsToString(m.getParameterTypes()) + " -> " + m.getReturnType() + "\r\n");
1573             }
1574         }
1575         return result.toString();
1576     }
1577 
1578     /**
1579      * Test the interpolate method.
1580      * @param vectorClass Class&lt;?&gt;; the class to test
1581      * @param abs boolean; if true; scalarClass is Absolute; if false; scalarClass is Relative
1582      * @param doubleType boolean; if true; perform tests on DoubleScalar; if false; perform tests on FloatScalar
1583      * @param storageType StorageType; DENSE or SPARSE
1584      * @throws NoSuchMethodException on class or method resolving error
1585      * @throws NoSuchFieldException on class or method resolving error
1586      * @throws InvocationTargetException on class or method resolving error
1587      * @throws IllegalAccessException on class or method resolving error
1588      * @throws InstantiationException on class or method resolving error
1589      * @throws ValueException when index out of range
1590      */
1591     private void testInterpolateMethod(final Class<?> vectorClass, final boolean abs, final boolean doubleType,
1592             final StorageType storageType) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
1593             InvocationTargetException, NoSuchFieldException, ValueException
1594     {
1595         // System.out.println("class name is " + vectorClass.getName());
1596         Constructor<?> constructor = vectorClass.getConstructor(doubleType ? double[].class : float[].class,
1597                 getUnitClass(vectorClass), StorageType.class);
1598         if (doubleType)
1599         {
1600             double[] zeroValue = { 1.23456, 2.45678 };
1601             // AbstractDoubleVector<?, ?> zero =
1602             // abs ? (DoubleVector.Abs<?>) constructor.newInstance(zeroValue,
1603             // getSIUnitInstance(getUnitClass(vectorClass)), storageType) : (DoubleVector.Rel<?>) constructor
1604             // .newInstance(zeroValue, getSIUnitInstance(getUnitClass(vectorClass)), storageType);
1605             AbstractDoubleVector<?, ?> zero = (AbstractDoubleVector<?, ?>) constructor.newInstance(zeroValue,
1606                     getSIUnitInstance(getUnitClass(vectorClass)), storageType);
1607             double[] oneValue = { 3.45678, 4.678901 };
1608             AbstractDoubleVector<?, ?> one = (AbstractDoubleVector<?, ?>) constructor.newInstance(oneValue,
1609                     getSIUnitInstance(getUnitClass(vectorClass)), storageType);
1610             for (double ratio : new double[] { -5, -1, 0, 0.3, 1, 2, 10 })
1611             {
1612                 double[] expectedResult = new double[zeroValue.length];
1613                 for (int i = 0; i < expectedResult.length; i++)
1614                 {
1615                     expectedResult[i] = (1.0 - ratio) * zeroValue[i] + ratio * oneValue[i];
1616                 }
1617                 // TODO: interpolate is not yet generated by the code generator ...
1618                 // Method interpolate = ClassUtil.resolveMethod(vectorClass, "interpolate", vectorClass, vectorClass,
1619                 // double.class);
1620                 // AbstractDoubleScalar<?, ?> result;
1621                 // result = (AbstractDoubleScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
1622                 // verifyAbsRelPrecisionAndValues(abs, doubleType, result, expectedResult, 0.01);
1623             }
1624         }
1625         else
1626         {
1627             float[] zeroValue = { 1.23456f, 2.45678f };
1628             AbstractFloatVector<?, ?> zero = (AbstractFloatVector<?, ?>) constructor.newInstance(zeroValue,
1629                     getSIUnitInstance(getUnitClass(vectorClass)), storageType);
1630             float[] oneValue = { 3.45678f, 4.678901f };
1631             AbstractFloatVector<?, ?> one = (AbstractFloatVector<?, ?>) constructor.newInstance(oneValue,
1632                     getSIUnitInstance(getUnitClass(vectorClass)), storageType);
1633             for (float ratio : new float[] { -5, -1, 0, 0.3f, 1, 2, 10 })
1634             {
1635                 float[] expectedResult = new float[zeroValue.length];
1636                 for (int i = 0; i < expectedResult.length; i++)
1637                 {
1638                     expectedResult[i] = (float) ((1.0 - ratio) * zeroValue[i] + ratio * oneValue[i]);
1639                 }
1640                 // Method interpolate = ClassUtil.resolveMethod(vectorClass, "interpolate", vectorClass, vectorClass,
1641                 // float.class);
1642                 // AbstractFloatScalar<?, ?> result;
1643                 // result = (AbstractFloatScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
1644                 // verifyAbsRelPrecisionAndValues(abs, doubleType, storageType, result, expectedResult, 0.01);
1645             }
1646         }
1647     }
1648 
1649     /**
1650      * Various small experiments are done here. <br>
1651      * Prove (?) that order of items does not change in Arrays.stream(a).parallel().toArray().
1652      * @param args String[]; command line arguments; not used
1653      * @throws ValueException when index out of range
1654      */
1655     public static void main(final String[] args) throws ValueException
1656     {
1657         Length l = new Length(3, METER);
1658         Length w = new Length(2, METER);
1659         Area area = l.multiplyBy(w);
1660         System.out.println("Area is " + area);
1661 
1662         // Does not work (and should not work).
1663         // Position la = new Position(5, METER);
1664         // Position lb = new Position(7, METER);
1665         // la.multiplyBy(lb);
1666 
1667         // Check that Arrays.stream(.).parallel().toArray() does not affect ordering of elements
1668         // NB. The fact that this code finds no problem is no guarantee that this will always work.
1669         int size = 100000000;
1670         int[] a = new int[size];
1671         for (int i = 0; i < size; i++)
1672         {
1673             a[i] = i;
1674         }
1675 
1676         int[] b = Arrays.stream(a).parallel().toArray();
1677         for (int i = 0; i < size; i++)
1678         {
1679             if (b[i] != i)
1680             {
1681                 System.out.println("Oops b[" + i + "] is " + b[i]);
1682             }
1683         }
1684         System.out.println("finished");
1685     }
1686 }