- Find roots of $f(x)$. That is, find the value of $x$ so that $f(x)=0$.
- All nonlinear algebraic problems can be written in the form $f(x)=0$. Just move all terms to one side of the equation.
- Numerical methods for nonlinear problems proceed by setting an initial guess for the solution, and iterating to improve the guess until some desired error tolerance is achieved.
- Open and Closed domain methods.
- Here:
- discuss closed domain methods
- one equation in one unknown
Bound the solution
- Bracket the root:
- Choose two guesses for the solution: $x_1$ and $x_2$. If $f(x_1)\cdot f(x_2)<0$ then the two guesses bracket the root.
- This implies that the root is between the two guesses.
Procedures
- Graph it.
- Visual picture can be very helpful.
- Provides an intial guess of the root.
- Indicates the function behavior, and possible problem areas.
- May not be practical, however.
- Cost of function evaluation may be excessive.
- Do a simple incremental search.
- Simply set a small $\Delta x$ and search the domain for $f(x)=0$.
- Obviously not very practical.
- Past experience
- Output of one problem may be a good guess for the input of another problem.
- This especially true in cases where we do multiple solves, which is quite common.
- Use intuition:
- species mass fractions should be between 0 and 1.
- most temperatures in K should be in reasonable ranges.
- Output of one problem may be a good guess for the input of another problem.
- Solve a simpler problem to get a guess for the harder problem.
- For example, if solving for a nonideal gas, get an initial guess using an ideal gas.
- Another example, if solving for temperature with a variable heat capacity, find a temperature guess using a constant heat capacity, which results in an easy linear solve for the guess.
- In combustion, we might solve using a simple 1-step reaction mechanism, instead of a more complex 400 step mechanism.
Once you have a bracket refine the root
- Reduce the size of the interval, while maintaining the bracket.
- Two methods: bisection, and regula falsi (false position)
- These are robust (they work!), but they are not overly fast.
Bisection
- Guess two points that bracket the root: $a$, $b$
- Check for $f(a)=0$ or $f(b)=0$
- Bracket tests:
- $f(a)f(b)<0$
- ($f(a)>0$ and $f(b)<0$) or ($f(a)<0$ and $f(b)>0$)
- Refine: $c = (a+b)/2$
- Select new bracket:
- if $f(a)f(c) < 0 \rightarrow b=c$
- else $a=c$
![](https://ignite.byu.edu/che541/lectures/figs/l08f02.png)
Error
- The error is always bounded by $\epsilon_n\le|b-a|$
- $\epsilon_{n+1} = \epsilon_n/2$ $\rightarrow$ linear convergence.
- $\epsilon_0$, $\epsilon_1=\epsilon_0/2$, $\epsilon_2 = \epsilon_1/2 = \epsilon_0/4 = \epsilon_0/2^2$
- $\rightarrow \epsilon_n = \epsilon_0/2^n$.
- Hence: $$n = \log_2\left(\frac{\epsilon_0}{\epsilon_n}\right)$$
- That is, to reduce the error from $\epsilon_0 \le |a-b|$ to some desired $\epsilon_n$ requires $n=\log_2(\epsilon_0/\epsilon_n)$ iterations.
Regula Falsi
-
Rather than bisect the interval to find $c$, draw an intersecting line between $f(a)$ and $f(b)$ as an approximation to the function.
-
Solve the root of this linear approximation:
- that is, where the line intersects the x-axis where $y=f(x)$ is zero.
- Equation for the line: $$f_l(x) = f(a) + \frac{f(b)-f(a)}{b-a}(x-a).$$
- Then let $f_l(c)=0$ and solve for $c$ to get: $$ c= a - f(a)\frac{b-a}{f(b)-f(a)}.$$
-
To retain the bracket, replace $a$ or $b$ with $c$ as for bisection.
![](https://ignite.byu.edu/che541/lectures/figs/l08f04.png)
- Robust
- Usually faster than bisection
- No error bound though.
- May get superlinear convergence
- Keeping the old versus new function evaluation…
- Consider the following case though (slow):
Convergence
- When to stop?
- $|b-a| < \epsilon$
- absolute error
- works for $x=1$
- not so good for $x=10^{20}$
- $|b-a|/|c| < \epsilon$
- relative error
- $|f(c)|< \epsilon$
- error in function versus error in root.
- $|b-a| < \epsilon$
Consider:
- On the left, the bracket is narrow, but the function is not zero.
- On the right, the function is near zero, but the bracket is not narrow.
- Do both $|b-a|/|c| < \epsilon_1$ and $|f(c)|<\epsilon_2$.
Bisection example
Find root of $f(x)=(x-2)^2 - 1$.
function bisection(f, a, b, tol=1E-5, maxit=10000)
fa = f(a)
fb = f(b)
if fa==0 return a, 0 end
if fb==0 return b, 0 end
if (fa>=0 && fb>=0) || (fa<=0 && fb<=0)
println("Error, a and b don't bracket the root")
return NaN, -1
end
for nit in 1:maxit
c = 0.5*(a+b)
fc = f(c)
if fc == 0 return c, nit end
if (fc > 0 && fa < 0) || (fc < 0 && fa > 0)
b = c
fb = fc
else
a = c
fa = fc
end
if (abs(fc) <= tol) || (abs((b-a)/c) <= tol)
return c, nit
end
end
println("Warning, no convergence in $maxit iterations")
c, maxit
end
#--------------------
func1(x) = (x-2.)^2 - 1.
#--------------------
x, nit = bisection(func1, 2., 3.5, 1E-8, 100)
println("Solution x = $x found in $nit iterations")
println("f(x) = $(func1(x))")
Solution x = 3.0000000074505806 found in 26 iterations
f(x) = 1.4901161193847656e-8
Compare with nlsolve
import NLsolve: nlsolve
function func1!(F,x)
F[1] = (x[1] - 2.0)^2 - 1.0
end
xguess = [20.]
results = nlsolve(func1!, xguess)
println("Solution x = $(results.zero)")
Solution x = [3.000000000000861]