org.ojalgo.series.BasicSeries Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ojalgo Show documentation
Show all versions of ojalgo Show documentation
oj! Algorithms - ojAlgo - is Open Source Java code that has to do with mathematics, linear algebra and optimisation.
/*
* Copyright 1997-2021 Optimatika
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.ojalgo.series;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import org.ojalgo.ProgrammingError;
import org.ojalgo.array.DenseArray;
import org.ojalgo.function.BinaryFunction;
import org.ojalgo.series.primitive.CoordinatedSet;
import org.ojalgo.series.primitive.PrimitiveSeries;
import org.ojalgo.structure.Access1D;
import org.ojalgo.structure.Structure1D;
import org.ojalgo.type.CalendarDate;
import org.ojalgo.type.ColourData;
import org.ojalgo.type.TimeIndex;
import org.ojalgo.type.keyvalue.KeyValue;
/**
* A BasicSeries is a {@linkplain SortedMap} with:
*
* - Keys restricted to {@linkplain Comparable} (the keys have a natural order)
* - Values restricted to {@linkplain Number} (you can do maths on the values)
* - The option to associate a name and colour with the data
* - The option to define an accumlator function to be used with multilple/subsequent put operations on the
* same key
* - Some additional methods to work with primitive keys and values more efficiently
* - A few additional methods to help access and modify series entries
*
* The extension {@link NaturallySequenced} is typically used with time series data.
*
* @author apete
*/
public interface BasicSeries, V extends Comparable> extends SortedMap {
/**
* A series with naturally sequenced keys - given any key there is a natural "next" key, e.g. with a
* series of daily values the natural next key is the next day. Further, natural sequencing implies a
* bidirectional mapping between the keys and long indices.
*
* @author apete
*/
interface NaturallySequenced, V extends Comparable> extends BasicSeries, Access1D {
default PrimitiveSeries asPrimitive() {
return PrimitiveSeries.wrap(this);
}
/**
* Will fill in missing values, inbetween the first and last keys.
*/
default void complete() {
K tmpKey = this.firstKey();
V tmpVal = null;
V patchVal = this.firstValue();
final K lastKey = this.lastKey();
while (tmpKey.compareTo(lastKey) <= 0) {
tmpVal = this.get(tmpKey);
if (tmpVal != null) {
patchVal = tmpVal;
} else {
this.put(tmpKey, patchVal);
}
tmpKey = this.step(tmpKey);
}
}
/**
* A natural sequence implies a bidirectional mapping between the keys and long indices. This
* {@link org.ojalgo.structure.Structure1D.IndexMapper} specifies that mapping. Please note that
* multiple instaces of the key type could correspnd to the same index, and not all long values are
* valid indices. The conversions key -> index -> key may not return the original key.
*/
IndexMapper mapper();
/**
* @return The next, after the {@link #lastKey()}, key.
*/
default K nextKey() {
return this.step(this.lastKey());
}
double put(long index, double value);
V put(long index, V value);
default int size() {
return Access1D.super.size();
}
K step(K key);
}
public static final class TimeSeriesBuilder> {
private K myReference = null;
private CalendarDate.Resolution myResolution = null;
private final TimeIndex myTimeIndex;
TimeSeriesBuilder(final TimeIndex timeIndex) {
super();
myTimeIndex = timeIndex;
}
public > BasicSeries.NaturallySequenced build(final DenseArray.Factory denseArrayFactory) {
ProgrammingError.throwIfNull(denseArrayFactory);
return this.doBuild(denseArrayFactory, null);
}
public > BasicSeries.NaturallySequenced build(final DenseArray.Factory denseArrayFactory,
final BinaryFunction accumularor) {
ProgrammingError.throwIfNull(denseArrayFactory, accumularor);
return this.doBuild(denseArrayFactory, accumularor);
}
public TimeSeriesBuilder reference(final K reference) {
myReference = reference;
return this;
}
public TimeSeriesBuilder resolution(final CalendarDate.Resolution resolution) {
myResolution = resolution;
return this;
}
private > BasicSeries.NaturallySequenced doBuild(final DenseArray.Factory arrayFactory,
final BinaryFunction accumularor) {
if (myReference != null) {
if (myResolution != null) {
return new MappedIndexSeries<>(arrayFactory, myTimeIndex.from(myReference, myResolution), accumularor);
} else {
return new MappedIndexSeries<>(arrayFactory, myTimeIndex.from(myReference), accumularor);
}
} else {
if (myResolution != null) {
return new MappedIndexSeries<>(arrayFactory, myTimeIndex.plain(myResolution), accumularor);
} else {
return new MappedIndexSeries<>(arrayFactory, myTimeIndex.plain(), accumularor);
}
}
}
}
BasicSeries.TimeSeriesBuilder CALENDAR = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.CALENDAR);
BasicSeries.TimeSeriesBuilder CALENDAR_DATE = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.CALENDAR_DATE);
BasicSeries.TimeSeriesBuilder DATE = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.DATE);
BasicSeries.TimeSeriesBuilder INSTANT = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.INSTANT);
BasicSeries.TimeSeriesBuilder LOCAL_DATE = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.LOCAL_DATE);
BasicSeries.TimeSeriesBuilder LOCAL_DATE_TIME = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.LOCAL_DATE_TIME);
BasicSeries.TimeSeriesBuilder LOCAL_TIME = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.LOCAL_TIME);
BasicSeries.TimeSeriesBuilder OFFSET_DATE_TIME = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.OFFSET_DATE_TIME);
BasicSeries.TimeSeriesBuilder ZONED_DATE_TIME = new BasicSeries.TimeSeriesBuilder<>(TimeIndex.ZONED_DATE_TIME);
static > CoordinatedSet coordinate(final List extends BasicSeries> uncoordinated) {
return CoordinatedSet.from(uncoordinated);
}
static > K findEarliestFirstKey(final Collection extends BasicSeries> collection) {
K retVal = null, tmpVal = null;
for (final BasicSeries individual : collection) {
tmpVal = individual.firstKey();
if ((retVal == null) || (tmpVal.compareTo(retVal) < 0)) {
retVal = tmpVal;
}
}
return retVal;
}
static > K findEarliestLastKey(final Collection extends BasicSeries> collection) {
K retVal = null, tmpVal = null;
for (final BasicSeries individual : collection) {
tmpVal = individual.lastKey();
if ((retVal == null) || (tmpVal.compareTo(retVal) < 0)) {
retVal = tmpVal;
}
}
return retVal;
}
static > K findLatestFirstKey(final Collection extends BasicSeries> collection) {
K retVal = null, tmpVal = null;
for (final BasicSeries individual : collection) {
tmpVal = individual.firstKey();
if ((retVal == null) || (tmpVal.compareTo(retVal) > 0)) {
retVal = tmpVal;
}
}
return retVal;
}
static > K findLatestLastKey(final Collection extends BasicSeries> collection) {
K retVal = null, tmpVal = null;
for (final BasicSeries individual : collection) {
tmpVal = individual.lastKey();
if ((retVal == null) || (tmpVal.compareTo(retVal) > 0)) {
retVal = tmpVal;
}
}
return retVal;
}
static BasicSeries make(final DenseArray.Factory arrayFactory) {
return new MappedIndexSeries<>(arrayFactory, MappedIndexSeries.MAPPER, null);
}
static BasicSeries make(final DenseArray.Factory arrayFactory, final BinaryFunction accumulator) {
return new MappedIndexSeries<>(arrayFactory, MappedIndexSeries.MAPPER, accumulator);
}
static > BasicSeries make(final DenseArray.Factory arrayFactory, final Structure1D.IndexMapper indexMapper) {
return new MappedIndexSeries<>(arrayFactory, indexMapper, null);
}
static > BasicSeries make(final DenseArray.Factory arrayFactory, final Structure1D.IndexMapper indexMapper,
final BinaryFunction accumulator) {
return new MappedIndexSeries<>(arrayFactory, indexMapper, accumulator);
}
PrimitiveSeries asPrimitive();
BasicSeries colour(ColourData colour);
double doubleValue(final K key);
V firstValue();
V get(final K key);
ColourData getColour();
String getName();
V lastValue();
BasicSeries name(String name);
/**
* @see #put(Comparable, Number)
*/
double put(final K key, final double value);
/**
* Some implementations may specify an accumulator function to be used with subsequent put operation with
* the same key. If such an accumulator is present it should be used here, and in that case the method
* returns the new/accumulated/mixed value. With out an accumulator this method should behave exactly as
* with any other {@link Map}.
*
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
V put(final K key, final V value);
default void putAll(final Collection extends KeyValue extends K, ? extends V>> data) {
for (final KeyValue extends K, ? extends V> tmpKeyValue : data) {
this.put(tmpKeyValue.getKey(), tmpKeyValue.getValue());
}
}
}