diff --git a/doap_math.rdf b/doap_math.rdf index ea3368f3f..85c4a08d2 100644 --- a/doap_math.rdf +++ b/doap_math.rdf @@ -30,10 +30,10 @@ Apache Commons Math The Math project is a library of lightweight, self-contained mathematics and statistics components addressing the most common practical problems not immediately available in the Java programming language or commons-lang. - - - - + + + + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index dc6539cd2..132509b4f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -59,6 +59,9 @@ If the output is not quite correct, check for invisible trailing spaces! when calling "optimize(...)" with linear constraints whose dimension does not match the dimension of the objective function. + + Fixed wrong event detection in case of close events pairs. + Reimplemented pow(double, double) in FastMath, for better accuracy in integral power cases and trying to fix erroneous JIT optimization again. diff --git a/src/main/java/org/apache/commons/math4/ode/AbstractIntegrator.java b/src/main/java/org/apache/commons/math4/ode/AbstractIntegrator.java index b9127ad86..e9326d9c6 100644 --- a/src/main/java/org/apache/commons/math4/ode/AbstractIntegrator.java +++ b/src/main/java/org/apache/commons/math4/ode/AbstractIntegrator.java @@ -292,9 +292,12 @@ public abstract class AbstractIntegrator implements FirstOrderIntegrator { * @param yDot placeholder array where to put the time derivative of the state vector * @exception MaxCountExceededException if the number of functions evaluations is exceeded * @exception DimensionMismatchException if arrays dimensions do not match equations settings + * @exception NullPointerException if the ODE equations have not been set (i.e. if this method + * is called outside of a call to {@link #integrate(ExpandableStatefulODE, double)} or {@link + * #integrate(FirstOrderDifferentialEquations, double, double[], double, double[])}) */ public void computeDerivatives(final double t, final double[] y, final double[] yDot) - throws MaxCountExceededException, DimensionMismatchException { + throws MaxCountExceededException, DimensionMismatchException, NullPointerException { evaluations.incrementCount(); expandable.computeDerivatives(t, y, yDot); } diff --git a/src/main/java/org/apache/commons/math4/ode/events/EventState.java b/src/main/java/org/apache/commons/math4/ode/events/EventState.java index fe3039a4c..1908440ce 100644 --- a/src/main/java/org/apache/commons/math4/ode/events/EventState.java +++ b/src/main/java/org/apache/commons/math4/ode/events/EventState.java @@ -296,7 +296,18 @@ public class EventState { ta = forward ? ta + convergence : ta - convergence; ga = f.value(ta); } while ((g0Positive ^ (ga >= 0)) && (forward ^ (ta >= tb))); - --i; + + if (forward ^ (ta >= tb)) { + // we were able to skip this spurious root + --i; + } else { + // we can't avoid this root before the end of the step, + // we have to handle it despite it is close to the former one + // maybe we have two very close roots + pendingEventTime = root; + pendingEvent = true; + return true; + } } else if (Double.isNaN(previousEventTime) || (FastMath.abs(previousEventTime - root) > convergence)) { pendingEventTime = root; diff --git a/src/main/java/org/apache/commons/math4/util/ResizableDoubleArray.java b/src/main/java/org/apache/commons/math4/util/ResizableDoubleArray.java index 09fd7482b..6377141a0 100644 --- a/src/main/java/org/apache/commons/math4/util/ResizableDoubleArray.java +++ b/src/main/java/org/apache/commons/math4/util/ResizableDoubleArray.java @@ -179,7 +179,6 @@ public class ResizableDoubleArray implements DoubleArray, Serializable { * The input array is copied, not referenced. * Other properties take default values: *
    - *
  • {@code initialCapacity = 16}
  • *
  • {@code expansionMode = MULTIPLICATIVE}
  • *
  • {@code expansionFactor = 2.0}
  • *
  • {@code contractionCriterion = 2.5}
  • @@ -189,7 +188,9 @@ public class ResizableDoubleArray implements DoubleArray, Serializable { * @since 2.2 */ public ResizableDoubleArray(double[] initialArray) { - this(DEFAULT_INITIAL_CAPACITY, + this(initialArray == null || initialArray.length == 0 ? + DEFAULT_INITIAL_CAPACITY : + initialArray.length, DEFAULT_EXPANSION_FACTOR, DEFAULT_CONTRACTION_DELTA + DEFAULT_EXPANSION_FACTOR, DEFAULT_EXPANSION_MODE, diff --git a/src/site/design/differentiation.puml b/src/site/design/differentiation.puml index ce24df740..8649345de 100644 --- a/src/site/design/differentiation.puml +++ b/src/site/design/differentiation.puml @@ -24,7 +24,7 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4 #ECEBD8 + package org.apache.commons.math4 #ECEBD8 { interface "FieldElement" as FieldElement_T_ { T add(T a) @@ -37,12 +37,12 @@ Field getField() } - package analysis #DDEBD8 + package analysis #DDEBD8 { interface UnivariateFunction { double value(double x) } - package differentiation #DDDBD8 + package differentiation #DDDBD8 { class DerivativeStructure { -DerivativeStructure(DSCompiler compiler) @@ -98,8 +98,8 @@ UnivariateDifferentiable <-- UnivariateDifferentiator : creates UnivariateDifferentiable --> DerivativeStructure : uses - end package - end package - end package + } + } + } @enduml diff --git a/src/site/design/oneD.puml b/src/site/design/oneD.puml index 368e9ab58..3f02d6e54 100644 --- a/src/site/design/oneD.puml +++ b/src/site/design/oneD.puml @@ -24,7 +24,7 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4.geometry #ECEBD8 + package org.apache.commons.math4.geometry #ECEBD8 { interface Space { +int getDimension() @@ -53,15 +53,15 @@ Space <-- Vector_S_ - package partitioning #DDEBD8 + package partitioning #DDEBD8 { interface "Region" as Region_S_ interface "Hyperplane" as Hyperplane_S_ interface "SubHyperplane" as SubHyperplane_S_ - end package + } - package euclidean #DDEBD8 + package euclidean #DDEBD8 { - package oned #DDDBD8 + package oned #DDDBD8 { class Euclidean1D class OrientedPoint @@ -72,10 +72,10 @@ Vector_S_ <|.. OrientedPoint Region_S_ <|.. IntervalSet - end package + } - end package + } - end package + } @enduml diff --git a/src/site/design/partitioning.puml b/src/site/design/partitioning.puml index dedfe24b2..bdf27dc83 100644 --- a/src/site/design/partitioning.puml +++ b/src/site/design/partitioning.puml @@ -24,9 +24,9 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4.geometry #ECEBD8 + package org.apache.commons.math4.geometry #ECEBD8 { - package partitioning #DDEBD8 + package partitioning #DDEBD8 { abstract "AbstractSubHyperplane" as AbstractSubHyperplane_S_T_ note left @@ -81,7 +81,7 @@ a region is a part of the space it may be empty, it may cover the whole space, - it may have infinite non-closed boudaries, + it may have infinite non-closed boundaries, it may be in several disconnected sub-parts, it may contain holes end note @@ -112,8 +112,7 @@ Region_S_ --> Side BSPTree_S_ <-- BSPTreeVisitor_S_ : visits - end package - - end package + } + } @enduml diff --git a/src/site/design/solver.puml b/src/site/design/solver.puml index 929a46d05..535a440f6 100644 --- a/src/site/design/solver.puml +++ b/src/site/design/solver.puml @@ -24,7 +24,7 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4.differentiation.solvers #ECEBD8 + package org.apache.commons.math4.differentiation.solvers #ECEBD8 { enum AllowedSolution { ANY_SIDE @@ -97,6 +97,6 @@ abstract class BaseSecantSolver AbstractPolynomialSolver <|-- LaguerreSolver AbstractUnivariateSolver <|-- BisectionSolver - end package + } @enduml diff --git a/src/site/design/threeD.puml b/src/site/design/threeD.puml index 81daf05a5..43175f632 100644 --- a/src/site/design/threeD.puml +++ b/src/site/design/threeD.puml @@ -24,7 +24,7 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4.geometry #ECEBD8 + package org.apache.commons.math4.geometry #ECEBD8 { interface Space { +int getDimension() @@ -53,15 +53,15 @@ Space <-- Vector_S_ - package partitioning #DDEBD8 + package partitioning #DDEBD8 { interface "Region" as Region_S_ interface "Hyperplane" as Hyperplane_S_ interface "SubHyperplane" as SubHyperplane_S_ - end package + } - package euclidean #DDEBD8 + package euclidean #DDEBD8 { - package threed #DDDBD8 + package threed #DDDBD8 { class Euclidean3D class Vector3D @@ -77,10 +77,10 @@ SubHyperplane_S_ <|.. SubPlane Region_S_ <|.. PolyhedronsSet - end package + } - end package + } - end package + } @enduml diff --git a/src/site/design/twoD.puml b/src/site/design/twoD.puml index 3de2827a6..b7f02d728 100644 --- a/src/site/design/twoD.puml +++ b/src/site/design/twoD.puml @@ -24,7 +24,7 @@ skinparam NoteFontColor #691616 skinparam ClassFontSize 11 - package org.apache.commons.math4.geometry #ECEBD8 + package org.apache.commons.math4.geometry #ECEBD8 { interface Space { +int getDimension() @@ -53,15 +53,15 @@ Space <-- Vector_S_ - package partitioning #DDEBD8 + package partitioning #DDEBD8 { interface "Region" as Region_S_ interface "Hyperplane" as Hyperplane_S_ interface "SubHyperplane" as SubHyperplane_S_ - end package + } - package euclidean #DDEBD8 + package euclidean #DDEBD8 { - package twod #DDDBD8 + package twod #DDDBD8 { class Euclidean2D class Vector2D @@ -75,10 +75,10 @@ SubHyperplane_S_ <|.. SubLine Region_S_ <|.. PolygonsSet - end package + } - end package + } - end package + } @enduml diff --git a/src/test/java/org/apache/commons/math4/ode/events/EventStateTest.java b/src/test/java/org/apache/commons/math4/ode/events/EventStateTest.java index b2041dcd3..bbb2bc51a 100644 --- a/src/test/java/org/apache/commons/math4/ode/events/EventStateTest.java +++ b/src/test/java/org/apache/commons/math4/ode/events/EventStateTest.java @@ -29,6 +29,7 @@ import org.apache.commons.math4.ode.SecondaryEquations; import org.apache.commons.math4.ode.events.EventHandler; import org.apache.commons.math4.ode.events.EventState; import org.apache.commons.math4.ode.nonstiff.DormandPrince853Integrator; +import org.apache.commons.math4.ode.nonstiff.LutherIntegrator; import org.apache.commons.math4.ode.sampling.AbstractStepInterpolator; import org.apache.commons.math4.ode.sampling.DummyStepInterpolator; import org.junit.Assert; @@ -43,21 +44,9 @@ public class EventStateTest { final double r1 = 90.0; final double r2 = 135.0; final double gap = r2 - r1; - EventHandler closeEventsGenerator = new EventHandler() { - public void init(double t0, double[] y0, double t) { - } - public void resetState(double t, double[] y) { - } - public double g(double t, double[] y) { - return (t - r1) * (r2 - t); - } - public Action eventOccurred(double t, double[] y, boolean increasing) { - return Action.CONTINUE; - } - }; final double tolerance = 0.1; - EventState es = new EventState(closeEventsGenerator, 1.5 * gap, + EventState es = new EventState(new CloseEventsGenerator(r1, r2), 1.5 * gap, tolerance, 100, new BrentSolver(tolerance)); es.setExpandable(new ExpandableStatefulODE(new FirstOrderDifferentialEquations() { @@ -226,4 +215,63 @@ public class EventStateTest { } + @Test + public void testEventsCloserThanThreshold() + throws DimensionMismatchException, NumberIsTooSmallException, + MaxCountExceededException, NoBracketingException { + + FirstOrderDifferentialEquations equation = new FirstOrderDifferentialEquations() { + + public int getDimension() { + return 1; + } + + public void computeDerivatives(double t, double[] y, double[] yDot) { + yDot[0] = 1.0; + } + }; + + LutherIntegrator integrator = new LutherIntegrator(20.0); + CloseEventsGenerator eventsGenerator = + new CloseEventsGenerator(9.0 - 1.0 / 128, 9.0 + 1.0 / 128); + integrator.addEventHandler(eventsGenerator, 1.0, 0.02, 1000); + double[] y = new double[1]; + double tEnd = integrator.integrate(equation, 0.0, y, 100.0, y); + Assert.assertEquals( 2, eventsGenerator.getCount()); + Assert.assertEquals( 9.0 + 1.0 / 128, tEnd, 1.0 / 32.0); + + } + + private class CloseEventsGenerator implements EventHandler { + + final double r1; + final double r2; + int count; + + public CloseEventsGenerator(final double r1, final double r2) { + this.r1 = r1; + this.r2 = r2; + this.count = 0; + } + + public void init(double t0, double[] y0, double t) { + } + + public void resetState(double t, double[] y) { + } + + public double g(double t, double[] y) { + return (t - r1) * (r2 - t); + } + + public Action eventOccurred(double t, double[] y, boolean increasing) { + return ++count < 2 ? Action.CONTINUE : Action.STOP; + } + + public int getCount() { + return count; + } + + } + }