View Javadoc
1   package org.djunits.value.vdouble.vector;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertNotEquals;
6   import static org.junit.Assert.assertTrue;
7   import static org.junit.Assert.fail;
8   
9   import java.lang.reflect.InvocationTargetException;
10  import java.lang.reflect.Method;
11  
12  import org.djunits.unit.AbsoluteTemperatureUnit;
13  import org.djunits.unit.AngleUnit;
14  import org.djunits.unit.AreaUnit;
15  import org.djunits.unit.DirectionUnit;
16  import org.djunits.unit.DurationUnit;
17  import org.djunits.unit.LengthUnit;
18  import org.djunits.unit.PositionUnit;
19  import org.djunits.unit.SIUnit;
20  import org.djunits.unit.TemperatureUnit;
21  import org.djunits.unit.TimeUnit;
22  import org.djunits.unit.Unit;
23  import org.djunits.unit.quantity.Quantities;
24  import org.djunits.unit.quantity.Quantity;
25  import org.djunits.unit.util.UnitException;
26  import org.djunits.unit.util.UnitRuntimeException;
27  import org.djunits.value.CLASSNAMES;
28  import org.djunits.value.ValueRuntimeException;
29  import org.djunits.value.storage.StorageType;
30  import org.djunits.value.vdouble.function.DoubleMathFunctions;
31  import org.djunits.value.vdouble.matrix.DOUBLEMATRIX;
32  import org.djunits.value.vdouble.matrix.SIMatrix;
33  import org.djunits.value.vdouble.matrix.base.AbstractDoubleMatrixRel;
34  import org.djunits.value.vdouble.scalar.AbsoluteTemperature;
35  import org.djunits.value.vdouble.scalar.Area;
36  import org.djunits.value.vdouble.scalar.Direction;
37  import org.djunits.value.vdouble.scalar.Duration;
38  import org.djunits.value.vdouble.scalar.Position;
39  import org.djunits.value.vdouble.scalar.Time;
40  import org.djunits.value.vdouble.vector.base.DoubleVector;
41  import org.djunits.value.vdouble.vector.data.DoubleVectorData;
42  import org.djutils.exceptions.Try;
43  import org.junit.Test;
44  
45  /**
46   * Test the incrementBy, etc. methods.
47   * <p>
48   * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
49   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
50   * </p>
51   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
52   */
53  public class DoubleVectorMethodTest
54  {
55  
56      /**
57       * Test the standard methods of all vector classes.
58       * @throws UnitException on error
59       * @throws ValueRuntimeException on error
60       */
61      @Test
62      public void testVectorMethods() throws ValueRuntimeException, UnitException
63      {
64          double[] denseTestData = DOUBLEVECTOR.denseArray(105);
65          double[] sparseTestData = DOUBLEVECTOR.sparseArray(105);
66          double[] reverseSparseTestData = new double[sparseTestData.length];
67          // sparseTestData and reverseSparseTestData should not "run out of values" at the same index
68          for (int index = 0; index < sparseTestData.length; index++)
69          {
70              reverseSparseTestData[reverseSparseTestData.length - 1 - index] = sparseTestData[index];
71          }
72          // Ensure that both have a value at some index (i.c. 10)
73          sparseTestData[10] = 123.456;
74          reverseSparseTestData[10] = sparseTestData[10];
75          // Ensure that there are > 50% positions where both have a non-zero value
76          for (int index = 20; index < 90; index++)
77          {
78              sparseTestData[index] = 10000.456 + index;
79              reverseSparseTestData[index] = 20000.567 + index;
80          }
81          for (StorageType storageType : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
82          {
83              for (AreaUnit au : new AreaUnit[] {AreaUnit.SQUARE_METER, AreaUnit.ACRE})
84              {
85                  double[] testData = storageType.equals(StorageType.DENSE) ? denseTestData : sparseTestData;
86                  AreaVector am =
87                          DoubleVector.instantiate(DoubleVectorData.instantiate(testData, au.getScale(), storageType), au);
88  
89                  // SPARSE AND DENSE
90                  assertEquals(am, am.toSparse());
91                  assertEquals(am, am.toDense());
92                  assertEquals(am, am.toSparse().toDense());
93                  assertEquals(am, am.toDense().toSparse());
94                  assertEquals(am.hashCode(), am.toSparse().hashCode());
95                  assertEquals(am.hashCode(), am.toDense().hashCode());
96                  assertTrue(am.toDense().isDense());
97                  assertFalse(am.toDense().isSparse());
98                  assertTrue(am.toSparse().isSparse());
99                  assertFalse(am.toSparse().isDense());
100 
101                 // EQUALS
102                 assertEquals(am, am);
103                 assertNotEquals(am, new Object());
104                 assertNotEquals(am, null);
105                 assertNotEquals(am, DoubleVector.instantiate(
106                         DoubleVectorData.instantiate(testData, LengthUnit.METER.getScale(), storageType), LengthUnit.METER));
107                 assertNotEquals(am, am.divide(2.0d));
108 
109                 // MUTABLE
110                 assertFalse(am.isMutable());
111                 AreaVector ammut = am.mutable();
112                 assertTrue(ammut.isMutable());
113                 assertFalse(am.isMutable());
114                 AreaVector ammut2 = ammut.multiplyBy(1.0);
115                 assertEquals(am, ammut2);
116                 assertTrue(ammut.isMutable());
117                 assertFalse(am.isMutable());
118                 assertTrue(ammut2.isMutable());
119                 ammut2 = ammut2.mutable().divideBy(2.0);
120                 assertEquals(am, ammut);
121                 assertNotEquals(am, ammut2);
122                 AreaVector ammut3 = ammut2.mutable().divideBy(0.0);
123                 for (int index = 0; index < ammut3.size(); index++)
124                 {
125                     if (ammut2.getSI(index) == 0)
126                     {
127                         assertTrue("Value should be NaN", Double.isNaN(ammut3.getSI(index)));
128 
129                     }
130                     else
131                     {
132                         assertTrue("Value should be Infinite", Double.isInfinite(ammut3.getSI(index)));
133                     }
134                 }
135 
136                 // ZSUM and CARDINALITY
137                 Area zSum = am.zSum();
138                 double sum = 0;
139                 int card = 0;
140                 for (int index = 0; index < testData.length; index++)
141                 {
142                     sum += testData[index];
143                     card += testData[index] == 0.0d ? 0 : 1;
144                 }
145                 assertEquals("zSum", sum, zSum.getInUnit(), 0.1);
146                 assertEquals("cardinality", card, am.cardinality());
147 
148                 // INCREMENTBY(SCALAR) and DECREMENTBY(SCALAR)
149                 AreaVector amold = am.clone();
150                 Area fa = Area.of(10.0d, "m^2");
151                 AreaVector aminc = am.mutable().incrementBy(fa).immutable();
152                 AreaVector amdec = am.mutable().decrementBy(fa).immutable();
153                 AreaVector amid = aminc.mutable().decrementBy(fa);
154                 assertEquals("immutable vector should not change when converted to mutable", am, amold);
155                 for (int index = 0; index < testData.length; index++)
156                 {
157                     assertEquals("increment and decrement with scalar should result in same vector", am.getSI(index),
158                             amid.getSI(index), 0.1);
159                     assertEquals("m + s = (m+s)", au.getScale().toStandardUnit(testData[index]) + 10.0, aminc.getSI(index),
160                             0.1);
161                     assertEquals("m - s = (m-s)", au.getScale().toStandardUnit(testData[index]) - 10.0, amdec.getSI(index),
162                             0.1);
163                 }
164 
165                 // MULTIPLYBY() and DIVIDEBY(), TIMES(), DIVIDE()
166                 AreaVector amt5 = am.mutable().multiplyBy(5.0d).immutable();
167                 AreaVector amd5 = am.mutable().divideBy(5.0d).immutable();
168                 AreaVector amtd = amt5.mutable().divideBy(5.0d);
169                 AreaVector amtimD = am.times(5.0d);
170                 AreaVector amtimF = am.times(5.0f);
171                 AreaVector amdivD = am.divide(5.0d);
172                 AreaVector amdivF = am.divide(5.0f);
173                 for (int index = 0; index < testData.length; index++)
174                 {
175                     assertEquals("times followed by divide with constant should result in same vector", am.getSI(index),
176                             amtd.getSI(index), 0.1);
177                     assertEquals("m * 5.0 = (m*5.0)", au.getScale().toStandardUnit(testData[index]) * 5.0d, amt5.getSI(index),
178                             0.1);
179                     assertEquals("m / 5.0 = (m/5.0)", au.getScale().toStandardUnit(testData[index]) / 5.0d, amd5.getSI(index),
180                             0.1);
181                     assertEquals("amtimD", amt5.getSI(index), amtimD.getSI(index), 0.1d);
182                     assertEquals("amtimF", amt5.getSI(index), amtimF.getSI(index), 0.1d);
183                     assertEquals("amdivD", amd5.getSI(index), amdivD.getSI(index), 0.01d);
184                     assertEquals("amdivD", amd5.getSI(index), amdivF.getSI(index), 0.01d);
185                 }
186 
187                 // GET(), GETINUNIT()
188                 assertEquals("get()", new Area(testData[2], au), am.get(2));
189                 assertEquals("getSI()", au.getScale().toStandardUnit(testData[2]), am.getSI(2), 0.1);
190                 assertEquals("getInUnit()", testData[2], am.getInUnit(2), 0.1);
191                 assertEquals("getInUnit(unit)",
192                         AreaUnit.SQUARE_YARD.getScale().fromStandardUnit(au.getScale().toStandardUnit(testData[2])),
193                         am.getInUnit(2, AreaUnit.SQUARE_YARD), 0.1);
194 
195                 // SET(), SETINUNIT()
196                 Area fasqft = new Area(10.5d, AreaUnit.SQUARE_FOOT);
197                 AreaVector famChange = am.clone().mutable();
198                 famChange.set(2, fasqft);
199                 assertEquals("set()", fasqft.si, famChange.get(2).si, 0.1d);
200                 famChange = am.clone().mutable();
201                 famChange.setSI(2, 123.4d);
202                 assertEquals("setSI()", 123.4d, famChange.get(2).si, 0.1d);
203                 famChange = am.clone().mutable();
204                 famChange.setInUnit(2, 1.2d);
205                 assertEquals("setInUnit()", 1.2d, famChange.getInUnit(2), 0.1d);
206                 famChange = am.clone().mutable();
207                 famChange.setInUnit(2, 1.5d, AreaUnit.HECTARE);
208                 assertEquals("setInUnit(unit)", 15000.0d, famChange.get(2).si, 1.0d);
209 
210                 // GETVALUES(), GETSCALARS()
211                 double[] valsi = am.getValuesSI();
212                 double[] valunit = am.getValuesInUnit();
213                 double[] valsqft = am.getValuesInUnit(AreaUnit.SQUARE_YARD);
214                 Area[] valscalars = am.getScalars();
215                 for (int index = 0; index < testData.length; index++)
216                 {
217                     assertEquals("getValuesSI()", au.getScale().toStandardUnit(testData[index]), valsi[index], 0.1);
218                     assertEquals("getValuesInUnit()", testData[index], valunit[index], 0.1);
219                     assertEquals("getValuesInUnit(unit)",
220                             AreaUnit.SQUARE_YARD.getScale().fromStandardUnit(au.getScale().toStandardUnit(testData[index])),
221                             valsqft[index], 0.1);
222                     assertEquals("getValuesInUnit(unit)", au.getScale().toStandardUnit(testData[index]), valscalars[index].si,
223                             0.1);
224                 }
225 
226                 // ASSIGN FUNCTION ABS, CEIL, FLOOR, NEG, RINT
227                 AreaVector amdiv2 = am.divide(2.0d);
228                 assertEquals(am.getStorageType(), amdiv2.getStorageType());
229                 assertEquals(am.getDisplayUnit(), amdiv2.getDisplayUnit());
230                 AreaVector amAbs = amdiv2.mutable().abs().immutable();
231                 assertEquals(am.getStorageType(), amAbs.getStorageType());
232                 assertEquals(am.getDisplayUnit(), amAbs.getDisplayUnit());
233                 AreaVector amCeil = amdiv2.mutable().ceil().immutable();
234                 assertEquals(am.getStorageType(), amCeil.getStorageType());
235                 assertEquals(am.getDisplayUnit(), amCeil.getDisplayUnit());
236                 AreaVector amFloor = amdiv2.mutable().floor().immutable();
237                 assertEquals(am.getStorageType(), amFloor.getStorageType());
238                 assertEquals(am.getDisplayUnit(), amFloor.getDisplayUnit());
239                 AreaVector amNeg = amdiv2.mutable().neg().immutable();
240                 assertEquals(am.getStorageType(), amNeg.getStorageType());
241                 assertEquals(am.getDisplayUnit(), amNeg.getDisplayUnit());
242                 AreaVector amRint = amdiv2.mutable().rint().immutable();
243                 assertEquals(am.getStorageType(), amRint.getStorageType());
244                 assertEquals(am.getDisplayUnit(), amRint.getDisplayUnit());
245                 for (int index = 0; index < testData.length; index++)
246                 {
247                     // TODO: Should be rounded IN THE UNIT rather than BY SI VALUES
248                     assertEquals("div2", au.getScale().toStandardUnit(testData[index]) / 2.0d, amdiv2.getSI(index), 0.1d);
249                     assertEquals("abs", Math.abs(au.getScale().toStandardUnit(testData[index]) / 2.0d), amAbs.getSI(index),
250                             0.1d);
251                     assertEquals("ceil", Math.ceil(au.getScale().toStandardUnit(testData[index]) / 2.0d), amCeil.getSI(index),
252                             0.1d);
253                     assertEquals("floor", Math.floor(au.getScale().toStandardUnit(testData[index]) / 2.0d),
254                             amFloor.getSI(index), 0.1d);
255                     assertEquals("neg", -au.getScale().toStandardUnit(testData[index]) / 2.0d, amNeg.getSI(index), 0.1d);
256                     assertEquals("rint", Math.rint(au.getScale().toStandardUnit(testData[index]) / 2.0d), amRint.getSI(index),
257                             0.1d);
258                 }
259 
260                 // TEST METHODS THAT INVOLVE TWO VECTOR INSTANCES
261 
262                 for (StorageType storageType2 : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
263                 {
264                     double[] testData2 = storageType2.equals(StorageType.DENSE) ? denseTestData : reverseSparseTestData;
265                     for (AreaUnit au2 : new AreaUnit[] {AreaUnit.SQUARE_METER, AreaUnit.ACRE})
266                     {
267                         // PLUS and INCREMENTBY(VECTOR)
268                         AreaVector am2 = DoubleVector
269                                 .instantiate(DoubleVectorData.instantiate(testData2, au2.getScale(), storageType2), au2);
270                         AreaVector amSum1 = am.plus(am2);
271                         AreaVector amSum2 = am2.plus(am);
272                         AreaVector amSum3 = am.mutable().incrementBy(am2).immutable();
273                         // different order of running out of nonzero values
274                         AreaVector amSum4 = am2.mutable().incrementBy(am).immutable();
275                         assertEquals("a+b == b+a", amSum1, amSum2);
276                         assertEquals("a+b == b+a", amSum1, amSum3);
277                         assertEquals("a+c == c+a", amSum1, amSum4);
278                         for (int index = 0; index < testData.length; index++)
279                         {
280                             double tolerance =
281                                     Double.isFinite(amSum1.getSI(index)) ? Math.abs(amSum1.getSI(index) / 10000.0d) : 0.1d;
282                             assertEquals("value in vector matches", au.getScale().toStandardUnit(testData[index])
283                                     + au2.getScale().toStandardUnit(testData2[index]), amSum1.getSI(index), tolerance);
284                         }
285 
286                         // MINUS and DECREMENTBY(VECTOR)
287                         AreaVector amDiff1 = am.minus(am2);
288                         AreaVector amDiff2 = am2.minus(am).mutable().neg();
289                         AreaVector amDiff3 = am.mutable().decrementBy(am2).immutable();
290                         // different order of running out of nonzero values
291                         AreaVector amDiff4 = am2.mutable().decrementBy(am).neg().immutable();
292                         assertEquals("a-b == -(b-a)", amDiff1, amDiff2);
293                         assertEquals("a-b == -(b-a)", amDiff1, amDiff3);
294                         assertEquals("a-c == -(c-a)", amDiff1, amDiff4);
295                         for (int index = 0; index < testData.length; index++)
296                         {
297                             double tolerance =
298                                     Double.isFinite(amDiff1.getSI(index)) ? Math.abs(amDiff1.getSI(index) / 10000.0d) : 0.1d;
299                             assertEquals("value in vector matches", au.getScale().toStandardUnit(testData[index])
300                                     - au2.getScale().toStandardUnit(testData2[index]), amDiff1.getSI(index), tolerance);
301                         }
302 
303                         // TIMES(VECTOR) and DIVIDE(VECTOR)
304                         SIVector amTim = am.times(am2);
305                         SIVector amDiv = am.divide(am2);
306                         assertEquals("unit of m2 * m2 should be m4", "m4",
307                                 amTim.getDisplayUnit().getQuantity().getSiDimensions().toString(false, false, false));
308                         assertEquals("unit of m2 / m2 should be 1", "1",
309                                 amDiv.getDisplayUnit().getQuantity().getSiDimensions().toString(false, false, false));
310                         for (int index = 0; index < testData.length; index++)
311                         {
312                             double tolerance =
313                                     Double.isFinite(amTim.getSI(index)) ? Math.abs(amTim.getSI(index) / 10000.0d) : 0.1d;
314                             assertEquals("value in m2 * m2 matches", au.getScale().toStandardUnit(testData[index])
315                                     * au2.getScale().toStandardUnit(testData2[index]), amTim.getSI(index), tolerance);
316                             tolerance = Double.isFinite(amTim.getSI(index)) ? Math.abs(amDiv.getSI(index) / 10000.0d) : 0.1d;
317                             assertEquals("value in m2 / m2 matches (could be NaN)",
318                                     au.getScale().toStandardUnit(testData[index])
319                                             / au2.getScale().toStandardUnit(testData2[index]),
320                                     amDiv.getSI(index), tolerance);
321                         }
322                         // This does not compile: SIVector amTim2 = am.immutable().multiplyBy(am2).immutable();
323                     }
324                 }
325             }
326         }
327     }
328 
329     /**
330      * Test if mutable methods give an error in case the vector is immutable.
331      */
332     @Test
333     public void testImmutableVector()
334     {
335         double[] denseTestData = DOUBLEVECTOR.denseArray(105);
336         double[] sparseTestData = DOUBLEVECTOR.sparseArray(105);
337 
338         for (StorageType storageType : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
339         {
340             for (AreaUnit au : new AreaUnit[] {AreaUnit.SQUARE_METER, AreaUnit.ACRE})
341             {
342                 double[] testData = storageType.equals(StorageType.DENSE) ? denseTestData : sparseTestData;
343                 AreaVector am =
344                         DoubleVector.instantiate(DoubleVectorData.instantiate(testData, au.getScale(), storageType), au);
345                 am = am.immutable();
346                 final AreaVector amPtr = am;
347                 Area fa = Area.of(10.0d, "m^2");
348                 Try.testFail(() -> amPtr.assign(DoubleMathFunctions.ABS), "ImmutableVector.assign(...) should throw error");
349                 Try.testFail(() -> amPtr.decrementBy(fa), "ImmutableVector.decrementBy(scalar) should throw error");
350                 Try.testFail(() -> amPtr.decrementBy(amPtr), "ImmutableVector.decrementBy(vector) should throw error");
351                 Try.testFail(() -> amPtr.incrementBy(fa), "ImmutableVector.incrementBy(scalar) should throw error");
352                 Try.testFail(() -> amPtr.incrementBy(amPtr), "ImmutableVector.incrementBy(vector) should throw error");
353                 Try.testFail(() -> amPtr.divideBy(2.0d), "ImmutableVector.divideBy(factor) should throw error");
354                 Try.testFail(() -> amPtr.multiplyBy(2.0d), "ImmutableVector.multiplyBy(factor) should throw error");
355                 Try.testFail(() -> amPtr.set(1, fa), "ImmutableVector.set() should throw error");
356                 Try.testFail(() -> amPtr.setSI(1, 20.1d), "ImmutableVector.setSI() should throw error");
357                 Try.testFail(() -> amPtr.setInUnit(1, 15.2d), "ImmutableVector.setInUnit(f) should throw error");
358                 Try.testFail(() -> amPtr.setInUnit(1, 15.2d, AreaUnit.ARE),
359                         "ImmutableVector.setInUnit(f, u) should throw error");
360                 Try.testFail(() -> amPtr.abs(), "ImmutableVector.abs() should throw error");
361                 Try.testFail(() -> amPtr.ceil(), "ImmutableVector.ceil() should throw error");
362                 Try.testFail(() -> amPtr.floor(), "ImmutableVector.floor() should throw error");
363                 Try.testFail(() -> amPtr.neg(), "ImmutableVector.neg() should throw error");
364                 Try.testFail(() -> amPtr.rint(), "ImmutableVector.rint() should throw error");
365             }
366         }
367     }
368 
369     /**
370      * Test toString() methods. TODO: expand?
371      */
372     @Test
373     public void testVectorToString()
374     {
375         double[] denseTestData = DOUBLEVECTOR.denseArray(105);
376         double[] sparseTestData = DOUBLEVECTOR.sparseArray(105);
377 
378         for (StorageType storageType : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
379         {
380             for (AreaUnit au : new AreaUnit[] {AreaUnit.SQUARE_METER, AreaUnit.ACRE})
381             {
382                 double[] testData = storageType.equals(StorageType.DENSE) ? denseTestData : sparseTestData;
383                 AreaVector am =
384                         DoubleVector.instantiate(DoubleVectorData.instantiate(testData, au.getScale(), storageType), au);
385                 String s1 = am.toString(); // non-verbose with unit
386                 assertTrue(s1.contains(au.getDefaultTextualAbbreviation()));
387                 String s2 = am.toString(AreaUnit.SQUARE_INCH); // non-verbose with unit
388                 assertTrue(s2.contains(AreaUnit.SQUARE_INCH.getDefaultTextualAbbreviation()));
389                 String s3 = am.toString(AreaUnit.SQUARE_INCH, true, true); // verbose with unit
390                 assertTrue(s3.contains(AreaUnit.SQUARE_INCH.getDefaultTextualAbbreviation()));
391                 if (storageType.equals(StorageType.DENSE))
392                 {
393                     assertTrue(s3.contains("Dense"));
394                     assertFalse(s3.contains("Sparse"));
395                 }
396                 else
397                 {
398                     assertFalse(s3.contains("Dense"));
399                     assertTrue(s3.contains("Sparse"));
400                 }
401                 assertTrue(s3.contains("Rel"));
402                 assertFalse(s3.contains("Abs"));
403                 assertTrue(s3.contains("Immutable"));
404                 assertFalse(s3.contains("Mutable"));
405                 AreaVector ammut = am.mutable();
406                 String smut = ammut.toString(AreaUnit.SQUARE_INCH, true, true); // verbose with unit
407                 assertFalse(smut.contains("Immutable"));
408                 assertTrue(smut.contains("Mutable"));
409                 String sNotVerbose = ammut.toString(false, false);
410                 assertFalse(sNotVerbose.contains("Rel"));
411                 assertFalse(sNotVerbose.contains("Abs"));
412                 assertFalse(sNotVerbose.contains("Immutable"));
413                 assertFalse(sNotVerbose.contains("Mutable"));
414                 assertFalse(sNotVerbose.contains(au.getDefaultTextualAbbreviation()));
415             }
416         }
417         TimeVector tm = DoubleVector.instantiate(
418                 DoubleVectorData.instantiate(denseTestData, TimeUnit.DEFAULT.getScale(), StorageType.DENSE), TimeUnit.DEFAULT);
419         String st = tm.toString(TimeUnit.DEFAULT, true, true); // verbose with unit
420         assertFalse(st.contains("Rel"));
421         assertTrue(st.contains("Abs"));
422         LengthVector lm = DoubleVector.instantiate(
423                 DoubleVectorData.instantiate(denseTestData, LengthUnit.SI.getScale(), StorageType.DENSE), LengthUnit.SI);
424         String sl = lm.toString(LengthUnit.SI, true, true); // verbose with unit
425         assertTrue(sl.contains("Rel"));
426         assertFalse(sl.contains("Abs"));
427     }
428 
429     /**
430      * Test the extra methods that Absolute and Relative with Absolute matrices implement.
431      */
432     @Test
433     public void testSpecialVectorMethodsRelWithAbs()
434     {
435         double[] denseTestData = DOUBLEVECTOR.denseArray(105);
436         TimeVector tm = DoubleVector.instantiate(
437                 DoubleVectorData.instantiate(denseTestData, TimeUnit.DEFAULT.getScale(), StorageType.DENSE), TimeUnit.DEFAULT);
438         DurationVector dm = DoubleVector.instantiate(
439                 DoubleVectorData.instantiate(denseTestData, DurationUnit.MINUTE.getScale(), StorageType.DENSE),
440                 DurationUnit.SECOND);
441         assertTrue(tm.isAbsolute());
442         assertFalse(dm.isAbsolute());
443         assertFalse(tm.isRelative());
444         assertTrue(dm.isRelative());
445 
446         TimeVector absPlusRel = tm.plus(dm);
447         TimeVector absMinusRel = tm.minus(dm);
448         double[] halfDenseData = DOUBLEVECTOR.denseArray(105);
449         for (int index = 0; index < halfDenseData.length; index++)
450         {
451             halfDenseData[index] *= 0.5;
452         }
453         TimeVector halfTimeVector = DoubleVector.instantiate(
454                 DoubleVectorData.instantiate(halfDenseData, TimeUnit.DEFAULT.getScale(), StorageType.DENSE), TimeUnit.DEFAULT);
455         DurationVector absMinusAbs = tm.minus(halfTimeVector);
456         TimeVector absDecByRelS = tm.mutable().decrementBy(Duration.of(1.0d, "min"));
457         TimeVector absDecByRelM = tm.mutable().decrementBy(dm.divide(2.0d));
458         TimeVector relPlusAbs = dm.plus(tm);
459         for (int index = 0; index < denseTestData.length; index++)
460         {
461             assertEquals("absPlusRel", 61.0 * denseTestData[index], absPlusRel.getSI(index), 0.01);
462             assertEquals("absMinusRel", -59.0 * denseTestData[index], absMinusRel.getSI(index), 0.01);
463             assertEquals("absMinusAbs", denseTestData[index] / 2.0, absMinusAbs.getSI(index), 0.01);
464             assertEquals("absDecByRelS", denseTestData[index] - 60.0, absDecByRelS.getSI(index), 0.01);
465             assertEquals("absDecByRelM", -29.0 * denseTestData[index], absDecByRelM.getSI(index), 0.01);
466             assertEquals("relPlusAbs", 61.0 * denseTestData[index], relPlusAbs.getSI(index), 0.01);
467         }
468         for (int dLength : new int[] {-1, 1})
469         {
470             double[] other = DOUBLEVECTOR.denseArray(denseTestData.length + dLength);
471             TimeVector wrongTimeVector = DoubleVector.instantiate(
472                     DoubleVectorData.instantiate(other, TimeUnit.DEFAULT.getScale(), StorageType.DENSE), TimeUnit.DEFAULT);
473             try
474             {
475                 tm.mutable().minus(wrongTimeVector);
476                 fail("Mismatching size should have thrown a ValueRuntimeException");
477             }
478             catch (ValueRuntimeException vre)
479             {
480                 // Ignore expected exception
481             }
482         }
483         assertTrue("toString returns something informative",
484                 DoubleVectorData.instantiate(denseTestData, TimeUnit.DEFAULT.getScale(), StorageType.DENSE).toString()
485                         .startsWith("DoubleVectorData"));
486     }
487 
488     /**
489      * Test the instantiateAbs method and instantiateScalarAbsSI method.
490      */
491     @Test
492     public void testInstantiateAbs()
493     {
494         double[] denseTestData = DOUBLEVECTOR.denseArray(105);
495         TimeVector timeVector = DoubleVector.instantiate(
496                 DoubleVectorData.instantiate(denseTestData, TimeUnit.DEFAULT.getScale(), StorageType.DENSE), TimeUnit.DEFAULT);
497         DurationVector durationVector = DoubleVector.instantiate(
498                 DoubleVectorData.instantiate(denseTestData, DurationUnit.MINUTE.getScale(), StorageType.DENSE),
499                 DurationUnit.SECOND);
500 
501         double[] halfDenseData = DOUBLEVECTOR.denseArray(105);
502         for (int index = 0; index < halfDenseData.length; index++)
503         {
504             halfDenseData[index] *= 0.5;
505         }
506         TimeVector relPlusAbsTime = durationVector.plus(timeVector);
507         for (int index = 0; index < denseTestData.length; index++)
508         {
509             assertEquals("relPlusAbsTime", 61.0 * denseTestData[index], relPlusAbsTime.getSI(index), 0.01);
510         }
511         Time time = durationVector.instantiateScalarAbsSI(123.456f, TimeUnit.EPOCH_DAY);
512         assertEquals("Unit of instantiateScalarAbsSI matches", TimeUnit.EPOCH_DAY, time.getDisplayUnit());
513         assertEquals("Value of instantiateScalarAbsSI matches", 123.456f, time.si, 0.1);
514 
515         AngleVector angleVector = DoubleVector.instantiate(
516                 DoubleVectorData.instantiate(denseTestData, AngleUnit.DEGREE.getScale(), StorageType.DENSE), AngleUnit.DEGREE);
517         DirectionVector directionVector = DoubleVector.instantiate(
518                 DoubleVectorData.instantiate(denseTestData, DirectionUnit.EAST_DEGREE.getScale(), StorageType.DENSE),
519                 DirectionUnit.EAST_DEGREE);
520 
521         DirectionVector relPlusAbsDirection = angleVector.plus(directionVector);
522         for (int index = 0; index < denseTestData.length; index++)
523         {
524             assertEquals("relPlusAbsDirection", 2.0 / 180 * Math.PI * denseTestData[index], relPlusAbsDirection.getSI(index),
525                     0.01);
526         }
527         Direction direction = angleVector.instantiateScalarAbsSI(123.456f, DirectionUnit.NORTH_RADIAN);
528         assertEquals("Unit of instantiateScalarAbsSI matches", DirectionUnit.NORTH_RADIAN, direction.getDisplayUnit());
529         assertEquals("Value of instantiateScalarAbsSI matches", 123.456f, direction.si, 0.1);
530 
531         TemperatureVector temperatureVector = DoubleVector.instantiate(
532                 DoubleVectorData.instantiate(denseTestData, TemperatureUnit.DEGREE_FAHRENHEIT.getScale(), StorageType.DENSE),
533                 TemperatureUnit.DEGREE_FAHRENHEIT);
534         AbsoluteTemperatureVector absoluteTemperatureVector = DoubleVector.instantiate(
535                 DoubleVectorData.instantiate(denseTestData, AbsoluteTemperatureUnit.KELVIN.getScale(), StorageType.DENSE),
536                 AbsoluteTemperatureUnit.KELVIN);
537 
538         AbsoluteTemperatureVector relPlusAbsTemperature = temperatureVector.plus(absoluteTemperatureVector);
539         for (int index = 0; index < denseTestData.length; index++)
540         {
541             assertEquals("relPlusAbsTemperature", (1.0 + 5.0 / 9.0) * denseTestData[index], relPlusAbsTemperature.getSI(index),
542                     0.01);
543         }
544         AbsoluteTemperature absoluteTemperature =
545                 temperatureVector.instantiateScalarAbsSI(123.456f, AbsoluteTemperatureUnit.DEGREE_FAHRENHEIT);
546         assertEquals("Unit of instantiateScalarAbsSI matches", AbsoluteTemperatureUnit.DEGREE_FAHRENHEIT,
547                 absoluteTemperature.getDisplayUnit());
548         assertEquals("Value of instantiateScalarAbsSI matches", 123.456f, absoluteTemperature.si, 0.1);
549 
550         LengthVector lengthVector = DoubleVector.instantiate(
551                 DoubleVectorData.instantiate(denseTestData, LengthUnit.MILE.getScale(), StorageType.DENSE), LengthUnit.MILE);
552         PositionVector positionVector = DoubleVector.instantiate(
553                 DoubleVectorData.instantiate(denseTestData, PositionUnit.KILOMETER.getScale(), StorageType.DENSE),
554                 PositionUnit.KILOMETER);
555 
556         PositionVector relPlusAbsPosition = lengthVector.plus(positionVector);
557         for (int index = 0; index < denseTestData.length; index++)
558         {
559             assertEquals("relPlusAbsPosition", 2609.344 * denseTestData[index], relPlusAbsPosition.getSI(index), 1);
560         }
561         Position position = lengthVector.instantiateScalarAbsSI(123.456f, PositionUnit.ANGSTROM);
562         assertEquals("Unit of instantiateScalarAbsSI matches", PositionUnit.ANGSTROM, position.getDisplayUnit());
563         assertEquals("Value of instantiateScalarAbsSI matches", 123.456f, position.si, 0.1);
564     }
565 
566     /**
567      * Test the <code>as</code> method of the SIVector class.
568      * @throws SecurityException on error
569      * @throws NoSuchMethodException on error
570      * @throws InvocationTargetException on error
571      * @throws IllegalArgumentException on error
572      * @throws IllegalAccessException on error
573      * @throws ClassNotFoundException on error
574      * @throws UnitException on error
575      * @param <U> the unit type
576      */
577     @SuppressWarnings("unchecked")
578     @Test
579     public <U extends Unit<U>> void testAsUnit() throws ClassNotFoundException, NoSuchMethodException, SecurityException,
580             IllegalAccessException, IllegalArgumentException, InvocationTargetException, UnitException
581     {
582         double[][] testValues = DOUBLEMATRIX.denseRectArrays(10, 20);
583         for (StorageType storageType : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
584         {
585             for (String type : CLASSNAMES.REL_LIST)
586             {
587                 Class.forName("org.djunits.unit." + type + "Unit");
588                 Quantity<U> quantity = (Quantity<U>) Quantities.INSTANCE.getQuantity(type + "Unit");
589                 for (U unit : quantity.getUnitsById().values())
590                 {
591                     for (StorageType storageType2 : new StorageType[] {StorageType.DENSE, storageType})
592                     {
593                         SIUnit siUnit = SIUnit.of(unit.getQuantity().getSiDimensions());
594                         SIMatrix matrix = SIMatrix.instantiate(testValues, siUnit, storageType2);
595                         Method asMethod = SIMatrix.class.getDeclaredMethod("as", Unit.class);
596                         AbstractDoubleMatrixRel<U, ?, ?, ?> asMatrix =
597                                 (AbstractDoubleMatrixRel<U, ?, ?, ?>) asMethod.invoke(matrix, siUnit);
598                         assertEquals(matrix.getDisplayUnit().getStandardUnit(), asMatrix.getDisplayUnit());
599                         siUnit = SIUnit.of(AbsoluteTemperatureUnit.KELVIN.getQuantity().getSiDimensions());
600                         for (int row = 0; row < testValues.length; row++)
601                         {
602                             for (int col = 0; col < testValues[0].length; col++)
603                             {
604                                 assertEquals("Values should match", testValues[row][col], matrix.getInUnit(row, col), 0.001);
605                             }
606                         }
607                         try
608                         {
609                             asMethod.invoke(matrix, siUnit);
610                             fail("as method should not be able to cast to unrelated (absoluteTemperature) unit");
611                         }
612                         catch (InvocationTargetException ite)
613                         {
614                             Throwable cause = ite.getCause();
615                             assertEquals("cause is UnitRuntimeException", UnitRuntimeException.class, cause.getClass());
616                             // Otherwise ignore expected exception
617                         }
618                     }
619                 }
620             }
621         }
622     }
623 
624     /**
625      * Test the equals method.
626      */
627     @SuppressWarnings("unlikely-arg-type")
628     @Test
629     public void testEquals()
630     {
631         double[] testData = DOUBLEVECTOR.denseArray(123);
632         testData[2] = 0;
633         for (StorageType storageType : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
634         {
635             DoubleVectorData dvd = DoubleVectorData.instantiate(testData, TemperatureUnit.KELVIN.getScale(), storageType);
636             assertTrue("Double vector data is equal to itself", dvd.equals(dvd));
637             assertFalse("Double vector data is not equal to null", dvd.equals(null));
638             assertFalse("Double vector data is not equal to some string", dvd.equals("some string"));
639             assertTrue("Double vector is equal to sparse version of itself", dvd.equals(dvd.toSparse()));
640             assertTrue("Double vector is equal to dense version of itself", dvd.equals(dvd.toDense()));
641             for (StorageType storageType2 : new StorageType[] {StorageType.DENSE, StorageType.SPARSE})
642             {
643                 DoubleVectorData dvd2 = DoubleVectorData.instantiate(testData, TemperatureUnit.KELVIN.getScale(), storageType2);
644                 assertEquals(
645                         "Double vector data is equal to other double vector containing same values regardless of storage type",
646                         dvd, dvd2);
647                 double[] testData2 = DOUBLEVECTOR.denseArray(122);
648                 testData2[2] = 0;
649                 dvd2 = DoubleVectorData.instantiate(testData2, TemperatureUnit.KELVIN.getScale(), storageType2);
650                 assertFalse("Double vector data is not equal to other double vector containing same values except last one",
651                         dvd.equals(dvd2));
652                 testData2 = DOUBLEVECTOR.denseArray(123);
653                 dvd2 = DoubleVectorData.instantiate(testData2, TemperatureUnit.KELVIN.getScale(), storageType2);
654                 assertFalse("Double vector data is not equal to other double vector containing same values except for one zero",
655                         dvd.equals(dvd2));
656             }
657         }
658     }
659 
660 }