com.opengamma.util.timeseries.fast.longint.FastArrayLongDoubleTimeSeries.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.util.timeseries.fast.longint.FastArrayLongDoubleTimeSeries.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.longint;

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.IntIterator;
import it.unimi.dsi.fastutil.longs.Long2DoubleMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongList;
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.timeseries.DoubleTimeSeries;
import com.opengamma.util.timeseries.fast.DateTimeNumericEncoding;
import com.opengamma.util.timeseries.fast.integer.FastIntDoubleTimeSeries;
import com.opengamma.util.tuple.LongDoublePair;

/**
 * 
 */
public class FastArrayLongDoubleTimeSeries extends AbstractFastLongDoubleTimeSeries {
    /** An empty double time series backed using milliseconds as the date encoding */
    public static final FastLongDoubleTimeSeries EMPTY_SERIES = new FastArrayLongDoubleTimeSeries(
            DateTimeNumericEncoding.TIME_EPOCH_MILLIS);

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

    private FastArrayLongDoubleTimeSeries(final DateTimeNumericEncoding encoding) {
        super(encoding);
        _times = new long[0];
        _values = new double[0];
    }

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

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

    private void init(final long[] 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
        long maxTime = Long.MIN_VALUE;
        for (final long time : _times) {
            if (time < maxTime) {
                throw new IllegalArgumentException("dates must be ordered");
            }
            maxTime = time;
        }
    }

    public FastArrayLongDoubleTimeSeries(final DateTimeNumericEncoding encoding, final List<Long> times,
            final List<Double> values) {
        super(encoding);
        if (times.size() != values.size()) {
            throw new IllegalArgumentException("lists are of different sizes");
        }
        _times = new long[times.size()];
        _values = new double[values.size()];
        final Iterator<Double> iter = values.iterator();
        int i = 0;
        long maxTime = Long.MIN_VALUE; // for checking the dates are sorted.
        for (final long 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 FastArrayLongDoubleTimeSeries(final FastLongDoubleTimeSeries dts) {
        super(dts.getEncoding());
        _times = dts.timesArrayFast();
        _values = dts.valuesArrayFast();
    }

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

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

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

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

    @Override
    public FastLongDoubleTimeSeries subSeriesFast(final long startTime, final long endTime) {
        if (isEmpty()) {
            return EMPTY_SERIES;
        }
        // throw new NoSuchElementException("Series is empty")
        int startPos = Arrays.binarySearch(_times, startTime);
        int endPos = (endTime == Long.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;
        if (endPos >= _times.length) {
            endPos--;
        }
        final long[] resultTimes = new long[length];
        final double[] resultValues = new double[length];
        System.arraycopy(_times, startPos, resultTimes, 0, length);
        System.arraycopy(_values, startPos, resultValues, 0, length);
        return new FastArrayLongDoubleTimeSeries(getEncoding(), resultTimes, resultValues);
    }

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

    @Override
    public long 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 long 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<Long2DoubleMap.Entry> {
        private int _current;

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

        @Override
        public Long2DoubleMap.Entry next() {
            if (hasNext()) {
                final Long2DoubleMap.Entry keyValuePair = new LongDoublePair(_times[_current], _values[_current]);
                _current++;
                return keyValuePair;
            } 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;
        }

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

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

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

    /* package */class PrimitiveArrayDoubleTimeSeriesTimesIterator implements LongIterator {
        private int _current;

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

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

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

        @Override
        public long nextLong() {
            if (hasNext()) {
                final long 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 PrimitiveArrayDoubleTimeSeriesValuesIterator 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();
            }
        }

        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 PrimitiveArrayDoubleTimeSeriesValuesIterator();
    }

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

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

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

    @Override
    public FastLongDoubleTimeSeries tail(final int numItems) {
        if (numItems <= _times.length) {
            final long[] times = new long[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 FastArrayLongDoubleTimeSeries(getEncoding(), times, values);
        } else {
            throw new NoSuchElementException("Not enough elements");
        }
    }

    @Override
    public FastLongDoubleTimeSeries tailFast(final int numItems) {
        return tail(numItems);
    }

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

    @Override
    public FastLongDoubleTimeSeries headFast(final int numItems) {
        return head(numItems);
    }

    /**
     * {@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 FastLongDoubleTimeSeries) {
                final FastLongDoubleTimeSeries other = (FastLongDoubleTimeSeries) obj;
                if (!Arrays.equals(other.valuesArrayFast(), _values)) {
                    return false;
                }
                if (other.getEncoding().equals(getEncoding())) {
                    return Arrays.equals(other.timesArrayFast(), _times);
                } else {
                    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.convertToLong(otherTimesIterator.nextLong(), myEncoding) != _times[i]) {
                            return false;
                        }
                        i++;
                    }
                }
            } else if (obj instanceof FastIntDoubleTimeSeries) {
                final FastIntDoubleTimeSeries other = (FastIntDoubleTimeSeries) obj;
                if (!Arrays.equals(other.valuesArrayFast(), _values)) {
                    return false;
                }
                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.convertToLong(otherTimesIterator.nextInt(), myEncoding) != _times[i]) {
                        return false;
                    }
                    i++;
                }
            } else {
                return false;
            }
        } else {
            final FastArrayLongDoubleTimeSeries other = (FastArrayLongDoubleTimeSeries) 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 long[] myTimes = _times;
                final long[] otherTimes = other._times;
                final DateTimeNumericEncoding encoding = other.getEncoding();
                final DateTimeNumericEncoding myEncoding = getEncoding();
                for (int i = 0; i < myTimes.length; i++) {
                    if (myTimes[i] != encoding.convertToLong(otherTimes[i], myEncoding)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    @Override
    public LongList timesFast() {
        return new LongArrayList(_times);
    }

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

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

    @Override
    public double getValueFast(final long 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];
    }

    @SuppressWarnings("unchecked")
    @Override
    public Iterator<Entry<Long, Double>> iterator() {
        return (Iterator<Entry<Long, Double>>) (Iterator<? extends Entry<Long, Double>>) new PrimitiveArrayDoubleTimeSeriesIterator();
    }

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

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

    @Override
    public LongIterator timesIteratorFast() {
        return new PrimitiveArrayDoubleTimeSeriesTimesIterator();
    }

    @Override
    public FastLongDoubleTimeSeries newInstanceFast(final long[] times, final double[] values) {
        return new FastArrayLongDoubleTimeSeries(getEncoding(), times, values);
    }

}