diff --git a/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java b/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java index d3962d2c4..5520a8410 100644 --- a/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java +++ b/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java @@ -17,13 +17,13 @@ package org.apache.commons.math.stat.univariate; import java.io.Serializable; -import org.apache.commons.math.util.ContractableDoubleArray; +import org.apache.commons.math.util.ResizableDoubleArray; /** * Default implementation of * {@link org.apache.commons.math.stat.univariate.DescriptiveStatistics}. * - * @version $Revision: 1.6 $ $Date: 2004/06/01 21:34:35 $ + * @version $Revision: 1.7 $ $Date: 2004/06/14 21:41:33 $ */ public class DescriptiveStatisticsImpl extends DescriptiveStatistics implements Serializable { @@ -36,7 +36,7 @@ public class DescriptiveStatisticsImpl extends DescriptiveStatistics implements /** * Stored data values */ - protected ContractableDoubleArray eDA; + protected ResizableDoubleArray eDA; /** * Construct a DescriptiveStatisticsImpl with infinite window @@ -51,7 +51,7 @@ public class DescriptiveStatisticsImpl extends DescriptiveStatistics implements */ public DescriptiveStatisticsImpl(int window) { super(); - eDA = new ContractableDoubleArray(); + eDA = new ResizableDoubleArray(); setWindowSize(window); } diff --git a/src/java/org/apache/commons/math/util/ContractableDoubleArray.java b/src/java/org/apache/commons/math/util/ContractableDoubleArray.java deleted file mode 100644 index c19017cff..000000000 --- a/src/java/org/apache/commons/math/util/ContractableDoubleArray.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - -import java.io.Serializable; - -/** - *

- * A variable length double array implementation and extension of - * ExpandableDoubleArray which automatically handles expanding and - * contracting double arrays. - *

- * - *

- * This class extends the functionality of ExpandableDoubleArray and - * inherits the expansion parameters from that class. If a developer - * instantiates a ContractableDoubleArray and only adds values to - * that instance, the behavior of this class is no different from - * the behavior of the super-class ExpandableDoubleArray. If, on the - * other hand, elements are removed from the array, this implementation - * tests an additional parameter contractionCriteria. The - * contractionCriteria dictates when this implementation - * will contract the size of the internal storage array to - * the number of elements + 1. This check is performed after every - * operation that alters the number of elements in the array. - *

- * - *

- * Note that the contractionCriteria must always be greater than the - * expansionFactor. If this were not the case (assume a - * contractionCriteria of 1.5f and a expansionFactor of 2.0f) an - * endless series of expansions and contractions would occur. If the - * length of this array is highly varied over time it is a good idea - * to trade efficient memory usage for performance. Each time an array - * is expanded or contracted the meaningful portions of the internal - * storage array are copied to a new array and the reference to the - * internal storage array is swapped. - *

- * - * @version $Revision: 1.14 $ $Date: 2004/05/19 14:16:32 $ - */ -public class ContractableDoubleArray extends ExpandableDoubleArray implements Serializable { - - /** Serializable version identifier */ - static final long serialVersionUID = -3485529955529426875L; - - /** The contraction criteria defines the conditions under which this - * object will "resize" the internal array to the number of elements - * contained in the element array + 1 - */ - private float contractionCriteria = 2.5f; - - /** - * Create an expandable double array with the default initial capacity of - * 16, an expansion factor of 2.00, and a contractionCriteria of 2.5 - */ - public ContractableDoubleArray() { - super(); - } - - /** - * Create an expandable double array with the specified initial capacity, - * the defult expansion factor of 2.00, and a contractionCriteria of 2.5 - * - * @param initialCapacity The initial size of the internal storage array - */ - public ContractableDoubleArray(int initialCapacity) { - super(initialCapacity); - } - - /** - * Create an expandable double array with the specificed initial capacity - * and expand factor, with a contractionCriteria of 2.5 - * - * @param initialCapacity The initial size of the internal storage array - * @param expansionFactor the array will be expanded based on this - * parameter - */ - public ContractableDoubleArray( - int initialCapacity, - float expansionFactor) { - this.expansionFactor = expansionFactor; - setInitialCapacity(initialCapacity); - internalArray = new double[initialCapacity]; - checkContractExpand(getContractionCriteria(), expansionFactor); - } - - /** - * Create an expandable double array with the - * specificed initial capacity, expand factor, and contractionCriteria - * - * @param initialCapacity The initial size of the internal storage array - * @param expansionFactor the array will be expanded based on this - * parameter - * @param contractionCriteria The contraction Criteria. - */ - public ContractableDoubleArray( - int initialCapacity, - float expansionFactor, - float contractionCriteria) { - this.contractionCriteria = contractionCriteria; - this.expansionFactor = expansionFactor; - setInitialCapacity(initialCapacity); - internalArray = new double[initialCapacity]; - checkContractExpand(contractionCriteria, expansionFactor); - } - - /** - * Contracts the storage array to the (size of the element set) + 1 - to - * avoid a zero length array. This function also resets the startIndex to - * zero. - */ - public synchronized void contract() { - double[] tempArray = new double[numElements + 1]; - - // Copy and swap - copy only the element array from the src array. - System.arraycopy(internalArray, startIndex, tempArray, 0, numElements); - internalArray = tempArray; - - // Reset the start index to zero - startIndex = 0; - } - - /** - * Adds an element to the end of this expandable array - * - * @param value to be added to end of array - */ - public synchronized void addElement(double value) { - super.addElement(value); - if (shouldContract()) { - contract(); - } - } - - /** - *

- * Adds an element to the end of this expandable array and - * discards a value from the front of the array. This method - * has the effect of adding a value to the end of the list - * and discarded an element from the front of the list. - *

- * - *

- * When an array rolls it actually "scrolls" the element array in - * the internal storage array. An element is added to the end of the - * array, and the first element of the array is discard by incrementing - * the starting index of the element array within the internal - * storage array. Over time this will create an orphaned prefix - * to the element array within the internal storage array. If this - * function is called frequently, this orphaned prefix list will - * gradually push the internal storage vs. element storage to - * the contractionCriteria. - *

- * @param value to be added to end of array - * @return value added - */ - public synchronized double addElementRolling(double value) { - double discarded = super.addElementRolling(value); - // Check the contraction criteria - if (shouldContract()) { - contract(); - } - return discarded; - } - - /** - * Should contract returns true if the ratio of (internal storage length) - * to (number of elements) is larger than the contractionCriteria value. - * In other words, using the default value of 2.5, if the internal storage - * array provides more than 2.5x the space needed to store numElements, - * then this function returns true - * - * @return true if array satisfies the contraction criteria - */ - private synchronized boolean shouldContract() { - boolean shouldContract = false; - if ((internalArray.length / numElements) > contractionCriteria) { - shouldContract = true; - } - return shouldContract; - } - - /** - * @see org.apache.commons.math.util.DoubleArray#setElement(int, double) - */ - public synchronized void setElement(int index, double value) { - super.setElement(index, value); - if (shouldContract()) { - contract(); - } - } - - /** - * Method invokes the super class' setExpansionFactor but first it - * must validate the combination of expansionFactor and - * contractionCriteria. - * - * @see org.apache.commons.math.util.ExpandableDoubleArray#setExpansionFactor(float) - */ - public void setExpansionFactor(float expansionFactor) { - checkContractExpand(getContractionCriteria(), expansionFactor); - super.setExpansionFactor(expansionFactor); - } - - /** - * The contraction criteria defines when the internal array will contract - * to store only the number of elements in the element array. This - * contractionCriteria gaurantees that the internal storage array will - * never exceed this factor more than the space needed to store - * numElements. - * - * @return the contraction criteria used to reclaim memory when array is - * empty - */ - public float getContractionCriteria() { - return contractionCriteria; - } - - /** - * Sets the contraction criteria for this ExpandContractDoubleArray. - * - * @param contractionCriteria contraction criteria - */ - public void setContractionCriteria(float contractionCriteria) { - checkContractExpand(contractionCriteria, getExpansionFactor()); - - this.contractionCriteria = contractionCriteria; - } - - /** - * Checks the expansion factor and the contraction criteria and throws an - * IllegalArgumentException if the contractionCriteria is less than the - * expansionCriteria - * - * @param expansionFactor factor to be checked - * @param contractionCritera critera to be checked - * @throws IllegalArgumentException if the contractionCriteria is less than - * the expansionCriteria. - */ - protected void checkContractExpand( - float contractionCritera, - float expansionFactor) { - - if (contractionCritera < expansionFactor) { - String msg = - "Contraction criteria can never be smaller than " + - "the expansion factor. This would lead to a never " + - "ending loop of expansion and contraction as a newly " + - "expanded internal storage array would immediately " + - "satisfy the criteria for contraction"; - throw new IllegalArgumentException(msg); - } - - if (contractionCriteria <= 1.0) { - String msg = - "The contraction criteria must be a number larger " + - "than one. If the contractionCriteria is less than or " + - "equal to one an endless loop of contraction and " + - "expansion would ensue as an internalArray.length " + - "== numElements would satisfy the contraction criteria"; - throw new IllegalArgumentException(msg); - } - - if (expansionFactor < 1.0) { - String msg = - "The expansion factor must be a number greater than 1.0"; - throw new IllegalArgumentException(msg); - } - } - - /** - * @see org.apache.commons.math.util.ExpandableDoubleArray#discardFrontElements(int) - */ - public synchronized void discardFrontElements(int i) { - super.discardFrontElements(i); - if (shouldContract()) { - contract(); - } - } -} diff --git a/src/java/org/apache/commons/math/util/DoubleArray.java b/src/java/org/apache/commons/math/util/DoubleArray.java index 371e9ae5e..e70b98bf1 100644 --- a/src/java/org/apache/commons/math/util/DoubleArray.java +++ b/src/java/org/apache/commons/math/util/DoubleArray.java @@ -17,19 +17,18 @@ package org.apache.commons.math.util; /** - * Provides a single interface for dealing with various flavors - * of double arrays. This arrays framework follows the model of the - * Collections API by allowing a user to select from a number of - * array implementations with support for various storage mechanisms + * Provides a standard interface for double arrays. Allows different + * array implementations to support various storage mechanisms * such as automatic expansion, contraction, and array "rolling". * - * @version $Revision: 1.11 $ $Date: 2004/06/08 14:19:40 $ + * @version $Revision: 1.12 $ $Date: 2004/06/14 21:41:33 $ */ public interface DoubleArray { /** * Returns the number of elements currently in the array. Please note - * that this is different from the length of the internal storage array. + * that this may be different from the length of the internal storage array. + * * @return number of elements */ int getNumElements(); @@ -47,9 +46,11 @@ public interface DoubleArray { double getElement(int index); /** - * Sets the element at the specified index. This method may expand the - * internal storage array to accomodate the insertion of a value at an - * index beyond the current capacity. + * Sets the element at the specified index. If the specified index is greater than + * getNumElements() - 1, the numElements property + * is increased to index +1 and additional storage is allocated + * (if necessary) for the new element and all (uninitialized) elements + * between the new element and the previous end of the array). * * @param index index to store a value in * @param value value to store at the specified index @@ -66,23 +67,29 @@ public interface DoubleArray { void addElement(double value); /** - * Adds an element and moves the window of elements up one. This - * has the effect of a FIFO. when you "roll" the array an element may be - * removed from the array. In this case, the return value of this function is the - * discarded double. In some implementations, removal will only occur when - * the array has reached a capacity threshold. *

- * When removal does occur, the effect is to add an element to the end of the - * array and to discard the element at the beginning of the array. + * Adds an element to the end of the array and removes the first + * element in the array. Returns the discarded first element. + * The effect is similar to a push operation in a FIFO queue. + *

+ *

+ * Example: If the array contains the elements 1, 2, 3, 4 (in that order) + * and addElementRolling(5) is invoked, the result is an array containing + * the entries 2, 3, 4, 5 and the value returned is 1. + *

* * @param value the value to be added to the array * @return the value which has been discarded or "pushed" out of the array - * by this rolling insert or null if no value has been discarded + * by this rolling insert */ double addElementRolling(double value); /** - * Returns a double[] of elements + * Returns a double[] array containing the elements of this + * DoubleArray. If the underlying implementation is + * array-based, this method should always return a copy, rather than a + * reference to the underlying array so that changes made to the returned + * array have no effect on the DoubleArray. * * @return all elements added to the array */ diff --git a/src/java/org/apache/commons/math/util/ExpandableDoubleArray.java b/src/java/org/apache/commons/math/util/ExpandableDoubleArray.java deleted file mode 100644 index cbb0f25d8..000000000 --- a/src/java/org/apache/commons/math/util/ExpandableDoubleArray.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - -import java.io.Serializable; - -/** - *

- * A DoubleArray implementation which automatically expands - * an internal double array to handle an array of arbitrary length. This - * implementation of DoubleArray is provided to support scenarios in - * which the ultimate length of an array is unknown, and the - * developer can control the expansion process through the - * initialCapacity and expansionFactor - * parameters. - *

- * - *

- * This implementation also allows a developer to: - *

- *

- * - *

- * The initialCapacity parameter sets the capacity of the initial - * storage array, and the expansionFactor is the factor by which - * the current storage capacity is multiplied each time the internal - * array needs to be expanded. Please note that the length of the - * internal storage array has nothing to do with the number of elements - * currently stored in this array. If one creates an instance of this - * class with an initialCapacity of "2" and an expansion factor of "2", and - * then adds 3546 elements to the array, this implementation will need to - * expand the array 10 times - first from 2 -> 4. then 4 -> 8, 8 -> 16, - * and so on until we reach 4096 which is sufficient to hold 3546 elements. - *

- * @version $Revision: 1.15 $ $Date: 2004/05/19 14:16:32 $ - */ -public class ExpandableDoubleArray implements Serializable, DoubleArray { - - /** Serializable version identifier */ - static final long serialVersionUID = -5697417774251632284L; - - // TODO: expansionFactor is valuable, by if I only need storage - // for 1025 items and I use the default settings, I'll end up - // with enough storage for 2048 elements. Maybe this implementation - // should have flags for incremental growth - (i.e. when expanding, only - // increase storage by a constant size - 100, 200 ) ? - - /** - * This is the internal storage array. - */ - protected double[] internalArray; - - /** - * Number of elements in the array - */ - protected int numElements = 0; - - /** - * Keeps track of a starting index - */ - protected int startIndex = 0; - - /**The initial capacity of the array. - * Initial capacity is not exposed as a property as it is only meaningful - * when passed to a constructor. - */ - protected int initialCapacity = 16; - - /** The expand factor of the array. When the array need to be expanded, - * the new array size will be internalArray.length * expandFactor - */ - protected float expansionFactor = 2.0f; - - /** - * Create an expandable double array with the - * default initial capactiy of 16 and an expansion factor of 2.00 - */ - public ExpandableDoubleArray() { - internalArray = new double[initialCapacity]; - } - - /** - * Create an expandable double array with the - * specified initial capacity and the defult expansion factor of 2.00 - * - * @param initialCapacity The initial size of the internal storage array - */ - public ExpandableDoubleArray(int initialCapacity) { - setInitialCapacity(initialCapacity); - internalArray = new double[this.initialCapacity]; - } - - /** - * Create an expandable double array with the - * specificed initial capacity and expand factor. - * - * @param initialCapacity The initial size of the internal storage array - * @param expansionFactor the array will be expanded based on this - * parameter - */ - public ExpandableDoubleArray(int initialCapacity, float expansionFactor) { - setInitialCapacity(initialCapacity); - setExpansionFactor(expansionFactor); - this.initialCapacity = initialCapacity; - internalArray = new double[initialCapacity]; - } - - /** - * The expansion factor controls the size of a new aray when an array - * needs to be expanded. When a value is inserted into a full array, the - * new array size is calculated as the current array size times this - * expansion factor. The default expansion factor is 2.0 - * - * @return the expansion factor of this expandable double array - */ - public float getExpansionFactor() { - return expansionFactor; - } - - /** - * Sets the expansion factor for this expandable double array. - * The expansion factor will affect the next expansion of this array. - * - * @param expansionFactor the expansion factor of this array - * @throws IllegalArgumentException if expansionFactor is less - * than or equal to 1.0 - */ - public void setExpansionFactor(float expansionFactor) { - - // The expansion factor *must* be larger than 1.0, otherwise we'll - // have an inconsistency upon expansion we'll start shrinking which - // will lead to ArrayIndexOutOfBound exceptions. - if (expansionFactor > 1.0) { - this.expansionFactor = expansionFactor; - } else { - String msg = - "The expansion factor must be a number greater " + "than 1.0"; - throw new IllegalArgumentException(msg); - } - } - - /** - * Sets the initial capacity - * @param initialCapacity of the array - * @throws IllegalArgumentException if initialCapacity is not - * positive. - */ - public void setInitialCapacity(int initialCapacity) { - if (initialCapacity > 0) { - this.initialCapacity = initialCapacity; - } else { - String msg = - "The initial capacity supplied: " + initialCapacity + - "must be a positive integer"; - throw new IllegalArgumentException(msg); - } - } - - /** - * Returns the internal storage array - * - * @return the internal storage array used by this object - */ - public double[] getValues() { - return (internalArray); - } - - /** - * Returns the starting index of the internal array. - * @return starting index - */ - public int start() { - return startIndex; - } - - /** - * Returns the number of elements currently in the array. Please note - * that this is different from the length of the internal storage array. - * @return number of elements - */ - public int getNumElements() { - return (numElements); - } - - /** - * This function allows you to control the number of elements contained - * in this array, and can be used to "throw" out the last n values in an - * array. This feature is mainly targetted at the subclasses of this - * array class. Note that this function will also expand the internal - * array as needed. - * - * @param i a new number of elements - * @throws IllegalArgumentException if i is negative. - */ - public synchronized void setNumElements(int i) { - - // If index is negative thrown an error - if (i < 0) { - String msg = - "Number of elements must be zero or a positive " + "integer"; - throw new IllegalArgumentException(msg); - } - - // Test the new num elements, check to see if the array needs to be - // expanded to accomodate this new number of elements - if ((startIndex + i) > internalArray.length) { - expandTo(startIndex + i); - } - - // Set the new number of elements to new value - numElements = i; - } - - /** - * Returns the element at the specified index - * - * @param index index to fetch a value from - * @return value stored at the specified index - * @throws ArrayIndexOutOfBoundsException if index is less than - * zero or is greater than getNumElements() - 1. - */ - public double getElement(int index) { - double value = Double.NaN; - if (index >= numElements) { - String msg = - "The index specified: " + index + - " is larger than the current number of elements"; - throw new ArrayIndexOutOfBoundsException(msg); - } else if (index >= 0) { - value = internalArray[startIndex + index]; - } else { - String msg = - "Elements cannot be retrieved from a negative array index"; - throw new ArrayIndexOutOfBoundsException(msg); - } - return value; - } - - /** - * Sets the element at the specified index. This method will expand the - * internal storage array to accomodate the insertion of a value at an - * index beyond the current capacity. - * - * @param index index to store a value in - * @param value value to store at the specified index - * @throws ArrayIndexOutOfBoundsException if index is less than - * zero. - */ - public synchronized void setElement(int index, double value) { - - if (index < 0) { - String msg = "Cannot set an element at a negative index"; - throw new ArrayIndexOutOfBoundsException(msg); - } - - if ((startIndex + index) >= internalArray.length) { - expandTo(startIndex + (index + 1)); - numElements = index + 1; - } - internalArray[startIndex + index] = value; - } - - /** - * Expands the internal storage array to the specified size. - * - * @param size Size of the new internal storage array - */ - private synchronized void expandTo(int size) { - double[] tempArray = new double[size]; - // Copy and swap - System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length); - internalArray = tempArray; - } - - /** - * Expands the internal storage array using the expansion factor - */ - protected synchronized void expand() { - - // notice the use of Math.ceil(), this gaurantees that we will always - // have an array of at least currentSize + 1. Assume that the - // current initial capacity is 1 and the expansion factor - // is 1.000000000000000001. The newly calculated size will be - // rounded up to 2 after the multiplication is performed. - int newSize = (int) Math.ceil(internalArray.length * expansionFactor); - double[] tempArray = new double[newSize]; - - // Copy and swap - System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length); - internalArray = tempArray; - } - - /** - * Adds an element to the end of this expandable array - * - * @param value value to be added to end of array - */ - public synchronized void addElement(double value) { - numElements++; - if ((startIndex + numElements) > internalArray.length) { - expand(); - } - internalArray[startIndex + (numElements - 1)] = value; - } - - /** - * Adds an element and moves the window of elements up one. This - * has the effect of a FIFO. when you "roll" the array an element is - * removed from the array. The return value of this function is the - * discarded double. - * @param value the value to add - * @return the value which has been discarded or "pushed" out of the array - * by this rolling insert. - */ - public synchronized double addElementRolling(double value) { - double discarded = internalArray[startIndex]; - - if ((startIndex + (numElements + 1)) > internalArray.length) { - expand(); - } - // Increment the start index - startIndex += 1; - - // Add the new value - internalArray[startIndex + (numElements - 1)] = value; - - return discarded; - } - - /** - * Notice the package scope on this method. This method is simply here - * for the JUnit test, it allows us check if the expansion is working - * properly after a number of expansions. This is not meant to be a part - * of the public interface of this class. - * - * @return the length of the internal storage array. - */ - int getInternalLength() { - return (internalArray.length); - } - - /** - * Clear the array, reset the size to the initialCapacity and the number - * of elements to zero. - */ - public synchronized void clear() { - numElements = 0; - internalArray = new double[initialCapacity]; - } - - /** - * Discards values from the front of the list. This function removes n - * elements from the front of the array. - * - * @param i number of elements to discard from the front of the array. - * @throws IllegalArgumentException if i is negative of is - * greater than getNumElements(). - */ - public synchronized void discardFrontElements(int i) { - - if (i > numElements) { - String msg = "Cannot discard more elements than are" + - "contained in this array."; - throw new IllegalArgumentException(msg); - } else if (i < 0) { - String msg = "Cannot discard a negative number of elements."; - throw new IllegalArgumentException(msg); - } else { - // "Subtract" this number of discarded from numElements - numElements -= i; - startIndex += i; - } - } - - /** - * @see org.apache.commons.math.util.DoubleArray#getElements() - */ - public double[] getElements() { - double[] elementArray = new double[numElements]; - System.arraycopy( - internalArray, - startIndex, - elementArray, - 0, - numElements); - return elementArray; - } - -} diff --git a/src/java/org/apache/commons/math/util/FixedDoubleArray.java b/src/java/org/apache/commons/math/util/FixedDoubleArray.java deleted file mode 100644 index 70dd7a868..000000000 --- a/src/java/org/apache/commons/math/util/FixedDoubleArray.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - -import java.io.Serializable; - -/** - *

- * Provides an implementation of the DoubleArray with a maximum number of - * elements. Creating an array implementation with an upper limit on the - * number of elements allows us to support a more efficient "rolling" - * mechanism to support addElementRoling(double). Please note that this - * implementation will not preserve the order of the values supplied to - * this array, calling getValues() will return an array of indeterminate - * order. - *

- * - *

- * Values are added to this array by calling addElement(double) or - * addElementRolling(double). If addElement(double) is called on - * an array that already contains the maximum number of elements, an - * ArrayIndexOutOfBoundsException will be thrown to reflect an attempt to - * add a value beyond the boundaries of the fixed length array - in this - * respect a FixedDoubleArray can be considered "full". Calling - * addElementRolling(double) on an array which contains the maximum - * number of elements will cause the array to overwrite the "oldest" - * value in the array. - *

- * - *

- * This class is called FixedDoubleArray not because it is of a fixed size. - * The name is appropriate because the internal storage array remains - * "fixed" in memory, this implementation will never allocate, or copy - * the internal storage array to a new array instance. - *

- * @version $Revision: 1.16 $ $Date: 2004/05/19 14:16:32 $ - */ -public class FixedDoubleArray implements DoubleArray, Serializable { - - /** Serializable version identifier */ - static final long serialVersionUID = 1247853239629842963L; - - /** - * This is the internal storage array. This array is assigned - * a known fixed size in the constructor - */ - private double[] internalArray; - - /** - * Size determined the number of elements in the array at - * any given time. When an array is created is maxElements - * of 100, it is of size 0, and size increases as values are - * added. - */ - private int size = 0; - - /** - * This index points to the location of the next update. Next - * add, cycles from 0 to (maxElement-1) - */ - private int nextAdd = 0; - - /** - * The maximum number of elements in the FixedDoubleArray - */ - private int maxElements = 0; - - /** - * Create a fixed array for double primitives which can hold up to - * maxElements doubles. This implementation of - * DoubleArray was created to provide a more "performance-oriented" - * in-place rolling mechanism for calculations which need to - * operate on a rolling window of values. - * - * @param maxElements the maximum number of elements this - * FixeddoubleArray may contain. - */ - public FixedDoubleArray(int maxElements) { - this.maxElements = maxElements; - internalArray = new double[maxElements]; - } - - /** - * Create a fixed array backed by the provided double[] implementation. - * the array should have all the elements occupied. the size and maxElements - * are drawn from the array's length. - * - * This implementation of DoubleArray was created to provide a more - * "performance-oriented" in-place rolling mechanism for calculations - * which need to operate on a rolling window of values. - * @param array the backing array - */ - public FixedDoubleArray(double[] array) { - this.maxElements = array.length; - this.size = array.length; - internalArray = array; - } - - /** - * Retrieves the current size of the array. - * @see org.apache.commons.math.util.DoubleArray#getNumElements() - */ - public int getNumElements() { - return size; - } - - /** - * Returns the element value at the specified index. Please note that - * the size of the element array is not directly related to the - * maximum number of elements which this array can contain. One can - * create an instance of FixedDoubleArray with a maximum of - * ten elements, add three items, and get any items from index 0 to index - * 2 - trying to retrieve an element outside of the current element - * array will throw an ArrayIndexOutOfBoundsException. - * - * @see org.apache.commons.math.util.DoubleArray#getElement(int) - * @throws ArrayIndexOutOfBoundsException if index is less than - * zero or is greater than getNumElements() - 1. - */ - public double getElement(int index) { - if (index > (size - 1)) { - String msg = - "Attempted to retrieve an element outside of " + - "the element array"; - throw new ArrayIndexOutOfBoundsException(msg); - } else { - // Return the element requested, if the index supplied - // is negative this statement may also throw an - // ArrayIndexOutOfBoundException. - return internalArray[index]; - } - } - - /** - *

- * Sets the element at the specified index to the value supplied. - *

- * - *

Implementation Notes: - *

- * - *

- * - * @see org.apache.commons.math.util.DoubleArray#setElement(int, double) - * @throws ArrayIndexOutOfBoundsException if index is less than - * zero or is greater than getNumElements() - 1. - */ - public void setElement(int index, double value) { - if (index > (size - 1)) { - String msg = - "Attempted to set an element outside of" + "the element array"; - throw new ArrayIndexOutOfBoundsException(msg); - } else { - internalArray[index] = value; - } - } - - /** - * Add an element to the current array, testing to see if - * this array has already met or exceeded the maximum number - * of elements - * - * @see org.apache.commons.math.util.DoubleArray#addElement(double) - * @throws ArrayIndexOutOfBoundsException if array is already at capacity. - */ - public void addElement(double value) { - if (size < internalArray.length) { - size++; - - internalArray[nextAdd] = value; - - // Incremenet nextAdd and then modulo it against maxElements - // this has the effect of repeatedly "cycling" nextAdd - // between 0 and (maxElements-1) endlessly. - nextAdd++; - nextAdd = nextAdd % (maxElements); - - } else { - // If the array has ALREADY reached the maximum size allowable, - // we throw an ArrayIndexOutOfBoundsException - the end-user - // is trying to add an element beyond the boundaries of the - // fixed array. - String msg = - "Attempted to add a value to an array of fixed " + - "size, please use addElementRolling " + - "to avoid this exception"; - throw new ArrayIndexOutOfBoundsException(msg); - } - } - - /** - *

- * Adds an element by "rolling" the new value into the current array - * while discarding the element which was added maxElement - * add operations ago. The value replaced is returned from this - * method. Until an array contains the maximum number of element, this - * method has the same result as the addElement(double) operation. Once - * the maximum number of elements has been reached this implementation - * inserts the new values starting at index 0 of the internal storage - * array. This allows for efficient rolling, but prevents us from - * preserving the order of the added values. - *

- * - *

- * Note: This function will return Double.NaN if - * no value has been discarded in this roll. This can happen when - * the array has not met the size limitation introduced in the - * constructor. - *

- * @param value the value to be added to the array - * @return Returns the value which a has been "removed" from the - * database. Important: If the element array has - * not reached the maximum size, then it is possible that - * no element will be discarded from a given roll. In this - * case this method will return a Double.NaN value. - * - * @see org.apache.commons.math.util.DoubleArray#addElementRolling(double) - */ - public double addElementRolling(double value) { - - // Create the discarded primitive. If no element is - // discarded by this roll, this method will return a - // Double.NaN value. - double discarded = Double.NaN; - - if (size < internalArray.length) { - size++; - } else { - // If we've reached the length of the internal - // storage array, we have to start "discarding" - // values from the original array. - - // Obtain the value discarded by this overwrite - discarded = internalArray[nextAdd]; - } - - internalArray[nextAdd] = value; - - // nextAdd cycles between 0 and (maxElements-1). - nextAdd++; - nextAdd = nextAdd % maxElements; - - // but we return the value which was "replaced" - return (discarded); - } - - /** - * Provides an array of double[] which contain the - * number of elements added to this array. This - * method will return an array from zero to maxElements in length. - * - * @return The array of elements added to this DoubleArray - * implementation. - * @see org.apache.commons.math.util.DoubleArray#getElements() - */ - public double[] getElements() { - double[] copy = new double[size]; - System.arraycopy(internalArray, 0, copy, 0, size); - return copy; - } - - /** - * Returns the internal storage array - * - * @return the internal storage array used by this object - */ - public double[] getValues() { - return (internalArray); - } - - /** - * The starting index in the InternalArray. - * @return starting index. - */ - public int start() { - return 0; - } - - /** - * Clear the array - drop all the data and start with a blank - * internal array. This implementation takes care of - * setting the size of the array back to zero, and reinitializing - * the internal storage array. - * - * @see org.apache.commons.math.util.DoubleArray#clear() - */ - public void clear() { - size = 0; - nextAdd = 0; - internalArray = new double[maxElements]; - } - -} diff --git a/src/java/org/apache/commons/math/util/ResizableDoubleArray.java b/src/java/org/apache/commons/math/util/ResizableDoubleArray.java new file mode 100644 index 000000000..16e7b087d --- /dev/null +++ b/src/java/org/apache/commons/math/util/ResizableDoubleArray.java @@ -0,0 +1,689 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.util; + +import java.io.Serializable; + +/** + *

+ * A variable length {@link DoubleArray} implementation that automatically + * handles expanding and contracting its internal storage array as elements + * are added and removed. + *

+ *

+ * The internal storage array starts with capacity determined by the + * initialCapacity property, which can be set by the constructor. + * The default initial capacity is 16. Adding elements using + * {@link #addElement(double)} appends elements to the end of the array. When + * there are no open entries at the end of the internal storage array, the + * array is expanded. The size of the expanded array depends on the + * expansionMode and expansionFactor properties. + * The expansionMode determines whether the size of the array is + * multiplied by the expansionFactor (MULTIPLICATIVE_MODE) or if + * the expansion is additive (ADDITIVE_MODE -- expansionFactor + * storage locations added). The default expansionMode is + * MULTIPLICATIVE_MODE and the default expansionFactor + * is 2.0. + *

+ *

+ * The {@link #addElementRolling(double)} method adds a new element to the end + * of the internal storage array and adjusts the "usable window" of the + * internal array forward by one position (effectively making what was the + * second element the first, and so on). Repeated activations of this method + * (or activation of {@link #discardFrontElements(int)}) will effectively orphan + * the storage locations at the beginning of the internal storage array. To + * reclaim this storage, each time one of these methods is activated, the size + * of the internal storage array is compared to the number of addressable + * elements (the numElements property) and if the difference + * is too large, the internal array is contracted to size + * numElements + 1. The determination of when the internal + * storage array is "too large" depends on the expansionMode and + * contractionFactor properties. If the expansionMode + * is MULTIPLICATIVE_MODE, contraction is triggered when the + * ratio between storage array length and numElements exceeds + * contractionFactor. If the expansionMode + * is ADDITIVE_MODE, the number of excess storage locations + * is compared to contractionFactor. + *

+ *

+ * To avoid cycles of expansions and contractions, the + * expansionFactor must not exceed the + * contractionFactor. Constructors and mutators for both of these + * properties enforce this requirement, throwing IllegalArgumentException if it + * is violated. + *

+ *

+ * @version $Revision: 1.1 $ $Date: 2004/06/14 21:41:33 $ + */ +public class ResizableDoubleArray implements DoubleArray, Serializable { + + /** Serializable version identifier */ + static final long serialVersionUID = -3485529955529426875L; + + /** additive expansion mode */ + public static final int ADDITIVE_MODE = 1; + + /** multiplicative expansion mode */ + public static final int MULTIPLICATIVE_MODE = 0; + + /** + * The contraction criteria determines when the internal array will be + * contracted to fit the number of elements contained in the element + * array + 1. + */ + protected float contractionCriteria = 2.5f; + + /** + * The expansion factor of the array. When the array needs to be expanded, + * the new array size will be + * internalArray.length * expansionFactor + * if expansionMode is set to MULTIPLICATIVE_MODE, or + * internalArray.length + expansionFactor if + * expansionMode is set to ADDITIVE_MODE. + */ + protected float expansionFactor = 2.0f; + + /** + * Determines whether array expansion by expansionFactor + * is additive or multiplicative. + */ + protected int expansionMode = MULTIPLICATIVE_MODE; + + /** + * The initial capacity of the array. Initial capacity is not exposed as a + * property as it is only meaningful when passed to a constructor. + */ + protected int initialCapacity = 16; + + /** + * The internal storage array. + */ + protected double[] internalArray; + + /** + * The number of addressable elements in the array. Note that this + * has nothing to do with the length of the internal storage array. + */ + protected int numElements = 0; + + /** + * The position of the first addressable element in the internal storage + * array. The addressable elements in the array are + * internalArray[startIndex],...,internalArray[startIndex + numElements -1] + * + */ + protected int startIndex = 0; + + /** + * Create a ResizableArray with default properties. + *

+ */ + public ResizableDoubleArray() { + internalArray = new double[initialCapacity]; + } + + /** + * Create a ResizableArray with the specified initial capacity. Other + * properties take default values: + * + * @param initialCapacity The initial size of the internal storage array + * @throws IllegalArgumentException if initialCapacity is not > 0 + */ + public ResizableDoubleArray(int initialCapacity) { + setInitialCapacity(initialCapacity); + internalArray = new double[this.initialCapacity]; + } + + /** + *

+ * Create a ResizableArray with the specified initial capacity + * and expansion factor. The remaining properties take default + * values: + *

+ *

+ * Throws IllegalArgumentException if the following conditions are + * not met: + *

+ * + * @param initialCapacity The initial size of the internal storage array + * @param expansionFactor the array will be expanded based on this + * parameter + * @throws IllegalArgumentException if parameters are not valid + */ + public ResizableDoubleArray(int initialCapacity, float expansionFactor) { + this.expansionFactor = expansionFactor; + setInitialCapacity(initialCapacity); + internalArray = new double[initialCapacity]; + setContractionCriteria(expansionFactor +0.5f); + } + + /** + *

+ * Create a ResizableArray with the specified initialCapacity, + * expansionFactor, and contractionCriteria. The expansionMode + * will default to MULTIPLICATIVE_MODE.

+ *

+ * Throws IllegalArgumentException if the following conditions are + * not met: + *

+ * @param initialCapacity The initial size of the internal storage array + * @param expansionFactor the array will be expanded based on this + * parameter + * @param contractionCriteria The contraction Criteria. + * @throws IllegalArgumentException if parameters are not valid + */ + public ResizableDoubleArray(int initialCapacity, float expansionFactor, + float contractionCriteria) { + this.expansionFactor = expansionFactor; + setContractionCriteria(contractionCriteria); + setInitialCapacity(initialCapacity); + internalArray = new double[initialCapacity]; + } + + /** + *

+ * Create a ResizableArray with the specified properties.

+ *

+ * Throws IllegalArgumentException if the following conditions are + * not met: + *

+ * + * @param initialCapacity the initial size of the internal storage array + * @param expansionFactor the array will be expanded based on this + * parameter + * @param contractionCriteria the contraction Criteria + * @param expansionMode the expansion mode + * @throws IllegalArgumentException if parameters are not valid + */ + public ResizableDoubleArray(int initialCapacity, float expansionFactor, + float contractionCriteria, int expansionMode) { + this.expansionFactor = expansionFactor; + setContractionCriteria(contractionCriteria); + setInitialCapacity(initialCapacity); + setExpansionMode(expansionMode); + internalArray = new double[initialCapacity]; + } + + /** + * Adds an element to the end of this expandable array. + * + * @param value to be added to end of array + */ + public synchronized void addElement(double value) { + numElements++; + if ((startIndex + numElements) > internalArray.length) { + expand(); + } + internalArray[startIndex + (numElements - 1)] = value; + if (shouldContract()) { + contract(); + } + } + + /** + *

+ * Adds an element to the end of the array and removes the first + * element in the array. Returns the discarded first element. + * The effect is similar to a push operation in a FIFO queue. + *

+ *

+ * Example: If the array contains the elements 1, 2, 3, 4 (in that order) + * and addElementRolling(5) is invoked, the result is an array containing + * the entries 2, 3, 4, 5 and the value returned is 1. + *

+ * + * @param value the value to be added to the array + * @return the value which has been discarded or "pushed" out of the array + * by this rolling insert + */ + public synchronized double addElementRolling(double value) { + double discarded = internalArray[startIndex]; + + if ((startIndex + (numElements + 1)) > internalArray.length) { + expand(); + } + // Increment the start index + startIndex += 1; + + // Add the new value + internalArray[startIndex + (numElements - 1)] = value; + + // Check the contraction criteria + if (shouldContract()) { + contract(); + } + return discarded; + } + + /** + * Checks the expansion factor and the contraction criteria and throws an + * IllegalArgumentException if the contractionCriteria is less than the + * expansionCriteria + * + * @param expansionFactor factor to be checked + * @param contractionCritera critera to be checked + * @throws IllegalArgumentException if the contractionCriteria is less than + * the expansionCriteria. + */ + protected void checkContractExpand( + float contractionCritera, + float expansionFactor) { + + if (contractionCritera < expansionFactor) { + String msg = + "Contraction criteria can never be smaller than " + + "the expansion factor. This would lead to a never " + + "ending loop of expansion and contraction as a newly " + + "expanded internal storage array would immediately " + + "satisfy the criteria for contraction"; + throw new IllegalArgumentException(msg); + } + + if (contractionCriteria <= 1.0) { + String msg = + "The contraction criteria must be a number larger " + + "than one. If the contractionCriteria is less than or " + + "equal to one an endless loop of contraction and " + + "expansion would ensue as an internalArray.length " + + "== numElements would satisfy the contraction criteria"; + throw new IllegalArgumentException(msg); + } + + if (expansionFactor <= 1.0) { + String msg = + "The expansion factor must be a number greater than 1.0"; + throw new IllegalArgumentException(msg); + } + } + + /** + * Clear the array, reset the size to the initialCapacity and the number + * of elements to zero. + */ + public synchronized void clear() { + numElements = 0; + internalArray = new double[initialCapacity]; + } + + /** + * Contracts the storage array to the (size of the element set) + 1 - to + * avoid a zero length array. This function also resets the startIndex to + * zero. + */ + public synchronized void contract() { + double[] tempArray = new double[numElements + 1]; + + // Copy and swap - copy only the element array from the src array. + System.arraycopy(internalArray, startIndex, tempArray, 0, numElements); + internalArray = tempArray; + + // Reset the start index to zero + startIndex = 0; + } + + /** + * Discards the i initial elements of the array. For example, + * if the array contains the elements 1,2,3,4, invoking + * discardFrontElements(2) will cause the first two elements + * to be discarded, leaving 3,4 in the array. Throws illegalArgumentException + * if i exceeds numElements. + * + * @param i the number of elements to discard from the front of the array + * @throws IllegalArgumentException if i is greater than numElements. + */ + public synchronized void discardFrontElements(int i) { + if (i > numElements) { + String msg = "Cannot discard more elements than are" + + "contained in this array."; + throw new IllegalArgumentException(msg); + } else if (i < 0) { + String msg = "Cannot discard a negative number of elements."; + throw new IllegalArgumentException(msg); + } else { + // "Subtract" this number of discarded from numElements + numElements -= i; + startIndex += i; + } + if (shouldContract()) { + contract(); + } + } + + /** + * Expands the internal storage array using the expansion factor. + *

+ * if expansionMode is set to MULTIPLICATIVE_MODE, + * the new array size will be internalArray.length * expansionFactor. + * If expansionMode is set to ADDITIVE_MODE, the length + * after expansion will be internalArray.length + expansionFactor + */ + protected synchronized void expand() { + + // notice the use of Math.ceil(), this gaurantees that we will always + // have an array of at least currentSize + 1. Assume that the + // current initial capacity is 1 and the expansion factor + // is 1.000000000000000001. The newly calculated size will be + // rounded up to 2 after the multiplication is performed. + int newSize = 0; + if (expansionMode == MULTIPLICATIVE_MODE) { + newSize = (int) Math.ceil(internalArray.length * expansionFactor); + } else { + newSize = internalArray.length + Math.round(expansionFactor); + } + double[] tempArray = new double[newSize]; + + // Copy and swap + System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length); + internalArray = tempArray; + } + + /** + * Expands the internal storage array to the specified size. + * + * @param size Size of the new internal storage array + */ + private synchronized void expandTo(int size) { + double[] tempArray = new double[size]; + // Copy and swap + System.arraycopy(internalArray, 0, tempArray, 0, internalArray.length); + internalArray = tempArray; + } + + /** + * The contraction criteria defines when the internal array will contract + * to store only the number of elements in the element array. + * If the expansionMode is MULTIPLICATIVE_MODE, + * contraction is triggered when the ratio between storage array length + * and numElements exceeds contractionFactor. + * If the expansionMode is ADDITIVE_MODE, the + * number of excess storage locations is compared to + * contractionFactor. + * + * @return the contraction criteria used to reclaim memory. + */ + public float getContractionCriteria() { + return contractionCriteria; + } + + /** + * Returns the element at the specified index + * + * @param index index to fetch a value from + * @return value stored at the specified index + * @throws ArrayIndexOutOfBoundsException if index is less than + * zero or is greater than getNumElements() - 1. + */ + public double getElement(int index) { + double value = Double.NaN; + if (index >= numElements) { + String msg = + "The index specified: " + index + + " is larger than the current number of elements"; + throw new ArrayIndexOutOfBoundsException(msg); + } else if (index >= 0) { + value = internalArray[startIndex + index]; + } else { + String msg = + "Elements cannot be retrieved from a negative array index"; + throw new ArrayIndexOutOfBoundsException(msg); + } + return value; + } + + /** + * Returns a double[] array containing the elements of this + * ResizableArray. This method returns a copy, not a + * reference to the underlying array, so that changes made to the returned + * array have no effect on this ResizableArray. + */ + public double[] getElements() { + double[] elementArray = new double[numElements]; + System.arraycopy( internalArray, startIndex, elementArray, 0, + numElements); + return elementArray; + } + + /** + * The expansion factor controls the size of a new aray when an array + * needs to be expanded. The expansionMode + * determines whether the size of the array is multiplied by the + * expansionFactor (MULTIPLICATIVE_MODE) or if + * the expansion is additive (ADDITIVE_MODE -- expansionFactor + * storage locations added). The default expansionMode is + * MULTIPLICATIVE_MODE and the default expansionFactor + * is 2.0. + * + * @return the expansion factor of this expandable double array + */ + public float getExpansionFactor() { + return expansionFactor; + } + + /** + * The expansionMode determines whether the internal storage + * array grows additively (ADDITIVE_MODE) or multiplicatively + * (MULTIPLICATIVE_MODE) when it is expanded. + * + * @return Returns the expansionMode. + */ + public int getExpansionMode() { + return expansionMode; + } + + /** + * Notice the package scope on this method. This method is simply here + * for the JUnit test, it allows us check if the expansion is working + * properly after a number of expansions. This is not meant to be a part + * of the public interface of this class. + * + * @return the length of the internal storage array. + */ + int getInternalLength() { + return (internalArray.length); + } + + /** + * Returns the number of elements currently in the array. Please note + * that this is different from the length of the internal storage array. + * + * @return number of elements + */ + public int getNumElements() { + return (numElements); + } + + /** + * Returns the internal storage array. Note that this method returns + * a reference to the internal storage array, not a copy, and to correctly + * address elements of the array, the startIndex is + * required (available via the {@link #start} method). This method should + * only be used in cases where copying the internal array is not practical. + * The {@link #getElements} method should be used in all other cases. + * + * + * @return the internal storage array used by this object + */ + public double[] getValues() { + return (internalArray); + } + + /** + * Sets the contraction criteria for this ExpandContractDoubleArray. + * + * @param contractionCriteria contraction criteria + */ + public void setContractionCriteria(float contractionCriteria) { + checkContractExpand(contractionCriteria, getExpansionFactor()); + this.contractionCriteria = contractionCriteria; + } + + + /** + * Sets the element at the specified index. If the specified index is greater than + * getNumElements() - 1, the numElements property + * is increased to index +1 and additional storage is allocated + * (if necessary) for the new element and all (uninitialized) elements + * between the new element and the previous end of the array). + * + * @param index index to store a value in + * @param value value to store at the specified index + * @throws ArrayIndexOutOfBoundsException if index is less than + * zero. + */ + public synchronized void setElement(int index, double value) { + if (index < 0) { + String msg = "Cannot set an element at a negative index"; + throw new ArrayIndexOutOfBoundsException(msg); + } + if (index + 1 > numElements) { + numElements = index + 1; + } + if ((startIndex + index) >= internalArray.length) { + expandTo(startIndex + (index + 1)); + } + internalArray[startIndex + index] = value; + } + + /** + * Sets the expansionFactor. Throws IllegalArgumentException if the + * the following conditions are not met: + *

    + *
  • expansionFactor > 1
  • + *
  • contractionFactor >= expansionFactor
  • + *
+ * + * @throws IllegalArgumentException if expansionFactor is <= 1 or greater + * than contractionFactor + */ + public void setExpansionFactor(float expansionFactor) { + checkContractExpand(getContractionCriteria(), expansionFactor); + // The check above verifies that the expansion factor is > 1.0; + this.expansionFactor = expansionFactor; + } + + /** + * Sets the expansionMode. The specified value must be one of + * ADDITIVE_MODE, MULTIPLICATIVE_MODE. + * + * @param expansionMode The expansionMode to set. + * @throws IllegalArgumentException if the specified mode value is not valid + */ + public void setExpansionMode(int expansionMode) { + if (expansionMode != MULTIPLICATIVE_MODE && + expansionMode != ADDITIVE_MODE) { + throw new IllegalArgumentException("Illegal expansionMode setting."); + } + this.expansionMode = expansionMode; + } + + /** + * Sets the initial capacity. Should only be invoked by constructors. + * + * @param initialCapacity of the array + * @throws IllegalArgumentException if initialCapacity is not + * positive. + */ + protected void setInitialCapacity(int initialCapacity) { + if (initialCapacity > 0) { + this.initialCapacity = initialCapacity; + } else { + String msg = + "The initial capacity supplied: " + initialCapacity + + "must be a positive integer"; + throw new IllegalArgumentException(msg); + } + } + + /** + * This function allows you to control the number of elements contained + * in this array, and can be used to "throw out" the last n values in an + * array. This function will also expand the internal array as needed. + * + * @param i a new number of elements + * @throws IllegalArgumentException if i is negative. + */ + public synchronized void setNumElements(int i) { + + // If index is negative thrown an error + if (i < 0) { + String msg = + "Number of elements must be zero or a positive " + "integer"; + throw new IllegalArgumentException(msg); + } + + // Test the new num elements, check to see if the array needs to be + // expanded to accomodate this new number of elements + if ((startIndex + i) > internalArray.length) { + expandTo(startIndex + i); + } + + // Set the new number of elements to new value + numElements = i; + } + + /** + * Returns true if the internal storage array has too many unused + * storage positions. + * + * @return true if array satisfies the contraction criteria + */ + private synchronized boolean shouldContract() { + if (expansionMode == MULTIPLICATIVE_MODE) { + return (internalArray.length / numElements) > contractionCriteria; + } else { + return (internalArray.length - numElements) > contractionCriteria; + } + } + + /** + * Returns the starting index of the internal array. The starting index is + * the position of the first addressable element in the internal storage + * array. The addressable elements in the array are + * internalArray[startIndex],...,internalArray[startIndex + numElements -1] + * + * + * @return starting index + */ + public int start() { + return startIndex; + } + +} diff --git a/src/test/org/apache/commons/math/util/ContractableDoubleArrayTest.java b/src/test/org/apache/commons/math/util/ContractableDoubleArrayTest.java deleted file mode 100644 index daf4f0e99..000000000 --- a/src/test/org/apache/commons/math/util/ContractableDoubleArrayTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - - -/** - * This class contains test cases for the ExpandableDoubleArray. - * - * @version $Revision: 1.9 $ $Date: 2004/05/04 13:15:47 $ - */ -public class ContractableDoubleArrayTest extends ExpandableDoubleArrayTest { - - public ContractableDoubleArrayTest(String name) { - super( name ); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception { - da = new ContractableDoubleArray(); - ra = new ContractableDoubleArray(); - } - - protected ExpandableDoubleArray newInstance(int initialCapacity) { - return new ContractableDoubleArray(initialCapacity); - } - - protected ExpandableDoubleArray newInstance() { - return new ContractableDoubleArray(); - } - - protected ExpandableDoubleArray newInstance(int initialCapacity, float expansionFactor) { - if (expansionFactor < 2.5f) { - return new ContractableDoubleArray(initialCapacity, expansionFactor); - } else { - return newInstance(initialCapacity, expansionFactor, expansionFactor + 1.0f); - } - } - - protected ExpandableDoubleArray newInstance(int initialCapacity, float expansionFactor, float contractionFactor) { - return new ContractableDoubleArray(initialCapacity, expansionFactor, contractionFactor); - } -} diff --git a/src/test/org/apache/commons/math/util/ExpandableDoubleArrayTest.java b/src/test/org/apache/commons/math/util/ExpandableDoubleArrayTest.java deleted file mode 100644 index 39bd1e09e..000000000 --- a/src/test/org/apache/commons/math/util/ExpandableDoubleArrayTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - - -/** - * This class contains test cases for the ExpandableDoubleArray. - * - * @version $Revision: 1.10 $ $Date: 2004/05/04 13:15:47 $ - */ -public class ExpandableDoubleArrayTest extends DoubleArrayAbstractTest { - - public ExpandableDoubleArrayTest(String name) { - super( name ); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception { - da = newInstance(); - ra = newInstance(); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - protected void tearDown() throws Exception { - da = null; - ra = null; - } - - - /** TEST NORMAL OPERATIONS - calling super class test and then checking internal - * storage **/ - - - public void testSetElementArbitraryExpansion() { - double[] controlArray = {2.0, 4.0, 6.0}; - - da.addElement(2.0); - da.addElement(4.0); - da.addElement(6.0); - da.setElement(1, 3.0); - - // Expand the array arbitrarily to 1000 items - da.setElement(1000, 3.4); - - assertEquals( "The number of elements should now be 1001, it isn't", da.getNumElements(), 1001); - - assertEquals( "Uninitialized Elements are default value of 0.0, index 766 wasn't", 0.0, - da.getElement( 760 ), Double.MIN_VALUE ); - - assertEquals( "The 1000th index should be 3.4, it isn't", 3.4, da.getElement(1000), Double.MIN_VALUE ); - assertEquals( "The 0th index should be 2.0, it isn't", 2.0, da.getElement(0), Double.MIN_VALUE); - - } - - public void testAdd1000() { - super.testAdd1000(); - assertEquals("Internal Storage length should be 1024 if we started out with initial capacity of " + - "16 and an expansion factor of 2.0", - 1024, ((ExpandableDoubleArray) da).getInternalLength()); - } - - public void testAddElementRolling() { - super.testAddElementRolling(); - } - - public void testSetNumberOfElements() { - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - assertEquals( "Number of elements should equal 6", da.getNumElements(), 6); - - ((ExpandableDoubleArray) da).setNumElements( 3 ); - assertEquals( "Number of elements should equal 3", da.getNumElements(), 3); - - try { - ((ExpandableDoubleArray) da).setNumElements( -3 ); - fail( "Setting number of elements to negative should've thrown an exception"); - } catch( IllegalArgumentException iae ) { - } - - ((ExpandableDoubleArray) da).setNumElements(1024); - assertEquals( "Number of elements should now be 1024", da.getNumElements(), 1024); - assertEquals( "Element 453 should be a default double", da.getElement( 453 ), 0.0, Double.MIN_VALUE); - - } - - /** TESTS WHICH FOCUS ON ExpandableSpecific internal storage */ - - public void testWithInitialCapacity() { - - ExpandableDoubleArray eDA2 = newInstance(2); - assertEquals("Initial number of elements should be 0", 0, eDA2.getNumElements()); - - int iterations = (int) Math.pow(2.0, 15.0); - - for( int i = 0; i < iterations; i++) { - eDA2.addElement( i ); - } - - assertEquals("Number of elements should be equal to 2^15", (int) Math.pow(2.0, 15.0), eDA2.getNumElements()); - - eDA2.addElement( 2.0 ); - - assertEquals("Number of elements should be equals to 2^15 + 1", - ( (int) Math.pow(2.0, 15.0) + 1 ), eDA2.getNumElements() ); - } - - public void testWithInitialCapacityAndExpansionFactor() { - - ExpandableDoubleArray eDA3 = newInstance(3, 3.0f); - assertEquals("Initial number of elements should be 0", 0, eDA3.getNumElements() ); - - int iterations = (int) Math.pow(3.0, 7.0); - - for( int i = 0; i < iterations; i++) { - eDA3.addElement( i ); - } - - assertEquals("Number of elements should be equal to 3^7", (int) Math.pow(3.0, 7.0), eDA3.getNumElements()); - - eDA3.addElement( 2.0 ); - - assertEquals("Number of elements should be equals to 3^7 + 1", - ( (int) Math.pow(3.0, 7.0) + 1 ), eDA3.getNumElements() ); - - assertEquals("Expansion factor should equal 3.0", 3.0f, eDA3.getExpansionFactor(), Double.MIN_VALUE); - } - - public void testDiscard() { - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - da.addElement(2.0); - assertEquals( "Number of elements should be 11", 11, da.getNumElements()); - - ((ExpandableDoubleArray)da).discardFrontElements(5); - assertEquals( "Number of elements should be 6", 6, da.getNumElements()); - - try { - ((ExpandableDoubleArray)da).discardFrontElements(-1); - fail( "Trying to discard a negative number of element is not allowed"); - } catch( Exception e ){ - } - - try { - ((ExpandableDoubleArray)da).discardFrontElements( 10000 ); - fail( "You can't discard more elements than the array contains"); - } catch( Exception e ){ - } - - } - - /** TEST ERROR CONDITIONS **/ - - public void testIllegalInitialCapacity() { - try { - ExpandableDoubleArray eDA = newInstance(-3, 2.0f); - fail( "That constructor should have thrown an IllegalArgumentException because " + "the initialCapacity was negative, if it didn't then" + " the range checking of initialCapacity is not working properly" ); - } catch( IllegalArgumentException iae ) { - } - try { - ExpandableDoubleArray eDA = newInstance(0, 2.0f); - fail( "That constructor should have thrown an IllegalArgumentException because " + - "the initialCapacity was ZERO if it didn't then" + - " the range checking of initialCapacity is not working properly" ); - } catch( IllegalArgumentException iae ) { - } - } - - public void testIllegalExpansionFactor() { - try { - ExpandableDoubleArray eDA = newInstance(3, 0.66f); - fail( "That constructor should have thrown an IllegalArgumentException because " + "the expansionFactor for 0.66 which would shrink the array instead of expand the array"); - } catch( IllegalArgumentException iae ) { - } - try { - ExpandableDoubleArray eDA = newInstance(3, 0.0f); - fail( "That constructor should have thrown an IllegalArgumentException because " + - "the expansionFactor for 0.0"); - } catch( IllegalArgumentException iae) { - } - - try { - ExpandableDoubleArray eDA = newInstance(3, -4.35f); - fail( "That constructor should have thrown an IllegalArgumentException because " + - "the expansionFactor for -4.35"); - } catch( IllegalArgumentException iae) { - } - } - - public void testSetOutOfBounds() { - try { - da.setElement( -1, 2.0); - fail( "Cannot set a negative index"); - } catch( Exception e ){ - } - } - - public void testGetOutOfBounds() { - try { - da.getElement(10000); - fail( "Cannot get an element that is larger than the number of elements"); - } catch( Exception e ) { - } - - try { - da.getElement(-3); - fail("Cannot get a negative index"); - } catch( Exception e ){ - } - } - - protected ExpandableDoubleArray newInstance(int initialCapacity) { - return new ExpandableDoubleArray(initialCapacity); - } - - protected ExpandableDoubleArray newInstance() { - return new ExpandableDoubleArray(); - } - - protected ExpandableDoubleArray newInstance(int initialCapacity, float expansionFactor) { - return new ExpandableDoubleArray(initialCapacity, expansionFactor); - } -} diff --git a/src/test/org/apache/commons/math/util/FixedDoubleArrayTest.java b/src/test/org/apache/commons/math/util/FixedDoubleArrayTest.java deleted file mode 100644 index 4917a854b..000000000 --- a/src/test/org/apache/commons/math/util/FixedDoubleArrayTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.math.util; - - -/** - * This class contains test cases for the ExpandableDoubleArray. - * - * @version $Revision: 1.10 $ $Date: 2004/02/21 21:35:18 $ - */ -public class FixedDoubleArrayTest extends DoubleArrayAbstractTest { - - public FixedDoubleArrayTest(String name) { - super( name ); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception { - da = new FixedDoubleArray(4000); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - protected void tearDown() throws Exception { - da = null; - } - - - /** TEST NORMAL OPERATIONS - calling super class test and then checking internal - * storage **/ - - public void testAddElementRolling() { - ra = new FixedDoubleArray(6); - - super.testAddElementRolling(); - - assertEquals( "FixedDoubleArray should have 6 size internal storage", - 6, ((FixedDoubleArray) ra).getValues().length); - } - - public void testExceedingElements() { - - for( int i = 0; i < 3999; i++) { - da.addElement( 1.0 ); - } - - da.addElement( 1.0 ); - - try { - da.addElement( 2.0 ); - fail( " Adding more than 4000 elements should cause an exception "); - } catch( Exception e ) { - } - - da.addElementRolling(2.0); - assertEquals( "This is the first rolling add, the first element should be 2.0", - 2.0, da.getElement(0), Double.MIN_VALUE); - } - - public void testGetExceeding() { - try { - da.getElement(100); - fail( "I haven't added 100 elements to the list yet, trying to getElement(100) should " + "thrown an error"); - } catch (Exception e ){ - } - - } - - public void testSetElement() { - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - da.addElement( 1.0 ); - - da.setElement( 2, 4.0 ); - assertEquals( "Index 2 should be 4.0", 4.0, da.getElement(2), Double.MIN_VALUE); - - try { - da.setElement(2000, 45.0); - fail( "The array does not contain 2000 elements yet, setting this element should" + " cause an excpetion"); - } catch(Exception e) { - } - - } - - public void testOnlyRolling() { - for( int i = 0; i < 8000; i++) { - da.addElementRolling( i ); - } - - assertEquals( "The 2000th element should equal 6000", - 6000.0, da.getElement(2000), Double.MIN_VALUE); - } - - public void testClear() { - for( int i = 0; i < 10; i++) { - da.addElementRolling(1.0); - } - - assertEquals( "There should be ten elements in the array", - 10, da.getNumElements() ); - - da.clear(); - - assertEquals( "There should be zero elements in the array", - 0, da.getNumElements() ); - - for( int i = 0; i < 10; i++) { - da.addElementRolling(1.0); - } - - assertEquals( "There should be ten elements in the array", - 10, da.getNumElements() ); - - } - - -} diff --git a/src/test/org/apache/commons/math/util/ResizableDoubleArrayTest.java b/src/test/org/apache/commons/math/util/ResizableDoubleArrayTest.java new file mode 100644 index 000000000..8d9737580 --- /dev/null +++ b/src/test/org/apache/commons/math/util/ResizableDoubleArrayTest.java @@ -0,0 +1,351 @@ +/* + * Copyright 2003-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.util; +import org.apache.commons.math.random.RandomDataImpl; +import org.apache.commons.math.random.RandomData; + + +/** + * This class contains test cases for the ResizableDoubleArray. + * + * @version $Revision: 1.1 $ $Date: 2004/06/14 21:41:33 $ + */ +public class ResizableDoubleArrayTest extends DoubleArrayAbstractTest { + + public ResizableDoubleArrayTest(String name) { + super( name ); + } + + protected void tearDown() throws Exception { + da = null; + ra = null; + } + + protected void setUp() throws Exception { + da = new ResizableDoubleArray(); + ra = new ResizableDoubleArray(); + } + + public void testConstructors() { + float defaultExpansionFactor = 2.0f; + float defaultContractionCriteria = 2.5f; + int defaultMode = ResizableDoubleArray.MULTIPLICATIVE_MODE; + + ResizableDoubleArray testDa = new ResizableDoubleArray(2); + assertEquals(0, testDa.getNumElements()); + assertEquals(2, testDa.getInternalLength()); + assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0); + assertEquals(defaultContractionCriteria, testDa.getContractionCriteria(), 0); + assertEquals(defaultMode, testDa.getExpansionMode()); + try { + da = new ResizableDoubleArray(-1); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + + testDa = new ResizableDoubleArray(2, 2.0f); + assertEquals(0, testDa.getNumElements()); + assertEquals(2, testDa.getInternalLength()); + assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0); + assertEquals(defaultContractionCriteria, testDa.getContractionCriteria(), 0); + assertEquals(defaultMode, testDa.getExpansionMode()); + + try { + da = new ResizableDoubleArray(2, 0.5f); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + + testDa = new ResizableDoubleArray(2, 3.0f); + assertEquals(3.0f, testDa.getExpansionFactor(), 0); + assertEquals(3.5f, testDa.getContractionCriteria(), 0); + + testDa = new ResizableDoubleArray(2, 2.0f, 3.0f); + assertEquals(0, testDa.getNumElements()); + assertEquals(2, testDa.getInternalLength()); + assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0); + assertEquals(3.0f, testDa.getContractionCriteria(), 0); + assertEquals(defaultMode, testDa.getExpansionMode()); + + try { + da = new ResizableDoubleArray(2, 2.0f, 1.5f); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + + testDa = new ResizableDoubleArray(2, 2.0f, 3.0f, + ResizableDoubleArray.ADDITIVE_MODE); + assertEquals(0, testDa.getNumElements()); + assertEquals(2, testDa.getInternalLength()); + assertEquals(defaultExpansionFactor, testDa.getExpansionFactor(), 0); + assertEquals(3.0f, testDa.getContractionCriteria(), 0); + assertEquals(ResizableDoubleArray.ADDITIVE_MODE, + testDa.getExpansionMode()); + + try { + da = new ResizableDoubleArray(2, 2.0f, 2.5f, -1); + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + + } + + + public void testSetElementArbitraryExpansion() { + + // MULTIPLICATIVE_MODE + da.addElement(2.0); + da.addElement(4.0); + da.addElement(6.0); + da.setElement(1, 3.0); + + // Expand the array arbitrarily to 1000 items + da.setElement(1000, 3.4); + + assertEquals( "The number of elements should now be 1001, it isn't", + da.getNumElements(), 1001); + + assertEquals( "Uninitialized Elements are default value of 0.0, index 766 wasn't", 0.0, + da.getElement( 760 ), Double.MIN_VALUE ); + + assertEquals( "The 1000th index should be 3.4, it isn't", 3.4, da.getElement(1000), + Double.MIN_VALUE ); + assertEquals( "The 0th index should be 2.0, it isn't", 2.0, da.getElement(0), + Double.MIN_VALUE); + + // Make sure numElements and expansion work correctly for expansion boundary cases + da.clear(); + da.addElement(2.0); + da.addElement(4.0); + da.addElement(6.0); + assertEquals(4, ((ResizableDoubleArray) da).getInternalLength()); + assertEquals(3, da.getNumElements()); + da.setElement(3, 7.0); + assertEquals(4, ((ResizableDoubleArray) da).getInternalLength()); + assertEquals(4, da.getNumElements()); + da.setElement(10, 10.0); + assertEquals(11, ((ResizableDoubleArray) da).getInternalLength()); + assertEquals(11, da.getNumElements()); + da.setElement(9, 10.0); + assertEquals(11, ((ResizableDoubleArray) da).getInternalLength()); + assertEquals(11, da.getNumElements()); + + try { + da.setElement(-2, 3); + fail("Expecting ArrayIndexOutOfBoundsException for negative index"); + } catch (ArrayIndexOutOfBoundsException ex) { + // expected + } + + // ADDITIVE_MODE + + ResizableDoubleArray testDa = new ResizableDoubleArray(2, 2.0f, 3.0f, + ResizableDoubleArray.ADDITIVE_MODE); + assertEquals(2, testDa.getInternalLength()); + testDa.addElement(1d); + testDa.addElement(1d); + assertEquals(2, testDa.getInternalLength()); + testDa.addElement(1d); + assertEquals(4, testDa.getInternalLength()); + } + + public void testAdd1000() { + super.testAdd1000(); + assertEquals("Internal Storage length should be 1024 if we started out with initial capacity of " + + "16 and an expansion factor of 2.0", + 1024, ((ResizableDoubleArray) da).getInternalLength()); + } + + public void testAddElementRolling() { + super.testAddElementRolling(); + + // MULTIPLICATIVE_MODE + da.clear(); + da.addElement(1); + da.addElement(2); + da.addElementRolling(3); + assertEquals(3, da.getElement(1), 0); + da.addElementRolling(4); + assertEquals(3, da.getElement(0), 0); + assertEquals(4, da.getElement(1), 0); + da.addElement(5); + assertEquals(5, da.getElement(2), 0); + da.addElementRolling(6); + assertEquals(4, da.getElement(0), 0); + assertEquals(5, da.getElement(1), 0); + assertEquals(6, da.getElement(2), 0); + + // ADDITIVE_MODE (x's are occupied storage locations, 0's are open) + ResizableDoubleArray testDa = new ResizableDoubleArray(2, 2.0f, 2.5f, + ResizableDoubleArray.ADDITIVE_MODE); + assertEquals(2, testDa.getInternalLength()); + testDa.addElement(1d); // x,0 + testDa.addElement(2d); // x,x + testDa.addElement(3d); // x,x,x,0 -- expanded + assertEquals(1d, testDa.getElement(0), 0); + assertEquals(2d, testDa.getElement(1), 0); + assertEquals(3d, testDa.getElement(2), 0); + assertEquals(4, testDa.getInternalLength()); // x,x,x,0 + assertEquals(3, testDa.getNumElements()); + testDa.addElementRolling(4d); + assertEquals(2d, testDa.getElement(0), 0); + assertEquals(3d, testDa.getElement(1), 0); + assertEquals(4d, testDa.getElement(2), 0); + assertEquals(4, testDa.getInternalLength()); // 0,x,x,x + assertEquals(3, testDa.getNumElements()); + testDa.addElementRolling(5d); // 0,0,x,x,x,0 -- time to contract + assertEquals(3d, testDa.getElement(0), 0); + assertEquals(4d, testDa.getElement(1), 0); + assertEquals(5d, testDa.getElement(2), 0); + assertEquals(4, testDa.getInternalLength()); // contracted -- x,x,x,0 + assertEquals(3, testDa.getNumElements()); + try { + testDa.getElement(4); + fail("Expecting ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException ex) { + // expected + } + try { + testDa.getElement(-1); + fail("Expecting ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException ex) { + // expected + } + } + + public void testSetNumberOfElements() { + da.addElement( 1.0 ); + da.addElement( 1.0 ); + da.addElement( 1.0 ); + da.addElement( 1.0 ); + da.addElement( 1.0 ); + da.addElement( 1.0 ); + assertEquals( "Number of elements should equal 6", da.getNumElements(), 6); + + ((ResizableDoubleArray) da).setNumElements( 3 ); + assertEquals( "Number of elements should equal 3", da.getNumElements(), 3); + + try { + ((ResizableDoubleArray) da).setNumElements( -3 ); + fail( "Setting number of elements to negative should've thrown an exception"); + } catch( IllegalArgumentException iae ) { + } + + ((ResizableDoubleArray) da).setNumElements(1024); + assertEquals( "Number of elements should now be 1024", da.getNumElements(), 1024); + assertEquals( "Element 453 should be a default double", da.getElement( 453 ), 0.0, Double.MIN_VALUE); + + } + + public void testWithInitialCapacity() { + + ResizableDoubleArray eDA2 = new ResizableDoubleArray(2); + assertEquals("Initial number of elements should be 0", 0, eDA2.getNumElements()); + + RandomData randomData = new RandomDataImpl(); + int iterations = randomData.nextInt(100, 1000); + + for( int i = 0; i < iterations; i++) { + eDA2.addElement( i ); + } + + assertEquals("Number of elements should be equal to " + iterations, iterations, eDA2.getNumElements()); + + eDA2.addElement( 2.0 ); + + assertEquals("Number of elements should be equals to " + (iterations +1), + iterations + 1 , eDA2.getNumElements() ); + } + + public void testWithInitialCapacityAndExpansionFactor() { + + ResizableDoubleArray eDA3 = new ResizableDoubleArray(3, 3.0f, 3.5f); + assertEquals("Initial number of elements should be 0", 0, eDA3.getNumElements() ); + + RandomData randomData = new RandomDataImpl(); + int iterations = randomData.nextInt(100, 3000); + + for( int i = 0; i < iterations; i++) { + eDA3.addElement( i ); + } + + assertEquals("Number of elements should be equal to " + iterations, iterations,eDA3.getNumElements()); + + eDA3.addElement( 2.0 ); + + assertEquals("Number of elements should be equals to " + (iterations +1), + iterations +1, eDA3.getNumElements() ); + + assertEquals("Expansion factor should equal 3.0", 3.0f, eDA3.getExpansionFactor(), Double.MIN_VALUE); + } + + public void testDiscard() { + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + da.addElement(2.0); + assertEquals( "Number of elements should be 11", 11, da.getNumElements()); + + ((ResizableDoubleArray)da).discardFrontElements(5); + assertEquals( "Number of elements should be 6", 6, da.getNumElements()); + + try { + ((ResizableDoubleArray)da).discardFrontElements(-1); + fail( "Trying to discard a negative number of element is not allowed"); + } catch( Exception e ){ + } + + try { + ((ResizableDoubleArray)da).discardFrontElements( 10000 ); + fail( "You can't discard more elements than the array contains"); + } catch( Exception e ){ + } + } + + public void testMutators() { + ((ResizableDoubleArray)da).setContractionCriteria(10f); + assertEquals(10f, ((ResizableDoubleArray)da).getContractionCriteria(), 0); + ((ResizableDoubleArray)da).setExpansionFactor(8f); + assertEquals(8f, ((ResizableDoubleArray)da).getExpansionFactor(), 0); + try { + ((ResizableDoubleArray)da).setExpansionFactor(11f); // greater than contractionCriteria + fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + ((ResizableDoubleArray)da).setExpansionMode( + ResizableDoubleArray.ADDITIVE_MODE); + assertEquals(ResizableDoubleArray.ADDITIVE_MODE, + ((ResizableDoubleArray)da).getExpansionMode()); + try { + ((ResizableDoubleArray)da).setExpansionMode(-1); + fail ("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + } +}