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