/**
  * Get data between two points in delta form.
  *
  * @param desc The data description.
  * @param index The index to get data from.
  * @return The requested data.
  */
 private double getDataDeltaChange(final TemporalDataDescription desc, final int index) {
   if (index == 0) {
     return 0.0;
   }
   final TemporalPoint point = this.points.get(index);
   final TemporalPoint previousPoint = this.points.get(index - 1);
   return point.getData(desc.getIndex()) - previousPoint.getData(desc.getIndex());
 }
 /**
  * Get data between two points in percent form.
  *
  * @param desc The data description.
  * @param index The index to get data from.
  * @return The requested data.
  */
 private double getDataPercentChange(final TemporalDataDescription desc, final int index) {
   if (index == 0) {
     return 0.0;
   }
   final TemporalPoint point = this.points.get(index);
   final TemporalPoint previousPoint = this.points.get(index - 1);
   final double currentValue = point.getData(desc.getIndex());
   final double previousValue = previousPoint.getData(desc.getIndex());
   return (currentValue - previousValue) / previousValue;
 }
  /** Calculate how many input and output neurons will be needed for the current data. */
  public void calculateNeuronCounts() {
    this.inputNeuronCount = 0;
    this.outputNeuronCount = 0;

    for (final TemporalDataDescription desc : this.descriptions) {
      if (desc.isInput()) {
        this.inputNeuronCount += this.inputWindowSize;
      }
      if (desc.isPredict()) {
        this.outputNeuronCount += this.predictWindowSize;
      }
    }
  }
  /**
   * Generate input neural data for the specified index.
   *
   * @param index The index to generate neural data for.
   * @return The input neural data generated.
   */
  public BasicNeuralData generateInputNeuralData(final int index) {
    if (index + this.inputWindowSize > this.points.size()) {
      throw new TemporalError(
          "Can't generate input temporal data " + "beyond the end of provided data.");
    }

    final BasicNeuralData result = new BasicNeuralData(this.inputNeuronCount);
    int resultIndex = 0;

    for (int i = 0; i < this.inputWindowSize; i++) {
      int descriptionIndex = 0;

      for (final TemporalDataDescription desc : this.descriptions) {
        if (desc.isInput()) {
          result.setData(resultIndex++, formatData(desc, index + i));
        }
        descriptionIndex++;
      }
    }
    return result;
  }
  /**
   * Format data according to the type specified in the description.
   *
   * @param desc The data description.
   * @param index The index to format the data at.
   * @return The formatted data.
   */
  private double formatData(final TemporalDataDescription desc, final int index) {
    final double[] result = new double[1];

    switch (desc.getType()) {
      case DELTA_CHANGE:
        result[0] = getDataDeltaChange(desc, index);
        break;
      case PERCENT_CHANGE:
        result[0] = getDataPercentChange(desc, index);
        break;
      case RAW:
        result[0] = getDataRAW(desc, index);
        break;
      default:
        throw new TemporalError("Unsupported data type.");
    }

    if (desc.getActivationFunction() != null) {
      desc.getActivationFunction().activationFunction(result, 0, result.length);
    }

    return result[0];
  }
  /**
   * Add a data description.
   *
   * @param desc The data description to add.
   */
  public void addDescription(final TemporalDataDescription desc) {
    if (this.points.size() > 0) {
      final String str =
          "Can't add anymore descriptions, there are " + "already temporal points defined.";

      throw new TemporalError(str);
    }

    final int index = this.descriptions.size();
    desc.setIndex(index);

    this.descriptions.add(desc);
    calculateNeuronCounts();
  }
 /**
  * Get data between two points in raw form.
  *
  * @param desc The data description.
  * @param index The index to get data from.
  * @return The requested data.
  */
 private double getDataRAW(final TemporalDataDescription desc, final int index) {
   final TemporalPoint point = this.points.get(index - 1);
   return point.getData(desc.getIndex());
 }