com.opengamma.util.timeseries.fast.integer.FastArrayIntDoubleTimeSeries.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.util.timeseries.fast.integer.FastArrayIntDoubleTimeSeries.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.util.timeseries.fast.integer;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleIterator;
import it.unimi.dsi.fastutil.doubles.DoubleList;
import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.objects.ObjectIterator;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.SortedMap;

import org.apache.commons.lang.ArrayUtils;

import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.timeseries.DoubleTimeSeries;
import com.opengamma.util.timeseries.fast.DateTimeNumericEncoding;
import com.opengamma.util.timeseries.fast.longint.FastLongDoubleTimeSeries;
import com.opengamma.util.tuple.IntDoublePair;

/**
 * 
 */
public class FastArrayIntDoubleTimeSeries extends AbstractFastIntDoubleTimeSeries {
    /** An empty double time series with the time expressed as int and the millisecond-from-epoch date encoding */
    public static final FastIntDoubleTimeSeries EMPTY_SERIES = new FastArrayIntDoubleTimeSeries(
            DateTimeNumericEncoding.TIME_EPOCH_MILLIS);

    private final int[] _times;
    private final double[] _values;

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding) {
        super(encoding);
        _times = new int[0];
        _values = new double[0];
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding, final Integer[] times,
            final Double[] values) {
        super(encoding);
        _times = new int[times.length];
        _values = new double[values.length];
        init(ArrayUtils.toPrimitive(times), ArrayUtils.toPrimitive(values));
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding, final int[] times,
            final double[] values) {
        super(encoding);
        _times = new int[times.length];
        _values = new double[values.length];
        init(times, values);
    }

    private void init(final int[] times, final double[] values) {
        if (times.length != values.length) {
            throw new IllegalArgumentException(
                    "Arrays are of different sizes: " + times.length + ", " + values.length);
        }
        System.arraycopy(times, 0, _times, 0, times.length);
        System.arraycopy(values, 0, _values, 0, values.length);
        // check dates are ordered
        int maxTime = Integer.MIN_VALUE;
        for (final int time : _times) {
            if (time < maxTime) {
                throw new IllegalArgumentException("dates must be ordered");
            }
            maxTime = time;
        }
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding, final List<Integer> times,
            final List<Double> values) {
        super(encoding);
        ArgumentChecker.isTrue(times.size() == values.size(), "lists are of different sizes; have {} and {}",
                times.size(), values.size());
        _times = new int[times.size()];
        _values = new double[values.size()];
        final Iterator<Double> iter = values.iterator();
        int i = 0;
        int maxTime = Integer.MIN_VALUE; // for checking the dates are sorted.
        for (final int time : times) {
            final double value = iter.next();
            if (maxTime < time) {
                _times[i] = time;
                _values[i] = value;
                maxTime = time;
            } else {
                throw new IllegalArgumentException("dates must be ordered");
            }
            i++;
        }
    }

    public FastArrayIntDoubleTimeSeries(final FastIntDoubleTimeSeries dts) {
        super(dts.getEncoding());
        _times = dts.timesArrayFast();
        _values = dts.valuesArrayFast();
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding, final FastIntDoubleTimeSeries dts) {
        super(encoding);
        DateTimeNumericEncoding sourceEncoding = dts.getEncoding();
        _times = dts.timesArrayFast();
        for (int i = 0; i < _times.length; i++) {
            _times[i] = sourceEncoding.convertToInt(_times[i], encoding);
        }
        _values = dts.valuesArrayFast();
    }

    public FastArrayIntDoubleTimeSeries(final FastLongDoubleTimeSeries dts) {
        this(dts.getEncoding(), dts);
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding,
            final FastLongDoubleTimeSeries dts) {
        super(encoding);
        DateTimeNumericEncoding otherEncoding = dts.getEncoding();
        long[] otherTimes = dts.timesArrayFast();
        _times = new int[otherTimes.length];
        for (int i = 0; i < otherTimes.length; i++) {
            _times[i] = otherEncoding.convertToInt(otherTimes[i], encoding);
        }
        _values = dts.valuesArrayFast();
    }

    public FastArrayIntDoubleTimeSeries(final DateTimeNumericEncoding encoding,
            final SortedMap<Integer, Double> initialMap) {
        super(encoding);
        final int size = initialMap.size();
        _times = new int[size];
        _values = new double[size];
        final Iterator<Entry<Integer, Double>> iterator = initialMap.entrySet().iterator();
        int i = 0;
        while (iterator.hasNext()) {
            final Entry<Integer, Double> entry = iterator.next();
            _times[i] = entry.getKey().intValue();
            _values[i] = entry.getValue().doubleValue();
            i++;
        }
    }

    @Override
    public FastIntDoubleTimeSeries subSeriesFast(final int startTime, final int endTime) {
        if (isEmpty()) {
            return EMPTY_SERIES;
        }
        // throw new NoSuchElementException("Series is empty")
        int startPos = Arrays.binarySearch(_times, startTime);
        int endPos = (endTime == Integer.MIN_VALUE) ? _times.length : Arrays.binarySearch(_times, endTime);
        // if either is -1, make it zero
        startPos = startPos >= 0 ? startPos : -(startPos + 1);
        endPos = endPos >= 0 ? endPos : -(endPos + 1);
        final int length = endPos - startPos; // trying it out anyway.
        if (endPos >= _times.length) {
            endPos--;
        }

        final int[] resultTimes = new int[length];
        final double[] resultValues = new double[length];
        System.arraycopy(_times, startPos, resultTimes, 0, length);
        System.arraycopy(_values, startPos, resultValues, 0, length);
        return new FastArrayIntDoubleTimeSeries(getEncoding(), resultTimes, resultValues);
    }

    public double getDataPointFast(final int time) {
        final int index = Arrays.binarySearch(_times, time);
        if (index >= 0) {
            return _values[index];
        } else {
            throw new NoSuchElementException();
        }
    }

    @Override
    public int getEarliestTimeFast() {
        if (_times.length > 0) {
            return _times[0];
        } else {
            throw new NoSuchElementException("Series is empty");
        }
    }

    @Override
    public double getEarliestValueFast() {
        if (_values.length > 0) {
            return _values[0];
        } else {
            throw new NoSuchElementException("Series is empty");
        }
    }

    @Override
    public int getLatestTimeFast() {
        if (_times.length > 0) {
            final int index = _times.length - 1;
            return _times[index];
        } else {
            throw new NoSuchElementException("Series is empty");
        }
    }

    @Override
    public double getLatestValueFast() {
        if (_values.length > 0) {
            return _values[_values.length - 1];
        } else {
            throw new NoSuchElementException("Series is empty");
        }
    }

    /* package */class PrimitiveArrayDoubleTimeSeriesIterator implements ObjectIterator<Int2DoubleMap.Entry> {
        private int _current;

        @Override
        public boolean hasNext() {
            return _current < _times.length;
        }

        @Override
        public Int2DoubleMap.Entry next() {
            if (hasNext()) {
                final Int2DoubleMap.Entry keyValuePair = new IntDoublePair(_times[_current], _values[_current]);
                _current++;
                return keyValuePair;
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public int skip(final int n) {
            final int skipped = n > (_times.length - _current) ? _times.length - _current : n;
            _current += n;
            if (_current >= _times.length) {
                _current = _times.length;
            }
            return skipped;
        }
    }

    @Override
    public int size() {
        return _times.length;
    }

    @Override
    public boolean isEmpty() {
        return _times.length == 0;
    }

    /* package */class PrimitiveArrayIntDoubleTimeSeriesTimesIterator implements IntIterator {
        private int _current;

        @Override
        public boolean hasNext() {
            return _current < _times.length;
        }

        @Override
        public Integer next() {
            if (hasNext()) {
                final int time = _times[_current];
                _current++;
                return time;
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public int nextInt() {
            if (hasNext()) {
                final int time = _times[_current];
                _current++;
                return time;
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public int skip(final int n) {
            final int skipped = n > (_times.length - _current) ? _times.length - _current : n;
            _current += n;
            if (_current >= _times.length) {
                _current = _times.length;
            }
            return skipped;
        }
    }

    /* package */class PrimitiveArrayIntDoubleTimeSeriesValuesIterator implements DoubleIterator {
        private int _current;

        @Override
        public boolean hasNext() {
            return _current < _values.length;
        }

        @Override
        public Double next() {
            if (hasNext()) {
                final Double value = _values[_current];
                _current++;
                return value;
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public double nextDouble() {
            if (hasNext()) {
                final double value = _values[_current];
                _current++;
                return value;
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public int skip(final int n) {
            final int skipped = n > (_times.length - _current) ? _times.length - _current : n;
            _current += n;
            if (_current >= _times.length) {
                _current = _times.length;
            }
            return skipped;
        }
    }

    @Override
    public DoubleIterator valuesIteratorFast() {
        return new PrimitiveArrayIntDoubleTimeSeriesValuesIterator();
    }

    @Override
    public double[] valuesArrayFast() {
        return _values.clone();
    }

    @Override
    public int[] timesArrayFast() {
        return _times.clone();
    }

    @Override
    public int getTimeFast(final int index) {
        return _times[index];
    }

    @Override
    public FastIntDoubleTimeSeries tailFast(final int numItems) {
        if (numItems <= _times.length) {
            final int[] times = new int[numItems];
            final double[] values = new double[numItems];
            System.arraycopy(_times, _times.length - numItems, times, 0, numItems);
            System.arraycopy(_values, _values.length - numItems, values, 0, numItems);
            return new FastArrayIntDoubleTimeSeries(getEncoding(), times, values);
        } else {
            throw new NoSuchElementException("Not enough elements");
        }
    }

    @Override
    public FastIntDoubleTimeSeries headFast(final int numItems) {
        if (numItems <= _times.length) {
            final int[] times = new int[numItems];
            final double[] values = new double[numItems];
            System.arraycopy(_times, 0, times, 0, numItems);
            System.arraycopy(_values, 0, values, 0, numItems);
            return new FastArrayIntDoubleTimeSeries(getEncoding(), times, values);
        } else {
            throw new NoSuchElementException("Not enough elements");
        }
    }

    /**
     * {@inheritDoc}
     * Note that this is so complicated to try and provide optimal performance. A
     * much slower version would be quite short.
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            if (obj instanceof FastIntDoubleTimeSeries) {
                final FastIntDoubleTimeSeries other = (FastIntDoubleTimeSeries) obj;
                if (!Arrays.equals(other.valuesArrayFast(), _values)) {
                    return false;
                }
                if (other.getEncoding().equals(getEncoding())) {
                    return Arrays.equals(other.timesArrayFast(), _times);
                } else {
                    final IntIterator otherTimesIterator = other.timesIteratorFast();
                    int i = 0;
                    final DateTimeNumericEncoding otherEncoding = other.getEncoding();
                    final DateTimeNumericEncoding myEncoding = getEncoding();
                    // invarient is that both are the same length as we got past the
                    // values equality
                    while (otherTimesIterator.hasNext()) {
                        if (otherEncoding.convertToInt(otherTimesIterator.nextInt(), myEncoding) != _times[i]) {
                            return false;
                        }
                        i++;
                    }
                }
            } else if (obj instanceof FastLongDoubleTimeSeries) {
                final FastLongDoubleTimeSeries other = (FastLongDoubleTimeSeries) obj;
                if (!Arrays.equals(other.valuesArrayFast(), _values)) {
                    return false;
                }
                final LongIterator otherTimesIterator = other.timesIteratorFast();
                int i = 0;
                final DateTimeNumericEncoding otherEncoding = other.getEncoding();
                final DateTimeNumericEncoding myEncoding = getEncoding();
                // invarient is that both are the same length as we got past the
                // values equality
                while (otherTimesIterator.hasNext()) {
                    if (otherEncoding.convertToInt(otherTimesIterator.nextLong(), myEncoding) != _times[i]) {
                        return false;
                    }
                    i++;
                }
            } else {
                return false;
            }
        } else {
            final FastArrayIntDoubleTimeSeries other = (FastArrayIntDoubleTimeSeries) obj;
            // invariant: none of these can be null.
            if (size() != other.size()) { // should always be O(1)
                return false;
            }
            if (!Arrays.equals(_values, other._values)) {
                return false;
            }
            if (other.getEncoding() == getEncoding()) {
                if (!Arrays.equals(_times, other._times)) {
                    return false;
                }
            } else {
                // encoding of other is different, must check...
                // invariant: other.size() == _times.size();
                final int[] myTimes = _times;
                final int[] otherTimes = other._times;
                final DateTimeNumericEncoding encoding = other.getEncoding();
                final DateTimeNumericEncoding myEncoding = getEncoding();
                for (int i = 0; i < myTimes.length; i++) {
                    if (myTimes[i] != encoding.convertToInt(otherTimes[i], myEncoding)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    @Override
    public IntList timesFast() {
        return new IntArrayList(_times);
    }

    @Override
    public DoubleList valuesFast() {
        return new DoubleArrayList(_values);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(_values);
    }

    @Override
    public double getValueFast(final int time) {
        final int binarySearch = Arrays.binarySearch(_times, time);
        if (binarySearch >= 0 && _times[binarySearch] == time) {
            return _values[binarySearch];
        } else {
            throw new NoSuchElementException();
        }
    }

    @Override
    public double getValueAtFast(final int index) {
        return _values[index];
    }

    @Override
    public ObjectIterator<Int2DoubleMap.Entry> iteratorFast() {
        return new PrimitiveArrayDoubleTimeSeriesIterator();
    }

    @Override
    public DoubleTimeSeries<Integer> subSeries(final Integer startTime, final Integer endTime) {
        return subSeriesFast(startTime, endTime);
    }

    @Override
    public IntIterator timesIteratorFast() {
        return new PrimitiveArrayIntDoubleTimeSeriesTimesIterator();
    }

    @Override
    public DoubleTimeSeries<Integer> head(final int numItems) {
        return headFast(numItems);
    }

    @Override
    public DoubleTimeSeries<Integer> tail(final int numItems) {
        return tailFast(numItems);
    }

    @Override
    public FastIntDoubleTimeSeries newInstanceFast(final int[] times, final double[] values) {
        return new FastArrayIntDoubleTimeSeries(getEncoding(), times, values);
    }

}