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.math3.util;
18  
19  import java.io.Serializable;
20  import java.util.Arrays;
21  
22  import org.apache.commons.math3.exception.MathIllegalArgumentException;
23  import org.apache.commons.math3.exception.MathIllegalStateException;
24  import org.apache.commons.math3.exception.MathInternalError;
25  import org.apache.commons.math3.exception.NullArgumentException;
26  import org.apache.commons.math3.exception.NotStrictlyPositiveException;
27  import org.apache.commons.math3.exception.NumberIsTooSmallException;
28  import org.apache.commons.math3.exception.util.LocalizedFormats;
29  
30  /**
31   * <p>
32   * A variable length {@link DoubleArray} implementation that automatically
33   * handles expanding and contracting its internal storage array as elements
34   * are added and removed.
35   * </p>
36   * <h3>Important note: Usage should not assume that this class is thread-safe
37   * even though some of the methods are {@code synchronized}.
38   * This qualifier will be dropped in the next major release (4.0).</h3>
39   * <p>
40   * The internal storage array starts with capacity determined by the
41   * {@code initialCapacity} property, which can be set by the constructor.
42   * The default initial capacity is 16.  Adding elements using
43   * {@link #addElement(double)} appends elements to the end of the array.
44   * When there are no open entries at the end of the internal storage array,
45   * the array is expanded.  The size of the expanded array depends on the
46   * {@code expansionMode} and {@code expansionFactor} properties.
47   * The {@code expansionMode} determines whether the size of the array is
48   * multiplied by the {@code expansionFactor}
49   * ({@link ExpansionMode#MULTIPLICATIVE}) or if the expansion is additive
50   * ({@link ExpansionMode#ADDITIVE} -- {@code expansionFactor} storage
51   * locations added).
52   * The default {@code expansionMode} is {@code MULTIPLICATIVE} and the default
53   * {@code expansionFactor} is 2.
54   * </p>
55   * <p>
56   * The {@link #addElementRolling(double)} method adds a new element to the end
57   * of the internal storage array and adjusts the "usable window" of the
58   * internal array forward by one position (effectively making what was the
59   * second element the first, and so on).  Repeated activations of this method
60   * (or activation of {@link #discardFrontElements(int)}) will effectively orphan
61   * the storage locations at the beginning of the internal storage array.  To
62   * reclaim this storage, each time one of these methods is activated, the size
63   * of the internal storage array is compared to the number of addressable
64   * elements (the {@code numElements} property) and if the difference
65   * is too large, the internal array is contracted to size
66   * {@code numElements + 1}.  The determination of when the internal
67   * storage array is "too large" depends on the {@code expansionMode} and
68   * {@code contractionFactor} properties.  If  the {@code expansionMode}
69   * is {@code MULTIPLICATIVE}, contraction is triggered when the
70   * ratio between storage array length and {@code numElements} exceeds
71   * {@code contractionFactor.}  If the {@code expansionMode}
72   * is {@code ADDITIVE}, the number of excess storage locations
73   * is compared to {@code contractionFactor}.
74   * </p>
75   * <p>
76   * To avoid cycles of expansions and contractions, the
77   * {@code expansionFactor} must not exceed the {@code contractionFactor}.
78   * Constructors and mutators for both of these properties enforce this
79   * requirement, throwing a {@code MathIllegalArgumentException} if it is
80   * violated.
81   * </p>
82   * @version $Id: ResizableDoubleArray.java 1462504 2013-03-29 15:48:57Z luc $
83   */
84  public class ResizableDoubleArray implements DoubleArray, Serializable {
85      /** Additive expansion mode.
86       * @deprecated As of 3.1. Please use {@link ExpansionMode#ADDITIVE} instead.
87       */
88      @Deprecated
89      public static final int ADDITIVE_MODE = 1;
90      /** Multiplicative expansion mode.
91       * @deprecated As of 3.1. Please use {@link ExpansionMode#MULTIPLICATIVE} instead.
92       */
93      @Deprecated
94      public static final int MULTIPLICATIVE_MODE = 0;
95      /** Serializable version identifier. */
96      private static final long serialVersionUID = -3485529955529426875L;
97  
98      /** Default value for initial capacity. */
99      private static final int DEFAULT_INITIAL_CAPACITY = 16;
100     /** Default value for array size modifier. */
101     private static final double DEFAULT_EXPANSION_FACTOR = 2.0;
102     /**
103      * Default value for the difference between {@link #contractionCriterion}
104      * and {@link #expansionFactor}.
105      */
106     private static final double DEFAULT_CONTRACTION_DELTA = 0.5;
107 
108     /**
109      * The contraction criteria determines when the internal array will be
110      * contracted to fit the number of elements contained in the element
111      *  array + 1.
112      */
113     private double contractionCriterion = 2.5;
114 
115     /**
116      * The expansion factor of the array.  When the array needs to be expanded,
117      * the new array size will be
118      * {@code internalArray.length * expansionFactor}
119      * if {@code expansionMode} is set to MULTIPLICATIVE_MODE, or
120      * {@code internalArray.length + expansionFactor} if
121      * {@code expansionMode} is set to ADDITIVE_MODE.
122      */
123     private double expansionFactor = 2.0;
124 
125     /**
126      * Determines whether array expansion by {@code expansionFactor}
127      * is additive or multiplicative.
128      */
129     private ExpansionMode expansionMode = ExpansionMode.MULTIPLICATIVE;
130 
131     /**
132      * The internal storage array.
133      */
134     private double[] internalArray;
135 
136     /**
137      * The number of addressable elements in the array.  Note that this
138      * has nothing to do with the length of the internal storage array.
139      */
140     private int numElements = 0;
141 
142     /**
143      * The position of the first addressable element in the internal storage
144      * array.  The addressable elements in the array are
145      * {@code internalArray[startIndex],...,internalArray[startIndex + numElements - 1]}.
146      */
147     private int startIndex = 0;
148 
149     /**
150      * Specification of expansion algorithm.
151      * @since 3.1
152      */
153     public static enum ExpansionMode {
154         /** Multiplicative expansion mode. */
155         MULTIPLICATIVE,
156         /** Additive expansion mode. */
157         ADDITIVE
158     }
159 
160     /**
161      * Creates an instance with default properties.
162      * <ul>
163      *  <li>{@code initialCapacity = 16}</li>
164      *  <li>{@code expansionMode = MULTIPLICATIVE}</li>
165      *  <li>{@code expansionFactor = 2.0}</li>
166      *  <li>{@code contractionCriterion = 2.5}</li>
167      * </ul>
168      */
169     public ResizableDoubleArray() {
170         this(DEFAULT_INITIAL_CAPACITY);
171     }
172 
173     /**
174      * Creates an instance with the specified initial capacity.
175      * Other properties take default values:
176      * <ul>
177      *  <li>{@code expansionMode = MULTIPLICATIVE}</li>
178      *  <li>{@code expansionFactor = 2.0}</li>
179      *  <li>{@code contractionCriterion = 2.5}</li>
180      * </ul>
181      * @param initialCapacity Initial size of the internal storage array.
182      * @throws MathIllegalArgumentException if {@code initialCapacity <= 0}.
183      */
184     public ResizableDoubleArray(int initialCapacity)
185         throws MathIllegalArgumentException {
186         this(initialCapacity, DEFAULT_EXPANSION_FACTOR);
187     }
188 
189     /**
190      * Creates an instance from an existing {@code double[]} with the
191      * initial capacity and numElements corresponding to the size of
192      * the supplied {@code double[]} array.
193      * If the supplied array is null, a new empty array with the default
194      * initial capacity will be created.
195      * The input array is copied, not referenced.
196      * Other properties take default values:
197      * <ul>
198      *  <li>{@code initialCapacity = 16}</li>
199      *  <li>{@code expansionMode = MULTIPLICATIVE}</li>
200      *  <li>{@code expansionFactor = 2.0}</li>
201      *  <li>{@code contractionCriterion = 2.5}</li>
202      * </ul>
203      *
204      * @param initialArray initial array
205      * @since 2.2
206      */
207     public ResizableDoubleArray(double[] initialArray) {
208         this(DEFAULT_INITIAL_CAPACITY,
209              DEFAULT_EXPANSION_FACTOR,
210              DEFAULT_CONTRACTION_DELTA + DEFAULT_EXPANSION_FACTOR,
211              ExpansionMode.MULTIPLICATIVE,
212              initialArray);
213     }
214 
215     /**
216      * Creates an instance with the specified initial capacity
217      * and expansion factor.
218      * The remaining properties take default values:
219      * <ul>
220      *  <li>{@code expansionMode = MULTIPLICATIVE}</li>
221      *  <li>{@code contractionCriterion = 0.5 + expansionFactor}</li>
222      * </ul>
223      * <br/>
224      * Throws IllegalArgumentException if the following conditions are
225      * not met:
226      * <ul>
227      *  <li>{@code initialCapacity > 0}</li>
228      *  <li>{@code expansionFactor > 1}</li>
229      * </ul>
230      *
231      * @param initialCapacity Initial size of the internal storage array.
232      * @param expansionFactor The array will be expanded based on this
233      * parameter.
234      * @throws MathIllegalArgumentException if parameters are not valid.
235      * @deprecated As of 3.1. Please use
236      * {@link #ResizableDoubleArray(int,double)} instead.
237      */
238     @Deprecated
239     public ResizableDoubleArray(int initialCapacity,
240                                 float expansionFactor)
241         throws MathIllegalArgumentException {
242         this(initialCapacity,
243              (double) expansionFactor);
244     }
245 
246     /**
247      * Creates an instance with the specified initial capacity
248      * and expansion factor.
249      * The remaining properties take default values:
250      * <ul>
251      *  <li>{@code expansionMode = MULTIPLICATIVE}</li>
252      *  <li>{@code contractionCriterion = 0.5 + expansionFactor}</li>
253      * </ul>
254      * <br/>
255      * Throws IllegalArgumentException if the following conditions are
256      * not met:
257      * <ul>
258      *  <li>{@code initialCapacity > 0}</li>
259      *  <li>{@code expansionFactor > 1}</li>
260      * </ul>
261      *
262      * @param initialCapacity Initial size of the internal storage array.
263      * @param expansionFactor The array will be expanded based on this
264      * parameter.
265      * @throws MathIllegalArgumentException if parameters are not valid.
266      * @since 3.1
267      */
268     public ResizableDoubleArray(int initialCapacity,
269                                 double expansionFactor)
270         throws MathIllegalArgumentException {
271         this(initialCapacity,
272              expansionFactor,
273              DEFAULT_CONTRACTION_DELTA + expansionFactor);
274     }
275 
276     /**
277      * Creates an instance with the specified initialCapacity,
278      * expansionFactor, and contractionCriterion.
279      * The expansion mode will default to {@code MULTIPLICATIVE}.
280      * <br/>
281      * Throws IllegalArgumentException if the following conditions are
282      * not met:
283      * <ul>
284      *  <li>{@code initialCapacity > 0}</li>
285      *  <li>{@code expansionFactor > 1}</li>
286      *  <li>{@code contractionCriterion >= expansionFactor}</li>
287      * </ul>
288      *
289      * @param initialCapacity Initial size of the internal storage array..
290      * @param expansionFactor The array will be expanded based on this
291      * parameter.
292      * @param contractionCriteria Contraction criteria.
293      * @throws MathIllegalArgumentException if parameters are not valid.
294      * @deprecated As of 3.1. Please use
295      * {@link #ResizableDoubleArray(int,double,double)} instead.
296      */
297     @Deprecated
298     public ResizableDoubleArray(int initialCapacity,
299                                 float expansionFactor,
300                                 float contractionCriteria)
301         throws MathIllegalArgumentException {
302         this(initialCapacity,
303              (double) expansionFactor,
304              (double) contractionCriteria);
305     }
306 
307     /**
308      * Creates an instance with the specified initial capacity,
309      * expansion factor, and contraction criteria.
310      * The expansion mode will default to {@code MULTIPLICATIVE}.
311      * <br/>
312      * Throws IllegalArgumentException if the following conditions are
313      * not met:
314      * <ul>
315      *  <li>{@code initialCapacity > 0}</li>
316      *  <li>{@code expansionFactor > 1}</li>
317      *  <li>{@code contractionCriterion >= expansionFactor}</li>
318      * </ul>
319      *
320      * @param initialCapacity Initial size of the internal storage array..
321      * @param expansionFactor The array will be expanded based on this
322      * parameter.
323      * @param contractionCriterion Contraction criterion.
324      * @throws MathIllegalArgumentException if the parameters are not valid.
325      * @since 3.1
326      */
327     public ResizableDoubleArray(int initialCapacity,
328                                 double expansionFactor,
329                                 double contractionCriterion)
330         throws MathIllegalArgumentException {
331         this(initialCapacity,
332              expansionFactor,
333              contractionCriterion,
334              ExpansionMode.MULTIPLICATIVE,
335              null);
336     }
337 
338     /**
339      * <p>
340      * Create a ResizableArray with the specified properties.</p>
341      * <p>
342      * Throws IllegalArgumentException if the following conditions are
343      * not met:
344      * <ul>
345      * <li><code>initialCapacity > 0</code></li>
346      * <li><code>expansionFactor > 1</code></li>
347      * <li><code>contractionFactor >= expansionFactor</code></li>
348      * <li><code>expansionMode in {MULTIPLICATIVE_MODE, ADDITIVE_MODE}</code>
349      * </li>
350      * </ul></p>
351      *
352      * @param initialCapacity the initial size of the internal storage array
353      * @param expansionFactor the array will be expanded based on this
354      *                        parameter
355      * @param contractionCriteria the contraction Criteria
356      * @param expansionMode  the expansion mode
357      * @throws MathIllegalArgumentException if parameters are not valid
358      * @deprecated As of 3.1. Please use
359      * {@link #ResizableDoubleArray(int,double,double,ExpansionMode,double[])}
360      * instead.
361      */
362     public ResizableDoubleArray(int initialCapacity, float expansionFactor,
363             float contractionCriteria, int expansionMode) throws MathIllegalArgumentException {
364         this(initialCapacity,
365              expansionFactor,
366              contractionCriteria,
367              expansionMode == ADDITIVE_MODE ?
368              ExpansionMode.ADDITIVE :
369              ExpansionMode.MULTIPLICATIVE,
370              null);
371         // XXX Just ot retain the expected failure in a unit test.
372         // With the new "enum", that test will become obsolete.
373         setExpansionMode(expansionMode);
374     }
375 
376     /**
377      * Creates an instance with the specified properties.
378      * <br/>
379      * Throws MathIllegalArgumentException if the following conditions are
380      * not met:
381      * <ul>
382      *  <li>{@code initialCapacity > 0}</li>
383      *  <li>{@code expansionFactor > 1}</li>
384      *  <li>{@code contractionCriterion >= expansionFactor}</li>
385      * </ul>
386      *
387      * @param initialCapacity Initial size of the internal storage array.
388      * @param expansionFactor The array will be expanded based on this
389      * parameter.
390      * @param contractionCriterion Contraction criteria.
391      * @param expansionMode Expansion mode.
392      * @param data Initial contents of the array.
393      * @throws MathIllegalArgumentException if the parameters are not valid.
394      */
395     public ResizableDoubleArray(int initialCapacity,
396                                 double expansionFactor,
397                                 double contractionCriterion,
398                                 ExpansionMode expansionMode,
399                                 double ... data)
400         throws MathIllegalArgumentException {
401         if (initialCapacity <= 0) {
402             throw new NotStrictlyPositiveException(LocalizedFormats.INITIAL_CAPACITY_NOT_POSITIVE,
403                                                    initialCapacity);
404         }
405         checkContractExpand(contractionCriterion, expansionFactor);
406 
407         this.expansionFactor = expansionFactor;
408         this.contractionCriterion = contractionCriterion;
409         this.expansionMode = expansionMode;
410         internalArray = new double[initialCapacity];
411         numElements = 0;
412         startIndex = 0;
413 
414         if (data != null) {
415             addElements(data);
416         }
417     }
418 
419     /**
420      * Copy constructor.  Creates a new ResizableDoubleArray that is a deep,
421      * fresh copy of the original. Needs to acquire synchronization lock
422      * on original.  Original may not be null; otherwise a {@link NullArgumentException}
423      * is thrown.
424      *
425      * @param original array to copy
426      * @exception NullArgumentException if original is null
427      * @since 2.0
428      */
429     public ResizableDoubleArray(ResizableDoubleArray original)
430         throws NullArgumentException {
431         MathUtils.checkNotNull(original);
432         copy(original, this);
433     }
434 
435     /**
436      * Adds an element to the end of this expandable array.
437      *
438      * @param value Value to be added to end of array.
439      */
440     public synchronized void addElement(double value) {
441         if (internalArray.length <= startIndex + numElements) {
442             expand();
443         }
444         internalArray[startIndex + numElements++] = value;
445     }
446 
447     /**
448      * Adds several element to the end of this expandable array.
449      *
450      * @param values Values to be added to end of array.
451      * @since 2.2
452      */
453     public synchronized void addElements(double[] values) {
454         final double[] tempArray = new double[numElements + values.length + 1];
455         System.arraycopy(internalArray, startIndex, tempArray, 0, numElements);
456         System.arraycopy(values, 0, tempArray, numElements, values.length);
457         internalArray = tempArray;
458         startIndex = 0;
459         numElements += values.length;
460     }
461 
462     /**
463      * <p>
464      * Adds an element to the end of the array and removes the first
465      * element in the array.  Returns the discarded first element.
466      * The effect is similar to a push operation in a FIFO queue.
467      * </p>
468      * <p>
469      * Example: If the array contains the elements 1, 2, 3, 4 (in that order)
470      * and addElementRolling(5) is invoked, the result is an array containing
471      * the entries 2, 3, 4, 5 and the value returned is 1.
472      * </p>
473      *
474      * @param value Value to be added to the array.
475      * @return the value which has been discarded or "pushed" out of the array
476      * by this rolling insert.
477      */
478     public synchronized double addElementRolling(double value) {
479         double discarded = internalArray[startIndex];
480 
481         if ((startIndex + (numElements + 1)) > internalArray.length) {
482             expand();
483         }
484         // Increment the start index
485         startIndex += 1;
486 
487         // Add the new value
488         internalArray[startIndex + (numElements - 1)] = value;
489 
490         // Check the contraction criterion.
491         if (shouldContract()) {
492             contract();
493         }
494         return discarded;
495     }
496 
497     /**
498      * Substitutes <code>value</code> for the most recently added value.
499      * Returns the value that has been replaced. If the array is empty (i.e.
500      * if {@link #numElements} is zero), an IllegalStateException is thrown.
501      *
502      * @param value New value to substitute for the most recently added value
503      * @return the value that has been replaced in the array.
504      * @throws MathIllegalStateException if the array is empty
505      * @since 2.0
506      */
507     public synchronized double substituteMostRecentElement(double value)
508         throws MathIllegalStateException {
509         if (numElements < 1) {
510             throw new MathIllegalStateException(
511                     LocalizedFormats.CANNOT_SUBSTITUTE_ELEMENT_FROM_EMPTY_ARRAY);
512         }
513 
514         final int substIndex = startIndex + (numElements - 1);
515         final double discarded = internalArray[substIndex];
516 
517         internalArray[substIndex] = value;
518 
519         return discarded;
520     }
521 
522     /**
523      * Checks the expansion factor and the contraction criterion and throws an
524      * IllegalArgumentException if the contractionCriteria is less than the
525      * expansionCriteria
526      *
527      * @param expansion factor to be checked
528      * @param contraction criteria to be checked
529      * @throws MathIllegalArgumentException if the contractionCriteria is less than
530      * the expansionCriteria.
531      * @deprecated As of 3.1. Please use
532      * {@link #checkContractExpand(double,double)} instead.
533      */
534     protected void checkContractExpand(float contraction, float expansion)
535         throws MathIllegalArgumentException {
536         checkContractExpand((double) contraction,
537                             (double) expansion);
538     }
539 
540     /**
541      * Checks the expansion factor and the contraction criterion and raises
542      * an exception if the contraction criterion is smaller than the
543      * expansion criterion.
544      *
545      * @param contraction Criterion to be checked.
546      * @param expansion Factor to be checked.
547      * @throws NumberIsTooSmallException if {@code contraction < expansion}.
548      * @throws NumberIsTooSmallException if {@code contraction <= 1}.
549      * @throws NumberIsTooSmallException if {@code expansion <= 1 }.
550      * @since 3.1
551      */
552     protected void checkContractExpand(double contraction,
553                                        double expansion)
554         throws NumberIsTooSmallException {
555         if (contraction < expansion) {
556             final NumberIsTooSmallException e = new NumberIsTooSmallException(contraction, 1, true);
557             e.getContext().addMessage(LocalizedFormats.CONTRACTION_CRITERIA_SMALLER_THAN_EXPANSION_FACTOR,
558                                       contraction, expansion);
559             throw e;
560         }
561 
562         if (contraction <= 1) {
563             final NumberIsTooSmallException e = new NumberIsTooSmallException(contraction, 1, false);
564             e.getContext().addMessage(LocalizedFormats.CONTRACTION_CRITERIA_SMALLER_THAN_ONE,
565                                       contraction);
566             throw e;
567         }
568 
569         if (expansion <= 1) {
570             final NumberIsTooSmallException e = new NumberIsTooSmallException(contraction, 1, false);
571             e.getContext().addMessage(LocalizedFormats.EXPANSION_FACTOR_SMALLER_THAN_ONE,
572                                       expansion);
573             throw e;
574         }
575     }
576 
577     /**
578      * Clear the array contents, resetting the number of elements to zero.
579      */
580     public synchronized void clear() {
581         numElements = 0;
582         startIndex = 0;
583     }
584 
585     /**
586      * Contracts the storage array to the (size of the element set) + 1 - to
587      * avoid a zero length array. This function also resets the startIndex to
588      * zero.
589      */
590     public synchronized void contract() {
591         final double[] tempArray = new double[numElements + 1];
592 
593         // Copy and swap - copy only the element array from the src array.
594         System.arraycopy(internalArray, startIndex, tempArray, 0, numElements);
595         internalArray = tempArray;
596 
597         // Reset the start index to zero
598         startIndex = 0;
599     }
600 
601     /**
602      * Discards the <code>i</code> initial elements of the array.  For example,
603      * if the array contains the elements 1,2,3,4, invoking
604      * <code>discardFrontElements(2)</code> will cause the first two elements
605      * to be discarded, leaving 3,4 in the array.  Throws illegalArgumentException
606      * if i exceeds numElements.
607      *
608      * @param i  the number of elements to discard from the front of the array
609      * @throws MathIllegalArgumentException if i is greater than numElements.
610      * @since 2.0
611      */
612     public synchronized void discardFrontElements(int i)
613         throws MathIllegalArgumentException {
614         discardExtremeElements(i,true);
615     }
616 
617     /**
618      * Discards the <code>i</code> last elements of the array.  For example,
619      * if the array contains the elements 1,2,3,4, invoking
620      * <code>discardMostRecentElements(2)</code> will cause the last two elements
621      * to be discarded, leaving 1,2 in the array.  Throws illegalArgumentException
622      * if i exceeds numElements.
623      *
624      * @param i  the number of elements to discard from the end of the array
625      * @throws MathIllegalArgumentException if i is greater than numElements.
626      * @since 2.0
627      */
628     public synchronized void discardMostRecentElements(int i)
629         throws MathIllegalArgumentException {
630         discardExtremeElements(i,false);
631     }
632 
633     /**
634      * Discards the <code>i</code> first or last elements of the array,
635      * depending on the value of <code>front</code>.
636      * For example, if the array contains the elements 1,2,3,4, invoking
637      * <code>discardExtremeElements(2,false)</code> will cause the last two elements
638      * to be discarded, leaving 1,2 in the array.
639      * For example, if the array contains the elements 1,2,3,4, invoking
640      * <code>discardExtremeElements(2,true)</code> will cause the first two elements
641      * to be discarded, leaving 3,4 in the array.
642      * Throws illegalArgumentException
643      * if i exceeds numElements.
644      *
645      * @param i  the number of elements to discard from the front/end of the array
646      * @param front true if elements are to be discarded from the front
647      * of the array, false if elements are to be discarded from the end
648      * of the array
649      * @throws MathIllegalArgumentException if i is greater than numElements.
650      * @since 2.0
651      */
652     private synchronized void discardExtremeElements(int i,
653                                                      boolean front)
654         throws MathIllegalArgumentException {
655         if (i > numElements) {
656             throw new MathIllegalArgumentException(
657                     LocalizedFormats.TOO_MANY_ELEMENTS_TO_DISCARD_FROM_ARRAY,
658                     i, numElements);
659        } else if (i < 0) {
660            throw new MathIllegalArgumentException(
661                    LocalizedFormats.CANNOT_DISCARD_NEGATIVE_NUMBER_OF_ELEMENTS,
662                    i);
663         } else {
664             // "Subtract" this number of discarded from numElements
665             numElements -= i;
666             if (front) {
667                 startIndex += i;
668             }
669         }
670         if (shouldContract()) {
671             contract();
672         }
673     }
674 
675     /**
676      * Expands the internal storage array using the expansion factor.
677      * <p>
678      * if <code>expansionMode</code> is set to MULTIPLICATIVE_MODE,
679      * the new array size will be <code>internalArray.length * expansionFactor.</code>
680      * If <code>expansionMode</code> is set to ADDITIVE_MODE,  the length
681      * after expansion will be <code>internalArray.length + expansionFactor</code>
682      * </p>
683      */
684     protected synchronized void expand() {
685         // notice the use of FastMath.ceil(), this guarantees that we will always
686         // have an array of at least currentSize + 1.   Assume that the
687         // current initial capacity is 1 and the expansion factor
688         // is 1.000000000000000001.  The newly calculated size will be
689         // rounded up to 2 after the multiplication is performed.
690         int newSize = 0;
691         if (expansionMode == ExpansionMode.MULTIPLICATIVE) {
692             newSize = (int) FastMath.ceil(internalArray.length * expansionFactor);
693         } else {
694             newSize = (int) (internalArray.length + FastMath.round(expansionFactor));
695         }
696         final double[] tempArray = new double[newSize];
697 
698         // Copy and swap
699         System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length);
700         internalArray = tempArray;
701     }
702 
703     /**
704      * Expands the internal storage array to the specified size.
705      *
706      * @param size Size of the new internal storage array.
707      */
708     private synchronized void expandTo(int size) {
709         final double[] tempArray = new double[size];
710         // Copy and swap
711         System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length);
712         internalArray = tempArray;
713     }
714 
715     /**
716      * The contraction criteria defines when the internal array will contract
717      * to store only the number of elements in the element array.
718      * If  the <code>expansionMode</code> is <code>MULTIPLICATIVE_MODE</code>,
719      * contraction is triggered when the ratio between storage array length
720      * and <code>numElements</code> exceeds <code>contractionFactor</code>.
721      * If the <code>expansionMode</code> is <code>ADDITIVE_MODE</code>, the
722      * number of excess storage locations is compared to
723      * <code>contractionFactor.</code>
724      *
725      * @return the contraction criteria used to reclaim memory.
726      * @deprecated As of 3.1. Please use {@link #getContractionCriterion()}
727      * instead.
728      */
729     @Deprecated
730     public float getContractionCriteria() {
731         return (float) getContractionCriterion();
732     }
733 
734     /**
735      * The contraction criterion defines when the internal array will contract
736      * to store only the number of elements in the element array.
737      * If  the <code>expansionMode</code> is <code>MULTIPLICATIVE_MODE</code>,
738      * contraction is triggered when the ratio between storage array length
739      * and <code>numElements</code> exceeds <code>contractionFactor</code>.
740      * If the <code>expansionMode</code> is <code>ADDITIVE_MODE</code>, the
741      * number of excess storage locations is compared to
742      * <code>contractionFactor.</code>
743      *
744      * @return the contraction criterion used to reclaim memory.
745      * @since 3.1
746      */
747     public double getContractionCriterion() {
748         return contractionCriterion;
749     }
750 
751     /**
752      * Returns the element at the specified index
753      *
754      * @param index index to fetch a value from
755      * @return value stored at the specified index
756      * @throws ArrayIndexOutOfBoundsException if <code>index</code> is less than
757      * zero or is greater than <code>getNumElements() - 1</code>.
758      */
759     public synchronized double getElement(int index) {
760         if (index >= numElements) {
761             throw new ArrayIndexOutOfBoundsException(index);
762         } else if (index >= 0) {
763             return internalArray[startIndex + index];
764         } else {
765             throw new ArrayIndexOutOfBoundsException(index);
766         }
767     }
768 
769      /**
770      * Returns a double array containing the elements of this
771      * <code>ResizableArray</code>.  This method returns a copy, not a
772      * reference to the underlying array, so that changes made to the returned
773      *  array have no effect on this <code>ResizableArray.</code>
774      * @return the double array.
775      */
776     public synchronized double[] getElements() {
777         final double[] elementArray = new double[numElements];
778         System.arraycopy(internalArray, startIndex, elementArray, 0, numElements);
779         return elementArray;
780     }
781 
782     /**
783      * The expansion factor controls the size of a new array when an array
784      * needs to be expanded.  The <code>expansionMode</code>
785      * determines whether the size of the array is multiplied by the
786      * <code>expansionFactor</code> (MULTIPLICATIVE_MODE) or if
787      * the expansion is additive (ADDITIVE_MODE -- <code>expansionFactor</code>
788      * storage locations added).  The default <code>expansionMode</code> is
789      * MULTIPLICATIVE_MODE and the default <code>expansionFactor</code>
790      * is 2.0.
791      *
792      * @return the expansion factor of this expandable double array
793      * @deprecated As of 3.1. Return type will be changed to "double" in 4.0.
794      */
795     @Deprecated
796     public float getExpansionFactor() {
797         return (float) expansionFactor;
798     }
799 
800     /**
801      * The expansion mode determines whether the internal storage
802      * array grows additively or multiplicatively when it is expanded.
803      *
804      * @return the expansion mode.
805      * @deprecated As of 3.1. Return value to be changed to
806      * {@link ExpansionMode} in 4.0.
807      */
808     public int getExpansionMode() {
809         switch (expansionMode) {
810         case MULTIPLICATIVE:
811             return MULTIPLICATIVE_MODE;
812         case ADDITIVE:
813             return ADDITIVE_MODE;
814         default:
815             throw new MathInternalError(); // Should never happen.
816         }
817     }
818 
819     /**
820      * Notice the package scope on this method.   This method is simply here
821      * for the JUnit test, it allows us check if the expansion is working
822      * properly after a number of expansions.  This is not meant to be a part
823      * of the public interface of this class.
824      *
825      * @return the length of the internal storage array.
826      * @deprecated As of 3.1. Please use {@link #getCapacity()} instead.
827      */
828     @Deprecated
829     synchronized int getInternalLength() {
830         return internalArray.length;
831     }
832 
833     /**
834      * Gets the currently allocated size of the internal data structure used
835      * for storing elements.
836      * This is not to be confused with {@link #getNumElements() the number of
837      * elements actually stored}.
838      *
839      * @return the length of the internal array.
840      * @since 3.1
841      */
842     public int getCapacity() {
843         return internalArray.length;
844     }
845 
846     /**
847      * Returns the number of elements currently in the array.  Please note
848      * that this is different from the length of the internal storage array.
849      *
850      * @return the number of elements.
851      */
852     public synchronized int getNumElements() {
853         return numElements;
854     }
855 
856     /**
857      * Returns the internal storage array.  Note that this method returns
858      * a reference to the internal storage array, not a copy, and to correctly
859      * address elements of the array, the <code>startIndex</code> is
860      * required (available via the {@link #start} method).  This method should
861      * only be used in cases where copying the internal array is not practical.
862      * The {@link #getElements} method should be used in all other cases.
863      *
864      *
865      * @return the internal storage array used by this object
866      * @since 2.0
867      * @deprecated As of 3.1.
868      */
869     @Deprecated
870     public synchronized double[] getInternalValues() {
871         return internalArray;
872     }
873 
874     /**
875      * Provides <em>direct</em> access to the internal storage array.
876      * Please note that this method returns a reference to this object's
877      * storage array, not a copy.
878      * <br/>
879      * To correctly address elements of the array, the "start index" is
880      * required (available via the {@link #getStartIndex() getStartIndex}
881      * method.
882      * <br/>
883      * This method should only be used to avoid copying the internal array.
884      * The returned value <em>must</em> be used for reading only; other
885      * uses could lead to this object becoming inconsistent.
886      * <br/>
887      * The {@link #getElements} method has no such limitation since it
888      * returns a copy of this array's addressable elements.
889      *
890      * @return the internal storage array used by this object.
891      * @since 3.1
892      */
893     protected double[] getArrayRef() {
894         return internalArray;
895     }
896 
897     /**
898      * Returns the "start index" of the internal array.
899      * This index is the position of the first addressable element in the
900      * internal storage array.
901      * The addressable elements in the array are at indices contained in
902      * the interval [{@link #getStartIndex()},
903      *               {@link #getStartIndex()} + {@link #getNumElements()} - 1].
904      *
905      * @return the start index.
906      * @since 3.1
907      */
908     protected int getStartIndex() {
909         return startIndex;
910     }
911 
912     /**
913      * Sets the contraction criteria.
914      *
915      * @param contractionCriteria contraction criteria
916      * @throws MathIllegalArgumentException if the contractionCriteria is less than
917      *         the expansionCriteria.
918      * @deprecated As of 3.1 (to be removed in 4.0 as field will become "final").
919      */
920     @Deprecated
921     public void setContractionCriteria(float contractionCriteria)
922         throws MathIllegalArgumentException {
923         checkContractExpand(contractionCriteria, getExpansionFactor());
924         synchronized(this) {
925             this.contractionCriterion = contractionCriteria;
926         }
927     }
928 
929     /**
930      * Performs an operation on the addressable elements of the array.
931      *
932      * @param f Function to be applied on this array.
933      * @return the result.
934      * @since 3.1
935      */
936     public double compute(MathArrays.Function f) {
937         final double[] array;
938         final int start;
939         final int num;
940         synchronized(this) {
941             array = internalArray;
942             start = startIndex;
943             num   = numElements;
944         }
945         return f.evaluate(array, start, num);
946     }
947 
948     /**
949      * Sets the element at the specified index.  If the specified index is greater than
950      * <code>getNumElements() - 1</code>, the <code>numElements</code> property
951      * is increased to <code>index +1</code> and additional storage is allocated
952      * (if necessary) for the new element and all  (uninitialized) elements
953      * between the new element and the previous end of the array).
954      *
955      * @param index index to store a value in
956      * @param value value to store at the specified index
957      * @throws ArrayIndexOutOfBoundsException if {@code index < 0}.
958      */
959     public synchronized void setElement(int index, double value) {
960         if (index < 0) {
961             throw new ArrayIndexOutOfBoundsException(index);
962         }
963         if (index + 1 > numElements) {
964             numElements = index + 1;
965         }
966         if ((startIndex + index) >= internalArray.length) {
967             expandTo(startIndex + (index + 1));
968         }
969         internalArray[startIndex + index] = value;
970     }
971 
972     /**
973      * Sets the expansionFactor.  Throws IllegalArgumentException if the
974      * the following conditions are not met:
975      * <ul>
976      * <li><code>expansionFactor > 1</code></li>
977      * <li><code>contractionFactor >= expansionFactor</code></li>
978      * </ul>
979      * @param expansionFactor the new expansion factor value.
980      * @throws MathIllegalArgumentException if expansionFactor is <= 1 or greater
981      * than contractionFactor
982      * @deprecated As of 3.1 (to be removed in 4.0 as field will become "final").
983      */
984     @Deprecated
985     public void setExpansionFactor(float expansionFactor) throws MathIllegalArgumentException {
986         checkContractExpand(getContractionCriterion(), expansionFactor);
987         // The check above verifies that the expansion factor is > 1.0;
988         synchronized(this) {
989             this.expansionFactor = expansionFactor;
990         }
991     }
992 
993     /**
994      * Sets the <code>expansionMode</code>. The specified value must be one of
995      * ADDITIVE_MODE, MULTIPLICATIVE_MODE.
996      *
997      * @param expansionMode The expansionMode to set.
998      * @throws MathIllegalArgumentException if the specified mode value is not valid.
999      * @deprecated As of 3.1. Please use {@link #setExpansionMode(ExpansionMode)} instead.
1000      */
1001     @Deprecated
1002     public void setExpansionMode(int expansionMode)
1003         throws MathIllegalArgumentException {
1004         if (expansionMode != MULTIPLICATIVE_MODE &&
1005             expansionMode != ADDITIVE_MODE) {
1006             throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_EXPANSION_MODE, expansionMode,
1007                                                    MULTIPLICATIVE_MODE, "MULTIPLICATIVE_MODE",
1008                                                    ADDITIVE_MODE, "ADDITIVE_MODE");
1009         }
1010         synchronized(this) {
1011             if (expansionMode == MULTIPLICATIVE_MODE) {
1012                 setExpansionMode(ExpansionMode.MULTIPLICATIVE);
1013             } else if (expansionMode == ADDITIVE_MODE) {
1014                 setExpansionMode(ExpansionMode.ADDITIVE);
1015             }
1016         }
1017     }
1018 
1019     /**
1020      * Sets the {@link ExpansionMode expansion mode}.
1021      *
1022      * @param expansionMode Expansion mode to use for resizing the array.
1023      * @deprecated As of 3.1 (to be removed in 4.0 as field will become "final").
1024      */
1025     @Deprecated
1026     public void setExpansionMode(ExpansionMode expansionMode) {
1027         this.expansionMode = expansionMode;
1028     }
1029 
1030     /**
1031      * Sets the initial capacity.  Should only be invoked by constructors.
1032      *
1033      * @param initialCapacity of the array
1034      * @throws MathIllegalArgumentException if <code>initialCapacity</code> is not
1035      * positive.
1036      * @deprecated As of 3.1, this is a no-op.
1037      */
1038     @Deprecated
1039     protected void setInitialCapacity(int initialCapacity)
1040         throws MathIllegalArgumentException {
1041         // Body removed in 3.1.
1042     }
1043 
1044     /**
1045      * This function allows you to control the number of elements contained
1046      * in this array, and can be used to "throw out" the last n values in an
1047      * array. This function will also expand the internal array as needed.
1048      *
1049      * @param i a new number of elements
1050      * @throws MathIllegalArgumentException if <code>i</code> is negative.
1051      */
1052     public synchronized void setNumElements(int i)
1053         throws MathIllegalArgumentException {
1054         // If index is negative thrown an error.
1055         if (i < 0) {
1056             throw new MathIllegalArgumentException(
1057                     LocalizedFormats.INDEX_NOT_POSITIVE,
1058                     i);
1059         }
1060 
1061         // Test the new num elements, check to see if the array needs to be
1062         // expanded to accommodate this new number of elements.
1063         final int newSize = startIndex + i;
1064         if (newSize > internalArray.length) {
1065             expandTo(newSize);
1066         }
1067 
1068         // Set the new number of elements to new value.
1069         numElements = i;
1070     }
1071 
1072     /**
1073      * Returns true if the internal storage array has too many unused
1074      * storage positions.
1075      *
1076      * @return true if array satisfies the contraction criteria
1077      */
1078     private synchronized boolean shouldContract() {
1079         if (expansionMode == ExpansionMode.MULTIPLICATIVE) {
1080             return (internalArray.length / ((float) numElements)) > contractionCriterion;
1081         } else {
1082             return (internalArray.length - numElements) > contractionCriterion;
1083         }
1084     }
1085 
1086     /**
1087      * Returns the starting index of the internal array.  The starting index is
1088      * the position of the first addressable element in the internal storage
1089      * array.  The addressable elements in the array are <code>
1090      * internalArray[startIndex],...,internalArray[startIndex + numElements -1]
1091      * </code>
1092      *
1093      * @return the starting index.
1094      * @deprecated As of 3.1.
1095      */
1096     @Deprecated
1097     public synchronized int start() {
1098         return startIndex;
1099     }
1100 
1101     /**
1102      * <p>Copies source to dest, copying the underlying data, so dest is
1103      * a new, independent copy of source.  Does not contract before
1104      * the copy.</p>
1105      *
1106      * <p>Obtains synchronization locks on both source and dest
1107      * (in that order) before performing the copy.</p>
1108      *
1109      * <p>Neither source nor dest may be null; otherwise a {@link NullArgumentException}
1110      * is thrown</p>
1111      *
1112      * @param source ResizableDoubleArray to copy
1113      * @param dest ResizableArray to replace with a copy of the source array
1114      * @exception NullArgumentException if either source or dest is null
1115      * @since 2.0
1116      *
1117      */
1118     public static void copy(ResizableDoubleArray source,
1119                             ResizableDoubleArray dest)
1120         throws NullArgumentException {
1121         MathUtils.checkNotNull(source);
1122         MathUtils.checkNotNull(dest);
1123         synchronized(source) {
1124            synchronized(dest) {
1125                dest.contractionCriterion = source.contractionCriterion;
1126                dest.expansionFactor = source.expansionFactor;
1127                dest.expansionMode = source.expansionMode;
1128                dest.internalArray = new double[source.internalArray.length];
1129                System.arraycopy(source.internalArray, 0, dest.internalArray,
1130                        0, dest.internalArray.length);
1131                dest.numElements = source.numElements;
1132                dest.startIndex = source.startIndex;
1133            }
1134        }
1135     }
1136 
1137     /**
1138      * Returns a copy of the ResizableDoubleArray.  Does not contract before
1139      * the copy, so the returned object is an exact copy of this.
1140      *
1141      * @return a new ResizableDoubleArray with the same data and configuration
1142      * properties as this
1143      * @since 2.0
1144      */
1145     public synchronized ResizableDoubleArray copy() {
1146         final ResizableDoubleArray result = new ResizableDoubleArray();
1147         copy(this, result);
1148         return result;
1149     }
1150 
1151     /**
1152      * Returns true iff object is a ResizableDoubleArray with the same properties
1153      * as this and an identical internal storage array.
1154      *
1155      * @param object object to be compared for equality with this
1156      * @return true iff object is a ResizableDoubleArray with the same data and
1157      * properties as this
1158      * @since 2.0
1159      */
1160     @Override
1161     public boolean equals(Object object) {
1162         if (object == this ) {
1163             return true;
1164         }
1165         if (object instanceof ResizableDoubleArray == false) {
1166             return false;
1167         }
1168         synchronized(this) {
1169             synchronized(object) {
1170                 boolean result = true;
1171                 final ResizableDoubleArray other = (ResizableDoubleArray) object;
1172                 result = result && (other.contractionCriterion == contractionCriterion);
1173                 result = result && (other.expansionFactor == expansionFactor);
1174                 result = result && (other.expansionMode == expansionMode);
1175                 result = result && (other.numElements == numElements);
1176                 result = result && (other.startIndex == startIndex);
1177                 if (!result) {
1178                     return false;
1179                 } else {
1180                     return Arrays.equals(internalArray, other.internalArray);
1181                 }
1182             }
1183         }
1184     }
1185 
1186     /**
1187      * Returns a hash code consistent with equals.
1188      *
1189      * @return the hash code representing this {@code ResizableDoubleArray}.
1190      * @since 2.0
1191      */
1192     @Override
1193     public synchronized int hashCode() {
1194         final int[] hashData = new int[6];
1195         hashData[0] = Double.valueOf(expansionFactor).hashCode();
1196         hashData[1] = Double.valueOf(contractionCriterion).hashCode();
1197         hashData[2] = expansionMode.hashCode();
1198         hashData[3] = Arrays.hashCode(internalArray);
1199         hashData[4] = numElements;
1200         hashData[5] = startIndex;
1201         return Arrays.hashCode(hashData);
1202     }
1203 
1204 }