public void testBoundaries() throws DerivativeException, IntegratorException {
   integ.setStepHandler(new ContinuousOutputModel());
   integ.integrate(
       pb,
       pb.getInitialTime(),
       pb.getInitialState(),
       pb.getFinalTime(),
       new double[pb.getDimension()]);
   ContinuousOutputModel cm = (ContinuousOutputModel) integ.getStepHandler();
   cm.setInterpolatedTime(2.0 * pb.getInitialTime() - pb.getFinalTime());
   cm.setInterpolatedTime(2.0 * pb.getFinalTime() - pb.getInitialTime());
   cm.setInterpolatedTime(0.5 * (pb.getFinalTime() + pb.getInitialTime()));
 }
  public void testRandomAccess() throws DerivativeException, IntegratorException {

    ContinuousOutputModel cm = new ContinuousOutputModel();
    integ.setStepHandler(cm);
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);

    Random random = new Random(347588535632l);
    double maxError = 0.0;
    for (int i = 0; i < 1000; ++i) {
      double r = random.nextDouble();
      double time = r * pb.getInitialTime() + (1.0 - r) * pb.getFinalTime();
      cm.setInterpolatedTime(time);
      double[] interpolatedY = cm.getInterpolatedState();
      double[] theoreticalY = pb.computeTheoreticalState(time);
      double dx = interpolatedY[0] - theoreticalY[0];
      double dy = interpolatedY[1] - theoreticalY[1];
      double error = dx * dx + dy * dy;
      if (error > maxError) {
        maxError = error;
      }
    }

    assertTrue(maxError < 1.0e-9);
  }
  public void testModelsMerging() throws DerivativeException, IntegratorException {

    // theoretical solution: y[0] = cos(t), y[1] = sin(t)
    FirstOrderDifferentialEquations problem =
        new FirstOrderDifferentialEquations() {
          public void computeDerivatives(double t, double[] y, double[] dot)
              throws DerivativeException {
            dot[0] = -y[1];
            dot[1] = y[0];
          }

          public int getDimension() {
            return 2;
          }
        };

    // integrate backward from &pi; to 0;
    ContinuousOutputModel cm1 = new ContinuousOutputModel();
    FirstOrderIntegrator integ1 = new DormandPrince853Integrator(0, 1.0, 1.0e-8, 1.0e-8);
    integ1.setStepHandler(cm1);
    integ1.integrate(problem, Math.PI, new double[] {-1.0, 0.0}, 0, new double[2]);

    // integrate backward from 2&pi; to &pi;
    ContinuousOutputModel cm2 = new ContinuousOutputModel();
    FirstOrderIntegrator integ2 = new DormandPrince853Integrator(0, 0.1, 1.0e-12, 1.0e-12);
    integ2.setStepHandler(cm2);
    integ2.integrate(problem, 2.0 * Math.PI, new double[] {1.0, 0.0}, Math.PI, new double[2]);

    // merge the two half circles
    ContinuousOutputModel cm = new ContinuousOutputModel();
    cm.append(cm2);
    cm.append(new ContinuousOutputModel());
    cm.append(cm1);

    // check circle
    assertEquals(2.0 * Math.PI, cm.getInitialTime(), 1.0e-12);
    assertEquals(0, cm.getFinalTime(), 1.0e-12);
    assertEquals(cm.getFinalTime(), cm.getInterpolatedTime(), 1.0e-12);
    for (double t = 0; t < 2.0 * Math.PI; t += 0.1) {
      cm.setInterpolatedTime(t);
      double[] y = cm.getInterpolatedState();
      assertEquals(Math.cos(t), y[0], 1.0e-7);
      assertEquals(Math.sin(t), y[1], 1.0e-7);
    }
  }