All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cern.jet.stat.tfloat.quantile.FloatBufferSet Maven / Gradle / Ivy

Go to download

Parallel Colt is a multithreaded version of Colt - a library for high performance scientific computing in Java. It contains efficient algorithms for data analysis, linear algebra, multi-dimensional arrays, Fourier transforms, statistics and histogramming.

The newest version!
/*
Copyright (C) 1999 CERN - European Organization for Nuclear Research.
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
is hereby granted without fee, provided that the above copyright notice appear in all copies and 
that both that copyright notice and this permission notice appear in supporting documentation. 
CERN makes no representations about the suitability of this software for any purpose. 
It is provided "as is" without expressed or implied warranty.
 */
package cern.jet.stat.tfloat.quantile;

import cern.jet.stat.BufferSet;

/**
 * A set of buffers holding float elements; internally used for
 * computing approximate quantiles.
 */
class FloatBufferSet extends BufferSet {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    protected FloatBuffer[] buffers;

    private boolean nextTriggerCalculationState; // tmp var only

    /**
     * Constructs a buffer set with b buffers, each having k elements
     * 
     * @param b
     *            the number of buffers
     * @param k
     *            the number of elements per buffer
     */
    public FloatBufferSet(int b, int k) {
        this.buffers = new FloatBuffer[b];
        this.clear(k);
    }

    /**
     * Returns an empty buffer if at least one exists. Preferably returns a
     * buffer which has already been used, i.e. a buffer which has already been
     * allocated.
     */
    public FloatBuffer _getFirstEmptyBuffer() {
        FloatBuffer emptyBuffer = null;
        for (int i = buffers.length; --i >= 0;) {
            if (buffers[i].isEmpty()) {
                if (buffers[i].isAllocated())
                    return buffers[i];
                emptyBuffer = buffers[i];
            }
        }

        return emptyBuffer;
    }

    /**
     * Returns all full or partial buffers.
     */
    public FloatBuffer[] _getFullOrPartialBuffers() {
        // count buffers
        int count = 0;
        for (int i = buffers.length; --i >= 0;) {
            if (!buffers[i].isEmpty())
                count++;
        }

        // collect buffers
        FloatBuffer[] collectedBuffers = new FloatBuffer[count];
        int j = 0;
        for (int i = buffers.length; --i >= 0;) {
            if (!buffers[i].isEmpty()) {
                collectedBuffers[j++] = buffers[i];
            }
        }

        return collectedBuffers;
    }

    /**
     * Determines all full buffers having the specified level.
     * 
     * @return all full buffers having the specified level
     */
    public FloatBuffer[] _getFullOrPartialBuffersWithLevel(int level) {
        // count buffers
        int count = 0;
        for (int i = buffers.length; --i >= 0;) {
            if ((!buffers[i].isEmpty()) && buffers[i].level() == level)
                count++;
        }

        // collect buffers
        FloatBuffer[] collectedBuffers = new FloatBuffer[count];
        int j = 0;
        for (int i = buffers.length; --i >= 0;) {
            if ((!buffers[i].isEmpty()) && buffers[i].level() == level) {
                collectedBuffers[j++] = buffers[i];
            }
        }

        return collectedBuffers;
    }

    /**
     * @return The minimum level of all buffers which are full.
     */
    public int _getMinLevelOfFullOrPartialBuffers() {
        int b = this.b();
        int minLevel = Integer.MAX_VALUE;
        FloatBuffer buffer;

        for (int i = 0; i < b; i++) {
            buffer = this.buffers[i];
            if ((!buffer.isEmpty()) && (buffer.level() < minLevel)) {
                minLevel = buffer.level();
            }
        }
        return minLevel;
    }

    /**
     * Returns the number of empty buffers.
     */
    public int _getNumberOfEmptyBuffers() {
        int count = 0;
        for (int i = buffers.length; --i >= 0;) {
            if (buffers[i].isEmpty())
                count++;
        }

        return count;
    }

    /**
     * Returns all empty buffers.
     */
    public FloatBuffer _getPartialBuffer() {
        for (int i = buffers.length; --i >= 0;) {
            if (buffers[i].isPartial())
                return buffers[i];
        }
        return null;
    }

    /**
     * @return the number of buffers
     */
    public int b() {
        return buffers.length;
    }

    /**
     * Removes all elements from the receiver. The receiver will be empty after
     * this call returns, and its memory requirements will be close to zero.
     */
    public void clear() {
        clear(k());
    }

    /**
     * Removes all elements from the receiver. The receiver will be empty after
     * this call returns, and its memory requirements will be close to zero.
     */
    protected void clear(int k) {
        for (int i = b(); --i >= 0;)
            this.buffers[i] = new FloatBuffer(k);
        this.nextTriggerCalculationState = true;
    }

    /**
     * Returns a deep copy of the receiver.
     * 
     * @return a deep copy of the receiver.
     */

    public Object clone() {
        FloatBufferSet copy = (FloatBufferSet) super.clone();

        copy.buffers = copy.buffers.clone();
        for (int i = buffers.length; --i >= 0;) {
            copy.buffers[i] = (FloatBuffer) copy.buffers[i].clone();
        }
        return copy;
    }

    /**
     * Collapses the specified full buffers (must not include partial buffer).
     * 
     * @return a full buffer containing the collapsed values. The buffer has
     *         accumulated weight.
     * @param buffers
     *            the buffers to be collapsed (all of them must be full or
     *            partially full)
     */
    public FloatBuffer collapse(FloatBuffer[] buffers) {
        // determine W
        int W = 0; // sum of all weights
        for (int i = 0; i < buffers.length; i++) {
            W += buffers[i].weight();
        }

        // determine outputTriggerPositions
        int k = this.k();
        long[] triggerPositions = new long[k];
        for (int j = 0; j < k; j++) {
            triggerPositions[j] = this.nextTriggerPosition(j, W);
        }

        // do the main work: determine values at given positions in sorted
        // sequence
        float[] outputValues = this.getValuesAtPositions(buffers, triggerPositions);

        // mark all full buffers as empty, except the first, which will contain
        // the output
        for (int b = 1; b < buffers.length; b++)
            buffers[b].clear();

        FloatBuffer outputBuffer = buffers[0];
        outputBuffer.values.elements(outputValues);
        outputBuffer.weight(W);

        return outputBuffer;
    }

    /**
     * Returns whether the specified element is contained in the receiver.
     */
    public boolean contains(float element) {
        for (int i = buffers.length; --i >= 0;) {
            if ((!buffers[i].isEmpty()) && buffers[i].contains(element)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Applies a procedure to each element of the receiver, if any. Iterates
     * over the receiver in no particular order.
     * 
     * @param procedure
     *            the procedure to be applied. Stops iteration if the procedure
     *            returns false, otherwise continues.
     */
    public boolean forEach(cern.colt.function.tfloat.FloatProcedure procedure) {
        for (int i = buffers.length; --i >= 0;) {
            for (int w = buffers[i].weight(); --w >= 0;) {
                if (!(buffers[i].values.forEach(procedure)))
                    return false;
            }
        }
        return true;
    }

    /**
     * Determines all values of the specified buffers positioned at the
     * specified triggerPositions within the sorted sequence and fills them into
     * outputValues.
     * 
     * @param buffers
     *            the buffers to be searched (all must be full or partial)
     * @param triggerPositions
     *            the positions of elements within the sorted sequence to be
     *            retrieved
     * @return outputValues a list filled with the values at triggerPositions
     */
    protected float[] getValuesAtPositions(FloatBuffer[] buffers, long[] triggerPositions) {
        // if (buffers.length==0)
        // {
        // throw new IllegalArgumentException("Oops! buffer.length==0.");
        // }

        // System.out.println("triggers="+cern.it.util.Arrays.toString(positions));

        // new FloatArrayList(outputValues).fillFromToWith(0,
        // outputValues.length-1, 0.0f);
        // delte the above line, it is only for testing

        // cern.it.util.Log.println("\nEntering getValuesAtPositions...");
        // cern.it.util.Log.println("hitPositions="+cern.it.util.Arrays.toString(positions));

        // sort buffers.
        for (int i = buffers.length; --i >= 0;) {
            buffers[i].sort();
        }

        // collect some infos into fast cache; for tuning purposes only.
        int[] bufferSizes = new int[buffers.length];
        float[][] bufferValues = new float[buffers.length][];
        int totalBuffersSize = 0;
        for (int i = buffers.length; --i >= 0;) {
            bufferSizes[i] = buffers[i].size();
            bufferValues[i] = buffers[i].values.elements();
            totalBuffersSize += bufferSizes[i];
            // cern.it.util.Log.println("buffer["+i+"]="+buffers[i].values);
        }

        // prepare merge of equi-distant elements within buffers into output
        // values

        // first collect some infos into fast cache; for tuning purposes only.
        final int buffersSize = buffers.length;
        final int triggerPositionsLength = triggerPositions.length;

        // now prepare the important things.
        int j = 0; // current position in collapsed values
        int[] cursors = new int[buffers.length]; // current position in each
        // buffer; init with zeroes
        long counter = 0; // current position in sorted sequence
        long nextHit = triggerPositions[j]; // next position in sorted sequence
        // to trigger output population
        float[] outputValues = new float[triggerPositionsLength];

        if (totalBuffersSize == 0) {
            // nothing to output, because no elements have been filled (we are
            // empty).
            // return meaningless values
            for (int i = 0; i < triggerPositions.length; i++) {
                outputValues[i] = Float.NaN;
            }
            return outputValues;
        }

        // fill all output values with equi-distant elements.
        while (j < triggerPositionsLength) {
            // System.out.println("\nj="+j);
            // System.out.println("counter="+counter);
            // System.out.println("nextHit="+nextHit);

            // determine buffer with smallest value at cursor position.
            float minValue = Float.POSITIVE_INFINITY;
            int minBufferIndex = -1;

            for (int b = buffersSize; --b >= 0;) {
                // FloatBuffer buffer = buffers[b];
                // if (cursors[b] < buffer.length) {
                if (cursors[b] < bufferSizes[b]) {
                    // /float value = buffer.values[cursors[b]];
                    float value = bufferValues[b][cursors[b]];
                    if (value <= minValue) {
                        minValue = value;
                        minBufferIndex = b;
                    }
                }
            }

            FloatBuffer minBuffer = buffers[minBufferIndex];

            // trigger copies into output sequence, if necessary.
            counter += minBuffer.weight();
            while (counter > nextHit && j < triggerPositionsLength) {
                outputValues[j++] = minValue;
                // System.out.println("adding to output="+minValue);
                if (j < triggerPositionsLength)
                    nextHit = triggerPositions[j];
            }

            // that element has now been treated, move further.
            cursors[minBufferIndex]++;
            // System.out.println("cursors="+cern.it.util.Arrays.toString(cursors));

        } // end while (j= 0;) {
            totalSize += fullBuffers[i].size() * fullBuffers[i].weight();
        }

        return totalSize;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy