public void testIncreasingTolerance() throws DerivativeException, IntegratorException {

    int previousCalls = Integer.MAX_VALUE;
    for (int i = -12; i < -2; ++i) {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0;
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double scalAbsoluteTolerance = Math.pow(10.0, i);
      double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

      FirstOrderIntegrator integ =
          new HighamHall54Integrator(
              minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);

      // the 1.3 factor is only valid for this test
      // and has been obtained from trial and error
      // there is no general relation between local and global errors
      assertTrue(handler.getMaximalValueError() < (1.3 * scalAbsoluteTolerance));
      assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);

      int calls = pb.getCalls();
      assertEquals(integ.getEvaluations(), calls);
      assertTrue(calls <= previousCalls);
      previousCalls = calls;
    }
  }
  public void testMinStep() {

    try {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0.1 * (pb.getFinalTime() - pb.getInitialTime());
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double[] vecAbsoluteTolerance = {1.0e-15, 1.0e-16};
      double[] vecRelativeTolerance = {1.0e-15, 1.0e-16};

      FirstOrderIntegrator integ =
          new HighamHall54Integrator(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (DerivativeException de) {
      fail("wrong exception caught");
    } catch (IntegratorException ie) {
    }
  }
  public void testEvents() throws DerivativeException, IntegratorException {

    TestProblem4 pb = new TestProblem4();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);
    EventHandler[] functions = pb.getEventsHandlers();
    for (int l = 0; l < functions.length; ++l) {
      integ.addEventHandler(functions[l], Double.POSITIVE_INFINITY, 1.0e-8 * maxStep, 1000);
    }
    assertEquals(functions.length, integ.getEventHandlers().size());
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);

    assertTrue(handler.getMaximalValueError() < 1.0e-7);
    assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
    assertEquals(12.0, handler.getLastTime(), 1.0e-8 * maxStep);
    integ.clearEventHandlers();
    assertEquals(0, integ.getEventHandlers().size());
  }
  public void testBackward() throws DerivativeException, IntegratorException {

    TestProblem5 pb = new TestProblem5();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new GraggBulirschStoerIntegrator(
            minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);

    assertTrue(handler.getLastError() < 9.0e-10);
    assertTrue(handler.getMaximalValueError() < 9.0e-10);
    assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
    assertEquals("Gragg-Bulirsch-Stoer", integ.getName());
  }
 private double getMaxError(FirstOrderIntegrator integrator, TestProblemAbstract pb)
     throws DerivativeException, IntegratorException {
   TestProblemHandler handler = new TestProblemHandler(pb, integrator);
   integrator.addStepHandler(handler);
   integrator.integrate(
       pb,
       pb.getInitialTime(),
       pb.getInitialState(),
       pb.getFinalTime(),
       new double[pb.getDimension()]);
   return handler.getMaximalValueError();
 }
  public void testEventsErrors() {

    final TestProblem1 pb = new TestProblem1();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(
            minStep, maxStep,
            scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);

    integ.addEventHandler(
        new EventHandler() {
          public int eventOccurred(double t, double[] y, boolean increasing) {
            return EventHandler.CONTINUE;
          }

          public double g(double t, double[] y) throws EventException {
            double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2;
            double offset = t - middle;
            if (offset > 0) {
              throw new EventException("Evaluation failed for argument = {0}", t);
            }
            return offset;
          }

          public void resetState(double t, double[] y) {}

          private static final long serialVersionUID = 935652725339916361L;
        },
        Double.POSITIVE_INFINITY,
        1.0e-8 * maxStep,
        1000);

    try {
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (IntegratorException ie) {
      // expected behavior
    } catch (Exception e) {
      fail("wrong exception type caught");
    }
  }
  public void testEventsNoConvergence() {

    final TestProblem1 pb = new TestProblem1();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(
            minStep, maxStep,
            scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);

    integ.addEventHandler(
        new EventHandler() {
          public int eventOccurred(double t, double[] y, boolean increasing) {
            return EventHandler.CONTINUE;
          }

          public double g(double t, double[] y) {
            double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2;
            double offset = t - middle;
            return (offset > 0) ? (offset + 0.5) : (offset - 0.5);
          }

          public void resetState(double t, double[] y) {}

          private static final long serialVersionUID = 935652725339916361L;
        },
        Double.POSITIVE_INFINITY,
        1.0e-8 * maxStep,
        3);

    try {
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (IntegratorException ie) {
      assertTrue(ie.getCause() != null);
      assertTrue(ie.getCause() instanceof ConvergenceException);
    } catch (Exception e) {
      fail("wrong exception type caught");
    }
  }
  public void testKepler() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double[] vecAbsoluteTolerance = {1.0e-8, 1.0e-8, 1.0e-10, 1.0e-10};
    double[] vecRelativeTolerance = {1.0e-10, 1.0e-10, 1.0e-8, 1.0e-8};

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
    integ.addStepHandler(new KeplerHandler(pb));
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);
    assertEquals("Higham-Hall 5(4)", integ.getName());
  }
  public void testVariableSteps() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double absTolerance = 1.0e-8;
    double relTolerance = 1.0e-8;
    FirstOrderIntegrator integ =
        new GraggBulirschStoerIntegrator(
            minStep, maxStep,
            absTolerance, relTolerance);
    integ.addStepHandler(new VariableStepHandler());
    double stopTime =
        integ.integrate(
            pb,
            pb.getInitialTime(),
            pb.getInitialState(),
            pb.getFinalTime(),
            new double[pb.getDimension()]);
    assertEquals(pb.getFinalTime(), stopTime, 1.0e-10);
    assertEquals("Gragg-Bulirsch-Stoer", integ.getName());
  }
  public void testKepler() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double absTolerance = 1.0e-6;
    double relTolerance = 1.0e-6;

    FirstOrderIntegrator integ =
        new GraggBulirschStoerIntegrator(
            minStep, maxStep,
            absTolerance, relTolerance);
    integ.addStepHandler(new KeplerStepHandler(pb));
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);

    assertEquals(integ.getEvaluations(), pb.getCalls());
    assertTrue(pb.getCalls() < 2150);
  }
  public void testIncreasingTolerance() throws DerivativeException, IntegratorException {

    int previousCalls = Integer.MAX_VALUE;
    for (int i = -12; i < -4; ++i) {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0;
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double absTolerance = Math.pow(10.0, i);
      double relTolerance = absTolerance;

      FirstOrderIntegrator integ =
          new GraggBulirschStoerIntegrator(
              minStep, maxStep,
              absTolerance, relTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);

      // the coefficients are only valid for this test
      // and have been obtained from trial and error
      // there is no general relation between local and global errors
      double ratio = handler.getMaximalValueError() / absTolerance;
      assertTrue(ratio < 2.4);
      assertTrue(ratio > 0.02);
      assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);

      int calls = pb.getCalls();
      assertEquals(integ.getEvaluations(), calls);
      assertTrue(calls <= previousCalls);
      previousCalls = calls;
    }
  }