View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math4.legacy.stat.descriptive;
18  
19  import org.apache.commons.math4.legacy.core.MathArrays;
20  import org.apache.commons.statistics.distribution.DiscreteDistribution;
21  import org.apache.commons.statistics.distribution.UniformDiscreteDistribution;
22  import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
23  import org.apache.commons.math4.legacy.exception.NullArgumentException;
24  import org.apache.commons.rng.simple.RandomSource;
25  import org.apache.commons.math4.legacy.stat.descriptive.ResizableDoubleArray.ExpansionMode;
26  import org.junit.After;
27  import org.junit.Assert;
28  import org.junit.Before;
29  import org.junit.Test;
30  
31  
32  /**
33   * This class contains test cases for the ResizableDoubleArray.
34   */
35  public class ResizableDoubleArrayTest extends DoubleArrayAbstractTest {
36  
37      @After
38      public void tearDown() throws Exception {
39          da = null;
40          ra = null;
41      }
42  
43      @Before
44      public void setUp() throws Exception {
45          da = new ResizableDoubleArray();
46          ra = new ResizableDoubleArray();
47      }
48  
49      @Test
50      public void testConstructors() {
51          float defaultExpansionFactor = 2.0f;
52          double defaultContractionCriteria = 2.5;
53          ExpansionMode defaultMode = ResizableDoubleArray.ExpansionMode.MULTIPLICATIVE;
54  
55          ResizableDoubleArray testDa = new ResizableDoubleArray(2);
56          Assert.assertEquals(0, testDa.getNumElements());
57          Assert.assertEquals(2, testDa.getCapacity());
58          Assert.assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0);
59          Assert.assertEquals(defaultContractionCriteria, testDa.getContractionCriterion(), 0);
60          Assert.assertEquals(defaultMode, testDa.getExpansionMode());
61          try {
62              da = new ResizableDoubleArray(-1);
63              Assert.fail("Expecting MathIllegalArgumentException");
64          } catch (MathIllegalArgumentException ex) {
65              // expected
66          }
67  
68          testDa = new ResizableDoubleArray((double[]) null);
69          Assert.assertEquals(0, testDa.getNumElements());
70  
71          double[] initialArray = new double[] { 0, 1, 2 };
72          testDa = new ResizableDoubleArray(initialArray);
73          Assert.assertEquals(3, testDa.getNumElements());
74  
75          testDa = new ResizableDoubleArray(2, 2.0);
76          Assert.assertEquals(0, testDa.getNumElements());
77          Assert.assertEquals(2, testDa.getCapacity());
78          Assert.assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0);
79          Assert.assertEquals(defaultContractionCriteria, testDa.getContractionCriterion(), 0);
80          Assert.assertEquals(defaultMode, testDa.getExpansionMode());
81  
82          try {
83              da = new ResizableDoubleArray(2, 0.5);
84              Assert.fail("Expecting MathIllegalArgumentException");
85          } catch (MathIllegalArgumentException ex) {
86              // expected
87          }
88  
89          testDa = new ResizableDoubleArray(2, 3.0);
90          Assert.assertEquals(3.0f, testDa.getExpansionFactor(), 0);
91          Assert.assertEquals(3.5f, testDa.getContractionCriterion(), 0);
92  
93          testDa = new ResizableDoubleArray(2, 2.0, 3.0);
94          Assert.assertEquals(0, testDa.getNumElements());
95          Assert.assertEquals(2, testDa.getCapacity());
96          Assert.assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0);
97          Assert.assertEquals(3.0f, testDa.getContractionCriterion(), 0);
98          Assert.assertEquals(defaultMode, testDa.getExpansionMode());
99  
100         try {
101             da = new ResizableDoubleArray(2, 2.0, 1.5);
102             Assert.fail("Expecting MathIllegalArgumentException");
103         } catch (MathIllegalArgumentException ex) {
104             // expected
105         }
106 
107         testDa = new ResizableDoubleArray(2, 2.0, 3.0, ResizableDoubleArray.ExpansionMode.ADDITIVE);
108         Assert.assertEquals(0, testDa.getNumElements());
109         Assert.assertEquals(2, testDa.getCapacity());
110         Assert.assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0);
111         Assert.assertEquals(3.0f, testDa.getContractionCriterion(), 0);
112         Assert.assertEquals(ResizableDoubleArray.ExpansionMode.ADDITIVE, testDa.getExpansionMode());
113 
114         try {
115             da = new ResizableDoubleArray(2, 2.0d, 2.5d, null);
116             Assert.fail("Expecting NullArgumentException");
117         } catch (NullArgumentException ex) {
118             // expected
119         }
120 
121         // Copy constructor
122         testDa = new ResizableDoubleArray(2, 2.0, 3.0,
123                                           ResizableDoubleArray.ExpansionMode.ADDITIVE);
124         testDa.addElement(2.0);
125         testDa.addElement(3.2);
126         ResizableDoubleArray copyDa = new ResizableDoubleArray(testDa);
127         Assert.assertEquals(copyDa, testDa);
128         Assert.assertEquals(testDa, copyDa);
129 
130         // JIRA: MATH-1252
131         final double[] values = {1};
132         testDa = new ResizableDoubleArray(values);
133         Assert.assertArrayEquals(values, testDa.getElements(), 0);
134         Assert.assertEquals(1, testDa.getNumElements());
135         Assert.assertEquals(1, testDa.getElement(0), 0);
136     }
137 
138     @Test
139     public void testSetElementArbitraryExpansion1() {
140 
141         // MULTIPLICATIVE_MODE
142         da.addElement(2.0);
143         da.addElement(4.0);
144         da.addElement(6.0);
145         da.setElement(1, 3.0);
146 
147         // Expand the array arbitrarily to 1000 items
148         da.setElement(1000, 3.4);
149 
150         Assert.assertEquals( "The number of elements should now be 1001, it isn't",
151                 da.getNumElements(), 1001);
152 
153         Assert.assertEquals( "Uninitialized Elements are default value of 0.0, index 766 wasn't", 0.0,
154                 da.getElement( 760 ), Double.MIN_VALUE );
155 
156         Assert.assertEquals( "The 1000th index should be 3.4, it isn't", 3.4, da.getElement(1000),
157                 Double.MIN_VALUE );
158         Assert.assertEquals( "The 0th index should be 2.0, it isn't", 2.0, da.getElement(0),
159                 Double.MIN_VALUE);
160     }
161 
162     @Test
163     public void testSetElementArbitraryExpansion2() {
164         // Make sure numElements and expansion work correctly for expansion boundary cases
165         da.addElement(2.0);
166         da.addElement(4.0);
167         da.addElement(6.0);
168         Assert.assertEquals(16, ((ResizableDoubleArray) da).getCapacity());
169         Assert.assertEquals(3, da.getNumElements());
170         da.setElement(3, 7.0);
171         Assert.assertEquals(16, ((ResizableDoubleArray) da).getCapacity());
172         Assert.assertEquals(4, da.getNumElements());
173         da.setElement(10, 10.0);
174         Assert.assertEquals(16, ((ResizableDoubleArray) da).getCapacity());
175         Assert.assertEquals(11, da.getNumElements());
176         da.setElement(9, 10.0);
177         Assert.assertEquals(16, ((ResizableDoubleArray) da).getCapacity());
178         Assert.assertEquals(11, da.getNumElements());
179 
180         try {
181             da.setElement(-2, 3);
182             Assert.fail("Expecting ArrayIndexOutOfBoundsException for negative index");
183         } catch (ArrayIndexOutOfBoundsException ex) {
184             // expected
185         }
186 
187         // ADDITIVE_MODE
188 
189         ResizableDoubleArray testDa = new ResizableDoubleArray(2, 2.0, 3.0,
190                                                                ResizableDoubleArray.ExpansionMode.ADDITIVE);
191         Assert.assertEquals(2, testDa.getCapacity());
192         testDa.addElement(1d);
193         testDa.addElement(1d);
194         Assert.assertEquals(2, testDa.getCapacity());
195         testDa.addElement(1d);
196         Assert.assertEquals(4, testDa.getCapacity());
197     }
198 
199     @Override
200     @Test
201     public void testAdd1000() {
202         super.testAdd1000();
203         Assert.assertEquals("Internal Storage length should be 1024 if we started out with initial capacity of " +
204                 "16 and an expansion factor of 2.0",
205                 1024, ((ResizableDoubleArray) da).getCapacity());
206     }
207 
208     @Test
209     public void testAddElements() {
210         ResizableDoubleArray testDa = new ResizableDoubleArray();
211 
212         // MULTIPLICATIVE_MODE
213         testDa.addElements(new double[] {4, 5, 6});
214         Assert.assertEquals(3, testDa.getNumElements(), 0);
215         Assert.assertEquals(4, testDa.getElement(0), 0);
216         Assert.assertEquals(5, testDa.getElement(1), 0);
217         Assert.assertEquals(6, testDa.getElement(2), 0);
218 
219         testDa.addElements(new double[] {4, 5, 6});
220         Assert.assertEquals(6, testDa.getNumElements());
221 
222         // ADDITIVE_MODE  (x's are occupied storage locations, 0's are open)
223         testDa = new ResizableDoubleArray(2, 2.0, 2.5,
224                                           ResizableDoubleArray.ExpansionMode.ADDITIVE);
225         Assert.assertEquals(2, testDa.getCapacity());
226         testDa.addElements(new double[] { 1d }); // x,0
227         testDa.addElements(new double[] { 2d }); // x,x
228         testDa.addElements(new double[] { 3d }); // x,x,x,0 -- expanded
229         Assert.assertEquals(1d, testDa.getElement(0), 0);
230         Assert.assertEquals(2d, testDa.getElement(1), 0);
231         Assert.assertEquals(3d, testDa.getElement(2), 0);
232         Assert.assertEquals(4, testDa.getCapacity());  // x,x,x,0
233         Assert.assertEquals(3, testDa.getNumElements());
234     }
235 
236     @Override
237     @Test
238     public void testAddElementRolling() {
239         super.testAddElementRolling();
240 
241         // MULTIPLICATIVE_MODE
242         da.clear();
243         da.addElement(1);
244         da.addElement(2);
245         da.addElementRolling(3);
246         Assert.assertEquals(3, da.getElement(1), 0);
247         da.addElementRolling(4);
248         Assert.assertEquals(3, da.getElement(0), 0);
249         Assert.assertEquals(4, da.getElement(1), 0);
250         da.addElement(5);
251         Assert.assertEquals(5, da.getElement(2), 0);
252         da.addElementRolling(6);
253         Assert.assertEquals(4, da.getElement(0), 0);
254         Assert.assertEquals(5, da.getElement(1), 0);
255         Assert.assertEquals(6, da.getElement(2), 0);
256 
257         // ADDITIVE_MODE  (x's are occupied storage locations, 0's are open)
258         ResizableDoubleArray testDa = new ResizableDoubleArray(2, 2.0, 2.5,
259                                                                ResizableDoubleArray.ExpansionMode.ADDITIVE);
260         Assert.assertEquals(2, testDa.getCapacity());
261         testDa.addElement(1d); // x,0
262         testDa.addElement(2d); // x,x
263         testDa.addElement(3d); // x,x,x,0 -- expanded
264         Assert.assertEquals(1d, testDa.getElement(0), 0);
265         Assert.assertEquals(2d, testDa.getElement(1), 0);
266         Assert.assertEquals(3d, testDa.getElement(2), 0);
267         Assert.assertEquals(4, testDa.getCapacity());  // x,x,x,0
268         Assert.assertEquals(3, testDa.getNumElements());
269         testDa.addElementRolling(4d);
270         Assert.assertEquals(2d, testDa.getElement(0), 0);
271         Assert.assertEquals(3d, testDa.getElement(1), 0);
272         Assert.assertEquals(4d, testDa.getElement(2), 0);
273         Assert.assertEquals(4, testDa.getCapacity());  // 0,x,x,x
274         Assert.assertEquals(3, testDa.getNumElements());
275         testDa.addElementRolling(5d);   // 0,0,x,x,x,0 -- time to contract
276         Assert.assertEquals(3d, testDa.getElement(0), 0);
277         Assert.assertEquals(4d, testDa.getElement(1), 0);
278         Assert.assertEquals(5d, testDa.getElement(2), 0);
279         Assert.assertEquals(4, testDa.getCapacity());  // contracted -- x,x,x,0
280         Assert.assertEquals(3, testDa.getNumElements());
281         try {
282             testDa.getElement(4);
283             Assert.fail("Expecting ArrayIndexOutOfBoundsException");
284         } catch (ArrayIndexOutOfBoundsException ex) {
285             // expected
286         }
287         try {
288             testDa.getElement(-1);
289             Assert.fail("Expecting ArrayIndexOutOfBoundsException");
290         } catch (ArrayIndexOutOfBoundsException ex) {
291             // expected
292         }
293     }
294 
295     @Test
296     public void testSetNumberOfElements() {
297         da.addElement( 1.0 );
298         da.addElement( 1.0 );
299         da.addElement( 1.0 );
300         da.addElement( 1.0 );
301         da.addElement( 1.0 );
302         da.addElement( 1.0 );
303         Assert.assertEquals( "Number of elements should equal 6", da.getNumElements(), 6);
304 
305         ((ResizableDoubleArray) da).setNumElements( 3 );
306         Assert.assertEquals( "Number of elements should equal 3", da.getNumElements(), 3);
307 
308         try {
309             ((ResizableDoubleArray) da).setNumElements( -3 );
310             Assert.fail( "Setting number of elements to negative should've thrown an exception");
311         } catch(MathIllegalArgumentException iae) {
312         }
313 
314         ((ResizableDoubleArray) da).setNumElements(1024);
315         Assert.assertEquals( "Number of elements should now be 1024", da.getNumElements(), 1024);
316         Assert.assertEquals( "Element 453 should be a default double", da.getElement( 453 ), 0.0, Double.MIN_VALUE);
317     }
318 
319     @Test
320     public void testWithInitialCapacity() {
321 
322         ResizableDoubleArray eDA2 = new ResizableDoubleArray(2);
323         Assert.assertEquals("Initial number of elements should be 0", 0, eDA2.getNumElements());
324 
325         final DiscreteDistribution.Sampler randomData =
326             UniformDiscreteDistribution.of(100, 1000).createSampler(RandomSource.WELL_19937_C.create());
327         final int iterations = randomData.sample();
328 
329         for( int i = 0; i < iterations; i++) {
330             eDA2.addElement( i );
331         }
332 
333         Assert.assertEquals("Number of elements should be equal to " + iterations, iterations, eDA2.getNumElements());
334 
335         eDA2.addElement( 2.0 );
336 
337         Assert.assertEquals("Number of elements should be equals to " + (iterations +1),
338                 iterations + 1 , eDA2.getNumElements() );
339     }
340 
341     @Test
342     public void testWithInitialCapacityAndExpansionFactor() {
343 
344         ResizableDoubleArray eDA3 = new ResizableDoubleArray(3, 3.0, 3.5);
345         Assert.assertEquals("Initial number of elements should be 0", 0, eDA3.getNumElements() );
346 
347         final DiscreteDistribution.Sampler randomData =
348             UniformDiscreteDistribution.of(100, 3000).createSampler(RandomSource.WELL_19937_C.create());
349 
350         final int iterations = randomData.sample();
351 
352         for( int i = 0; i < iterations; i++) {
353             eDA3.addElement( i );
354         }
355 
356         Assert.assertEquals("Number of elements should be equal to " + iterations, iterations,eDA3.getNumElements());
357 
358         eDA3.addElement( 2.0 );
359 
360         Assert.assertEquals("Number of elements should be equals to " + (iterations +1),
361                 iterations +1, eDA3.getNumElements() );
362 
363         Assert.assertEquals("Expansion factor should equal 3.0", 3.0f, eDA3.getExpansionFactor(), Double.MIN_VALUE);
364     }
365 
366     @Test
367     public void testDiscard() {
368         da.addElement(2.0);
369         da.addElement(2.0);
370         da.addElement(2.0);
371         da.addElement(2.0);
372         da.addElement(2.0);
373         da.addElement(2.0);
374         da.addElement(2.0);
375         da.addElement(2.0);
376         da.addElement(2.0);
377         da.addElement(2.0);
378         da.addElement(2.0);
379         Assert.assertEquals( "Number of elements should be 11", 11, da.getNumElements());
380 
381         ((ResizableDoubleArray)da).discardFrontElements(5);
382         Assert.assertEquals( "Number of elements should be 6", 6, da.getNumElements());
383 
384         da.addElement(2.0);
385         da.addElement(2.0);
386         da.addElement(2.0);
387         da.addElement(2.0);
388         Assert.assertEquals( "Number of elements should be 10", 10, da.getNumElements());
389 
390         ((ResizableDoubleArray)da).discardMostRecentElements(2);
391         Assert.assertEquals( "Number of elements should be 8", 8, da.getNumElements());
392 
393         try {
394             ((ResizableDoubleArray)da).discardFrontElements(-1);
395             Assert.fail( "Trying to discard a negative number of element is not allowed");
396         } catch( Exception e ){
397         }
398 
399         try {
400             ((ResizableDoubleArray)da).discardMostRecentElements(-1);
401             Assert.fail( "Trying to discard a negative number of element is not allowed");
402         } catch( Exception e ){
403         }
404 
405         try {
406             ((ResizableDoubleArray)da).discardFrontElements( 10000 );
407             Assert.fail( "You can't discard more elements than the array contains");
408         } catch( Exception e ){
409         }
410 
411         try {
412             ((ResizableDoubleArray)da).discardMostRecentElements( 10000 );
413             Assert.fail( "You can't discard more elements than the array contains");
414         } catch( Exception e ){
415         }
416     }
417 
418     @Test
419     public void testSubstitute() {
420 
421         da.addElement(2.0);
422         da.addElement(2.0);
423         da.addElement(2.0);
424         da.addElement(2.0);
425         da.addElement(2.0);
426         da.addElement(2.0);
427         da.addElement(2.0);
428         da.addElement(2.0);
429         da.addElement(2.0);
430         da.addElement(2.0);
431         da.addElement(2.0);
432         Assert.assertEquals( "Number of elements should be 11", 11, da.getNumElements());
433 
434         ((ResizableDoubleArray)da).substituteMostRecentElement(24);
435 
436         Assert.assertEquals( "Number of elements should be 11", 11, da.getNumElements());
437 
438         try {
439             ((ResizableDoubleArray)da).discardMostRecentElements(10);
440         } catch( Exception e ){
441             Assert.fail( "Trying to discard a negative number of element is not allowed");
442         }
443 
444         ((ResizableDoubleArray)da).substituteMostRecentElement(24);
445 
446         Assert.assertEquals( "Number of elements should be 1", 1, da.getNumElements());
447     }
448 
449     @Test
450     public void testEqualsAndHashCode() throws Exception {
451 
452         // Wrong type
453         ResizableDoubleArray first = new ResizableDoubleArray();
454         Double other = Double.valueOf(2);
455         Assert.assertFalse(first.equals(other));
456 
457         // Null
458         other = null;
459         Assert.assertFalse(first.equals(other));
460 
461         // Reflexive
462         Assert.assertEquals(first, first);
463 
464         // Non-argument constructor
465         ResizableDoubleArray second = new ResizableDoubleArray();
466         verifyEquality(first, second);
467 
468         // Equals iff same data, same properties
469         ResizableDoubleArray third = new ResizableDoubleArray(3, 2.0, 2.0);
470         verifyInequality(third, first);
471         ResizableDoubleArray fourth = new ResizableDoubleArray(3, 2.0, 2.0);
472         ResizableDoubleArray fifth = new ResizableDoubleArray(2, 2.0, 2.0);
473         verifyEquality(third, fourth);
474         verifyInequality(third, fifth);
475         third.addElement(4.1);
476         third.addElement(4.2);
477         third.addElement(4.3);
478         fourth.addElement(4.1);
479         fourth.addElement(4.2);
480         fourth.addElement(4.3);
481         verifyEquality(third, fourth);
482 
483         // expand
484         fourth.addElement(4.4);
485         verifyInequality(third, fourth);
486         third.addElement(4.4);
487         verifyEquality(third, fourth);
488         fourth.addElement(4.4);
489         verifyInequality(third, fourth);
490         third.addElement(4.4);
491         verifyEquality(third, fourth);
492         fourth.addElementRolling(4.5);
493         third.addElementRolling(4.5);
494         verifyEquality(third, fourth);
495 
496         // discard
497         third.discardFrontElements(1);
498         verifyInequality(third, fourth);
499         fourth.discardFrontElements(1);
500         verifyEquality(third, fourth);
501 
502         // discard recent
503         third.discardMostRecentElements(2);
504         fourth.discardMostRecentElements(2);
505         verifyEquality(third, fourth);
506 
507         // wrong order
508         third.addElement(18);
509         fourth.addElement(17);
510         third.addElement(17);
511         fourth.addElement(18);
512         verifyInequality(third, fourth);
513 
514         // Copy constructor
515         verifyEquality(fourth, new ResizableDoubleArray(fourth));
516 
517         // Instance copy
518         verifyEquality(fourth, fourth.copy());
519     }
520 
521     @Test
522     public void testGetArrayRef() {
523         final ResizableDoubleArray a = new ResizableDoubleArray();
524 
525         // Modify "a" through the public API.
526         final int index = 20;
527         final double v1 = 1.2;
528         a.setElement(index, v1);
529 
530         // Modify the internal storage through the protected API.
531         final double v2 = v1 + 3.4;
532         final double[] aInternalArray = a.getArrayRef();
533         aInternalArray[a.getStartIndex() + index] = v2;
534 
535         Assert.assertEquals(v2, a.getElement(index), 0d);
536     }
537 
538     @Test
539     public void testCompute() {
540         final ResizableDoubleArray a = new ResizableDoubleArray();
541         final int max = 20;
542         for (int i = 1; i <= max; i++) {
543             a.setElement(i, i);
544         }
545 
546         final MathArrays.Function add = new MathArrays.Function() {
547                 @Override
548                 public double evaluate(double[] a, int index, int num) {
549                     double sum = 0;
550                     final int max = index + num;
551                     for (int i = index; i < max; i++) {
552                         sum += a[i];
553                     }
554                     return sum;
555                 }
556                 @Override
557                 public double evaluate(double[] a) {
558                     return evaluate(a, 0, a.length);
559                 }
560             };
561 
562         final double sum = a.compute(add);
563         Assert.assertEquals(0.5 * max * (max + 1), sum, 0);
564     }
565 
566     private void verifyEquality(ResizableDoubleArray a, ResizableDoubleArray b) {
567         Assert.assertEquals(b, a);
568         Assert.assertEquals(a, b);
569         Assert.assertEquals(a.hashCode(), b.hashCode());
570     }
571 
572     private void verifyInequality(ResizableDoubleArray a, ResizableDoubleArray b) {
573         Assert.assertNotEquals(b, a);
574         Assert.assertNotEquals(a, b);
575         Assert.assertNotEquals(a.hashCode(), b.hashCode());
576     }
577 }