using System; using System.Collections.Generic; using System.Linq; using System.Text; using Azimuth.RootFinding; namespace Azimuth.UnitTests.RootFinding { public class ConservativeAdvancementTests : UnitTestSharp.TestFixture { public void Basic() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => Math.Cos(x), x => -Math.Sin(x), 1, new Interval(0, 10), 10000, out root, ref iterations); CheckEqual(EndingState.SUCCESS, success); CheckEqual(Math.PI / 2, root); } public void NegativeAcceleration() { Scalar root; int iterations = 0; CheckThrow(typeof(System.Exception)); var success = ConservativeAdvancement.FindRoot( x => Math.Cos(x), x => -Math.Sin(x), -1, new Interval(0, 10), 10000, out root, ref iterations); } public void IterationsExceeded() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => Math.Cos(x), x => -Math.Sin(x), 1, new Interval(0, 10), 2, out root, ref iterations); CheckEqual(EndingState.MAX_ITERATIONS_EXCEEDED, success); CheckEqual(Math.Sqrt(2), root); } public void NoRoots() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => Math.Cos(x) + 1.5, x => -Math.Sin(x), 1, new Interval(0, 10), 10000, out root, ref iterations); CheckEqual(EndingState.BOUNDS_EXCEEDED, success); Check(Scalar.IsNaN(root)); } public void Disparate() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => 1, x => 0, 0, new Interval(0, 10), 10000, out root, ref iterations); CheckEqual(EndingState.BOUNDS_EXCEEDED, success); Check(Scalar.IsNaN(root)); } public void Forward() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => 4 + x * (x - 4), x => 2*x - 4, 2, new Interval(0, 10), 10000, out root, ref iterations); CheckEqual(EndingState.SUCCESS, success); Check(Scalar.FuzzyEquality(2, root, 1e-5)); } public void Backward() { Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( x => -(x - 2) * (x - 2), x => -(2 * x - 4), 2, new Interval(0, 10), 10000, out root, ref iterations); CheckEqual(EndingState.SUCCESS, success); Check(Scalar.FuzzyEquality(2, root, 1e-5)); } public void LongIterations() { // Takes a while to converge (more than a hundred iterations) // (mainly because of the conservative advancement) and the // fact that the collision window is so large Func function = delegate(Scalar t) { var accum = new RobustAccumulator(); accum.AddHarmonic(2 - 2 * t, 0, Math.PI / 2 * t); return accum.ComputedSum; }; Func derivative = delegate(Scalar t) { var accum = new RobustAccumulator(); accum.AddHarmonic(0, Math.PI * (t - 1), Math.PI / 2 * t); accum.AddHarmonic(-2, 0, Math.PI / 2 * t); return accum.ComputedSum; }; Scalar root; int iterations = 0; var success = ConservativeAdvancement.FindRoot( function, derivative, 2 * Math.PI + 50.5 * Math.PI * Math.PI, new Interval(0, 100), 200, out root, ref iterations); Scalar currRoot = 1; Scalar nextRoot = 3; CheckEqual(EndingState.SUCCESS, success); Check(Scalar.FuzzyEquality(1, root, 1e-5)); } } public class SafeStepForward : UnitTestSharp.TestFixture { public void NotAtZero() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => x, x => 1, 0, 2, 1000, out h, ref iterations); CheckEqual(EndingState.SUCCESS, success); CheckEqual(Scalar.PositiveInfinity, h); } public void NegativeAcceleration() { CheckThrow(typeof(Exception)); int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => x, x => 1, -1, 0, 1000, out h, ref iterations); CheckEqual(EndingState.SUCCESS, success); } public void Flat_Zero() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => x, x => 0, 0, 0, 1000, out h, ref iterations); CheckEqual(Scalar.PositiveInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void StraightLine() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => x, x => 1, 0, 0, 1000, out h, ref iterations); CheckEqual(Scalar.PositiveInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void Flat_ButAcceleration() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => x, x => 0, 1, 0, 1000, out h, ref iterations); Check(h > 0 && h < 1); CheckEqual(EndingState.SUCCESS, success); } public void Stationary_ButAcceleration() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => 0, x => 0, 1, 0, 1000, out h, ref iterations); CheckEqual(Scalar.PositiveInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void MaxIterations() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => 0, x => Scalar.FuzzyEqualityEpsilon * 100, 1000000, 0, 100, out h, ref iterations); CheckEqual(EndingState.MAX_ITERATIONS_EXCEEDED, success); CheckEqual(100, iterations); Check(Scalar.FuzzyEquality(Scalar.FuzzyEqualityEpsilon * 100, h.Value, 1e-22)); } public void ReasonableFunctions() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => Math.Cos(x), x => -Math.Sin(x), 1, Math.PI / 2, 100, out h, ref iterations); Check(h > 0 && h < Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void ReasonableFunctions_DoubleRoot() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward(x => Math.Cos(x) + 1, x => -Math.Sin(x), 1, Math.PI, 100, out h, ref iterations); Check(h > 0 && h < Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void MoreThanOneStep() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward( x => Math.Sin(-Math.PI/2 * x) + 1, x => -Math.Cos(-Math.PI / 2 * x) * -Math.PI / 2, Math.PI * Math.PI / 4, 1, 100, out h, ref iterations); Check(h > 0 && h < Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void NeedToIterateForMoreThanBaselineEpsilon() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward( x => Math.Sin(Math.PI / 2 * x) + 1, x => -Math.Cos(Math.PI / 2 * x) * Math.PI / 2, Math.PI * Math.PI / 4, 3, 100, out h, ref iterations); Check(h > 0 && h < Math.PI); CheckNotEqual(3, 3 + h); CheckEqual(EndingState.SUCCESS, success); } public void NearMiss() { Func func = x => 2 + x * (-2 + 505*x); int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward( func, x => 1010*x-2, 1010, 0, 100, out h, ref iterations); Check(h > 0 && h < Math.PI); CheckNotEqual(0, h); CheckNotEqual(func(0), func(h)); CheckEqual(EndingState.SUCCESS, success); } public void ShallowFunction() { // 1 - sin(pi/2 * (-1 + x)) - 2 * sin(pi/2*(1+ x/2)) Func func = x => 1 - Math.Sin(Math.PI / 2 * (-1 + x)) - 2 * Math.Sin(Math.PI / 2 * (1 + x/2)); int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepForward( func, x => -Math.PI / 2 * (Math.Cos(Math.PI / 2 * (x - 1)) + Math.Cos(Math.PI / 2 * (1 + x/2))), 10, 0, 1000, out h, ref iterations); Check(h > 0 && h < 2); CheckNotEqual(0, h); CheckNotEqual(func(0), func(h)); CheckEqual(EndingState.SUCCESS, success); } } public class SafeStepBackward : UnitTestSharp.TestFixture { public void NotAtZero() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => x, x => 1, 0, 2, 1000, out h, ref iterations); CheckEqual(EndingState.SUCCESS, success); CheckEqual(Scalar.NegativeInfinity, h); } public void NegativeAcceleration() { CheckThrow(typeof(Exception)); int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => x, x => 1, -1, 0, 1000, out h, ref iterations); CheckEqual(EndingState.SUCCESS, success); } public void Flat_Zero() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => x, x => 0, 0, 0, 1000, out h, ref iterations); CheckEqual(Scalar.NegativeInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void StraightLine() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => x, x => 1, 0, 0, 1000, out h, ref iterations); CheckEqual(Scalar.NegativeInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void Flat_ButAcceleration() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => x, x => 0, 1, 0, 1000, out h, ref iterations); Check(h < 0 && h > -1); CheckEqual(EndingState.SUCCESS, success); } public void Stationary_ButAcceleration() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => 0, x => 0, 1, 0, 1000, out h, ref iterations); CheckEqual(Scalar.NegativeInfinity, h); CheckEqual(EndingState.SUCCESS, success); } public void MaxIterations() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => 0, x => Scalar.FuzzyEqualityEpsilon * 100, 1000000, 0, 100, out h, ref iterations); CheckEqual(EndingState.MAX_ITERATIONS_EXCEEDED, success); CheckEqual(100, iterations); Check(Scalar.FuzzyEquality(-Scalar.FuzzyEqualityEpsilon * 100, h.Value, 1e-22)); } public void ReasonableFunctions() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => Math.Cos(x), x => -Math.Sin(x), 1, Math.PI / 2, 100, out h, ref iterations); Check(h < 0 && h > -Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void ReasonableFunctions_DoubleRoot() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward(x => Math.Cos(x) + 1, x => -Math.Sin(x), 1, Math.PI, 100, out h, ref iterations); Check(h < 0 && h > -Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void MoreThanOneStep() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward( x => Math.Sin(-Math.PI / 2 * x) + 1, x => -Math.Cos(-Math.PI / 2 * x) * -Math.PI / 2, Math.PI * Math.PI / 4, 1, 100, out h, ref iterations); Check(h < 0 && h > -Math.PI); CheckEqual(EndingState.SUCCESS, success); } public void NeedToIterateForMoreThanBaselineEpsilon() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward( x => Math.Sin(Math.PI / 2 * x) + 1, x => -Math.Cos(Math.PI / 2 * x) * Math.PI / 2, Math.PI * Math.PI / 4, 3, 100, out h, ref iterations); Check(h < 0 && h > -Math.PI); CheckNotEqual(3, 3 + h); CheckEqual(EndingState.SUCCESS, success); } public void NearMiss() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward( x => 2 + x * (-2 + 505 * x), x => 1010 * x - 2, 1010, 0, 100, out h, ref iterations); Check(h < 0 && h >- Math.PI); CheckNotEqual(0, h); CheckEqual(EndingState.SUCCESS, success); } public void AnotherOne() { int iterations = 0; Scalar h; var success = ConservativeAdvancement.SafeStepBackward( x => x - 2 + Math.Sin(Math.PI / 2 * x), x => 1 + Math.Cos(Math.PI / 2 * x) * Math.PI / 2, Math.PI * Math.PI / 4, 2, 100, out h, ref iterations); Check(h > -1 && h < 0); CheckNotEqual(2, h); CheckEqual(EndingState.SUCCESS, success); } } }