Current section
Files
Jump to
Current section
Files
lib/newton_solver.ex
defmodule Fluxion.NewtonSolver do
@moduledoc """
A nonlinear equation solver which uses Newton's Method to find the zeros of
an arbitrary function.
"""
@doc """
Find a zero of the provided function starting from an initial guess.
# Example
iex> defmodule XSq do
...> @behaviour Fluxion.Function
...> def f(x), do: x*x - 4
...> def dfdx(x), do: 2*x
...> end
iex> computed_zero = Fluxion.NewtonSolver.find_zero(XSq, 10)
iex> Fluxion.Math.is_equal(computed_zero, 2)
:true
iex> computed_zero = Fluxion.NewtonSolver.find_zero(XSq, -0.1)
iex> IO.puts computed_zero
iex> Fluxion.Math.is_equal(computed_zero, -2)
:true
"""
@spec find_zero(Fluxion.Function.t(), number(), number()) :: number
def find_zero(function, guess, max_iterations \\ 100) do
iterate(function, guess, 0, max_iterations)
end
# rase an error if the solution cannot be found within the max iteration
# count
defp iterate(function, _current_guess, max_iterations, max_iterations) do
raise "cannot find the zero for #{Kernel.inspect(function)} in #{
max_iterations
} iterations"
end
# compute the next guess for the zero
# return the guess if it's close enough to zero, otherwise iterate again
defp iterate(function, current_guess, iteration, max_iterations) do
next_guess =
current_guess - function.f(current_guess) / function.dfdx(current_guess)
if Fluxion.Math.is_equal(function.f(next_guess), 0) do
next_guess
else
iterate(function, next_guess, iteration + 1, max_iterations)
end
end
end