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