Root Bracketing Solvers in C# QuickStart Sample

Illustrates the use of the root bracketing solvers for solving equations in one variable in C#.

View this sample in: Visual Basic F# IronPython

using System;
// The RootBracketingSolver and derived classes reside in the 
// Numerics.NET.EquationSolvers namespace.
using Numerics.NET.EquationSolvers;
// Function delegates reside in the Numerics.NET
// namespace.
using Numerics.NET;
using Numerics.NET.Algorithms;

namespace Numerics.NET.QuickStart.CSharp
{
    /// <summary>
    /// Illustrates the use of the root bracketing solvers 
    /// in the Numerics.NET.EquationSolvers namespace of Numerics.NET.
    /// </summary>
    class RootBracketingSolvers
    {
        static void Main(string[] args)
        {
            // The license is verified at runtime. We're using
            // a 30 day trial key here. For more information, see
            //     https://numerics.net/trial-key
            Numerics.NET.License.Verify("64542-18980-57619-62268");
if 


            // Root bracketing solvers are used to solve 
            // non-linear equations in one variable.
            //
            // Root bracketing solvers start with an interval
            // which is known to contain a root. This interval
            // is made smaller and smaller in successive 
            // iterations until a certain tolerance is reached,
            // or the maximum number of iterations has been
            // exceeded.
            //
            // The properties and methods that give you control
            // over the iteration are shared by all classes
            // that implement iterative algorithms.
            
            //
            // Target function
            //

            // The function we are trying to solve must be
            // provided as a Func<double, double>. For more
            // information about this delegate, see the
            // FunctionDelegates QuickStart sample.
            Func<double, double> f = Math.Cos;

            // All root bracketing solvers inherit from
            // RootBracketingSolver, an abstract base class.
            RootBracketingSolver solver;

            //
            // Bisection method
            //

            // The bisection method halves the interval during
            // each iteration. It is implemented by the
            // BisectionSolver class.
            Console.WriteLine("BisectionSolver: cos(x) = 0 over [1,2]");
            solver = new BisectionSolver();
            solver.LowerBound = 1;
            solver.UpperBound = 2;
            // The target function is a Func<double, double>.
            // See above.
            solver.TargetFunction = f;
            double result = solver.Solve();
            // The Status property indicates
            // the result of running the algorithm.
            Console.WriteLine($"  Result: {solver.Status}");
            // The result is also available through the
            // Result property.
            Console.WriteLine($"  Solution: {solver.Result}");
            // You can find out the estimated error of the result
            // through the EstimatedError property:
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");

            //
            // Regula Falsi method
            //
            // The Regula Falsi method optimizes the selection
            // of the next interval. Unfortunately, the 
            // optimization breaks down in some cases.
            // Here is an example:
            Console.WriteLine("RegulaFalsiSolver: cos(x) = 0 over [1,2]");
            solver = new RegulaFalsiSolver();
            solver.LowerBound = 1;
            solver.UpperBound = 2;
            solver.MaxIterations = 1000;
            solver.TargetFunction = f;
            result = solver.Solve();
            Console.WriteLine($"  Result: {solver.Status}");
            Console.WriteLine($"  Solution: {solver.Result}");
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");
            
            // However, for sin(x) = 0, everything is fine:
            Console.WriteLine("RegulaFalsiSolver: sin(x) = 0 over [-0.5,1]");
            solver = new RegulaFalsiSolver();
            solver.LowerBound = -0.5;
            solver.UpperBound = 1;
            solver.TargetFunction = Math.Sin;
            result = solver.Solve();
            Console.WriteLine($"  Result: {solver.Status}");
            Console.WriteLine($"  Solution: {solver.Result}");
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");

            //
            // Dekker-Brent method
            //
            // The Dekker-Brent method combines the best of
            // both worlds. It is the most robust and, on average,
            // the fastest method.
            Console.WriteLine("DekkerBrentSolver: cos(x) = 0 over [1,2]");
            solver = new DekkerBrentSolver();
            solver.LowerBound = 1;
            solver.UpperBound = 2;
            solver.TargetFunction = f;
            result = solver.Solve();
            Console.WriteLine($"  Result: {solver.Status}");
            Console.WriteLine($"  Solution: {solver.Result}");
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");

            //
            // Controlling the process
            //
            Console.WriteLine("Same with modified parameters:");
            // You can set the maximum # of iterations:
            // If the solution cannot be found in time, the
            // Status will return a value of
            // IterationStatus.IterationLimitExceeded
            solver.MaxIterations = 20;
            // You can specify how convergence is to be tested
            // through the ConvergenceCriterion property:
            solver.ConvergenceCriterion = 
                ConvergenceCriterion.WithinRelativeTolerance;
            // And, of course, you can set the absolute or
            // relative tolerance.
            solver.RelativeTolerance = 1e-6;
            // In this example, the absolute tolerance will be 
            // ignored.
            solver.AbsoluteTolerance = 1e-24;
            solver.LowerBound = 157081;
            solver.UpperBound = 157082;
            solver.TargetFunction = f;
            result = solver.Solve();
            Console.WriteLine($"  Result: {solver.Status}");
            Console.WriteLine($"  Solution: {solver.Result}");
            // The estimated error will be less than 0.157
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");
            
            Console.Write("Press Enter key to exit...");
            Console.ReadLine();
        }
    }
}