/**
   * Calculate the Euclidean distance for the specified output neuron and the input vector. This is
   * the square root of the squares of the differences between the weight and input vectors.
   *
   * @param matrix The matrix to get the weights from.
   * @param input The input vector.
   * @param outputNeuron The neuron we are calculating the distance for.
   * @return The Euclidean distance.
   */
  public double calculateEuclideanDistance(
      final Matrix matrix, final MLData input, final int outputNeuron) {
    double result = 0;

    // Loop over all input data.
    for (int i = 0; i < input.size(); i++) {
      final double diff = input.getData(i) - matrix.get(outputNeuron, i);
      result += diff * diff;
    }
    return BoundMath.sqrt(result);
  }
  /** {@inheritDoc} */
  @Override
  public final void iteration() {

    if (this.mustInit) {
      initWeights();
    }

    double worstDistance = Double.NEGATIVE_INFINITY;

    for (final MLDataPair pair : this.training) {
      final MLData out = this.network.computeInstar(pair.getInput());

      // determine winner
      final int winner = EngineArray.indexOfLargest(out.getData());

      // calculate the distance
      double distance = 0;
      for (int i = 0; i < pair.getInput().size(); i++) {
        final double diff =
            pair.getInput().getData(i) - this.network.getWeightsInputToInstar().get(i, winner);
        distance += diff * diff;
      }
      distance = BoundMath.sqrt(distance);

      if (distance > worstDistance) {
        worstDistance = distance;
      }

      // train
      for (int j = 0; j < this.network.getInputCount(); j++) {
        final double delta =
            this.learningRate
                * (pair.getInput().getData(j)
                    - this.network.getWeightsInputToInstar().get(j, winner));

        this.network.getWeightsInputToInstar().add(j, winner, delta);
      }
    }

    setError(worstDistance);
  }