ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 17.04.2021

Просмотров: 3716

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Introduction to Python for Science, Release 0.9.23

Generalized eigenvalue problem

The

scipy.linalg.eig

function can also solve the

generalized

eigenvalue problem

A

x

=

λ

B

x

where

B

is a square matrix with the same size as

A

. Suppose, for example, that we have

In [22]:

A

=

array([[

2

,

4

,

6

], [

1

,

-

3

,

-

9

], [

8

,

5

,

-

7

]])

Out[22]:

B

=

array([[

5

,

9

,

1

], [

-

3

,

1

,

6

], [

4

,

2

,

8

]])

Then we can solve the generalized eigenvalue problem by entering

B

as the optional

second argument to

scipy.linalg.eig

In [23]:

lam, evec

=

scipy

.

linalg

.

eig(A,B)

The solutions are returned in the same fashion as before, as an array

lam

whose entries

are the eigenvalues and a matrix

evac

whose rows are the eigenvectors.

In [24]:

lam

Out[24]:

array([

-

1.36087907

+

0.j

,

0.83252442

+

0.j

,

-0.10099858+0.j])

In [25]:

evec

Out[25]:

array([[

-

0.0419907

,

-

1.

,

0.93037493

],

[-0.43028153,

0.17751302, -1.

],

[ 1.

, -0.29852465,

0.4226201 ]])

Hermitian and banded matrices

SciPy has a specialized routine for solving eigenvalue problems for Hermitian (or real
symmetric) matrices. The routine for hermitian matrices is

scipy.linalg.eigh

. It

is more efficient (faster and uses less memory) than

scipy.linalg.eig

. The basic

syntax of the two routines is the same, although some of the

optional

arguments are

different. Both routines can solve generalized as well as standard eigenvalue problems.

SciPy also has a specialized routine

scipy.linalg.eig_banded

for solving eigen-

value problems for real symmetric or complex hermitian banded matrices.

9.3 Solving non-linear equations

SciPy has many different routines for numerically solving non-linear equations or systems
of non-linear equations. Here we will introduce only a few of these routines, the ones that

9.3. Solving non-linear equations

165


background image

Introduction to Python for Science, Release 0.9.23

are relatively simple and appropriate for the most common types of nonlinear equations.

9.3.1 Single equations of a single variable

Solving a single nonlinear equation is enormously simpler than solving a system of non-
linear equations, so that is where we start. A word of caution: solving non-linear equa-
tions can be a tricky business so it is important that you have a good sense of the behavior
of the function you are trying to solve. The best way to do this is to plot the function over
the domain of interest before trying to find the solutions. This will greatly assist you in
finding the solutions you seek and avoiding spurious solutions.

We begin with a concrete example. Suppose we want to find the solutions to the equation

tan

x

=

p

(8

/x

)

2

1

Plots of

tan

x

and

p

(8

/x

)

2

1

vs

x

are shown in the top plot in the figure

Crossing

functions

albeit with

x

replaced by

θ

. The solutions to this equation are those

x

values

where the two curves

tan

x

and

p

(8

/x

)

2

1

cross each other. The first step towards

obtaining a numerical solution is to rewrite the equation to be solved in the form

f

(

x

) = 0

.

Doing so, the above equation becomes

tan

x

p

(8

/x

)

2

1 = 0

Obviously the two equations above have the same solutions for

x

. Parenthetically we

mention that the problem of finding the solutions to equations of the form

f

(

x

) = 0

is

often referred to as

finding the roots

of

f

(

x

)

.

Next, we plot

f

(

x

)

over the domain of interest, in this case from

x

= 0

to 8. We are only

interested in positive solutions and for

x >

8

, the equation has no real solutions as the

argument of the square root becomes negative. The solutions, the points where

f

(

x

) = 0

are indicated by green circles; there are three of them. Another notable feature of the
function is that it diverges to

±∞

at

x

=

{

0

, π/

2

,

3

π/

2

,

5

π/

2

}

.

Brent method

One of the workhorses for finding solutions to a single variable nonlinear equation is the
method of Brent, discussed in many texts on numerical methods. SciPy’s implementa-
tion of the Brent algorithm is the function

scipy.optimize.brentq(f, a, b)

,

which has three required arguments. The first

f

is the name of the user-defined function

166

Chapter 9. Numerical Routines: SciPy and NumPy


background image

Introduction to Python for Science, Release 0.9.23

x

tan

x

x

true roots
false roots

Figure 9.2: Roots of a nonlinear function

to be solved. The next two,

a

and

b

are the

x

values that bracket the solution you are

looking for. You should choose

a

and

b

so that there is only one solutions in the inter-

val between

a

and

b

. Brent’s method also requires that

f(a)

and

f(b)

have opposite

signs; an error message is returned if they do not. Thus to find the three solutions to

tan

x

p

(8

/x

)

2

1 = 0

, we need to run

scipy.optimize.brentq(f, a, b)

three times using three different values of

a

and

b

that bracket each of the three solutions.

The program below illustrates the how to use

scipy.optimize.brentq

import

numpy

as

np

import

scipy

as

sp

import

matplotlib.pyplot

as

plt

def

tdl

(x):

y

=

8.

/

x

return

np

.

tan(x)

-

np

.

sqrt(y

*

y

-

1.0

)

# Find true roots

rx1

=

sp

.

optimize

.

brentq(tdl,

0.5

,

0.49

*

np

.

pi)

rx2

=

sp

.

optimize

.

brentq(tdl,

0.51

*

np

.

pi,

1.49

*

np

.

pi)

rx3

=

sp

.

optimize

.

brentq(tdl,

1.51

*

np

.

pi,

2.49

*

np

.

pi)

9.3. Solving non-linear equations

167


background image

Introduction to Python for Science, Release 0.9.23

rx

=

np

.

array([rx1, rx2, rx3])

ry

=

np

.

zeros(

3

)

# print using a list comprehension

print

(

\n

True roots:’

)

print

(

\n

.

join(

’f({0:0.5f}) = {1:0.2e}’

.

format(x, tdl(x))

for

x

in

rx))

# Find false roots

rx1f

=

sp

.

optimize

.

brentq(tdl,

0.49

*

np

.

pi,

0.51

*

np

.

pi)

rx2f

=

sp

.

optimize

.

brentq(tdl,

1.49

*

np

.

pi,

1.51

*

np

.

pi)

rx3f

=

sp

.

optimize

.

brentq(tdl,

2.49

*

np

.

pi,

2.51

*

np

.

pi)

rxf

=

np

.

array([rx1f, rx2f, rx3f])

# print using a list comprehension

print

(

\n

False roots:’

)

print

(

\n

.

join(

’f({0:0.5f}) = {1:0.2e}’

.

format(x, tdl(x))

for

x

in

rxf))

# Plot function and various roots

x

=

np

.

linspace(

0.7

,

8

,

128

)

y

=

tdl(x)

# Create masked array for plotting

ymask

=

np

.

ma

.

masked_where(np

.

abs(y)

>

20.

, y)

plt

.

figure(figsize

=

(

6

,

4

))

plt

.

plot(x, ymask)

plt

.

axhline(color

=

’black’

)

plt

.

axvline(x

=

np

.

pi

/

2.

, color

=

"gray"

, linestyle

=

’--’

, zorder

=-

1

)

plt

.

axvline(x

=

3.

*

np

.

pi

/

2.

, color

=

"gray"

, linestyle

=

’--’

, zorder

=-

1

)

plt

.

axvline(x

=

5.

*

np

.

pi

/

2.

, color

=

"gray"

, linestyle

=

’--’

, zorder

=-

1

)

plt

.

xlabel(

r’$x$’

)

plt

.

ylabel(

r’$\tan x - \sqrt{(8/x)^2-1}$’

)

plt

.

ylim(

-

8

,

8

)

plt

.

plot(rx, ry,

’og’

, ms

=

5

, label

=

’true roots’

)

plt

.

plot(rxf, ry,

’xr’

, ms

=

5

, label

=

’false roots’

)

plt

.

legend(numpoints

=

1

, fontsize

=

’small’

, loc

=

’upper right’

,

bbox_to_anchor

=

(

0.92

,

0.97

))

plt

.

tight_layout()

plt

.

show()

Running this code generates the following output:

In [1]:

run rootbrentq

.

py

168

Chapter 9. Numerical Routines: SciPy and NumPy


background image

Introduction to Python for Science, Release 0.9.23

True roots:

f(1.39547) = -6.39e-14

f(4.16483) = -7.95e-14

f(6.83067) = -1.11e-15

False roots:

f(1.57080) = -1.61e+12

f(4.71239) = -1.56e+12

f(7.85398) = 1.16e+12

The Brent method finds the three true roots of the equation quickly and accurately when
you provide values for the brackets

a

and

b

that are valid. However, like many numerical

methods for finding roots, the Brent method can produce spurious roots as it does in the
above example when

a

and

b

bracket singularities like those at

x

=

{

π/

2

,

3

π/

2

,

5

π/

2

}

.

Here we evaluated the function at the purported roots found by

brentq

to verify that

the values of

x

found were indeed roots. For the true roots, the values of the function

were very near zero, to within an acceptable roundoff error of less than

10

13

. For the

false roots, exceedingly large numbers on the order of

10

12

were obtained, indicating a

possible problem with these roots. These results, together with the plots, allow you to
unambiguously identify the true solutions to this nonlinear function.

The

brentq

function has a number of optional keyword arguments that you may find

useful. One keyword argument causes

brentq

to return not only the solution but the

value of the function evaluated at the solution. Other arguments allow you to specify a
tolerance to which the solution is found as well as a few other parameters possibly of
interest. Most of the time, you can leave the keyword arguments at their default values.
See the

brentq

entry online on the SciPy web site for more information.

Other methods for solving equations of a single variable

SciPy provides a number of other methods for solving nonlinear equations of a
single variable.

It has an implementation of the Newton-Raphson method called

scipy.optimize.newton

. It’s the racecar of such methods; its super fast but less

stable that the Brent method. To fully realize its speed, you need to specify not only the
function to be solved, but also its first derivative, which is often more trouble than its
worth. You can also specify its second derivative, which may further speed up finding the
solution. If you do not specify the first or second derivatives, the method uses the secant
method, which is usually slower than the Brent method.

Other methods, including the Ridder (

scipy.optimize.ridder

) and bisection

(

scipy.optimize.bisect

), are also available, although the Brent method is gen-

erally superior. SciPy let’s you use your favorite.

9.3. Solving non-linear equations

169