Package ch.agent.t2.timeseries

Source Code of ch.agent.t2.timeseries.AbstractTimeSeries

/*
*   Copyright 2011-2013 Hauser Olsson GmbH
*
* 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 ch.agent.t2.timeseries;

import java.util.Collection;
import java.util.Iterator;

import ch.agent.t2.T2Exception;
import ch.agent.t2.T2Msg;
import ch.agent.t2.T2Msg.K;
import ch.agent.t2.time.Range;
import ch.agent.t2.time.TimeDomain;
import ch.agent.t2.time.TimeIndex;


/**
* AbstractTimeseries is the basis for {@link RegularTimeSeries} and {@link SparseTimeSeries}.
*
* @author Jean-Paul Vetterli
* @param <T>
*/
public abstract class AbstractTimeSeries<T> implements TimeAddressable<T> {

  private TimeDomain domain;
 
  private T missingValue; // for each type, there is a single object (can use ==)

  /**
   * The parameterless constructor always throws an UnsupportedOperationException.
   */
  protected AbstractTimeSeries() {
    throw new UnsupportedOperationException();
  }
 
  /**
   * Construct a time series with the given time domain and missing value.
   *
   * @param domain a non-null time domain
   * @param missingValue the object to use for representing missing values
   */
  public AbstractTimeSeries(TimeDomain domain, T missingValue) {
    if (domain == null)
      throw new IllegalArgumentException("calendar null");
    this.domain = domain;
    this.missingValue = missingValue;
  }

  @Override
  public boolean isMissing(T value) {
    return value == missingValue;
  }

  @Override
  public TimeAddressable<T> copy() throws T2Exception {
    TimeAddressable<T> ts = makeEmptyCopy();
    ts.put(this, null);
    return ts;
  }
 
  @Override
  public T get(long t) throws T2Exception {
    return internalGet(t);
  }
 
  @Override
  public abstract TimeAddressable<T> get(long first, long last) throws T2Exception;
 
  @Override
  public T get(TimeIndex t) throws T2Exception {
    if (!domain.equals(t.getTimeDomain()))
      throw T2Msg.exception(K.T5011);
    return get(t.asLong());
  }

  @Override
  public TimeDomain getTimeDomain() {
    return domain;
  }

  @Override
  public Range getRange() {
    // do not cache the (immutable) range object, the actual range can change
    if (getSize() < 1)
      return new Range(domain);
    else
      return new Range(domain, internalGetFirstIndex(), internalGetLastIndex());
  }
 
  @Override
  public long getFirstIndex() {
    return internalGetFirstIndex();
  }

  @Override
  public long getLastIndex() {
    return internalGetLastIndex();
  }
 
  @Override
  public Observation<T> getLast(TimeIndex t) throws T2Exception {
    if (t == null) {
      long l = internalGetLastIndex();
      return l >= 0 ? internalGetLast(l) : null;
    } else {
      if (!t.getTimeDomain().equals(getTimeDomain()))
        throw T2Msg.exception(K.T5013, t.toString(), t.getTimeDomain().getLabel(),
            getTimeDomain().getLabel());
      return internalGetLast(t.asLong());
    }
  }
 
  @Override
  public Observation<T> getFirst(TimeIndex t) throws T2Exception {
    if (t == null) {
      long f = internalGetFirstIndex();
      return f >= 0 ? internalGetFirst(f) : null;
    } else {
      if (!t.getTimeDomain().equals(getTimeDomain()))
        throw T2Msg.exception(K.T5013, t.toString(), t.getTimeDomain().getLabel(),
            getTimeDomain().getLabel());
      return internalGetFirst(t.asLong());
    }
  }

  @Override
  public int getSize() {
    return internalGetSize();
  }
 
  @Override
  public void put(long index, T value) throws T2Exception {
    internalPut(index, value);

  }
 
  @Override
  public void put(long index, T[] values) throws T2Exception {
    if (values.length == 0)
      return;
    // add last value first so resizing occurs at most once
    internalPut(index + values.length - 1, values[values.length - 1]);
    for (int i = 0; i < values.length - 1; i++) {
      internalPut(index++, values[i]);
    }
  }
 
  @Override
  public void put(TimeAddressable<T> values, UpdateReviewer<T> reviewer) throws T2Exception {
    // check for domain compatibility, then for Integer overflow
    getRange().union(values.getRange()).getSizeAsInt();
   
    int rejectCount = accept(values, reviewer);
    if (rejectCount > 0)
      throw T2Msg.exception(K.T5012, rejectCount, values.getSize());
   
    if (values.isIndexable()) {
      put(values.getFirstIndex(), ((TimeIndexable<T>)values).getArray());
    } else {
      Iterator<Observation<T>> it = values.iterator();
      while (it.hasNext()) {
        Observation<T> obs = it.next();
        internalPut(obs.getIndex(), obs.getValue());
      }
    }
  }
 
  @Override
  public void put(TimeIndex t, T value) throws T2Exception {
    if (!domain.equals(t.getTimeDomain()))
      throw T2Msg.exception(K.T5011);
    internalPut(t.asLong(), value);
  }

  @Override
  public void put(TimeIndex t, T[] values) throws T2Exception {
    if (!domain.equals(t.getTimeDomain()))
      throw T2Msg.exception(K.T5011);
    put(t.asLong(), values);
  }

  @Override
  public void remove(TimeIndex t) throws T2Exception {
    if (!domain.equals(t.getTimeDomain()))
      throw T2Msg.exception(K.T5011);
    internalRemove(t.asLong());
  }

  @Override
  public boolean setRange(Range range) throws T2Exception {
    Range current = getRange();
    if (current.isEmpty())
      return false;
    if (current.equals(range))
      return false;
    if (range == null) {
      internalClear();
      return true;
    }
    Range inter = current.intersection(range);
    if (inter.isEmpty()) {
      internalClear();
      return true;
    } else if (inter.equals(current)) {
      return false;
    } else {
      internalSetBounds(inter.getFirstIndex(), inter.getLastIndex());
      return true;
    }

  }
 
  @Override
  public T getMissingValue() {
    return missingValue;
  }

  @Override
  public String toString() {
    StringBuffer b = new StringBuffer();
    long last = getLastIndex();
    int count = 0;
    int max = 3;
    for (Observation<T> o : this) {
      if (count < max || o.getIndex() == last) {
        b.append(o.toString());
        if (o.getIndex() != last)
          b.append(", ");
      } else if (count == max) {
        b.append("..., ");
      }
      ++count;
    }
    return b.toString();
  }

  /**
   * Replace all objects equal to the missing value with the "official"
   * missing value object.
   * <p>
   * Null values are illegal and produce an exception, unless they represent
   * missing values.
   *
   * @param value
   *            the value to normalize
   * @return the value, normalized
   * @throws T2Exception
   */
  protected T normalizeMissingValue(T value) throws T2Exception {
    if (value == null) {
      if (missingValue == null)
        return value;
      else
        throw T2Msg.exception(K.T5014);
    } else {
      if (value.equals(missingValue))
        return missingValue;
      else
        return value;
    }
  }

  /**
   * Return the number of updates rejected by the reviewer. A result of 0 means all
   * updates have been accepted
   *
   * @param updates a non-null time series of updates
   * @param reviewer a non-null reviewer
   * @return the number of updates rejected
   * @throws T2Exception
   */
  protected int accept(TimeAddressable<T> updates, UpdateReviewer<T> reviewer) throws T2Exception {
    int rejected = 0;
    if (reviewer != null) {
      for (Observation<T> update : updates) {
        try {
          if (!reviewer.accept(this, update.getIndex(), update.getValue()))
            rejected++;
        } catch (Exception e) {
          throw T2Msg.exception(e, K.T5031, update);
        }
      }
    }
    return rejected;
  }
 
  /**
   * Return the numerical time index of the first element.
   * 
   * @return a numerical time index
   */
  protected abstract long internalGetFirstIndex();
 
  /**
   * Return the numerical time index of the last element.
   * 
   * @return a numerical time index
   */
  protected abstract long internalGetLastIndex();

  /**
   * Return the observation at or after the given numerical time index. Return
   * null when there is no such observation. When the result is not null, its
   * value will not be a missing value (this is not a general rule for
   * {@link Observation}, only a special rule for this method).
   *
   * @param index a number
   * @return an observation or null
   * @throws T2Exception
   */
  protected abstract Observation<T> internalGetFirst(long index) throws T2Exception;
 
  /**
   * Return the observation at or before the given numerical time index. Return
   * null when there is no such observation. When the result is not null, its
   * value will not be a missing value (this is not a general rule for
   * {@link Observation}, only a special rule for this method).
   *
   * @param time a numerical time index
   * @return an observation or null
   * @throws T2Exception
   */
  protected abstract Observation<T> internalGetLast(long time) throws T2Exception;

  /**
   * Remove all values from the time series.
   */
  protected abstract void internalClear();
 
  /**
   * Get the value identified by the given numerical time index.
   *
   * @param time a numerical time index
   * @return a value
   * @throws T2Exception
   */
  protected abstract T internalGet(long time) throws T2Exception;
 
  /**
   * Return the used size of the data structure where values are stored.
   * @return the used size of the data structure with the values
   */
  protected abstract int internalGetSize();

  /**
   * Put the value into the series at the given numerical time index.
   * <p>
   * The method silently ignores missing values added out of range. Adding
   * missing values at the boundary shrinks the range.
   *
   * @param time a numerical time index
   * @param value a value
   * @throws T2Exception
   */
  protected abstract void internalPut(long time, T value) throws T2Exception;
 
  /**
   * Remove the value at the given numerical time index.
   *
   * @param time a numerical time index
   * @throws T2Exception
   */
  protected abstract void internalRemove(long time) throws T2Exception;
 
  /**
   * Shrink the range to the one given by the two numerical time indexes. The
   * method assumes that the new range lies within the current range. Not
   * playing by the rules is likely to result in a RuntimeException being
   * thrown.
   *
   * @param first
   *            a numerical time index giving the lower bound of the new range
   * @param last
   *            a numerical time index giving the upper bound of the new range
   * @throws T2Exception
   */
  protected abstract void internalSetBounds(long first, long last) throws T2Exception;

  /**
   * Return all values as a {@link Collection}.
   *
   * @return all values as a collection
   */
  protected abstract Collection<T> internalGetData();

}
TOP

Related Classes of ch.agent.t2.timeseries.AbstractTimeSeries

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.