/** {@inheritDoc} */
    @Override
    public Evaluation evaluate(final RealVector point) {
      // Copy so optimizer can change point without changing our instance.
      final RealVector p =
          paramValidator == null ? point.copy() : paramValidator.validate(point.copy());

      if (lazyEvaluation) {
        return new LazyUnweightedEvaluation((ValueAndJacobianFunction) model, target, p);
      } else {
        // Evaluate value and jacobian in one function call.
        final Pair<RealVector, RealMatrix> value = model.value(p);
        return new UnweightedEvaluation(value.getFirst(), value.getSecond(), target, p);
      }
    }
  /**
   * Get the function value tensor.
   *
   * @param point The point.
   * @param bandwidth The bandwidth grid.
   * @return The function value tensor.
   */
  private double[] getFunctionValueTensor(final double[] point, final double[] bandwidth) {

    double[] tensor = new double[finiteDifference.getCoefficients().length];

    // use the iteration helper.
    RowMajorIteration iteration =
        new RowMajorIteration(finiteDifference.getFiniteDifferenceLengths());

    for (Pair<int[], Integer> index : iteration) {

      int[] multi = index.getFirst();

      // get the point with bandwidth shifts applied.
      double[] indexPoint = getPointForIndex(point, bandwidth, multi);
      double functionValue = function.value(indexPoint);

      // and store in the proper place in the tensor.
      int arrayIndex = index.getSecond();
      tensor[arrayIndex] = functionValue;
    }

    return tensor;
  }