psteitz     2004/06/14 14:41:33

  Modified:    math/src/java/org/apache/commons/math/stat/univariate
                        DescriptiveStatisticsImpl.java
               math/src/java/org/apache/commons/math/util DoubleArray.java
  Added:       math/src/java/org/apache/commons/math/util
                        ResizableDoubleArray.java
               math/src/test/org/apache/commons/math/util
                        ResizableDoubleArrayTest.java
  Removed:     math/src/java/org/apache/commons/math/util
                        ContractableDoubleArray.java
                        ExpandableDoubleArray.java FixedDoubleArray.java
               math/src/test/org/apache/commons/math/util
                        ContractableDoubleArrayTest.java
                        ExpandableDoubleArrayTest.java
                        FixedDoubleArrayTest.java
  Log:
  Combined Expandable, ContractableDoubleArrays into ResizableDoubleArray and dropped 
FixedDoubleArray.
  
  Revision  Changes    Path
  1.7       +4 -4      
jakarta-commons/math/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java
  
  Index: DescriptiveStatisticsImpl.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/math/src/java/org/apache/commons/math/stat/univariate/DescriptiveStatisticsImpl.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DescriptiveStatisticsImpl.java    1 Jun 2004 21:34:35 -0000       1.6
  +++ DescriptiveStatisticsImpl.java    14 Jun 2004 21:41:33 -0000      1.7
  @@ -17,7 +17,7 @@
   
   import java.io.Serializable;
   
  -import org.apache.commons.math.util.ContractableDoubleArray;
  +import org.apache.commons.math.util.ResizableDoubleArray;
   
   /**
    * Default implementation of
  @@ -36,7 +36,7 @@
       /** 
        *  Stored data values
        */
  -    protected ContractableDoubleArray eDA;
  +    protected ResizableDoubleArray eDA;
   
       /**
        * Construct a DescriptiveStatisticsImpl with infinite window
  @@ -51,7 +51,7 @@
        */
       public DescriptiveStatisticsImpl(int window) {
        super();
  -     eDA = new ContractableDoubleArray();
  +     eDA = new ResizableDoubleArray();
           setWindowSize(window);
       }
   
  
  
  
  1.12      +25 -18    
jakarta-commons/math/src/java/org/apache/commons/math/util/DoubleArray.java
  
  Index: DoubleArray.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/math/src/java/org/apache/commons/math/util/DoubleArray.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- DoubleArray.java  8 Jun 2004 14:19:40 -0000       1.11
  +++ DoubleArray.java  14 Jun 2004 21:41:33 -0000      1.12
  @@ -17,10 +17,8 @@
   
   
   /**
  - * 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$ $Date$
  @@ -29,7 +27,8 @@
   
       /**
        * 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 @@
       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
  +     * <code>getNumElements() - 1</code>, the <code>numElements</code> property
  +     * is increased to <code>index +1</code> 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 @@
       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.  
        * <p>
  -     * 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.
  +     * </p>
  +     * <p>
  +     * 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.
  +     * </p>
        * 
        * @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 
  +     * <code>DoubleArray</code>.  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 <code>DoubleArray.</code>
        *
        * @return all elements added to the array
        */
  
  
  
  1.1                  
jakarta-commons/math/src/java/org/apache/commons/math/util/ResizableDoubleArray.java
  
  Index: ResizableDoubleArray.java
  ===================================================================
  /*
   * 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;
  
  /**
   * <p>
   * A variable length [EMAIL PROTECTED] DoubleArray} implementation that 
automatically 
   * handles expanding and contracting its internal storage array as elements 
   * are added and removed.
   * </p>
   * <p>
   *  The internal storage array starts with capacity determined by the
   * <code>initialCapacity</code> property, which can be set by the constructor.
   * The default initial capacity is 16.  Adding elements using 
   * [EMAIL PROTECTED] #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 
   * <code>expansionMode</code> and <code>expansionFactor</code> properties.  
   * The <code>expansionMode</code> determines whether the size of the array is 
   * multiplied by the <code>expansionFactor</code> (MULTIPLICATIVE_MODE) or if 
   * the expansion is additive (ADDITIVE_MODE -- <code>expansionFactor</code>
   * storage locations added).  The default <code>expansionMode</code> is 
   * MULTIPLICATIVE_MODE and the default <code>expansionFactor</code>
   * is 2.0.
   * </p>
   * <p>
   * The [EMAIL PROTECTED] #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 [EMAIL PROTECTED] #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 <code>numElements</code> property) and if the difference
   * is too large, the internal array is contracted to size 
   * <code>numElements + 1.</code>  The determination of when the internal
   * storage array is "too large" depends on the <code>expansionMode</code> and
   * <code>contractionFactor</code> properties.  If  the <code>expansionMode</code>
   * is <code>MULTIPLICATIVE_MODE</code>, contraction is triggered when the
   * ratio between storage array length and <code>numElements</code> exceeds
   * <code>contractionFactor.</code>  If the <code>expansionMode</code>
   * is <code>ADDITIVE_MODE,</code> the number of excess storage locations
   * is compared to <code>contractionFactor.</code>  
   * </p>
   * <p>
   * To avoid cycles of expansions and contractions, the 
   * <code>expansionFactor</code> must not exceed the 
   * <code>contractionFactor.</code> Constructors and mutators for both of these
   * properties enforce this requirement, throwing IllegalArgumentException if it
   * is violated.
   * </p>
   * <p>
   * @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 
       * <code>internalArray.length * expansionFactor</code>
       * if <code>expansionMode</code> is set to MULTIPLICATIVE_MODE, or
       * <code>internalArray.length + expansionFactor</code> if 
       * <code>expansionMode</code> is set to ADDITIVE_MODE.
       */
      protected float expansionFactor = 2.0f;
      
      /**
       * Determines whether array expansion by <code>expansionFactor</code>
       * 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 <code>
       * internalArray[startIndex],...,internalArray[startIndex + numElements -1]
       * </code>
       */
      protected int startIndex = 0;
  
      /**
       * Create a ResizableArray with default properties.
       * <ul>
       * <li><code>initialCapacity = 16</code></li>
       * <li><code>expansionMode = MULTIPLICATIVE_MODE</code></li>
       * <li><code>expansionFactor = 2.5</code></li>
       * <li><code>contractionFactor = 2.0</code></li>
       * </ul>
       */
      public ResizableDoubleArray() {
          internalArray = new double[initialCapacity];
      }
  
      /**
       * Create a ResizableArray with the specified initial capacity.  Other
       * properties take default values:
        * <ul>
       * <li><code>expansionMode = MULTIPLICATIVE_MODE</code></li>
       * <li><code>expansionFactor = 2.5</code></li>
       * <li><code>contractionFactor = 2.0</code></li>
       * </ul>
       * @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];
      }
  
      /**
       * <p>
       * Create a ResizableArray with the specified initial capacity 
       * and expansion factor.  The remaining properties take default
       * values:
       * <ul>
       * <li><code>expansionMode = MULTIPLICATIVE_MODE</code></li>
       * <li><code>contractionFactor = 0.5 + expansionFactor</code></li>
       * </ul></p>
       * <p>
       * Throws IllegalArgumentException if the following conditions are
       * not met:
       * <ul>
       * <li><code>initialCapacity > 0</code></li>
       * <li><code>expansionFactor > 1</code></li>
       * </ul></p>
       * 
       * @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);
      }
  
      /**
       * <p>
       * Create a ResizableArray with the specified initialCapacity, 
       * expansionFactor, and contractionCriteria. The <code>expansionMode</code>
       * will default to <code>MULTIPLICATIVE_MODE.</code></p>
       * <p>
       * Throws IllegalArgumentException if the following conditions are
       * not met:
       * <ul>
       * <li><code>initialCapacity > 0</code></li>
       * <li><code>expansionFactor > 1</code></li>
       * <li><code>contractionFactor >= expansionFactor</code></li>
       * </ul></p>
       * @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];
      }
      
      /**
       * <p>
       * Create a ResizableArray with the specified properties.</p>
      * <p>
       * Throws IllegalArgumentException if the following conditions are
       * not met:
       * <ul>
       * <li><code>initialCapacity > 0</code></li>
       * <li><code>expansionFactor > 1</code></li>
       * <li><code>contractionFactor >= expansionFactor</code></li>
       * <li><code>expansionMode in {MULTIPLICATIVE_MODE, ADDITIVE_MODE}</code>
       * </li>
       * </ul></p>
       * 
       * @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();
          }
      }
  
      /**
       * <p>
       * 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.
       * </p>
       * <p>
       * 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.
       * </p>
       * 
       * @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 <code>i<code> initial elements of the array.  For example,
       * if the array contains the elements 1,2,3,4, invoking 
       * <code>discardFrontElements(2)</code> 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.
       * <p>
       * if <code>expansionMode</code> is set to MULTIPLICATIVE_MODE,
       * the new array size will be <code>internalArray.length * 
expansionFactor.</code>
       * If <code>expansionMode</code> is set to ADDITIVE_MODE,  the length
       * after expansion will be <code>internalArray.length + expansionFactor</code>
       */
      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 <code>expansionMode</code> is <code>MULTIPLICATIVE_MODE</code>,
       * contraction is triggered when the ratio between storage array length 
       * and <code>numElements</code> exceeds <code>contractionFactor</code>.
       * If the <code>expansionMode</code> is <code>ADDITIVE_MODE</code>, the
       * number of excess storage locations is compared to 
       * <code>contractionFactor.</code>   
       * 
       * @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 <code>index</code> is less than
       *         zero or is greater than <code>getNumElements() - 1</code>.
       */
      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 
       * <code>ResizableArray</code>.  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 <code>ResizableArray.</code>
       */
      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 <code>expansionMode</code>
       * determines whether the size of the array is multiplied by the 
       * <code>expansionFactor</code> (MULTIPLICATIVE_MODE) or if 
       * the expansion is additive (ADDITIVE_MODE -- <code>expansionFactor</code>
       * storage locations added).  The default <code>expansionMode</code> is 
       * MULTIPLICATIVE_MODE and the default <code>expansionFactor</code>
       * is 2.0.
       * 
       * @return the expansion factor of this expandable double array
       */
      public float getExpansionFactor() {
          return expansionFactor;
      }
      
      /**
       * The <code>expansionMode</code> 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 <code>startIndex</code> is
       * required (available via the [EMAIL PROTECTED] #start} method).  This method 
should
       * only be used in cases where copying the internal array is not practical.
       * The [EMAIL PROTECTED] #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
       * <code>getNumElements() - 1</code>, the <code>numElements</code> property
       * is increased to <code>index +1</code> 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 <code>index</code> 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:
       * <ul>
       * <li><code>expansionFactor > 1</code></li>
       * <li><code>contractionFactor >= expansionFactor</code></li>
       * </ul>
       *
       * @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 <code>expansionMode</code>. 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 <code>initialCapacity</code> 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 <code>i</code> 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 <code>
       * internalArray[startIndex],...,internalArray[startIndex + numElements -1]
       * </code>
       *
       * @return starting index
       */
      public int start() {
          return startIndex;
      }
  
  }
  
  
  
  1.1                  
jakarta-commons/math/src/test/org/apache/commons/math/util/ResizableDoubleArrayTest.java
  
  Index: ResizableDoubleArrayTest.java
  ===================================================================
  /*
   * 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
          }
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to