Newton-Raphson Equation Solver in C# QuickStart Sample

Illustrates the use of the NewtonRaphsonSolver class for solving equations in one variable and related functions for numerical differentiation in C#.

View this sample in: Visual Basic F# IronPython

using System;
// The NewtonRaphsonSolver class resides in the 
// Numerics.NET.EquationSolvers namespace.
using Numerics.NET.EquationSolvers;
// Function delegates reside in the Numerics.NET
// namespace.
using Numerics.NET;
// The FunctionMath class resides in the
// Numerics.NET.Calculus namespace.
using Numerics.NET.Calculus;
using Numerics.NET.Algorithms;

namespace Numerics.NET.QuickStart.CSharp
{
    /// <summary>
    /// Illustrates the use of the Newton-Raphson equation solver 
    /// in the Numerics.NET.EquationSolvers namespace of Numerics.NET.
    /// </summary>
    class NewtonEquationSolver
    {
        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");

            // The Newton-Raphson solver is used to solve 
            // non-linear equations in one variable.
            //
            // The algorithm starts with one starting value,
            // and uses the target function and its derivative
            // to iteratively find a closer approximation to
            // the root of the target function.
            //
            // 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.Sin;
            // The Newton-Raphson method also requires knowledge
            // of the derivative:
            Func<double, double> df = Math.Cos;

            // Now let's create the NewtonRaphsonSolver object.
            NewtonRaphsonSolver solver = new NewtonRaphsonSolver();
            // Set the target function and its derivative:
            solver.TargetFunction = f;
            solver.DerivativeOfTargetFunction = df;
            // Set the initial guess:
            solver.InitialGuess = 4;
            // These values can also be passed in a constructor:
            NewtonRaphsonSolver solver2 = new NewtonRaphsonSolver(f, df, 4);

            Console.WriteLine("Newton-Raphson Solver: sin(x) = 0");
            Console.WriteLine("  Initial guess: 4");
            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}");

            // When you want just the zero without any additional information,
            // and you don't need to set any parameters (see below), then
            // you can call the FindZero extension method on the delegate
            // that defines your function:
            result = f.FindZero(df, 4);
            Console.WriteLine($"  Solution: {result}");

            //
            // When you don't have the derivative...
            //

            // You can still use this class if you don't have
            // the derivative of the target function. In this
            // case, use the static CreateDelegate method of the
            // FunctionMath class (Numerics.NET.Calculus
            // namespace) to create a Func<double, double>
            // that represents the numerical derivative of the
            // target function:
            solver.TargetFunction = f = new Func<double, double>(Special.BesselJ0);
            solver.DerivativeOfTargetFunction = f.GetNumericalDifferentiator();
            solver.InitialGuess = 5;
            Console.WriteLine("Zero of Bessel function near x=5:");
            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 = 10;
            // 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-14;
            // In this example, the absolute tolerance will be 
            // ignored.
            solver.AbsoluteTolerance = 1e-4;
            solver.InitialGuess = 5;
            result = solver.Solve();
            Console.WriteLine($"  Result: {solver.Status}");
            Console.WriteLine($"  Solution: {solver.Result}");
            // The estimated error will be less than 5e-14
            Console.WriteLine($"  Estimated error: {solver.EstimatedError}");
            Console.WriteLine($"  # iterations: {solver.IterationsNeeded}");
            
            Console.Write("Press Enter key to exit...");
            Console.ReadLine();
        }
    }
}