numerical library in c for scientists and engineers a

798
Numerical Library for Scientists and Engineers H.T. Lau, Ph.D. CRC Press Boca Raton Ann Arbor London Tokyo Copyright 1995 by CRC Press, Inc

Upload: phamxuyen

Post on 08-Dec-2016

226 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Numerical Library in C for Scientists and Engineers A

Numerical Library

for Scientists

and Engineers

H.T. Lau, Ph.D.

CRC Press Boca Raton Ann Arbor London Tokyo

Copyright 1995 by CRC Press, Inc

Page 2: Numerical Library in C for Scientists and Engineers A

LIMITED WARRANTY

CRC Press warrants the physical diskette(s) enclosed herein to be free of defects in materials and workmanship for a period of thirty days from the date of purchase. If within the warranty period CRC Press receives written notification of defects in materials or workmanship, and such notification is determined by CRC Press to be correct, CRC Press will replace the defective diskette(s).

The entire and exclusive liability and remedy for breach of this Limited Warranty shall be limited to replacement of defective diskette(s) and shall not include or extend to any claim for or right to cover any other damages, including but not limited to, loss of profit, data, or use of the software, or special, incidental, or consequential damages or other similar claims, even if CRC Press has been specifically advised of the possibility of such damages. In no event will the liability of CRC Press for any damages to you or any other person ever exceed the lower suggested list price or actual price paid for the software, regardless of any form of the claim.

CRC Press SPECIFICALLY DISCLAIMS ALL OTHER WARRANTIES, EXPRESS OR IMPLIED, INCLUD- ING BUT NOT LIMITED TO, ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Specifically, CRC Press makes no representation or warranty that the software is fit for any particular purpose and any implied warranty of merchantability is limited to the thirty-day duration of the Limited Warranty covering the physical diskette(s) only (and not the software) and is otherwise expressly and specifically disclaimed.

Since some states do not allow the exclusion of incidental or consequential damages, or the limitation on how long an implied warranty lasts, some of the above may not apply to you

DISCLAIMER OF WARRANTY AND LIMITS OF LIABILITY: The author(s) of this book have used their best efforts in preparing this material. These efforts include the development, research, and testing of the theories and programs to determine their effectiveness. NEITHER THE AUTHOR(S) NOR THE PUBLISHER MAKE WAR- RANTIES OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THESE PROGRAMS OR THE DOCUMENTATION CONTAINED IN THIS BOOK, INCLUDING WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NO LIABILITY IS ACCEPTED IN ANY EVENT FOR ANY DAMAGES, INCLUDING INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST PROFITS, COSTS OF LOST DATA OR PROGRAM MATERIAL, OR OTHERWISE IN CONNECTION WITH OR ARISING OUT OF THE FURNISHING, PERFORMANCE, OR USE OF THE PROGRAMS IN THIS BOOK.

Library of Congress Cataloging-in-Publication Data

Lau, H. T. (Hang Tong), 1952- Numerical library in C for scientists and engineers / Hang-Tong Lau.

p. cm. Includes bibliographical references and index. ISBN 0-8493-7376-X 1. C (Computer program language) I. Title.

QA76.73.Cl5L38 1994 51 9.4'0285'53--&20 94-37928

CIP

This book contains information obtained from authentic and highly regarded sources. Reprinted material is quoted with permission, and sources are indicated. A wide variety of references are listed. Reasonable efforts have been made to publish reliable data and information, but the author(s) and the publisher cannot assume responsibility for the validity of all materials or for the consequences of their use.

Neither this book nor any part may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, microfilming, and recording, or by any information storage or retrieval system, without prior permission in writing from the publisher.

CRC Press, Inc.'s consent does not extend to copying for general distribution, for promotion, for creating new works, or for resale. Specific permission must be obtained in writing from CRC Press for such copying.

Direct all inquiries to CRC Press, Inc., 2000 Corporate Blvd. N.W., Boca Raton, Florida 3343 1.

O 1995 by CRC Press, Inc

No claim to original U S . Government works International Standard Book Number 0-8493-7376-X Library of Congress Card Number 94-37928 Printed in the United States of America 1 2 3 4 5 6 7 8 9 0 Printed on acid-free paper

Copyright 1995 by CRC Press, Inc

Page 3: Numerical Library in C for Scientists and Engineers A

To my wife, Helen, and the children Matthew, Lawrence and Tabia

for their love and support

Copyright 1995 by CRC Press, Inc

Page 4: Numerical Library in C for Scientists and Engineers A

Contents

Introduction

1. Elementary Procedures 1.1 Real vector and matri

A. inivecB. inimatC. inimatD. inisymE. inisymrow

1.2 Real vector 'and mA. dupvec B. dupvecrC. duprowvec D. dupveccol E. dupcolvec F. dupmat

1.3 Real vector an rix - Multiplication A. mulvec B. mulrow C. mulcol D. colcst E. rowcst

1.4 Real vector vec products A. vecvec B. matvec C. tamvec D. matmatE. LmmatF. mattam G. seqvec H. scaprdlI. symmat

1.5 Real matrix vectorA. fulmatvec B. fultamvec C. fulsymmatD. resvec E. symres

1.6 Real matrix matrixA. hshvecmat B. hshcolmat C. hshrowmatD. hshvectam E. hshcol~

Copyright 1995 by CRC Press, Inc

Page 5: Numerical Library in C for Scientists and Engineers A

F. hshrowta1.7 Real vector and

A. elmveB. elmcolC. elmroD. elmveccE. elmcolveF. elmvecroG. elmrowveH. elmcolroI. elmrowcolJ. maxelmro

1.8 Real vector 'and matrix - Interch'anging A. ichvec B, ichcoC. ichroD. ichrowcoE. ichseqvecF. ichse

1.9 Real vector and matrix - RotatioA. rotcol B. rotrow

1.10 Real vector and matrix - NormsA. infnrmveB. infnrmroC. infnrmcolD. infnrmmaE. onenrmveF. onenrmrow G. onenrmco H. onenrmmat I. absmaxma

1.1 1 Real vector and trix - Scalinreascl

1.12 Complex vector 'and matrix MultiplicationA. comcolcstB. comrowcst

1.13 Complex vector and matrix - Scalar productA. commatvecB. hshcomcoC. hshcomprd

1.14 Complex vector and matrix EliminatioA. elmcomveccolB. elmcomcol C. elmcomrowvec

1.15 Complex vector 'and matrix Rotation A. rotcomcolB. rotcornroC. chsh2

Copyright 1995 by CRC Press, Inc

Page 6: Numerical Library in C for Scientists and Engineers A

1.16 Complex vector 'and ma& - Norms comeucnr

1.17 Complex vectA. comsclB. sclcom

1.18 Complex moA. comab B. comsqC. carpo

1 .I9 Complex dy operationA. commul B. comdi

1.20 Long integer ithmeticA. lngintaddB. lngintsubC. IngintmulD. lngintdiviE. lngintpowe

Algebraic Evaluatio2.1 Evaluation o Grunert form

A. polB. tay C. nordeD. derpol

2.2 Evaluation of ral orthogonal polynomial A, ortpo B. ortpol C. allortpol

D. allortpol E. sumortpo

F. sumortpol2.3 Evaluation of Chebyshev polynomials

A. chepolsum B. oddchepolsC. chepol

D. allchep2.4 Evaluation of F

A. sinser B. cosse

C. fouseD. fouse E. fouser2 F. comfouG. comfouseH. comfouser2

2.5 Evaluation of continuejfra

2.6 Transfo

Copyright 1995 by CRC Press, Inc

Page 7: Numerical Library in C for Scientists and Engineers A

A. polchB. chspolC. polshtchs D. shtchspol E. grnne F. newgrG . lintfmpo

2.7 Operations on orthogonal polynomials intchs

. 3. Linear Algebr 3.1 Full

3.1.1 Preplvatory prA. dec

B. gsselC. onenrmin

D. erbel E. gsser

. F. gssnri3.1.2 Calculat

deter3.1.3 Solution of linear equations

A. so B. decsol .

. C. solelm D. gssso

E. gsssoler 3.1.4 Matrix inversio

A. in B. de C. invl

D. gssinv E. gssinverb

3.1.5 Iteratively improved solution A. itisol B. gssitisol

C. itisolerb D. gssitisolerb

3.2 Real Symmetric positive definite matrices 3.2.1 Preparatory procedure

A. chldec2 B. chldecl

3.2.2 Calculation of determinant A. chldeterm2B. chldeterm 1

3.2.3 Solution of linear equationA. chlsol2 B. chlsoll C. chldecsol2

Copyright 1995 by CRC Press, Inc

Page 8: Numerical Library in C for Scientists and Engineers A

D. chldecsoll 3.2.4 Matrix inversio

A. chlinvB. chlinvC. chldecinvD. chldecin

3.3 General real symmetric matrice 3.3.1 Preparatory procedur decsym2

3.3.2 Calculation ntdetermsym

3.3.3 Solution of linear equatio A. solsym

B. decsolsym3.4 Real full rank overdetermined syste

3.4.1 Preparatory proceduresA. lsqortdecB. lsqdglinv

3.4.2 Least squares solutioA. Isqso

B. lsqortdecso3.4.3 Inverse matrix of norm

. lsqinv3.4.4 Least sq ts

A. lsqdecomp B. Isqrefsol

3.5 Other real matrix problem 3.5.1 Solution of overdetermined systems

A. solsvdov B. solo

3.5.2 Solution of underdetermined systems A. solsvdun B. solund

3.5.3 Solution of ho A. homsolsvdB. homso

3.5.4 Pseudo-inversionA. psdinvsvd

B, psdinv 3.6 Real sparse non-symmetric band matrices

3.6.1 Preparatory procedure decbn 3.6.2 Calculation of determinant

determbnd 3.6.3 Solution of linear equation A. solbnd B. decsolbnd

3.7 Real sparse non-symmetric tridiagonal matrices 3.7.1 Preparatory procedures

Copyright 1995 by CRC Press, Inc

Page 9: Numerical Library in C for Scientists and Engineers A

A. dectriB. dectri

3.7.2 Solution of linear equations A. soltri

B. decsoltri C. soltripiv

D. decsoltri3.8 Sparse symmetric positive d inite band matrices

3.8.1 Preparatory procedurechldecbnd

3.8.2 Calculation nt chldetermbnd

3.8.3 Solution of lineA. chlsolbndB. chldecsol

3.9 Symmetric positive definite tridiagond matrices 3.9.1 Preparatory procedure

decsymtri3.9.2 Solution of linear equ

A. solsymtri B. decsolsym

3.10 Sparse real matrices - Iterative methods conjgrad 3.1 1 Simil'arity t

3.1 1.1 Equilibration - A. eqilbr

B. baklbr3.1 1.2 Equilibrati

A. eqilbrcomB. baklbrcom

3.1 1.3 To Hessenberg form real symmetriA. tfmsymtri2 B . baksymtri2 C. tfmprevecD. tfmsymtriE. baksymtri

3.1 1.4 To Hessenberg l asymmetricA. tfmreahes B. bakreahes C. b'akreahes2

3.1 1.5 To Hessenberg form - complex Hermitian A. hshhrmtri B. hshhrm~ivC. bakhrmtri

3.1 1.6 To Hessenberg form - complex non-HermitiaA. hshcomhes B. bakcomhes

3.12 Other transformations 3.12.1 To bidiagon - red matrices

Copyright 1995 by CRC Press, Inc

Page 10: Numerical Library in C for Scientists and Engineers A

A. hshreabid B. psttfmmat C. pretfmmat

3.13 The (ordin'uy) eigenvalue problem3.13.1 Real symmetric tridiago

A. valsymtri B. vecsymmC. qrivalsyD. qrisymtri

3.13.2 Real symmetri ll matrices A. eigvalsym2B. eigsym2 C. eigvalsy

D. eigsymlE. qrivalsyF. qrisym G . qrival

3.13.3 Symmetric matrices - Auxiliq proceduresA. mergesort B. vecperm C. rowperm

3.13.4 Symmetric matrices - Orthogonalizationorthog

3.13.5 Symme Iterative improvement symeigim

3.13.6 AsymmetriA. reavalqriB. reavecheC. reaqriD. comvE. comveche

3.13.7 Real asymmetA. reaeigval B, reaeiglC. reaeig3D. comeig

E. comeigl3.13.8 Complex Her

A. eigvalhrm B. eighrC. qrivalhD. qlihrm

3.13.9 Complex u Hessenberg matrices A. valqricom

B. qricom 3.13.10 Complex

A. eigvalcom B. eigcom

3.14 The generalized eigen

Copyright 1995 by CRC Press, Inc

Page 11: Numerical Library in C for Scientists and Engineers A

3.14.1 Red asymmetric matrices A. qzivaB. qziC. hsD. hestglE. hestgl2F. hsh2coG. hsh3coH. hsh2rowI. hsh2rowJ. hsh3rowK. hsh3row

3.15 Singular values3.15.1 Red

A. qrisngvalbidB. qrisngvaldec

3.15.2 Real full matricesA. qrisngvalB. qrisngval

3.16 Zeros of polynomial3.16.1 Zeros of general r ials

A. zerpol B. bounds

3.16.2 Zeros of ortA. allzerortpolB. lupzerortpoC. selzerortpoD. alljacze E. alllagze

3.16.3 Zeros of co olynomialcornkw

4. Analytic Evaluations4.1 Evaluation ite series

A. euler . B. surnp

4.2 Quadratur4.2.1

A. qadrat B. integra

4.2.2 Multidimensi tricu

4.2.3 Gaussia weights A. reccof B. gsswts

C. gsswts4.2.4 Gaussian quadrat

A. gssjacwghts B. gsslagwghts

Copyright 1995 by CRC Press, Inc

Page 12: Numerical Library in C for Scientists and Engineers A

4.3 Numerical differentiation4.3.1 Calculation wit

A. jacobnnf B. jacobnmC. jacobnbnd

5. Analytic Problem5.1 Non-lin

5.1.1 Single eqA. zeroin B. zeroin

5.1.2 Single equatiozeroinder

5.1.3 System of A. quanewbnd B. quanewbn

5.2 Unconstrained optimization 5.2.1 One variable - No rivativ

minin 5.2.3 One v'v

mininder 5.2.4 More varia Auxiliary procedures

A. linemin B. rnklupd C. davupdD. fleupd

5.2.5 More variablpraxis

5.2.6 More va A. rnklmin

B. flemin 5.3 Overdetermined nonlin

5.3.1 Least squares - With JaA. marquardB. gssnewto

. 5.4 Differential equations In5.4.1 First order - No derivatives right ha

A. rkl B. r C. rk D. rk4E. rk5naF. multisG. diffsyH. aI. efr

5.4.2 First Or obian matrix available A. efsirk B. eferk

Copyright 1995 by CRC Press, Inc

Page 13: Numerical Library in C for Scientists and Engineers A

C. liniger 1 vs D. liniger2E. gms F. imp

. 5.4.3 First Order eral derivatives availabl A. modifiedtaylo

B. eft 5.4.4 Second erivatives right hand side

A. rk2 B. rk2C. rkD. rk

5.4.5 Initial boun&q value problemarkmat

5.5 Two point boundar5.5.1 Linear methods - Second

A. femlagsymB. femlag C . femlag

5.5.2 Linear methods - Second order skew adjointfemlagskew

5.5.3 Linear method femhermsym 5.5.4 Non-linear meth nonlinfemlagskew

5.6 Two-dimension;d boundii val5.6.1 Elliptic special linear systems

A. richardson B. elimination

5.6 Parameter estimation in diff 5.6.1 Initial value problems

peid

6. Special Functions 6.1 Element

6.1.1 HyperboliA. arcsinB. arccosC. arctan

6.1.2 Logarithmic logoneplusx

6.2 Exponential integral 6.2.1 Exponenti

A. ei B, ei

C. enx D. non

6.2.2 Sine 'and cosine iA. sincosin

Copyright 1995 by CRC Press, Inc

Page 14: Numerical Library in C for Scientists and Engineers A

B. sincosfg 6.3 Gamma functio A. recipga B. gamma C. logga D. incomga

E. incbeta F. ibpplus

. G. ibqplus H. ixqfix I. ixpfix J. forwar K. backwa 6.4 Error function A. errorf B. nonexperfc C. inverseerro D. fresnel E. f 6.5 Bessel fu

6.5.1 Bessel functions J and YA. bessjO B. bessjlC. bessj D. bessyE. bessy F. bessp G. besspql

6.5.2 Bessel functio A. bessiO B. bessil

C. bessi D. bessk

E. bessk F. nonexG. nonexpbessi 1 H. nonexpbessi I. nonexpbesskJ. nonexpbessk

6.6 Bessel functions of real order6.6.1 Bessel functions J

A. bessjaplusn B. bessya0l C. bessyaplD. besspqaolE. besszeros F. start

6.6.2 Bessel fun d KA. bessiaplusn

Copyright 1995 by CRC Press, Inc

Page 15: Numerical Library in C for Scientists and Engineers A

B. besska0 C. besskapl

D. nonexpbess E. nonexpbesska0

F. nonexpbesskapl 6.6.3 Spherical Bessel functio

A. spherbessjB. spherbess

C. spherbessi D, spherbess E. nonexpspherbessi

F. nonexpspherbess 6.6.4 Any functions

A. airyB. airy

7. Interpolation and Approximatio7.1 Red data in one dime

7.1.1 Interpolation withnewton

7.1.2 ApproximA. iniB. snC. minmaxp

Worked Ex'mples Examples 1

hshcomcol, hshcomprdelmcomcol rotcomcolcomabs comsqrt carpol commucomdivlngintad intsubtract, Ingintmult, lngintdivide

Examples for chapter 2 procedures derpol allortpchepolsoddchepolschepol, allchefouser jfrachspolshtchs, shtnewgm, gmnew lintfmpol

intch

Copyright 1995 by CRC Press, Inc

Page 16: Numerical Library in C for Scientists and Engineers A

Examples for chapter 3 procedures determ, gsselm decsol gsssol gsssolerb decinv gssinv gssinverb gssitisol gssitisolerb chldec2, chlsol2, chlinv2 chldecl, chlsoll, chlinvl chldecsol2, chldeterm2, chldecinv2 chldecsoll, chldeterm 1, chldecinvl determsym2 decsolsymlsqortdec, lsqsol, lsqdglinv lsqortdecsol lsqinv lsqdecomp, lsqrefsol

solovr solund homsolpsdinv solbnd, decbnd, determbnd decsolbnddecsolmsoltripiv decsoltripiv chlsolbnd, chldecbnd, chldetermbnd chldecsolbnd, chldetermbnd decsolsymtriconjgradeqilbrco hshhrmtrivalsymtri, vecsymtri eigsym 1symeigimpcomvalqri, comveches reaeig3eighrmqrihrm valqricomqricom eigcomqzival qziqrisngvaldezerpol, boun

Copyright 1995 by CRC Press, Inc

Page 17: Numerical Library in C for Scientists and Engineers A

allzerortpol lupzerortpol selzerortpol alljaczerdllagzercomkwd

Examples for chapter 4 procedures euler sumposserieqadrat integraltricubreccofgsswtssym gssjacwghtsgsslagwghts jacobnnf jacobnmf jacobnbndf

Examples for chapter 5 procedures zeroin zeroinrzeroindequanewbndl mininmininderpraxis mklmin, flemin marquardt gssnewto rkl rke rk4a rk4na

rk5namultistep diffsys ark efrkefsirkeferk linigerlvsliniger2 gms impex modified~~ylor eft rk2rk2n

Copyright 1995 by CRC Press, Inc

Page 18: Numerical Library in C for Scientists and Engineers A

rk3 rk3narkfemlagsym femlag femlagspher femlagskew femhermsymnonlinfemlagskew richardson elimination peide

Examples for chapter 6 and 7 procedures ei eialpha enx, nonexpenx sincosint, sincosfg

recipgamma gamma loggamma incomgam incbeta ibpplusn ibqplusn errorfunction, nonexperfc

inverseerrorfunction fresnel, fg bessj0, bessjl, bessj bessyOl bessy besspq0, besspql bessi, bessk besskOl

nonexpbesskol nonexpbessk

bessjaplusn besspqaO 1 besszeros spherbessi, nonexpspherbessi spherbessk, nonexpspherbessk airy airyzerosnewton ini sndremezminmaxpol

Appendix A: References

Copyright 1995 by CRC Press, Inc

Page 19: Numerical Library in C for Scientists and Engineers A

Appendix B: Prototype Declarations

Appendix C: Procedure Descriptions

Appendix D: Memory Management Utilities

Copyright 1995 by CRC Press, Inc

Page 20: Numerical Library in C for Scientists and Engineers A

1. Elementary Procedures

This chapter contains elementary operations for vectors and matrices such as the assignment of initial values to vectors and matrix slices, duplication and interchange of such slices, rotations and reflections. The procedures are taken from [Dek68, DekHo681. Most of them are used in subsequent chapters. The elementary procedures are all quite short; prepared versions may be re-coded, making optimal use of machine capabilities, in assembly language.

1.1 Real vector and matrix - Initialization

A. inivec

Initializes part of a vector a by setting a,=x (i=l,l+l, ..., u).

Function Parameters: void inivec (I, u, a,x)

1,u: int; lower and upper index of the vector a, respectively; a: float a[l:u]; the array to be initialized; x: float; initialization constant.

yoid inivec (int 1, int u, float a[] , float x)

B. inimat

Initializes a rectangular submatrix a by setting ai,,=x (i=lr,lr+l, ..., ur; j=lc,lc+l, ..., uc).

Function Parameters: void inimat (Ir, ur, lc, uc, a,x)

Ir,ur,lc,uc: int; lower and upper row-index, and lower and upper column-index of the matrix a, respectively;

a: float a[lr:ur,lc:uc]; the matrix to be initialized; x: float; initialization constant.

void inimat(int lr, int ur, int lc, int uc, float **a, float x) I

int j;

for ( ; lr<=ur; lr++) for (j=lc; jc=uc; j++) a [lrl [jl =x;

I

C. inimatd

Copyright 1995 by CRC Press, Inc

Page 21: Numerical Library in C for Scientists and Engineers A

Initializes a forward diagonal sequence of elements of a rectangular matrix a by setting a,,,+sh~=x (i=lr, lr+ 1,. . . , ur) .

Function Parameters: void inimatd (Ir, ur,shift,a,x)

r r : int; lower and upper row-index of the codiagonal to be initialized; shift: int; distance between diagonal and codiagonal; a: float a[lr:ur,lr+shift:ur+shift]; the array to be initialized; x: float; initialization constant.

void inimatd(int lr, int ur, int shift, float **a, float x) {

for ( ; lr<=ur; lr++) a[lrl [lr+shiftl =x; 1

D. inisymd

Initializes a forward diagonal sequence of elements of a symmetric square matrix b. The upper triangle of b is stored columnwise in a linear array a such that b,, is ali-llj/2+i.

Function Parameters: void inisymd (lr, ur,shift,a,x)

r r : int; lower and upper row-index of a codiagonal of a symmetric matrix of order n to be initialized, Ir and ur should satisfy: lr 2 1, ur I n;

shift: distance between diagonal and codiagonal, -n < shift < n; a: float a[l:n(n+l)/2]; the linear array containing the columnwise stored upper triangle of

a symmetric matrix; x: float; initialization constant.

void inisymd(int lr, int ur, int shift, float a[] , float x)

shift=abs (shift) : ur += shift+l; shift += lr; lr += ( (shift-3) *shift) /2; lr += shift; while (shift < ur) {

a [lrl =x; shift++; lr += shift;

E. inisymrow

Initializes part of a row of a symmetric square matrix b. The upper triangle of b is stored columnwise in a linear array a such that bij is ali-l,j,2+i.

Function Parameters: void inisymrow ( I , u, i, a,x)

1,u: int; lower and upper index of row-element of a codiagonal of a symmetric matrix of

Copyright 1995 by CRC Press, Inc

Page 22: Numerical Library in C for Scientists and Engineers A

order n to be initialized, 1 and u should satisfy: 1 I I I n, 1 I u I n; i : row index, 1 i 2 n; a: float a[l:n(n+l)/2]; the linear array containing the columnwise stored upper triangle of

a symmetric matrix; x: float; initialization constant.

void inisymrow(int 1, int u, int i, float a[] , float x) I

int k;

if (1 <= i) { k=( (1-1) *i)/2; 1 += k; k += (u<i) ? u : i; for ( ; l<=k; I++) a[ll=x; l=i+l;

I if (U > i) {

k= ( (1-1) *l) /2+i; do (

a [kl =x; I++; k += 1-1;

) while (1 <= u) ;

1 1

1.2 Real vector and matrix - Duplication

A. dupvec

Duplicates part of a vector b by setting a,=b,,,+sh~ (i=l,l+l, ..., U)

Function Parameters: void dupvec (I, u,shift,a, b)

1,u: int; lower and upper vector-index, respectively; shift: int; index-shifting parameter; a,b: float a[l:u], b[l+shift:u+shift]; the array b is copied into a.

void dupvec (int 1, int u, int shift, float a [I , float b [I ) {

for ( ; l<=u; 1++) a [l] =b [lcshift] ; 1

B. dupvecrow

Duplicates part of a row vector of a rectangular matrix b by setting a,=b,,, (j=l,l+l, ..., u).

Function Parameters: void dupvecrow ( I , u , i , a , b)

1 , u : int; lower and upper vector-index, respectively; i: int; row-index of the matrix b; a , b : float a [ l : u ] , b [ i : i , l : u ] ; b is copied into a .

Copyright 1995 by CRC Press, Inc

Page 23: Numerical Library in C for Scientists and Engineers A

void dupvecrow(int 1, int u, int i, float a[] , float **b) (

for ( ; lc=u; I++) a [ll =b [ i l [ll ; 1

C. duprowvec

Replaces part of a row vector of a rectangular matrix a by a corresponding part of a vector b by setting

a . 'J .=b. I Q=l,I+l, ..., u).

Function Parameters: void duprowvec (I, u, i,a, b)

1,u: int; lower and upper vector-index, respectively; i: int; row-index of the matrix a ; a, b: float a[i:i,l:u], b[l:u]; b is copied into a.

void duprowvec(int 1, int u, int i, float **a, float b[l) I

for ( ; lc=u; I++) a [il [ll =b [ll ; 1

D. dupveccol

Duplicates part of a column vector of a rectangular matrix b by setting a,=b, (i=l,l+l, ..., u).

Function Parameters: void dupveccol (I, u,j,a, b)

1,u: int; lower and upper vector-index, respectively; j : int; column-index of the matrix b; a,b: float a[l:u], b[l:uJ~]; b is copied into a.

void dupveccol (int 1, int u, int j, float a [ I , float **b) I

for ( ; lc=u; I++) a 111 =b [ll [ j l ; 1

E. dupcolvec

Replaces part of a column vector of a rectangular matrix a by a corresponding part of a vector b by setting

aij=bi (i=l,I+l, ..., u).

Function Parameters void dupcolvec (1, u,j,a, b)

1,u: int; lower and upper vector-index, respectively; j: int; column-index of the matrix a ; a,b: float a[l:u,i:i], b[l:u]; b is copied into a.

Copyright 1995 by CRC Press, Inc

Page 24: Numerical Library in C for Scientists and Engineers A

void dupcolvec (int 1, int u, int j , float **a, float b [ I )

{ for ( ; lc=u; I++) a111 [jl =b[ll ;

1

F. dupmat

Replaces a submatrix of the rectangular matrix a by a corresponding submatrix of the rectangular matrix b by setting

amfn=bmSn (m=l , l+l , ..., u; n=i , i+ l , ...) j).

Function Parameters: void dupmat (I, u, i,j, a, b)

1,u: int; lower and upper row-index, respectively; i,j: int; lower and upper column-index, respectively; a, b: float a[l:u,ig], b[l:u, ig]; b is copied into a.

void dupmat (int 1, int u, int i, int j, float **a, float **b) l

int k;

for ( ; lc=u; 1++) for (k=i; kc=j ; kc+) a [ll [kl =b [ll [kl ;

I

1.3 Real vector and matrix - Multiplication

A. mulvec

Forms a constant multiple of part of a vector by setting u ~ = x ~ ~ + ~ ~ ~ ~ (i=l)l+I ,..., u).

Function Parameters: void mulvec (I, u,shift,a, b,x)

1,u: int; lower and upper vector-index, respectively; shift: int; subscript-shifting parameter; a,b: float a[l:u], b[l+sh$t:u+shift]; the product of the contents of b are stored in a; x : multiplication factor.

void mulvec (int 1, int u, int shift, float a [I , float b [ I , float x) {

for ( ; lc=u; 1++) a[l]=b[l+shiftl*x; 1

B. mulrow

Replaces a row sequence of elements of a rectangular matrix a by a constant multiple of a row sequence of elements of a rectangular matrix b by setting

ai,,=xbjek (k=l, l+l , ..., u).

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 25: Numerical Library in C for Scientists and Engineers A

void mulrow (l,u, i,j,a, b,x) 1,u: int; lower and upper column-index, respectively; i,j: int; row indices of a and b; 4 b : float a[i:i,l:u], bo:j,l:u]; the contents of b multiplied by x are stored into a ; x: multiplication factor.

void mulrow(int 1, int u, int i, int j, float **a, float **b, float x) (

for ( ; lc=u; 1++) a[il [ll =b[jl [ll *x; I

C. mulcol

Replaces a column sequence of elements of a rectangular matrix a by a constant multiple of a column sequence of elements of a rectangular matrix b by setting

a,,=xb, (k=l,l+l, ..., u).

Function Parameters: void mulcol (I, u, i,j,a, b,x)

1,u: int; lower and upper row-index, respectively; i,j: int; column indices of a and b; a,b: float a[l:u,i:i], b[l:u,jj]; the contents of b multiplied by x are stored into a; x: multiplication factor.

void mulcol(int 1, int u, int i, int j, float **a, float **b, float x) (

for ( ; lc=u; I++) a111 [il =b[ll [jl *x; 1

D. colcst

Replaces the elements of a column sequence taken from a rectangular matrix a by constant multiples of the same elements, by setting

a,=xa, (i=l,l+l, ..., u).

Function Parameters: void colcst (I, u,j,a,x)

1,u: int; lower and upper row-index, respectively; j: int; column index; a : float a[l:u,j:j]; the rectangular matrix; x: multiplication factor.

void colcst(int 1, int u, int j, float **a, float x) (

for ( ; lc=u; 1++) a[ll [jl *= x; 1

E. rowcst

Replaces the elements of a row sequence taken from a rectangular matrix a by constant

Copyright 1995 by CRC Press, Inc

Page 26: Numerical Library in C for Scientists and Engineers A

multiples of the same elements, by setting a,,J=xa,,J Q=l, l+l, ..., u).

Function Parameters: void rowcst ( I , u, i,a,x)

1,u: int; lower and upper column-index, respectively; i: int; row index; a: float a[i: i,l:u]; the rectangular matrix; x: multiplication factor.

void rowcst(int 1, int u, int i, float **a, float x) {

for ( ; l<=u; 1++) a[il [ll *= x; 1

1.4 Real vector vector products

A. vecvec

Forms the inner product s of part of a vector a and part of a vector b by setting

Function Parameters: float vecvec (I, u,shift,a, b )

vecvec: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; shift: int; index-shifting parameter of the vector b; a, b: float a[l:u], b[l+shift:u+shift].

£loat vecvec (int 1, int u, int shift, float a [I , float b [I ) L

int k; float s;

s=o.o; for (k=l; k<=u; k++) s += a[kl*b[k+shiftl; return (s) ;

B. matvec

Forms the inner product s of part of a row of a rectangular matrix a and the corresponding part of a vector b by setting

Copyright 1995 by CRC Press, Inc

Page 27: Numerical Library in C for Scientists and Engineers A

Function Parameters: float matvec (I, u, i, a, b)

maivec: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; i: int; row-index of a; a, b: float a[i: i, I: u], b[l:u].

f l o a t rnatvec ( i n t 1 , i n t u , i n t i , f l o a t **a, f l o a t b [ l ) I I

i n t k; f l o a t s ;

s = o . o ; f o r ( k = l ; kc=u; k++) s += a [il [kl *b [kl ; r e t u r n ( s ) ;

I

C. tamvec

Forms the inner product s of part of a column of corresponding part of a vector b by setting

a rectangular matrix a and the

Function Parameters: float tarnvec (I, u, i,a, b)

tamvec: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; i: int; column-index of a; a, b: float a[l:u, i:i], b[l:u].

f l o a t tarnvec(int 1, i n t u , i n t i , f l o a t **a, f l o a t b [ l ) I

i n t k; f l o a t s ;

s = o . 0; f o r ( k = l ; kc=u; k++) s += a [k] [ i l *b [kl ; r e t u r n ( s ) ;

1

D. matmat

Forms the inner product s of part of a row of a rectangular matrix a and the corresponding part of a column of a rectangular matrix b by setting

Copyright 1995 by CRC Press, Inc

Page 28: Numerical Library in C for Scientists and Engineers A

Function Parameters: float matmat (I, u, i,j,a, b)

matmat: given the value of s in the above; 1 , ~ : int; lower and upper bound of the running subscript; i,j: int; row-index of a and column-index of b; a, b: float a[i: i, 1: u], b[l: u,jj].

f l o a t rnatrnat(int 1 , i n t u , i n t i , i n t j , f l o a t **a, f l o a t **b) I

i n t k; f l o a t s;

s = o . o ; f o r ( k = l ; k<=u; k++) s += a [ i l [kl *b[kl [ j l ; r e t u r n ( s ) ;

1

E. tammat

Forms the inner product s of part of a column of a rectangular matrix a and the corresponding part of a column of a rectangular matrix b by setting

Function Parameters: float tammat ( I , u, i,j,a, b)

tammat: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; i,j: int; column-indices of a and b, respectively; a, b: float a[l:u,i:i], b[l:u,jj].

f l o a t t ammat( in t 1 , i n t u , i n t i , i n t j , f l o a t **a, f l o a t **b) 1 I

i n t k ; f l o a t s ;

s = o . o ; f o r ( k = l ; k<=u; k++) s += a[k l [ i l *b [k l [ j l ; r e t u r n ( s ) ;

I

F. mattam

Forms the inner product s of part of a row of a rectangular matrix a and the corresponding part of a row of a rectangular matrix b by setting

Copyright 1995 by CRC Press, Inc

Page 29: Numerical Library in C for Scientists and Engineers A

Function Parameters: float mattam (I, u, i,j,a, b)

mattam: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; i,j: int; row-indices of a and b, respectively; a,b: float a[i:i,l:u], bfi$l:u].

float mattam(int 1, int u, int i, int j, float **a, float **b) I

int k; float s;

s=O.O; for (k=l; k<=u; k++) s += a [il [kl *b [ j l [kl ; return ( s ) ;

I

G. seqvec

Forms the sum

Function Parameters: float seqvec (I, u, il,shift, a, b)

seqvec: given the value of s in the above; 1,u: int; lower and upper bound of the running subscript; il: int; lower bound of the vector a; shift: int; index-shifting parameter of the vector b; a,b: float a[p:q], b[l+shift:u+shift]; where p 5 il and q 2 il+(u+l-l)(u-1)/2.

£loat seqvec (int 1, int u, int il, int shift, float a [I , float b [ I ) L

float s;

s=o. 0; for ( ; ls=u; I++) {

s += a [ill *b [l+shiftl ; il += 1;

1 return (s) ;

I

H. scaprdl

Copyright 1995 by CRC Press, Inc

Page 30: Numerical Library in C for Scientists and Engineers A

Forms the stepped inner product

from the elements of two vectors a and b.

Function Parameters: float scaprdl (la,sa,lb,sb,n,a, b)

scaprdl: given the value of s in the above; la,Ib: int; lower bounds of the vectors a and b, respectively; sa,sb: int; index-shifting parameters of the vectors a and b, respectively; a,b: float a[p:q], b[r:s]; the subscripts above and the values of la+&l)*sa and Ib+G;-

I)*sb, j=l, . . ,n should not contradict each other.

float scaprdl (int la, int sa, int lb, int sb, int n, float a[], float b[l )

i int k; float s;

s=o. 0; for (k=l; k<=n; k++) {

s += a [la] *b [lbl ; la += sa; lb += sb;

J return (s) ;

1

I. symmatvec

Forms the inner product of part of a row of a symmetric square matrix c, whose elements are stored columnwise in the linear array a, and the corresponding part of a vector b, by setting

Function Parameters: float symmatvec (I, u, i, a, b)

symmatvec: given the value of s in the above; 1,u: int; lower and upper bound of the vector b, I 2 I ; i: int; row index of a, i 2 I ; a : float a[p:q]; array with:

if i > I then p=(i-l)i/2+1 else p=(l-1)1/2+i and if i > u then q=(i-l)i/2+u else q=(u-l)u/2+i;

b: float b[l:u].

Functions used: vecvec, seqvec.

Copyright 1995 by CRC Press, Inc

Page 31: Numerical Library in C for Scientists and Engineers A

float symrnatvec(int 1, int u, int i, float a[], float b[l) 1

rn=(l>i) ? 1 : i; k=(m* (m-1)) /2; return (vecvec(1, (ic=u) ? i-1 : u, k,b,a) + seqvec(rn,u,k+i,O,a,b));

I

1.5 Real matrix vector products

A. fulmatvec

Premultiplies part of a vector by a submatrix by setting

c, = a,,* b,, i =lr ,..., ur. j=lc

Function Parameters: void fulmatvec (Ir, ur, lc, uc, a, b, c)

r r : int; lower and upper bound of the row-index; Ic,uc: int; lower and upper bound of the column-index; a: float a[lr:ur,lc:uc]; the matrix; b: float b[lc:uc]; the vector; c: float c[lr:ur]; the result a*b is delivered in c.

void fulmatvec(int lr, int ur, int lc, int uc, float **a, float b[l , float c [ I )

I float matvec (int, int, int, float ** , float [ I ) ;

for ( ; lrc=ur; lr++) c [lrl =matvec (lc,uc, lr, a,b) ; 1

B. fultamvec

Premultiplies part of a vector by a transposed submatrix by setting

cj = aii*bi, j=lc ,..., uc.

Function Parameters: void fultarnvec (Ir, ur, lc, uc,a, b,c)

r r : int; lower and upper bound of the row-index; Ic,uc: int; lower and upper bound of the column-index; a: float a[lr:ur,lc:uc]; the matrix; b: float b[lr:ur]; the vector;

Copyright 1995 by CRC Press, Inc

Page 32: Numerical Library in C for Scientists and Engineers A

c: float c[lc:uc]; the result a'*b is delivered in c, a ' denotes the transposed of the matrix a .

void fultamvec (int lr, int ur, int lc, int uc, float **a, float b [I , float c [I )

{ float tamvec (int, int, int, float **, float [I ) ;

C. fulsymmatvec

Premultiplies part of a vector by a submatrix of a linearly stored symmetric matrix by setting

Function Parameters: void fulsymmatvec (Ir, ur, lc, uc, a, b, c)

r r : int; lower and upper bound of the row-index, Ir 2 1; Ic,uc: int; lower and upper bound of the column-index, Ic 2 1; a: float a[l:u]; where

I = min (Ir(1r-1)/2+Ic, Ic(lc-1)/2+lr), u = max (ur(ur-1)/2+uc, uc(uc-1)/2+ur) and the (ij)-th element of the symmetric matrix should be given in ajl;-1,,2+i;

b: float b[lc:uc]; the vector; c: float c[lr:ur]; the result a*b is delivered in c.

void fulsymmatvec(int lr, int ur, int lc, int uc, float a [ I , float b [I , float c [I )

I float symmatvec (int, int, int, float [ I , float [I ) ;

for ( ; lr<=ur; lr++) c [lrl =symmatvec (lc,uc, lr, a, b) ; 1

D. resvec

Determines a residual vector by setting

UC

ci = aij*bj + xc, i=Zr ,..., ur. j=lc

Function Parameters: void resvec (Ir, ur,lc, uc,a, b,c,x)

r r : int; lower and upper bound of the row-index;

Copyright 1995 by CRC Press, Inc

Page 33: Numerical Library in C for Scientists and Engineers A

Ic,uc: int; lower and upper bound of the column-index; a : float a[lr:ur,lc:uc]; the matrix; b: float b[lc:uc]; the vector; x: float; the value of the multiplying scalar; c: float c[lr:ur]; the result a*b+x*c is overwritten on c.

void resvec (int lr, int ur, int lc, int uc, float **a, float b [ I , float c [I, float x)

I float matvec(int, int, int, float ** , float [I ) ;

for ( ; lr<=ur; lr++) c [lrl =matvec (lc,uc, lr, a, b) +c [lrl *x; 1

E. symresvec

Determines a residual vector from a submatrix of a linearly stored symmetric matrix by setting

ci = aiJ*bj + xc, i=Zr ,..., ur.

Function Parameters: void symresvec (Ir, ur,lc, uc,a, b,c,x)

r r : int; lower and upper bound of the row-index, Ir 1 1; Ic,uc: int; lower and upper bound of the column-index, Ic 2 1; a : float a[l:u]; where

I = min (Ir(1r-1)/2+lc, Ic(1c-I)R+lr), u = max (ur(ur-1)/2+uc, uc(uc-1)/2+ur) and the (ij)-th element of the symmetric matrix should be given in aj0.1),2+,;

b: float b[lc:uc]; the vector; x: float; the value of the multiplying scalar; c: float c[lr:ur]; the result a*b+x*c is overwritten on c.

void symresvec(int lr, int ur, int lc, int uc, float a[], float b[l, float c[l, float x)

float symmatvec(int, int, int, float [I, float [I 1 ;

for ( ; lrc=ur; lr++) c [lr] =symmatvec (lc, uc, lr, a, b) +c [lrl *x; 1

1.6 Real matrix matrix products

A. hshvecmat

Premultiplies a submatrix by an elementary reflector: a=(l-xuTu)a where a,-lr+l,j-lc+l=a,j (i=h ,..., ur; j = k ,..., uc), U , ~ ~ ~ + ~ = U , (i=lr ,..., ur).

Copyright 1995 by CRC Press, Inc

Page 34: Numerical Library in C for Scientists and Engineers A

Function Parameters: void hshvecmat (Ir, ur, lc, uc,x, u, a)

r r : int; lower and upper row indices; Ic,uc: int; lower and upper column indices; x: float; the Householder constant; u: float u[lr:ur]; the Householder vector; a: float a[lr:ur,lc:uc]; the matrix to be premultiplied by the Householder matrix.

Functions used: tamvec, elmcolvec.

void hshvecmat (int lr, int ur, int lc, int uc, float x, float u [ I , float **a)

I void elmcolvec(int, int, int, float * * , float [I , float) ; float tamvec(int, int, int, float ** , float [ I ) ;

for ( ; lcc=uc; lc++) elmcolvec (lr,ur, lc,a,u, tamvec (lr,ur, lc, a,u) *x) ; I

B. hshcolmat

Premultiplies one submatrix by an elementary reflector formed from a column of another: a=(I-xuTu)a where ak++, j-lc+l =akl (k=lr, . . . , ur; j = k , . . . , uc), u ~ - ~ ~ + ~ = Uki (k= lr, . . . , ur) .

Function Parameters: void hshcolmat (Ir, ur, lc, uc, i,x, u,a)

r r : int; lower and upper row indices; Ic,uc: int; lower and upper column indices; i: int; the column index of the Householder vector; x: float; the Householder constant; u: float u[lr:ur, i:i]; the Householder vector; a: float a[lr:ur,lc:uc]; the matrix to be premultiplied by the Householder matrix.

Functions used: tammat, elmcol.

void hshcolmat(int lr, int ur, int lc, int uc, int i, float x, float **u, float **a)

I 1

void elmcol (int, int, int, int, float ** , float ** , float) ; float tammat(int, int, int, int, float **, float * * I ;

for ( ; lc<=uc; lc++) elmcol (lr,ur, lc, i, a,u, tammat (lr,ur, lc, i, a,u) *x) ; 1

C. hshrowmat

Premultiplies one submatrix by an elementary reflector formed from a row of another: - a= (I-xuTu)a where a,,,, ,,+,-a,, ( k = l r . . . r ; j=Ic,. . ., uc), ukmlr+,= U,,,

(k=lr, . . . , ur) .

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 35: Numerical Library in C for Scientists and Engineers A

void hshrowmat (lr, ur,lc, uc, i,x, u,a) r r : int; lower and upper row indices; Ic,uc: int; lower and upper column indices; i: int; the row index of the Householder vector; x: float; the Householder constant; u: float u[i:i,lr:ur]; the Householder vector; a : float a[lr:ur,lc:uc]; the matrix to be premultiplied by the Householder matrix.

Functions used: matmat, elmcolrow.

void hshrowmat (int lr, int ur, int lc, int uc, int i, float x, float **u, float **a)

float matmat (int, int, int, int, float **, float * * ) ; void elmcolrow (int, int, int, int, float ** , float ** , float) ;

for ( ; lc<=uc; lc++) elmcolrow(lr,ur,lc,i,a,u,matmat(lr,ur,i,l~,~,a~*~~;

hshvectam

Postmultiplies a submatrix by an elementary reflector: a=(I-xuTu)a where ai-rr+lsrc+r =a,,, (i=lr, . . . , ur; j=lc, .. . , uc), u,-,+, =u, (i=lc, . . ., uc) .

Function Parameters: void hshvectam (Ir, ur,lc, uc,x, u,a)

r r : int; lower and upper row indices; lc,uc: int; lower and upper column indices; x: float; the Householder constant; u: float u[lc:uc]; the Householder vector; a: float a[lr:ur,lc:uc]; the matrix to be postmultiplied by the Householder matrix.

Functions used: matvec, elrnrowvec.

void hshvectam(int lr, int ur, int lc, int uc, float x, float u[l, float **a)

{ float matvec (int, int, int, float **, float [I ) ; void elmrowvec (int, int, int, float ** , float [ I , float) ;

for ; lrc=ur; lr++) elmrowvec (lc,uc, lr, a,u,matvec (lc,uc, lr, a,u) *x) ; 1

E. hshcoltam

Postmultiplies one submatrix by an elementary reflector formed from a column of another: - a= (I-xuTu)a where ak.lr+l,,-lc+l -akj (kdr , . . . , Ur; j=k,. . . , UC), u ~ - , ~ + ~ = Uki

(k=lc, . . . , uc) .

Function Parameters: void hshcoltam (lr, ur,lc, uc, i,x, u,a)

r r : int; lower and upper row indices;

Copyright 1995 by CRC Press, Inc

Page 36: Numerical Library in C for Scientists and Engineers A

Ic,uc: int; lower and upper column indices; i: int; the column index of the Householder vector; x: float; the Householder constant; u: float u[lc:uc, i:i]; the Householder vector; a: float a[lr:ur,lc:uc]; the matrix to be postmultiplied by the Householder matrix.

Functions used: matmat, elmrowcol.

void hshcoltam(int lr, int ur, int lc, int uc, int i, float x, float **u, float **a)

' float matmat (int, int, int, int, float ** , float **) ; void elmrowcol(int, int, int, int, float ** , float ** , float);

for ( ; lr<=ur; lr++) elmrowcol(lc,uc,lr,i,a,u,matmat(lc,uc,lr,i,a,u~*x~; 1

F. hshrowtam

Postmultiplies one submatrix by an elementary reflector formed from a row of another: - a=(l-xuTu)a where Uk-b+lSlc+l-Ukl (k=lr, ..., ur; j = k ,..., UC), ~ ~ - ~ ~ + ~ = u ~ , ~

(k=lc, . . . , uc) .

Function Parameters: void hshrowtam (Ir, ur,lc,uc, i,x, u,a)

r , : int; lower and upper row indices; Ic,uc: int; lower and upper column indices; i: int; the row index of the Householder vector; x: float; the Householder constant; u: float u[i: i, lc: uc]; the Householder vector; a: float a[lr:ur,lc:uc]; the matrix to be postmuitiplied by the Householder matrix.

Functions used: mattam, elmrow.

void hshrowtam(int lr, int ur, int lc, int uc, int i, float x, float **u, float **a)

I float mattam(int, int, int, int, float **, float * * ) ; void elmrow(int, int, int, int, float **, float ** , float);

for ( ; lr<=ur; lr++) elmrow(lc,uc,lr,i,a,u,mattam(lc,uc, lr,i,a,u) *x) ; 1

1.7 Real vector and matrix - Elimination

A. elmvec

Adds a constant multiple of part of a vector b to part of a vector a by setting a, = ~ , + x b , + ~ ~ ~ ((i=l,l+l, ..., u).

Function Parameters: void elmvec (I,u,shift,a, b,x)

Copyright 1995 by CRC Press, Inc

Page 37: Numerical Library in C for Scientists and Engineers A

1,u: int; lower and upper bound of the running subscript; shifi: int; index-shifting parameter of the vector b; a, b: float a[l:u], b[l+shift:u+shijl]; x: float; elimination factor.

void elmvec(int 1, int u, int shift, float a[], float b[l , float x) {

for ( ; l<=u; 1++) a[l] += b[l+shiftl*x; 1

B. elmcol

Adds a constant multiple of part of a column of a rectangular matrix b to part of a column of a rectangular matrix a by setting

ak, = a,,+xb,, (k=E, E+ I,.. ., u).

Function Parameters: void elmcol (I, u, i,j,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; column-index of a; j : int; column-index of b; a, b: float a[l:u, i:i], b[l:u Jg]; x: float; elimination factor.

void elmcol(int 1, int u, int i, int j, float **a, float **b, float x) {

for ( ; lc=u; I++) a[ll [il += b[ll [jl *x; 1

C. elmrow

Adds a constant multiple of part of a row of a rectangular matrix b to part of a row of a rectangular matrix a by setting

a, , = a,,+xb,,, (k=l, l+l,. . ., u).

Function Parameters: void elrnrow (I, u, i,j,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; row-index of a ; j : int; row-index of b; a, b: float a[i: i,l:u], bbj,l:u]; x: float; elimination factor.

void elmrow(int 1, int u, int i, int j, float **a, float **b, float x) I

for ( ; l<=u; I++) a[il ill += b[jl [ll*x; 1

D. elmveccol

Copyright 1995 by CRC Press, Inc

Page 38: Numerical Library in C for Scientists and Engineers A

Adds a constant multiple of part of a column of a rectangular matrix b to part of a vector a by setting

a, = ak+xbkj (k=l, l+l , . .., u).

Function Parameters: void elmveccol (I, u, i,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; column-index of b; a, b: float a[l:u], b[l:u, i:i]; x: float; elimination factor.

void elrnveccol(int 1, int u, int i, float a[], float **b, float x) I

for (; lc=u; I++) a [ll += b[ll [il *x; I

E. elmcolvec

Adds a constant multiple of part of a vector b to part of a column of a rectangular matrix a by setting

aki = ak,+xbk (k=l,l+l, ..., u).

Function Parameters: void elmcolvec (I, u, i, a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; column-index of a; a, b: float a[l:u, i:i], b[l:u]; x: float; elimination factor.

void elmcolvec(int 1, int u, int i, float **a, float b[l , float x) (

for (; lc=u; I++) a [ll [il += b[ll *x; I

F. elmvecrow

Adds a constant multiple of part of a row of a rectangular matrix b to the corresponding part of a vector a by setting

a, = a,+xb,, (k=l,l+l, ..., u).

Function Parameters: void elmvecrow (I, u, i,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; row-index of b; a, b: float a[l:u], b[i:i, l:u]; x: float; elimination factor.

void elmvecrow(int 1, int u, int i, float a[], float **b, float x) I

for ( ; l<=u; 1++) a[ll += b[il [ll*x; I

Copyright 1995 by CRC Press, Inc

Page 39: Numerical Library in C for Scientists and Engineers A

G. elmrowvec

Adds a constant multiple of part of a vector b to the corresponding part of a row of a rectangular matrix a by setting

a , , = a,,,+xb, (k=l,l+l, ..., ti).

Function Parameters: void elmrowvec (I, u, i, a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; row-index of a; a, b: float a[i: i, l:u], b[l:u]; x: float; elimination factor.

void elmrowvec (int 1, int u, int i, float **a, float b[] , float x) {

for ( ; lc=u; I++) a [il [ll += b [ll *x; 1

H. elmcolrow

Adds a constant multiple of part of a row of a rectangular matrix b to the corresponding part of a column of a rectangular matrix a by setting

a,, = ~ , , + x b , , ~ (k=l,l+l, ..., u).

Function Parameters: void elmcolrow (I, u, ij,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; column-index of a; j: int; row-index of b; a,b: float a[l:u,i:i], b/jg,l:u], when a=b then correct elimination is guaranteed only

when the row and column are disjunct; x: float; elimination factor.

void elmcolrow(int 1, int u, int i, int j, float **a, float **b, float x) {

for (; l<=u; I++) a[l] [il += b[j l [ll *x; 1

I. elmrowcol

Adds a constant multiple of part of a column of a rectangular matrix b to the corresponding part of a row of a rectangular matrix a by setting

a , , = a,,+xb,, @=I, E+l, ..., u).

Function Parameters: void elmrowcol (I, u, ij,a, b,x)

1,u: int; lower and upper bound of the running subscript; i: int; row-index of a;

Copyright 1995 by CRC Press, Inc

Page 40: Numerical Library in C for Scientists and Engineers A

j : int; column-index of b; a,b: float a[i:i,l:u], b[l:u,j~], when a=b then correct elimination is guaranteed only

when the row and column are disjunct; x: float; elimination factor.

void elmrowcol(int 1, int u, int i, int j, float **a, float **b, float x) I

for ( ; lc=u; 1++) a[il [ll += b[ll [jl *x; 1

J. maxelmrow

Perfoms the same operations as elmrow and, in addition, sets maxelmrow=l if I > u and otherwise maxelmrow=m where m is that value of k for which I alk I is a maximum over k=l,l+l, ..., u.

Function Parameters: int maxelrnrow ( I , u, i,j,a, b,x)

maxelmrow: delivers the index of the maximal element after elimination step upon a; 1,u: int; lower and upper bound of the running subscript; i: int; row-index of a; j : int; row-index of b; a, b: float a[i:i, l:u], b[i: i, l:u]; x: float; elimination factor.

#include cmath.h>

int maxelmrow(int 1, int u, int i, int j, float **a, float **b, float x) I

int k; float r, s;

s=o.o; for (k=l; kc=u; k++) (

r= (a [il [kl += b [j] [kl *x) ; if (fabs(r) > s) {

s=fabs (r) ; l=k;

1 1

return (1) ; 1

1.8 Real vector and matrix - Interchanging

A. ichvec

Interchanges two parts of the same vector a by setting a,-ai+sh$ (i=l,l+l, ..., u).

Function Parameters: void ichvec (I, u,shift,a)

1,u: int; lower and upper bound of the running subscript; shift: int; index-shifting parameter;

Copyright 1995 by CRC Press, Inc

Page 41: Numerical Library in C for Scientists and Engineers A

a: float a[p:q]; p and q should satisfy: p sf, q 2 u, p ll+shift, q qlu+shift.

void ichvec(int 1, int u, int shift, float a[]) {

float r;

for ( ; lc=u; I++) { r=a [ll ; a [l] =a [l+shiftl ; a [l+shiftl =r;

1 I

B. ichcol

Interchanges corresponding parts of two columns of the same rectangular matrix a by setting a,,--ak, (k=l, l+l , ..., u).

Function Parameters: void ichcol (I, u,i,j,a)

I,u: int; lower and upper bound of the running subscript; i,j: int; column-indices of a; a: float a[l:u,p:q]; p and q should satisfy: p l i, p 5 , q 2 i, q 2 j .

void ichcol(int 1, int u, int i, int j, float **a) I 1

float r;

for ( ; l<=u; I++) { r=a Ill [il ; a [ll Iil =a ill 111 ; a [ll Ijl =r;

I I

C. ichrow

Interchanges corresponding parts of two rows of the same rectangular matrix a by setting a,,k-aj,k (k=l, l+l , ..., u).

Function Parameters: void ichrow (I,u, i,j,a)

1,u: int; lower and upper bound of the running subscript; i,j: int; row-indices of a; a: float a[p:q,l:u]; p and q should satisfy: p 5 i, p Sj, q 2 i, q l j ;

void ichrow(int 1, int u, int i, int j, float **a) I

float r;

for ( ; lc=u; I++) { r=a [il [ll ; a Iil Ill =a[jl 111 ; a [j I Ill =r;

1 1

Copyright 1995 by CRC Press, Inc

Page 42: Numerical Library in C for Scientists and Engineers A

D. ichrowcol

Interchanges corresponding parts of a row and a column of the same rectangular matrix a by setting

a,pa, (k=l , l+l ,..., u).

Function Parameters: void ichrowcol (I, u, i,j,a)

1,u: int; lower and upper bound of the running subscript; i: int; row-index of a; j: int; column-index of a; a: float a[p:q,r:s]; p, q, r and s should satisfy: p 5 i, p I, q 2 i, q 2 u, r Sj, r 5 I, s 2j and s 1 u,

furthermore the row and column to be interchanged should be disjoint.

void ichrowcol(int 1, int u, int i, int j, float **a) (

float r;

for ( ; l<=u; I++) { r=a [il [ll ; a [il 111 =a [ll [jl ; a [ll [jl =r;

1

E. ichseqvec

Interchanges two parts of the same vector by setting

ail+o+l-1)o-1)/2+*a j+shifr ( 7 4 , I + ] , . . ., 4.

Function Parameters: void ichseqvec (I, u, il,shift,a)

1,u: int; lower and upper bound of the running subscript; il: int; lower bound of the vector a; shift: int; index-shifting parameter; a: float a[p:q]; it is assumed that the values of I+shift, u+shift and il+(u+l-l)(u-1)/2 are

not out of range.

void ichseqvec(int 1, int u, int il, int shift, float a[] ) 1

float r;

for ( ; l<=u; 1++) { r=a [ill ; a [ill =a [l+shiftl ; a [l+shiftl =r; il += 1;

F. ichseq

Interchanges two parts of the same vector by setting

a;/+0+/-1)&1)/2~a shifr+i/+o+/-I)o-l)/2 (7=l1 l+l , . ..,

Copyright 1995 by CRC Press, Inc

Page 43: Numerical Library in C for Scientists and Engineers A

Function Parameters: void ichseq ( I , u, il,shift,a)

1,u: int; lower and upper bound of the running subscript; il: int; lower bound of the vector a; shift: int; index-shifting parameter; a: float a[p:q]; it is assumed that the values of il+shift+0+l-I)~-l)/2, j=l, ..., u, do not go

out of range.

f o r ( ; l < = u ; 1++) { r=a [ i l l ; a [ i l l =a [ i l + s h i f t l ; a [ i l + s h i f t l =r;

1.9 Real vector and matrix - Rotation

A. rotcol

Rotates two columns of a rectangular matrix by setting - a,, = ca,, + sau akj - cakj - saki (k=l,l+l, ..., u).

Function Parameters: void rotcol (l,u, i J,a,c,s)

1,u: int; lower and upper bound of the running subscript; i j : int; column-indices of the array a; a: float a[l:u,p:q]; p and q should satisfy: p 5 i, p Sj, q T i and q Tj; c,s: float; rotation factors.

void r o t c o l ( i n t 1, i n t u , i n t i , i n t j , f l o a t **a, f l o a t c , f l o a t s) I

f l o a t x , y ;

f o r ( ; l < = u ; I++) { x=a [ l l [ i l ; y=a[ l l [ j l ; a [1] [ i l =x*c+y*s; a [ l l [ j l =y*C-x*s;

1 1

B. rotrow

Rotates two rows of a rectangular matrix by setting - a i , k = c a i , k + ~ a j , , k a j , k - ~ a j , k - ~ a , , k (k=l, l+ l , . . ., u).

Function Parameters: void rotrow (I,u,ij,a,c,s)

1,u: int; lower and upper bound of the running subscript;

Copyright 1995 by CRC Press, Inc

Page 44: Numerical Library in C for Scientists and Engineers A

i,j: int; row-indices of the array a; a: float a[p:q,l:u]; p and q should satisfy: p 5 i, p Sj, q 2 i and q 2 j ; c,s: float; rotation factors.

void rotrow(int 1, int u, int i, int j, float **a, float c, float s) {

float x, y;

for ( ; lc=u; I++) ( x=a [il [ll ; y=a[jl [ll; a [i] [l] =x*c+y*s; a [j] [l] =y*c-x*s;

1 1

1.10 Real vector and matrix - Norms

A. infnrmvec

Computes the co-norm of part of a vector and determines the index of the element with largest absolute value (p = max I ai I (I S i 5 u) and the smallest k such that I a, 1 =p (1 5 k S u)).

Function Parameters: float infnrmvec (I, u, k, a)

infnrmvec: delivers the oo-norm of the vector a, the value of p above; 1,u: int; lower and upper bound of the index of the vector a, respectively; k: int *; exit: the value of k above; a: float a[l:u].

float infnrmvec(int 1, int u, int *k, float a[]) I

float r, max;

max=O. 0 ; *k=l; for ( ; lc=u; I++) {

r=fabs (a [ll ) ; if (r > max) {

max=r; *k=l;

1 1

return (max) ; 1

B. infnrmrow

Computes the co-norm of part of a row of a rectangular matrix, and determines the index of the element with largest absolute value (p = rnax I ajj I (1 5j 5 u) and the smallest k such that Ia;,kI=p (Isksu)).

Function Parameters: float infnrrnrow (1, u, i, k, a)

infnrmrow: delivers the co-norm of the row vector of a, the value of p above;

Copyright 1995 by CRC Press, Inc

Page 45: Numerical Library in C for Scientists and Engineers A

1,u: int; lower and upper bound of the column index of a, respectively; i: int; the row index; k: int *; exit: the value of k above; a: float a[i:i,l:u].

float infnrmrow(int 1, int u, int i, int *k, float **a) 1 6

float r, max;

max=O. 0 ; *k=l; for ( ; l<=u; 1++) {

r=fabs (a [il [ll ) ; if (r > max) {

max=r ;

C, infnrmcol

Computes the oo-norm of part of a column of a rectangular matrix, and determines the index of the element with largest absolute value ( p = max I ai j I (I 5 i 5 u) and the smallest k such that lakjl=p ( I S k S u ) ) .

Function Parameters: float infnrmcol (I, u,j, k, a)

infnrmcol: delivers the oo-norm of the column vector of a, the value of p above; 1,u: int; lower and upper bound of the row index of a, respectively; j : int; the column index; k: int *; exit: the value of k above; a: float a[l:u,jj].

#include <math.h>

float infnrmcol(int 1, int u, int j, int *k, float **a) I

float r, max;

max=O. 0 ; *k=l; for ( ; l<=u; I++) {

r=fabs (a [ l l [ j I ) ; if (r > max) {

max=r :

D. infnrmmat

Computes the oo-norm of a submatrix and determines the index of the row whose 1-norm is equal to the oo-norm of the submatrix:

Copyright 1995 by CRC Press, Inc

Page 46: Numerical Library in C for Scientists and Engineers A

and the smallest b such that

Function Parameters: float infnrmmat (Ir, ur, lc, uc, kr, a)

infnrmmat: delivers the a-norm of the matrix a, the value of p above; r r : int; lower and upper bound of the row index, respectively; lc,uc: int; lower and upper bound of the column index, respectively; b : int *; exit: the value of b above; a: float a[lr:ur, lc:uc].

Function used: onenrmrow.

float infnrmmat(int lr, int ur, int lc, int uc, int *kr, float **a) (

float onenrmrow (int, int, int, float * * ) ; float r, max;

rnax=O. 0 ; *kr=lr; for ( ; lr<=ur; lr++) {

r=onenrmrow(lc,u~, lr, a) ; if (r > max) {

max=r ; *kr=lr;

1 return (rnax) ;

1

E. onenrmvec

Computes the 1-norm of part of a vector:

Function Parameters: float onenrmvec (I, u,a)

onenrmvec: delivers the 1-norm of the vector a, the value of p above; 1,u: int; lower and upper bound of the index of the vector a, respectively; a : float a[l:u].

Copyright 1995 by CRC Press, Inc

Page 47: Numerical Library in C for Scientists and Engineers A

float onenrmvec(int 1, int u, float a[]) (

float sum;

sum=O. 0 ; for ( ; l<=u; I++) sum += fabs (a [ll ) ; return (sum) ;

I

F. onenrmrow

Computes the I-norm of part of a row of a rectangular matrix:

Function Parameters: float onenrmrow (I, u, i, a)

onenrmrow: delivers the 1-norm of a row vector, the value of p above; 1,u: int; lower and upper bound of the column index of a, respectively; i: int; the row index; a: float a[i:i,l:u].

float onenrmrow(int 1, int u, int i, float **a)

float sum;

sum=O. 0 ; for ( ; l<=u; I++) sum += fabs(a[il 111); return (sum) ;

I

G. onenrmcol

Computes the 1-norm of part of a column of a rectangular matrix:

Function Parameters: float onenrmcol (I, u,j, a)

onenrmcol: delivers the 1-norm of a column vector, the value of p above; I,u: int; lower and upper bound of the row index of a, respectively; j: int; the column index; a: float a[l:u,j:j].

Copyright 1995 by CRC Press, Inc

Page 48: Numerical Library in C for Scientists and Engineers A

float onenrmcol (int 1, int u, int j, float **a) I

float sum;

sum=O. 0 ; for ( ; lc=u; I++) sum += fabs(a 111 [jl ) ; return (sum) ;

1

H. onenrmmat

Computes the l-norm of a submatrix and determines the index of the column whose l-norm is that of the submatrix:

and the smallest kc such that

Function Parameters: float onenrmmat (lr, ur, lc, uc, kc, a )

onenrmmat: delivers the l-norm of the matrix a , the value of p above; r : int; lower and upper bound of the row index, respectively; Ic,uc: int; lower and upper bound of the column index, respectively; kc: int *; exit: the value of kc above; a : float a[lr: ur, lc: uc].

Function used: onenrmcol.

float onenrmmat(int lr, int ur, int lc, int uc, int *kc, float **a) {

float onenrmcol(int 1, int u, int j, float **a) ; float r, max;

max=O. 0 ; *kc=lc; for ( ; lc<=uc; lc++) (

r=onenrmcol (lr, ur, lc, a) ; if (r > max) {

max=r :

1

return (max) ; I

I. absmaxmat

Copyright 1995 by CRC Press, Inc

Page 49: Numerical Library in C for Scientists and Engineers A

Computes the absolute value of an element with largest absolute value belonging to a submatrix, and the row and column indices of the element in question (p = max 1 a, , 1 , (Ir I k I ur, Ic 5 h 5 uc) and the smallest i for the smallest j such that p = I aij I ).

Function Parameters: float absmaxmat (Ir, ur, lc, uc, i,j, a)

absmaxmat: delivers for a given matrix a the modulus of an element which is of maximum absolute value, the value of p above;

r r : int; lower and upper bound of the row index, respectively; Ic,uc: int; lower and upper bound of the column index, respectively; i : int *; exit: the row and column index of an element for which the modulus is maximal; a: float a[lr:ur, lc:uc].

Function used: infnrmcol.

float absmaxmat(int lr, int ur, int lc, int uc, int *i, int *j, float **a) I

float infnrmcol (int, int, int, int * , float * * ) ; int ii; float r, max;

max=O. 0 ; *i=lr; *j=lc; for ( ; lcc=uc; lc++) {

r=infnrmcol (lr,ur, lc, &ii, a) ; if (r > max) {

max=r ; *i=ii. *j=lc;

1 1

return (max) ; 1

1.1 1 Real vector and matrix - Scaling

reascl

Normalizes the (non-null) columns of a matrix in such a way that, in each column, an element of maximum absolute value equals 1. The normalized vectors are delivered in the corresponding columns of the matrix.

Function Parameters: void reascl (a,n,nl,n2)

a : float a[l:n,nl:n2]; entry: the n2-nl+l column vectors must be given in a; exit: the normalized vectors (i.e. in each vector an element of maximum absolute

value equals 1) are delivered in the corresponding columns of a; n: int; the number of rows of a ; nl,n2: int; the lower and upper bound of the column indices of a .

void reascl(f1oat **a, int n, int nl, int n2) {

Copyright 1995 by CRC Press, Inc

Page 50: Numerical Library in C for Scientists and Engineers A

int i, j; float s;

for (j=nl; j<=n2; j++) { = o . 0:

if (S ! = 0.0) for (i=l; i<=n; i++) a[il [jl /= s;

\

1.12 Complex vector and matrix - Multiplication

A. comcolcst

Replaces part of a column of a matrix with complex elements by a constant complex multiple of that part:

a. .=xu. i=l, ..., u. 1J IJ'

Function Parameters: void comcolcst (l,u,j,ar,ai,xr,xi)

1,u: int; lower and upper bound of the column vector;

j: int; column-index of the column vector; ar,ai: float ar[l:ujj], ai[l:ujj];

entry: ar: real part; ai: imaginary part of the column vector;

exit: the transformed complex column; xr,xi: float;

entry: xr: real part of the multiplication factor; xi: imaginary part of the multiplication factor.

Function used: commul.

void comcolcst(int 1, int u, int j, float **ar, float **ai, float xr, float xi)

( void comrnul(float, float, float, float, float * , float * ) ;

B. comrowcst

Replaces part of a row of a matrix with complex elements by a constant complex multiple of that part:

a,,,=xa ,,, j=l, ..., u.

Function Parameters: void comrowcst (I, u, i,ar,ai,xr,xi)

1,u: int; lower and upper bound of the row vector;

j : int; row-index of the row vector;

Copyright 1995 by CRC Press, Inc

Page 51: Numerical Library in C for Scientists and Engineers A

ar, ai: float ar[i: i, I: u], a#: i, I: u]; entry: ar: real part;

ai: imaginary part of the row vector; exit: the transformed complex row;

xr,xi: float; entry: xr: real part of the multiplication factor;

xi: imaginary part of the multiplication factor.

Function used: comrnul.

void comrowcst(int 1, int u, int i, float **ar, float **ai, float xr, float xi)

I 1

void commul(float, float, float, float, float *, float * ) ;

for ( ; lc=u; I++) commul (ar [il [l] ,ai [i] [l] ,xr,xi, &ar [il [ll , &ai [il [ll ) ;

1

1.13 Complex vector and matrix - Scalar products

A. commatvec

Forms the inner product of part of a row of a matrix and part of a vector, both having complex elements:

Function Parameters: void commatvec (1, u, i,ar,ai, br, bi,rr,ri)

1,u: int; lower and upper bound of the vectors; i: int; the row index of a r and ai; ar, ai: float ar[i:i, l:u], ai[i: i, I: u];

entry: ar: real part and ai: imaginary part of the matrix;

br, bi: float br[l:u],bi[l:u]; entry: br: real part and

bi: imaginary part of the vector; i : float *;

exit: IT: the real part and ri: the imaginary part of the scalar product.

Function used: matvec.

void commatvec(int 1, int u, int i, float **ar, float **ai, float br [I, float bi [ I , float *rr, float *ri)

I 1

float matvec(int, int, int, float ** , float [ I ) ; float mv:

Copyright 1995 by CRC Press, Inc

Page 52: Numerical Library in C for Scientists and Engineers A

rnv=matvec (1, u, i , a r , b r ) -matvec (l,u, i , a i , b i ) ; *ri=rnatvec (l,u, i , ai ,br)+matvec (l,u, i , a r , b i ) ; *rr=rnv;

I

B. hshcomcol

Given the components aij (i=l+l, ..., n) of the j-th column of the complex valued matrix a, and a real tolerance tol, and if

this function determines a complex vector c such that, the j-th column of

a = (I-2ccT/(cTc))a ( where CT denotes conjugating and transposing)

has zero elements in the second, ..., last positions, and computes

and the first component of c.

Function Parameters: int hshcomcol ( I , u,j,ar,ai, tol,k,c,s,t)

hshcomcol: if the condition (1) above is satisfied then a transformation is performed and hshcomcol=l , otherwise hshcomcol=O.

1 , j : int; the complex vector to be transformed, must be given in the j-th column from row I until row u of a complex matrix;

ar,ai: float ar[l:u,jj:j],ai[l:u,jj:j]; entry: the real part and the imaginary part of the vector to be transformed must be

given in the arrays a r and ai, respectively; exit: if the condition (1) above is satisfied then the real part and the imaginary part

of the vector c of the Householder matrix are delivered in the arrays a r and ai, respectively, otherwise the arrays a r and ai are unaltered;

tol: float; entry: a tolerance (for example, the square of the machine precision times a norm of

the matrix under consideration); k,c,s: float *;

exit: if the condition (1) above is satisfied then the modulus, cosine and sine of the argument of the first element of the transformed vector are delivered in k, c and s, respectively, otherwise the modulus, cosine and sine of the argument of the complex number ar[lj]+ai[l,j]*I are delivered;

t: float *; exit: if the condition (1) above is satisfied then it has the value t in the above,

otherwise it has the value - 1 .

Functions used: carpol, tammat.

Copyright 1995 by CRC Press, Inc

Page 53: Numerical Library in C for Scientists and Engineers A

int hshcomcol(int 1, int u, int j, float **ar, float **ai, float tol, float *k, float *c, float *s, float *t)

void carpol(float, float, float *, float * , float * ) ; float tarnmat (int, int, int, int, float ** , float * * ) ; float vr, mod, h, arlj, ailj;

vr=tammat (l+l,u, j, j, ar, ar) +tammat (l+l,u, j , j, ai, ai) ; arlj=ar[ll [jl ; ailj=ai [ll [jl ; carpol(arlj,ailj,&mod,c,s); if (vr > tol) {

vr += arlj;arlj+ailj *ailj ; h = *k = sart (vr) : . . . . *t=vr+mod*h; if (arlj == 0.0 && ailj == 0.0)

ar [ll [ j 1 =h; else {

arc11 [jl =arlj + *c * *k; ai [ll [j I =ailj + *s *k;

*c = - *c; return (1) ;

) else { *k=mod; *t = -1.0; return (0) ;

C. hshcomprd

Given the components of the complex vector c, and

t = (cCT)/2 ( where CT denotes conjugating and transposing)

and the submatrix a composed of the elements a,, (k=i,.. ., ii; h=l,. .., u) of the complex matrix a, forms the product

it being known that c is such that the elements in rows I+l, ..., u of the j-th column of a are zero.

Function Parameters: void hshcomprd (i, ii,l, u,j,ar,ai, br, bi, t )

i I , u: int; the complex matrix to be premultiplied must be given in the I-th to u-th column from row i to row ii of a complex matrix;

j: int; the complex vector c of the Householder matrix must be given in the j-th column from row i to row ii of a complex matrix given in (br, bi).

ar, ai: float ar[i: ii, I: u], ai[i: ii, l:u]; entry: the real part and the imaginary part of the vector to be premultiplied must be

given in the arrays a r and ai, respectively; exit: the real part and the imaginary part of the resulting matrix are delivered in the

arrays a r and ai, respectively, otherwise the arrays a r and a i are unaltered; br, bi: float br[i:ii,jj:j], bi[i:ii,jj:j];

Copyright 1995 by CRC Press, Inc

Page 54: Numerical Library in C for Scientists and Engineers A

entry: the real part and the imaginary part of the complex vector c of the Householder matrix must be given in the arrays br and bi, respectively;

t: float; entry: the scalar t above of the Householder matrix (for example, as delivered by

hshcomcol).

Functions used: tammat, elmcomcol.

void hshcomprd(int i, int ii, int 1, int u, int j, float **ar, float **ai, float **br, float **bi, float t)

void elmcomcol (int, int, int, int, float ** , float **, float * * , float ** , float, float) ;

float tammat (int, int, int, int, float **, float * * ) ;

for ( ; l<=u; I++) elmcomcol (i, ii, 1, j, ar, ai,br, bi,

(-tammat (i, ii, j, l,br,ar) -tammat (i, ii, j , l,bi,ai) ) /t, (tammat(i,ii, j,l,bi,ar) -tammat(i,ii, j,l,br,ai) )/t) ;

1

1.14 Complex vector and matrix - Elimination

A. elmcomveccol

Adds a constant complex multiple of part of a column of a rectangular matrix to part of a vector, both having complex elements: a,=a,+xbjj, i=l, ..., u.

Function Parameters: void elmcomveccol (I,u,j,ar,ai, br, bi,xr,xi)

1,u: int; lower and upper bounds of the vectors; j : int; column-index of br and bi; ar, ai: float ar[l: u], ai[l: u];

entry: ar: real part and ai: imaginary part of the vector;

exit: the resulting vector (adds xr+xi*i times the complex column vector given in arrays br and bi to the complex vector given in arrays a r and ai);

br, bi: float br[l:u,jj], bi[l:u,jj]; entry: br: real part and

bi: imaginary part of the column vector; xr,xi: float;

entry: xr: real part and xi: imaginary part of the elimination factor.

Function used: elmveccol.

void elmcomveccol(int 1, int u, int j, float ar[l, float air], float **br, float **bi, float xr, float xi)

( void elmveccol (int, int, int, float [ I , float **, float) ;

elmveccol (l,u, j, ar, br,xr) ; elmveccol(l,u,j,ar,bi,-xi); elmveccol(l,u, j,ai,br,xi) ; elmveccol(l,u, j,ai,bi,xr) ;

Copyright 1995 by CRC Press, Inc

Page 55: Numerical Library in C for Scientists and Engineers A

B. elmcomcol

Adds a constant complex multiple of part of a column of one complex matrix to part of a column of another: a,,=a,,+(xr+xi*i)b,, k=l, ..., u.

Function Parameters: void elmcomcol (I, u, i,j,ar,ai, br, bi,xr,xi)

I, u: int; lower and upper bounds of the vectors; i,j: int;

i: column-index of a r and ai; j: column-index of br and bi;

ar, ai: float ar[l: u, i: i], ai[l:u, i: i]; entry: ar: real part and

ai: imaginary part of the column vector; exit: the resulting vector (adds xr+xi*i times the complex column vector given in

arrays br and bi to the complex column vector given in arrays a r and ai); br, bi: float br[l:u,jj], bi[l:u,jj];

entry: br: real part and bi: imaginary part of the column vector;

xr,xi: float; entry: xr: real part and

xi: imaginary part of the elimination factor.

Function used: elmcol.

void elmcomcol(int 1, int u, int i, int j, float **ar, float **ai, float **br, float **bi, float xr, float xi)

l void elmcol (int, int, int, int, float ** , float ** , float) ;

elmcol(l,u,i, j,ar,br,xr) ; elmcol (l,u,i, j,ar,bi, -xi) ; elmcol (l,u,i, j,ai,br,xi) ; elmcol(l,u,i, j,ai,bi,xr) ;

1

C. elmcomrowvec

Adds a constant complex multiple of part of a vector to part of a row of a rectangular matrix, both having complex elements: aij=aij+xb,, j=l, . . ., u.

Function Parameters: void elmcornrowvec (I, u, i,ar,ai, br, bi,xr,xi)

1 , ~ : int; lower and upper bounds of the vectors; i: int; row-index of a r and ai; ar, ai: float ar[i: i, l:u], ai[i: i, I: u];

entry: ar: real part and ai: imaginary part of the row vector;

exit: the resulting vector (adds xr+xi*i times the complex vector given in arrays br

Copyright 1995 by CRC Press, Inc

Page 56: Numerical Library in C for Scientists and Engineers A

and bi to the complex row vector given in arrays a r and ai); br, bi: float br[l:u], bi[l:u];

entry: br: real part and bi: imaginary part of the vector;

xr,xi: float; entry: xr: real part and

xi: imaginary part of the elimination factor.

Function used: elmrowvec.

void elmcomrowvec(int 1, int u, int i, float **ar, float **ai, float br [I, float bi [I, float xr, float xi)

{ void elmrowvec (int, int, int, float ** , float [I , float) ;

1.15 Complex vector and matrix - Rotation

A. rotcomcol

Rotates two columns of a matrix with complex elements: aki = (cr+ci*i)ak, + saki, akj = (cr+ci*i)a,, - sak, (k=l, ..., u).

Function Parameters: void rotcomcol (I, u, i,j,ar,ai,cr,ci,s)

i j : int; the rotation is performed on the column vectors ar[l:u,i:i], ai[l:u,i:i] and ar[l:u,jj], ai[l:u,jj];

ar, ai: float ar[l: u, ij], ai[l: u, iy]; entry: ar: real part and

ai: imaginary part of the column vectors; exit: the resulting vectors;

cr,ci,s: float; rotation factors.

void rotcomcol(int 1, int u, int i, int j, float **ar, float **ai, float cr, float ci, float s)

float arli,aili,arlj,ailj;

for ( ; l<=u; 1++) { arli=ar [ll [il ; aili=ai [l] [il ; arlj=ar[ll [jl ; ailj=ai [l] [jl ; ar [ll [il =cr*arli+ci*aili-s*arlj ; ai [ll [il =cr*aili-ci*arli-s*ailj ; ar [ll [j I =cr*arlj -ci*ailj+s*arli; ai [l] [j] =cr*ailj+ci*arlj+s*aili;

1 1

B. rotcornrow

Copyright 1995 by CRC Press, Inc

Page 57: Numerical Library in C for Scientists and Engineers A

Rotates two rows of a matrix with complex elements: ai,k=(cr+ci*i)ai ,k+saj,k, aj ,k=(cr+ci*i)aj ,k-sai ,k (k=l) ...) u).

Function Parameters: void rotcornrow (I, u, i,j,ar,ai,cr,ci,s)

, i , j : int; the rotation is performed on the row vectors ar[i:i,l:u], ai[i:i,l:u] and arfij,l:u], aifij,,l: u];

ar,ai: float ar[ij, I: u], ai[i.% I: u]; entry: ar: real part and

ai: imaginary part of the row vectors; exit: the resulting vectors;

cr,ci,s: float; rotation factors.

void rotcomrow(int 1, int u, int i, int j, float **ar, float **ai, float cr, float ci, float s)

1 float aril,aiil,arjl,aijl;

for ( ; lea; I++) { aril=ar [il 111 ; aiil=ai [il [ll ; arjl=ar [jl [ll ; aijl=ai [jl [ll ; ar [i] [l] =cr*aril+ci*aiil+s*arjl; ai [i] [l] =cr*aiil-ci*aril+s*aijl; ar [j] [l] =cr*arjl-ci*aijl-s*aril; ai [j] [l] =cr*aijl+ci*arjl-s*aiil;

I 1

Computes the complex Householder matrix that maps the complex vector (a,,a,) into the direction (1,O): given complex a, and a,, it determines real c and complex s such that

where z is nonzero if 1 a, I + 1 a, 120.

Function Parameters: void chsh2 (alr,ali,a2r,a2i,c,sr,si)

a l r : float; entry: the real part of the first vector component a, above; a l i : float; entry: the imaginary part of the first vector component a, above; a2r: float; entry: the real part of the second vector component a, above; a2i: float; entry: the imaginary part of the second vector component a, above; c: float *; exit: the value of c above; sr,si: float *; exit: the real part and imaginary part of s above.

void chsh2(float alr, float ali, float aZr, float a2i, float *c, float *sr, float *si)

{

Copyright 1995 by CRC Press, Inc

Page 58: Numerical Library in C for Scientists and Engineers A

float r;

if (a2r ! = 0.0 I I a2i ! = 0.0) { if (alr ! = 0.0 I I ali ! = 0.0) (

r=sqrt (alr*alr+ali*ali) ; *c=r; *sr= (alr*a2r+ali*aZi) /r; *si= (alr*a2i-ali*a2r) /r; r=sqrt(*c * *c + *sr * *sr + *si * *si); *c /= r; *sr / = r; *si /= r;

) else ( *si = *c = 0.0; *sr=l.O;

1 ) else (

*c=1.0; *sr = *si = 0.0;

. )

1.16 Complex vector and matrix - Norms

comeucnrm

Computes the Euclidean norm

of the nxn complex band matrix a for which aij=O when I i-j I >Iw.

Function Parameters: float comeucnrm (ar,ai, lw, n)

comeucnrm: float; delivers the Euclidean norm of matrix a with Iw codiagonals, value of p above;

n: int; the order of the matrix; lw: int; the number of lower codiagonals; ar,ai: float ar[l:n, l:n],ai[l:n, l:n]; the real part and imaginary part of the complex matrix

with Iw lower codiagonals.

Function used: mattam.

float comeucnrm(f1oat **ar, float **ai, int lw, int n) 1 ' float rnattam(int, int, int, int, float ** , float * * ) ;

int i,l; float r;

r=O.O; for (i=l; i<=n; i++) {

l=(i>lw) ? i-lw : 1; r += mattam(l,n, i,i,ar,ar) +mattam(l,n,i, i,ai,ai) ;

\ Geturn (sqrt (r) ) ;

1

Copyright 1995 by CRC Press, Inc

Page 59: Numerical Library in C for Scientists and Engineers A

1.17 Complex vector and matrix - Scaling

A. comscl

Scales a sequence of columns, some complex, others pure real of an n-rowed matrix a. The real and imaginary components of the complex columns, and the real elements of the pure real columns are stored in succession in columns n l to n2 of the matrix a. The complex and pure real columns of the original matrix may be distinguished by inspection of the values stored in locations n l to n2 of the real vector im. In succession, starting with j ,=nl, if im(i,)=O, column j, of a contains the elements of a real column of the input a ; if im(jk)+O then im(jk+l)=-im(jk), and columns j, and j,+l of a contain the real and imaginary parts respectively of a complex column of the input a ; in the first case jk+,=jk+l, in the second jk+/=jk+2. The columns are scaled by taking p,=akj where I pj 1 1 aij 1 ( I l i l n ) and aij=aiJb (i=l, ..., n) where j runs through the column suffices of the stored columns of a.

Function Parameters: void comscl (a,n,nl,n2, im)

a : float a[l:n,nl:n2]; entry: each real eigenvector must be given in a column of array a whose

corresponding element of array im equals 0; the real and imaginary part of each complex eigenvector must be given in consecutive columns of array a whose corresponding elements of array im are not equal to 0;

exit: the normalized eigenvectors (i.e. in each eigenvector an element of maximum modulus equals 1) are delivered in the corresponding columns of a;

n: int; the number of rows of array a; nl,n2: int; the lower and upper bound of the column indices of array a ; im: float im[nl:n2]; the imaginary parts of the eigenvalues of which the eigenvectors are

given in the corresponding columns of array a must be given in array im.

void comscl(float **a, int n, int nl, int n2, float im[l) {

int i,j,k; float s,u,v,w,aij,aijl;

for (j=nl; j<=n2; j++) ( s=o . 0 ; if (im[jl ! = 0.0) (

for (i=l; i<=n; i++) { aij=a[il [jl ; aijl=a [il [j+ll ; u=ai j*ai j+ai jl*ai jl; if (U > S) (

s=u;

if (s ! = 0.0) { v=a[kl [jl /s; w = -a[kl [j+lI /s; for (i=l; 1c=n; i++) (

u=a [il [ j I ; s=a [il [j+ll ; a [i] [j] =u*v-s*w; a [il [j+l] =u*w+s*v;

I

Copyright 1995 by CRC Press, Inc

Page 60: Numerical Library in C for Scientists and Engineers A

1 j++;

} else { for (i=l; i<=n; i++)

if (fabs(a[il [jl) > fabs(s) ) s=a[il [jl ; if (s ! = 0.0)

for (i=l; i<=n; i++) a[il [jl / = s;

B. sclcom

Scales the columns n l to n2 of an n-rowed matrix a with complex elements by dividing the elements in each column by the element of largest modulus in that column (with b=akj where I p, 1 =rnax 1 a,j I ( I l i l n), aij=aiJp, ( i=l ,..., n) when p,#O; j = n l ,..., n2)).

Function Parameters: void sclcom (ar,ai,n,nl,n2)

ar,ai: float ar[l:n,nl:n2], ai[l:n,nl:n2]; entry: the real part and the imaginary part of the matrix of which the columns are to

be scaled must be given in the arrays a r and ai, respectively; exit: the real part and imaginary part of the matrix with scaled columns are

delivered in the arrays a r and ai; n: int; the order of the matrix; nl,n2: int; the nl-th to n2-th column vectors are to be scaled.

Function used: comcolcst.

void sclcom(float **ar, float **ai, int n, int nl, int n2)

void comcolcst (int, int, int, float ** , float ** , float, float) ; int i, j,k; float s,r,arij,aiij;

for (j=nl; j<=n2; j++) { s=o.o; for (i=l; i<=n; i++) {

ari j =ar [il [j I ; aiij=ai [il [jl ; r=ari j *ari j +aii j *aii j ; if (r > S ) {

s=r;

1.18 Complex monadic operations

A. comabs

Computes the modulus of a complex number: p = (xr+xi*i 1

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 61: Numerical Library in C for Scientists and Engineers A

float comabs (xr,xi) comabs: float; delivers the modulus of the complex number, value of p above; xr,xi: float; the real part and imaginary part of the complex number, respectively.

#include cmath.h>

float comabs (float xr, float xi) 1

float temp;

xr=fabs (xr) ; xi=fabs (xi) ; if (xi > xr) {

temp=xr/xi; return (sqrt (temp*temp+l.O) *xi) ;

if (xi == 0.0) return (xr) ;

else { temp=xi/xr; return (sqrt (temp*temp+l. 0) *xr) ;

1 1

B. comsqrt

Forms the square root of a complex number.

Function Parameters: void comsqrt (ar,ai,pr,pi)

xr,xi: float; entry: the real part and imaginary part of the complex number, respectively;

pr,pi: float *; exit: the real part and imaginary part of the square root, respectively.

yoid comsqrt(f1oat ar, float ai, float *pr, float *pi) i

float br,bi,h,temp;

if (ar == 0.0 && ai == 0.0) *pr = *pi = 0.0;

else { br=fabs (ar) ; bi=fabs (ai) ; if (bi < br) {

temp=bi/br; if (br c 1.0)

h=sqrt ( (sqrt (temp*temp+l. 0) *O. 5+0.5) *br else

h=sqrt ( (sqrt (temp*temp+l. 0) *O. l25+O. 125 } else {

if (bi c 1.0) { temp=br/bi: h=s rt ( (sqrt (temp*temp+l. 0) *bi+br) *2) *O.

j else 7 if (brcl.0 == 1.0)

h=sqrt (bi*O. 5) ; else {

temp=br/bi; h=sqrt (sqrt (temp*temp+l. 0) *bi*O. l25+br*O. 125) *2;

1 1

1

Copyright 1995 by CRC Press, Inc

Page 62: Numerical Library in C for Scientists and Engineers A

if (ar >= 0.0) { *pr=h; *pi=ai/h*0.5;

) else ( *pi = (ai >= 0.0) ? h : -h; *pr = bi/h*0.5;

C. carpol

Determines the polar form of a complex number: obtains r, c=cos$ and s=sin$ where ar+ai* i=reiO.

Function Parameters: void carpol (ar,ai,r,c,s)

ar,ai: float; entry: the real part and imaginary part of the complex number, respectively;

r,c,s: float *; exit: the modulus of the complex number is delivered in r and the cosine and the

sine of the argument are delivered in c and s, respectively; when ar=ai=O then c = I and r=s=O.

void carpol(f1oat ar, float ai, float *r, float *c, float *s) I 1

float temp;

if (ar == 0.0 && ai == 0.0) { *c = 1.0: *r = *s = 0.0;

) else ( if (fabs(ar) > fabs(ai)) {

temp=ai/ar; *r = fabs (ar) *sqrt (l.O+temp*temp) ;

) else ( temp=ar/ai; *r = fabs (ail *sqrt (l.O+temp*temp) ;

1 *C = ar / *r; *S = ai / *r;

, I

1.19 Complex dyadic operations

A. commul

Forms the product of two complex numbers: rr+ri*i = (ar+ai*i)(br+bi*i).

Function Parameters: void commul (ar,ai, br, bi,rr,ri)

ar,ai: float; entry: the real part and imaginary part of the first complex number, respectively;

br,bi: float;

Copyright 1995 by CRC Press, Inc

Page 63: Numerical Library in C for Scientists and Engineers A

entry: the real part and imaginary part of the second complex number, respectively; r r : float *;

exit: the real part and imaginary part of the product of the two complex numbers, respectively.

void commul(float ar, float ai, float br, float bi, float *rr, float *ri) I

B. comdiv

Forms the quotient of two complex numbers zr+zi*i = (xr+xi*i)l@r+yi*i). yr+yi*i#O.

It is assumed that

Function Parameters: void comdiv (xr,xi, yr,yi,zr,zi)

xr,xi: float; entry: the real part and imaginary part of the first complex number, respectively;

yr,yi: float; entry: the real part and imaginary part of the second complex number, respectively;

zr,zi: float *; exit: the real part and imaginary part of the quotient of the two complex numbers,

respectively.

void comdiv(f1oat xr, float xi, float yr, float yi, float *zr, float *zi) I

float h, d;

if (fabs(yi) < fabs(yr)) { if (yi == 0.0) (

*zr=xr/yr; *zi=xi/yr;

} else { h=yi/yr; d=h*yi+yr; *zr= (xr+h*xi) /d; *zi= (xi-h*xr) /d;

I

1.20 Long integer arithmetic

A. lngintadd

Forms the sum of two multilength integers, each expressed in the form where the 4 are single length nonnegative integers, and B is a single length positive integer: so I max{uo,v,}+l; B2+B not greater than the largest integer having a machine

Copyright 1995 by CRC Press, Inc

Page 64: Numerical Library in C for Scientists and Engineers A

representation.

Function Parameters: void lngintadd (u,v,sum)

u, v: int u[O: u[O]], v[O:v[O]]; entry: the long integers to be added, values of u and v above;

sum: int sum[O,max(u[O],v[O~+ 11; exit: the multilength sum of u and v, while u and v remain unchanged.

Method: see the function Ingintpower.

#define BASE 100 / * value of B in the above * /

void lngintadd(int u [I , int v[] , int sum[] ) 1 L

int lu,lv,diff,carry,i,t,max;

lu=u [OI ; lv=v[Ol ; if (lu >= lv) {

max=lu; diff=lu-lv+l; carry=O ; for (i=lu; i>=diff; i--) {

t=u [il +v[i-diff+ll +carry; carry = (t < BASE) ? 0 : 1; sum [il =t-carry*BASE;

;or (i=diff-1; i>=l; i--) { t=u Iil +carry; carry = (t < BASE) ? 0 : 1; sum [il =t-carry*BASE;

I ) else {

max=lv; diff=lv-lu+l; carry=O ; for (i=lv; i>=diff; i--) {

t=v[il +u [i-diff+ll +carry; carry = (t < BASE) ? 0 : 1; sum [il =t-carry*BASE;

:or (i=diff-1; i>=l; i--) { t=v [il +carry; carry = (t < BASE) ? 0 : 1; sum [il =t-carry*BASE;

\

I if (carry == 1) (

for (i=max; i>=l; i--) sum[i+ll =sum[il ; sum[ll =l; max=max+l;

I sum [ 0 I =max ;

1

Copyright 1995 by CRC Press, Inc

Page 65: Numerical Library in C for Scientists and Engineers A

B. lngintsubtract

Forms the difference of two multilength integers, each expressed in the form

where the i, are single length nonnegative integers, and B is a single length positive integer:

do 2 u,; B2+B not greater than the largest integer having a machine representation.

Function Parameters: void lngintsubtract (u, v, difference)

u, v: int u[O: u[O]], v[O: v[O]]; entry: the long integers to be subtracted, values of u and v above;

difference: int difference[O, u[O]]; exit: the multilength difference u-v, if u<v then difference[O]=O;

u and v remain unchanged.

Method: see the function lngintpower.

#define BASE 100 / * value of B in the above * /

void lngintsubtract (int u [I , int v[l , int difference [I )

I int lu,lv,diff,i,t,j,carry;

lu=u [O] ; 1v=v[0] ; if ( (lu < lv) / I ( (lu == lv) && (u [l] < v[ll ) ) ) {

difference [OI =O; return;

1 diff=lu-lv+l; carry=O ; for (i=lu; i>=diff; i--) {

t=u [il -v[i-diff+ll +carry; carry = (t < 0) ? -1 : 0; difference [il =t-carry*BASE;

\ ior (i=diff-1; i>=l; i--) (

t=u [il +carry; carry = (t c 0) ? -1 : 0; difference [i] =t-carry*BASE;

I

if (carry == -1) { difference [O] =O; return;

) i=1; j=lu; while ((difference [il == 0) && ( j > 1)) {

I--; 1++ ;

Copyright 1995 by CRC Press, Inc

Page 66: Numerical Library in C for Scientists and Engineers A

J difference [O] =j ; if (j c lu)

for (i=l; i<=j ; i++) difference [il =difference [lu+i- jl ; 1

C. lngintmult

Forms the product of two multilength integers, each expressed in the form

where the i, are single length nonnegative integers, and B is a single length positive integer:

p, I u,+v,; B2+B not greater than the largest integer having a machine representation.

Function Parameters: void lngintmult (u,v,product)

u, v: int u[O:u[O]], v[O:v[O]]; entry: the long integers to be multiplied, values of u and v above;

product: int product[O, u[O]+v[O]]; exit: the multilength product of u and v, while u and v remain unchanged.

Method: see the function Ingintpower.

#define BASE 100 / * value of B in the above * /

void lngintmult (int u [I , int v [I , int product [I )

int lu, lv, luv, i, j , carry, t;

lu=u [O] ; lv=v [O] ; luv=lu+lv; for (i=lu+l; i<=luv; i++) product [il =O; for (j=lu; j>=l; j - - ) {

carry=O ; for (i=lv; i>=l; i--) {

t=u [jl *v[il +product [j+il +carry; carry=t/BASE; product [j +i] =t-carry*BASE;

1 product [ j I =carry;

1 if (product [ll == 0) {

for (i=2; ic=luv; i++) product [i-11 =product [il ; luv- - ;

1 product [O] =luv;

lngintdivide

Copyright 1995 by CRC Press, Inc

Page 67: Numerical Library in C for Scientists and Engineers A

Forms the quotient and remainder from two multilength integers, each expressed in the form

where the i, are single length nonnegative integers, and B is a single length positive integer:

qo=uo--vo+l; r o v 0 B2+B not greater than the largest integer having a machine representation.

Function Parameters: void lngintdivide (u,v,quotient,remainder)

u,v: int u[O: u[O]], v[O:v[O]]; entry: u contains the dividend, v the divisor (~0);

quotient,remainder: int quotient[O:u[O]-v[O]+ I], remainder[O:v[O]]; exit: results of the division, u and v remain unchanged.

Method: see the function Ingintpower.

#define BASE 100 / * value of B in the above * /

t int *allocate-integer-vector(int, int); void free-integer-vector(int * , int); int lu, lv, vl, diff, i, t, scale, d, ql, j, carry, *uu, *a;

if (lv == 1) { carry=O ; for (i=l; ic=lu; i++) {

t=carry*BASE+u [i] ; quotient [il =t/vl; carry=t-quotient [il *vl;

iemainder [Ol =l; remainder [ll =carry; if (quotient [ll == 0) {

for (i=2; ic=lu; i++) quotient [i-11 =quotient [il ; quotient [O] =lu - ((lu == 1) ? 0 : 1) ;

} else quotient [O] =lu;

return; I if (lu c lv) {

quotient [Ol =l; quotient [l] =O; for (i=O; i<=lu; i++) remainder [il =u [il ; return;

I

Copyright 1995 by CRC Press, Inc

Page 68: Numerical Library in C for Scientists and Engineers A

Copyright 1995 by CRC Press, Inc

Page 69: Numerical Library in C for Scientists and Engineers A

carry=O ; for (i=l; i<=lv; i++) {

t=carry*BASE+uu [dif f+i] ; remainder [il =t/scale; carry=t-remainder [il *scale;

I ) else

for (i=l; ic=lv; i++) remainder [il =uu [dif f+il ;

/ * correct storage of remainder * / i=l; j =lv; while (remainder [il == 0 && j > 1) {

j--. i++;

\ iemainder LO]= j ; if (j < lv)

for (i=l; ic=j ; i++) remainder [i] =remainder [lv+i- jl ;

/ * unnormalize the divisor v * / if (scale > 1) (

carry=O ; for (i=l; i<=lv; i++) (

t=carry*BASE+v [il ; v[il &/scale; carry=t-v[il *scale;

lngintpower

Forms the single length positive integer power of a multilength integer expressed in the form

where the 5 are single length nonnegative integers, and B is a single length positive integer:

r, I eu,; B2+B not greater than the largest integer having a machine representation.

Function Parameters: void lngintpower (u,exponent,result)

U: int u[O: u[O]]; entry: u must contain the long integer which has to be raised to the power

exponent; exponent: int;

entry: the (positive) power to which the long integer u will be raised; result: int result[O, u[O]*exponent];

Copyright 1995 by CRC Press, Inc

Page 70: Numerical Library in C for Scientists and Engineers A

exit: contains the value of u raised to the power of exponent, u remains unchanged.

Function used: lngintmult.

Method: For the method of the functions Ingintadd, Ingintsubtract, lngintmult and Ingintdivide, see [K69]; the function Inginpower uses the binary method for exponentiation [K69].

yoid lngintpower(int u[l, int exponent, int result[]) t

int *allocate-integer-vector(int, int) ; void free-integer-vector(int * , int) ; void lngintmult(int [I, int [I, int [I ) ; int max,i,n,exp,*y,*z,*h;

exp=exponent; max=u [OI *exp ; y=allocate~integer~vector(O,max) ; z=allocate~integer~vector(0,max); h=allocate-integer-vector(0,rnax) ;

y [Ol =y [ll =l; for (i=u[O] ; i>=O; i--) z [il =u[il ; while (1) {

n=exp/2 ; if (n+n ! = exp) (

lngintrnult ( y , z, h) ; for (i=h[O] ; i>=O; i--) y[il =h[il ; if (n == 0) {

for (i=y [Ol ; i>=O; i--) result [il =y [il ; f ree-integer-vector (y, 0) ; free-integer-vector(z,O) ; free-integer-vector(h,O) ; return;

1 1

lngintmult (z, z, h) ; for (i=h [O] ; i>=O; i--) z [il =h [il ; exp=n;

1 1

Copyright 1995 by CRC Press, Inc

Page 71: Numerical Library in C for Scientists and Engineers A

2. Algebraic Evaluations

2.1 Evaluation of polynomials in Grunert form

A. pol

Computes the sum of the polynomial

using Homer's rule. The error growth is given by a linear function of the degree of the polynomial [Wi63].

Function Parameters: float pol (n,x,a)

pol: given the value of p(x) above; n: int; the degree of the polynomial; x: float; the argument of the polynomial; a: float a[O:n];

entry: the coefficients of the polynomial.

float pol (int n, float x, float a [I ) I

float r;

r=O. 0 ; for ( ; n>=O; n--) r=r*x+a [nl ; return (r);

1

B. taypol

Computes the values of the terms x'Wp(x)/j! (j=O, ..., k l n ) where

Function Parameters: void taypol (n,k,x,a)

n: int; the degree of the polynomial; k: int; the first k terms of the above are to be calculated; x: float; the argument of the polynomial; a : float a[O:n];

entry: the coefficients of the polynomial; exit: the j-th term i*(j-th derivative)/j! is delivered in a/j], j=O,l ,..., k s n ,

Copyright 1995 by CRC Press, Inc

Page 72: Numerical Library in C for Scientists and Engineers A

the other elements of a are generally altered.

Method: The method of evaluation is given in [ShT74]. The more sophisticated algorithm based on divisors of n+l in [ShT74] was not implemented because of the more complex appearance of the implementation and because of the difficulty in choosing the most efficient divisor. In this implementation of the one-parameter family of algorithms, the linear number of multiplications is preserved. See [Wo74] for the k-th normalized derivative.

void taypol (int n, int k, float x, float a [I ) I i

int i,j,nml; float xj,aa,h;

if (X != 0.0) { xj=l; for (j=l; j<=n; j++) {

xj *= x; a[jl *= xj;

I aa=a [nl ; nml=n-1; for (j=O; jc=k; j++) {

h=aa; for (i=nml; i>=j; i--) h = a[il += h;

I I

} else { for (; k>=l; n--1 a[kl=O;

1 1

C. norderpol

Computes the first k normalized derivatives Dp(x)/j!, ( j=O ,..., ksn) of the polynomial

Function Parameters: void norderpol (n, k,x,a)

n: int; the degree of the polynomial; k: int; the first k normalized derivatives 0-th derivative / j factorial) are to be calculated; x: float; the argument of the polynomial; a: float a[O:n];

entry: the coefficients of the polynomial; exit: the j-th normalized derivative is delivered in ao], j=O,l, ..., k l n ,

the other elements of a are generally altered.

Method: see the function taypol.

void norderpol (int n, int k, float x, float a [I ) I

float "allocate-real-vector(int, int); void free-real-vector(f1oat *, int); int i, j,nml;

Copyright 1995 by CRC Press, Inc

Page 73: Numerical Library in C for Scientists and Engineers A

f l o a t x j , aa , h, *xx;

i f ( X != 0.0) { xx=allocate-real-vector(0,n); x j = l ; f o r ( j = l ; j<=n; j++) {

x x [ j ] = x j *= x; a [ j l *= x j ;

I J

h=aa=a [nl ; nml=n-1; f o r (i=nml; i s = O ; i--) h = a [ i l += h; f o r ( j = l ; j<=k; j++) (

h=aa ; fo r (i=nml; i > = j ; i--) h = a [ i l += h; a [ j l = h / x x [ j l ;

D. derpol

Computes the first k derivatives Dp(x) O=O, ..., k l n ) of the polynomial

Function Parameters: void derpol (n,%x,a)

n: int; the degree of the polynomial; k: int; the first k derivatives are to be calculated; x: float; the argument of the polynomial; a: float a[O:n];

entry: the coefficients of the polynomial; exit: the j-th derivative is delivered in afi], j=O, 1, ..., k l n,

the other elements of a are generally altered.

Function used: norderpol.

Method: see the function taypol.

void derpol ( i n t n, i n t k , f l o a t x, f l o a t a [I )

void norderpol ( i n t , i n t , f l o a t , f l o a t 11 ) ; i n t j ; f l o a t fac;

fac=l.O; norderpol (n ,k ,x ,a ) ; f o r ( j = 2 ; j<=k; j++) {

fac *= j ; a [ j ] *=fax;

Evaluation of general orthogonal polynomials

Copyright 1995 by CRC Press, Inc

Page 74: Numerical Library in C for Scientists and Engineers A

This section contains six procedures for evaluating orthogonal polynomials [AbS65, Lu691 The procedures ending with sym are versions for symmetric polynomials.

A. ortpol

Evaluates the single polynomial pn(x), where = 1, pi($ = x-bo,

pk+/(x) = (x-bJpk(x) - c~P~-~(x) , k=l,...,n-1 with given b, and c,.

Function Parameters: float ortpol (n,x,b,c)

ortpol: given the value of the orthogonal polynomial in the above; n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial; b,c: floatb[O:n-l],c[l:n-I];

entry: the recurrence coefficients of the polynomial.

:loat ortpol(int n, float x, float b [ l , float c[l) t

int k,l; float r,s,h;

if (n == 0) return (1.0); r=x-b [O] ; s=1.0; l=n- 1 ; for (k=l; k<=l; k++) {

h=r ; r= (x-b [kl ) *r-c [kl *s; s=h;

return (r); 1

B. ortpolsym

Given the ck and x, evaluates the single polynomial pn(x), where PO($ = 1, pI(x) = x,

pk+,(Y = xpkW - cgk&), k=l,...,n-I.

Function Parameters: float ortpolsym (n,x,c)

ortpolsym: given the value of the orthogonal polynomial in the above; n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial; c: float c[l:n-11;

entry: the recurrence coefficients of the polynomial.

float ortpolsym(int n, float x, float c [ I ) t

int k, 1; float r,s,h;

if (n == 0) return (1.0) ; r=x;

Copyright 1995 by CRC Press, Inc

Page 75: Numerical Library in C for Scientists and Engineers A

SG1.0 ; l=n-1; for (k=l; k<=l; k++) {

h=r ; r=x*r-c [kl *s; s=h;

1 return (r) ;

I

C. allortpol

Evaluates the sequence of polynomials pk(x) for k=O, ..., n, where pO(x) = 1, P,(x) = X-6,

P~+~(x) = (x-bJpk(x) - wk-, (x), k=l,...,n-1 with given b, and c,.

Function Parameters: void allortpol (n,x, b,c,p)

n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial; b,c: floatb[O:n-l],c[l:n-I];

entry: the recurrence coefficients of the polynomial; p: float p[O:n];

exit: p[k] contains, for the argument, the value of the k-th orthogonal polynomial as defined by the recurrence coefficients.

yoid allortpol(int n, float x, float b [ l , float c[l, float p[l) i

int k,kl; float r,s,h;

if (n == 0) { p[01=1.0; return;

1 r=p [ll =x-b [Ol ; s=p[0] =l.O; k=l ; for (kl=2; kl<=n; kl++) {

h=r ; p [kll =r= (x-b [kl ) *r-c [kl *s; s=h;

D, allortpolsym

Given the c, and x, evaluates the sequence of polynomials pk(x) for k=O, ..., n, where po(x) = 1, PI($ = X,

pk+](x) = xpk(x) - CA,(X), k=l,...,n-1 .

Function Parameters: void allortpolsym (n,x, c,p)

n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial;

Copyright 1995 by CRC Press, Inc

Page 76: Numerical Library in C for Scientists and Engineers A

c: float c[l:n-11; entry: the recurrence coefficients of the polynomial;

p: float p[O:n]; exit: p[k] contains, for the argument, the value of the k-th orthogonal polynomial

as defined by the recurrence coefficients.

void allortpolsym(int n, float x, float c[l , float p[l) I

int k; float r,s,h;

if (n == 0) { pro1 =1.0; return;

I r=p [ll =x; s=p [O] =l.O; for (k=2; kc=n; k++) {

h=r; p [k] =r=x*r-c [k-11 *s;

E. sumortpol

Evaluates the sum

Function Parameters: float sumortpol (n,x, b, c, a)

sumortpol: given the value of the sum s in the above; n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial; b,c: float b[O:n-11, c[l :n-I];

entry: the recurrence coefficients of the polynomial; a: float a[O:n];

entry: the value of a, in the above.

float sumortpol(int n, float x, float b[l, float c[l, float a[]) r \

int k; float h, r, s;

if (n == 0) return (a LO1 ) ; r=a En1 ; s=o.o; for (k=n-1; k>=l; k--) {

h=r; r=a [kl + (x-b [kl ) *r+s; s = -c[k] *h;

Copyright 1995 by CRC Press, Inc

Page 77: Numerical Library in C for Scientists and Engineers A

1 r e t u r n ( a [O] + (x-b [O] ) * r + s ) ;

1

F. sumortpolsym

Given the a, ck and x, evaluates the sum

Function Parameters: float sumortpolsym (n,x,c,a)

sumortpolsym: given the value of the sum s in the above; n: int; the degree of the polynomial; x: float; the argument of the orthogonal polynomial; c: float c[l:n-I];

entry: the recurrence coefficients of the polynomial; a: float a[O:n];

entry: the values of a, in the above.

f l o a t surnortpolsyrn(int n , f l o a t x , f l o a t c [ I , f l o a t a [ I ) i

i n t k ; f l o a t h , r , s;

i f (n == 0) r e t u r n ( a I01 ) ; r = a [nl ; s = o . o ; f o r (k=n-1; k s = l ; k - - ) {

h = r ; r = a [k] +x*r+s ; s = - c [k l *h;

2.3 Evaluation of Chebyshev polynomials

This section contains four procedures for evaluating Chebyshev polynomials of the first kind [FoP68, Riv741.

A. chepolsum

Uses the Clenshaw or generalized Homer algorithm [CIe62] to evaluate a sum of Chebyshev polynomials

Copyright 1995 by CRC Press, Inc

Page 78: Numerical Library in C for Scientists and Engineers A

where T,(x) is a Chebyshev polynomial, by use of the backward recursion S,+, = 0, S,, = a,,,

Sk = a, + 2xSk+, - Sk+,, k=n-2,n-3 ,..., I; S = a, + S,x - S,

for n 2 2 .

Function Parameters: float chepolsum (n,x,a)

chepolsum: given the value of the Chebyshev sum S in the above; n: int; the degree of the polynomial represented by the Chebyshev sum, n 1 0 ; x: float; the argument of the Chebyshev polynomials, I x 1 51; a : float a[O:n];

entry: a[k] is the coefficient of the Chebyshev polynomial of degree k, 0 k s n .

float chepolsum(int n, float x, float a [I ) I

int k; float h, r, s, tx;

if (n == 0) return (a I01 ) ; if (n == 1) return (a[Ol +a[ll *x) ; tx=x+x; r=a [nl ; h=a [n-11 +r*tx; for (k=n-2; ks=l; k--) {

s=r; r=h; h=a [kl +r*tx-s;

B. oddchepolsum

Given the a, and x, uses the Clenshaw or generalized Homer algorithm [Cle62] to evaluate a sum of Chebyshev polynomials of odd degree

the 7 j being Chebyshev polynomials.

Function Parameters: float oddchepolsum (n,x,a)

oddchepolsum: given the value of the Chebyshev sum S in the above; n: int; the degree of the polynomial represented by the Chebyshev sum is 2n+l , n 1 0 ; x: float; the argument of the Chebyshev polynomials, ( ~ ( 2 1 ; a: float a[O:n];

entry: ark] is the coefficient of the Chebyshev polynomial of degree 2k+I, 0 5 k l n .

float oddchepolsum(int n, float x, float a[]) I

int k; float h,r,s,y;

Copyright 1995 by CRC Press, Inc

Page 79: Numerical Library in C for Scientists and Engineers A

if (n == 0) return (x*a [Ol ; if (n == 1) return (x* (a [O] +a [ll* (4.0*x*x-3.0) ) ) ; y=4. o*x*x-2.0 ; r=a [nl ; h=a [n-11 +r*y; for (k=n-2; k>=O; k--) {

s=r; r=h; h=a [kl +r*y-s;

return (x* (h-r) ) ; 1

C. chepol

Computes the value of the Chebyshev polynomial T,,(x) by use of the recursion [St721 To(x) = I, Tl(x) =x ,

T,(x) = 2xTj,(x) - Ti,($, i=2 ,..., n.

Function Parameters: float chepol (n,x)

chepol: given the value of the Chebyshev polynomial of the first kind, T,,(x) above; n: int; the degree of the polynomial, n 2 0; x: float; the argument of the Chebyshev polynomial, I x 1 51.

float chepol(int n, float x) I

int i; float tl,t2,h,x2;

if (n == 0) return (1.0) ; if (n == 1) return (x) ; t2=x; tl=1.0; x2=x+x; for (i=2; ic=n; i++) {

h=x2*t2-tl; tl=t2; t2=h; ;

1 I

return (h) ; 1

D. allchepol

Computes the values of the Chebyshev polynomials T,(x), i=l, ..., n, by use of the recursion [St721

To(x) = I, Tl(x) = x, T,(x) =2xT,,(x)-Ti,(x), i=2 ,..., n.

Function Parameters: void allchepol (n,x, t)

n: int; the degree of the last polynomial, n 2 0; x: float; the argument of the Chebyshev polynomials, I x 1 21; t: float t[O:n];

exit: the value of the Chebyshev polynomial of the first kind of degree k, for the argument x, is delivered in t[k], k=O ,..., n.

Copyright 1995 by CRC Press, Inc

Page 80: Numerical Library in C for Scientists and Engineers A

void allchepol (int n, float x, float t [I ) {

int i; float tl, t2, h,x2;

if (n == 0) { t [01=1.0; return;

1 if (n == 1) {

t [O] =1.0; t [ll =x; return;

1 t 101 =tl=l.O; t 111 =t2=x; x2=x+x; for (i=2; ic=n; i++) {

t [il =h=x2*t2-tl; tl=t2; t2=h; ;

\

2.4 Evaluation of Fourier series

A. sinser

Computes the value of a sine series

where 8 and the b, are real. When -lh 1 cos(8) 1 %, the recursion u,+2 = %+I = 0,

Uk = ~cos(B)u~+, - Uk+* + bk k=n, ..., 1 is used. When cos(8) < 4 , the equivalent recursion

U"+I = d,+l = 0, d, = 2(1 + cos(B))uk+, - dk+, + b, k=n ,..., 1

uk = dk - uk+l, and when cos(8) > lh, the hrther recursion

U,+I = en+, = 0, ek = 2(cos(B) - I)uk+, - ek+, + b, k=n ,..., 1

Uk = ek - Uk+, are used. In each case s = u,sin(B).

Function Parameters: float sinser (n, theta, b)

sinser: given the value of the sine series, the value of s above; n: int;

entry: the number of terms in the sine series; theta: float;

entry: the argument of the sine series; b: float b[l:n];

entry: the coefficients of the sine series.

Copyright 1995 by CRC Press, Inc

Page 81: Numerical Library in C for Scientists and Engineers A

Method: see the function comfouser2.

float sinser(int n, float theta, float b[l) (

int k; float c,cc,lambda,h,dun,un,unl,temp;

c=cos (theta) ; if (C c -0.5) (

temp=cos(theta/2.0); lambda=4.O*temp*temp; un=dun=O.O; for (k=n; k>=l; k--) (

dun=lambda*un-dun+b [kl ; un=dun-un;

I ] else (

if (C > 0.5) ( temp=sin (theta/2.0) ; lambda = -4.O*temp*temp; un=dun=O.O; for (k=n; k>=l; k--) {

dun += lambda*un+b [kl ; un += dun;

\

1 el$e cc=c+c; un=unl=O.O; for (k=n; k>=l; k--) (

h=cc*un-unl+b [kl ; unl=un;

J return (un*sin (theta) ) ;

I

B. cosser

Computes the value of a cosine series

where 8 and the aj are real. The method used is based upon recursion of the documentation to sinser, where now s = a, + 2u,cos(B) - u,, and upon further recursions similar to those given in that documentation.

Function Parameters: float cosser (n, theta, a)

cosser: given the value of the cosine series, value of s above; n: int;

entry: the degree of the trigonometric polynomial; theta: float;

entry: the argument of the cosine series; a: float a[O:n];

entry: the coefficients of the cosine series.

Copyright 1995 by CRC Press, Inc

Page 82: Numerical Library in C for Scientists and Engineers A

Method: see the hnction comfouser2.

float cosser(int n, float theta, float a[]) I

int k; float c,cc,lambda,h,dun,un,unl,temp;

c=cos (theta) ; if (C < -0.5) {

temp=cos (theta/2.0) ; larnbda=4.O*ternp*temp; un=dun=O.O; for (k=n; k>=O; k--) {

un=dun-un; dun=lambda*un-dun+a [kl ;

1 ;eturn (dun-lambda/2.0*un) ;

] else { if (C > 0.5) {

temp=sin(theta/l.O) ; lambda = -4.O*temp*temp; un=dun=O.O; for (k=n; k>=O; k--) {

un += dun; dun += lambda*un+a [kl ;

} ieturn (dun-lambda/2.O*un);

] else ( cc=c+c; un=unl=0.0; for (k=n; k>=l; k--) {

h=cc*un-unl+a [kl ; unl=un; un=h;

1 return (a [Ol +un*c-unl) ;

I I

1

C. fouser

Computes the value of

where 8 and the q are real, by methods similar to those described in the documentations to sinser and comer.

Function Parameters: float fouser (n,theta,a)

fouser: given the value of the fourier series, value of s above; n: int;

entry: the degree of the trigonometric polynomial; theta: float;

entry: the argument of the fourier series; a: float a[O:n];

Copyright 1995 by CRC Press, Inc

Page 83: Numerical Library in C for Scientists and Engineers A

entry: the coefficients of the (finite) fourier series.

float fouser(int n, float theta, float a[]) {

int k; float c, cc, lambda, h, dun, un, unl, c2, s2 ;

c=cos (theta) ; if (C c -0.5) {

c2=cos (theta/2.0) ; lambda=4.0*~2*~2; un=dun=O.O; for (k=n; k>=O; k--) {

un=dun-un; dun=lambda*un-dun+a [kl ;

I J return (dun+2.0*~2* (sin(theta/2.0) -c2) *un) ;

} else { if (C > 0.5) {

s2=sin(theta/2.0) ; lambda = -4.O*s2*sZ; un=dun=O.O; for (k=n; k>=O; k--) {

un += dun; dun += lambda*un+a Ikl ;

1 keturn (dun+2.0*s2*(s2+cos(theta/2.O))*un);

} else { cc=c+c; un=unl=O.O; for (k=n; k>=l; k--) (

h=cc*un-unl+a [kl ; unl=un; un=h;

\ Ceturn (a [Ol -unl+ (c+sin (theta) ) *un) ;

1 1

1

D. fouserl

Computes the value of

where 8, aj and b, are real, using a Homer scheme.

Function Parameters: float fouser 1 (n, theta, a, b)

fouserl: given the value of the fourier series, value of s above; n: int;

entry: the degree of the trigonometric polynomial; theta: float;

entry: the argument of the fourier series; a, 6: float a[O:n], b[l:n];

entry: the coefficients of the (finite) fourier series,

Copyright 1995 by CRC Press, Inc

Page 84: Numerical Library in C for Scientists and Engineers A

with a, coefficient of cos(k*9), k=O, ..., n, and b, coefficient of sin(k*9), k=l ,..., n.

Method: see the function comfouser2.

float fouserl(int n, float theta, float a[], float b[l ) I \

int i; float r,s,h,co,si;

r=s=O.O; co=cos (theta) ; si=sin (theta) ; for (i=n; i>=l; i--) {

h=co*r+si*s+a [il ; s=co*s-si*r+b [il ; r=h;

I I return (co*r+si*s+a [Ol ) ;

1

Computes the value of

where 8, a, and b, are real, by methods similar to those described in the documentations to sinser and cosser.

Function Parameters: float fouser2 (n, theta, a, b)

fouser2: given the value of the fourier series, value of s above; n: int;

entry: the degree of the trigonometric polynomial; theta: float;

entry: the argument of the fourier series; a, b: float a[O:n], b[I:n];

entry: the coefficients of the (finite) fourier series, with a, coefficient of cos(k*9), k=O, ..., n, and b, coefficient of sin(k*9), k=l, ..., n.

Functions used: sinser, cosser.

Method: see the function comfouser2.

#include cmath.h>

float fouser2 (int n, float theta, float a [I , float b [I) I

float sinser (int, float, float [ I ) ; float cosser(int, float, float [ I ) ;

Copyright 1995 by CRC Press, Inc

Page 85: Numerical Library in C for Scientists and Engineers A

return (cosser(n,theta,a)+sinser(n,theta,b)); 1

F. comfouser

Computes the value of

where 8 and the a, are real, by methods similar to those described in the documentations to sinser and cosser.

Function Parameters: void comfouser (n, theta, a, rr,ri)

n: int; entry: the degree of the polynomial in ela;

theta: float; entry: the argument of the fourier series;

a: float a[O:n]; entry: the real coefficients in the series;

r r r i float *; exit: the real part and the imaginary part of s above are delivered in rr and ri,

respectively.

void comfouser(int n, float theta, float a[], float *rr, float *ri) I

int k; float c, cc, lambda, h, dun, un,unl, temp;

c=cos (theta) ; if (C < -0.5) {

temp=cos(theta/Z.O); lambda=l.O*temp*temp; un=dun=O.O; for (k=n; k>=O; k--1 {

un=dun-un; dun=lambda*un-dun+a [kl ;

I

Lrr=dun-lambda/2.O*un; ) else {

if ( c > 0 . 5 ) { temp=sin (theta/2.0) ; lambda = -4.O*temp*temp; un=dun=O.O; for (k=n; k>=O; k--) {

un += dun; dun += lambda*un+a [kl ;

1 1

*rr=dun-lambda/2.O*un; ) else {

cc=c+c; un=unl=O.O; for (k=n; k>=l; k--1 {

h=cc*un-unl+a [kl ; unl=un; un=h;

1

Copyright 1995 by CRC Press, Inc

Page 86: Numerical Library in C for Scientists and Engineers A

*rr=a [Ol +un*c-unl;

1 1

*ri=un*sin (theta) ; 1

G. comfouserl

Computes the value of

where 8 is real and the a, are complex, using a Homer scheme.

Function Parameters: void comfouser 1 (n, theta, ar, ai,rr,ri)

n: int; entry: the degree of the polynomial in eiO;

theta: float; entry: the argument of the fourier series;

ar, ai: float ar[O:n], ai[O:n]; entry: the real part and the imaginary part of the complex coefficients in the series

must be given in arrays ar and ai, respectively; rrri: float *;

exit: the real part and the imaginary part of s above are delivered in rr and ri, respectively.

Method: see the function comfouser2.

void comfouserl(int n, float theta, float ar[l, float ai[l, float *rr, float *ri)

{ int k; float h,hr,hi,co,si;

hr=hi=O.O; co=cos (theta) ; si=sin (theta) ; for (k=n; k>=l; k--) {

h=co*hr-si*hi+ar [kl ; hi=co*hi+si*hr+ai [kl ; hr=h;

1 *rr=co*hr-si*hi+ar [Ol ; *ri=co*hi+si*hr+ai [O] ;

1

Computes the value of where 8 is real and the a, are complex, by methods similar to those described in the documentations to sinser and cosser.

Copyright 1995 by CRC Press, Inc

Page 87: Numerical Library in C for Scientists and Engineers A

Function Parameters: void comfouser2 (n, theta,ar, ai,rr,ri)

n: int; entry: the degree of the polynomial in dB;

theta: float; entry: the argument of the fourier series;

ar,ai: float ar[O:n], ai[O:n]; entry: the real part and the imaginary part of the complex coefficients in the series

must be given in arrays a r and ai, respectively; r r r i : float *;

exit: the real part and the imaginary part of s above are delivered in rr and ri, respectively.

Function used: comfouser.

Method: For the evaluation of a finite fourier series two algorithms are used: (a) the Homer scheme in the function fouserl, and (b) a combination of the Clenshaw algorithm [Ge69, Lu69, St721 and the modification of Reinsch [Re67, St721 in the functions sinser, comer, fouser and fouser2. A modification of the idea of Newbery is not implemented because of the introduction of sine (cosine) terms in a cosine (sine) series and the inefficiency of the algorithm [N73]. For the evaluation of a finite complex fourier series, two algorithms, in real arithmetic, are used: (a) the Homer scheme in the function comfouserl, and (b) a combination of the Clenshaw algorithm and the modification of Reinsch in functions comfouser and comfouser2. The Homer scheme is implemented because of the simplicity of the algorithm (although this algorithm is less efficient than the Goertzel-Watt-Clenshaw-Reinsch algorithm) and the stable nature of orthogonal transformations. A combination of the algorithm of Goertzel-Watt-Clensaw and the modification of Reinsch is implemented because of the efficiency of the Goertzel-Watt-Clensaw algorithm and the stability of the modification of Reinsch, especially for small values of the argument. An upper bound for the error growth is given by a linear function of the degree for both implemented algorithms.

void comfouser2 (int n, float theta, float ar [ I , float ai [ I , float *rr, float *ri)

( void comfouser (int, float, float [ I , float *, float * ) ; float car,cai,sar,sai;

comfouser (n, theta, ar, &car, &sar) ; comf ouser (n, theta, ai, &cai, &sai) ; *rr=car-sai; *ri=cai+sar;

I

Copyright 1995 by CRC Press, Inc

Page 88: Numerical Library in C for Scientists and Engineers A

2.5 Evaluation of continued fractions

jfrac

Computes the value of the convergent

by use of the recursion D, = b",

Di+, = b,,, + aIj.,+,/Di, i=I ,..., n, when C, = Dn+,.

Function Parameters: float jfrac (n,a, b)

jyrac: delivers the value of the terminating continued fraction, the value of Cn above; n: int; the upper index of the arrays a and b; a,b: float a[l:n],b[O:n]; the elements of the continued fraction, a, and b, above.

float jfrac(int n, float a[], float b[l) i

int i; float d;

d=O. 0; for (i=n; i>=l; i--) d=a[il / (b [il +d) ; return (d+b[Ol) ;

1

2.6 Transformation of polynomial representation

A. polchs

Given the a,, derives the b, occurring in the relationship

the T,(x) being Chebyshev polynomials.

Function Parameters: void polchs (n,a)

n: int; the degree of the polynomial; a: float a[O:n];

entry: the coefficients of the power sum; exit: the coefficients of the Chebyshev sum.

Copyright 1995 by CRC Press, Inc

Page 89: Numerical Library in C for Scientists and Engineers A

Method: Although the transformation of representations of polynomials could have been obtained by fast evaluation and fast interpolation, the algorithm of Hamming [H73] was implemented here because of its simple appearance.

void polchs (int n, float a [I ) I

int k,l,twopow;

(n > 1) { twopow=2 ; for (k=l; kc=n-2; k++) {

a[kl /= twopow; twopow *= 2;

1 A [n-l]=2.0*a [n-11 /twopow; a [nl /= twopow; a [n-21 += a [nl ; for (k=n-2; k>=l; k--1 {

a [k-11 += a [k+ll ; a [k] =2.0*a [kl +a [k+21 ; for (l=k+l; lc=n-2; I++) a [ll += a[1+21 ;

1

B. chspol

Given the b,, derives the a, occurring in the relationship

the T,(x) being Chebyshev polynomials.

Function Parameters: void chspol (n,a)

n: int; the degree of the polynomial; a : float a[O:n];

entry: the coefficients of the Chebyshev sum; exit: the coefficients of the power sum.

Method: see the function polchs.

void chspol (int n, float a [I ) 1

int k, 1, twopow;

if (n > 1) ( for (k=O; kc=n-2; k++) {

for (l=n-2; l>=k; I--) a[ll - = a[1+21;

twopow=2 ; for (k=l; kc=n-2; k++) {

a [k] *= twopow; twopow *= 2;

1

Copyright 1995 by CRC Press, Inc

Page 90: Numerical Library in C for Scientists and Engineers A

C. polshtchs

Given the a,, derives the b, occurring in the relationship

the S,(x) being shifted Chebyshev polynomials defined by Sk(x)=Tk(2x-I), T,(x) being a Chebyshev polynomial.

Function Parameters: void polshtchs (n,a)

n: int; the degree of the polynomial; a : float a[O:n];

entry: the coefficients of the power sum; exit: the coefficients of the shifted Chebyshev sum.

Functions used: lintfmpol, polchs.

Method: see the function polchs.

void polshtchs (int n, float a [I ) I '

void lintfmpol (float, float, int, float I1 ) ; void polchs (int, float [I ;

lintfmpol(0.5,0.5,n,a); polchs (n, a) ;

1

D. shtchspol

Given the b,, derives the a, occurring in the relationship

the S,(x) being shifted Chebyshev polynomials defined by Sk(x)=Tk(2x-I), T,(x) being a Chebyshev polynomial.

Function Parameters: void shtchspol (n,a)

n: int; the degree of the polynomial; a: float a[O:n];

entry: the coefficients of the shifted Chebyshev sum; exit: the coefficients of the power sum.

Copyright 1995 by CRC Press, Inc

Page 91: Numerical Library in C for Scientists and Engineers A

Functions used: lintfrnpol, chspol.

Method: see the function polchs.

yoid shtchspol (int n, float a [I ) '

void chspol (int, float [ I ) ; void lintfmpol (float, float, int, float [] ) ;

chspol (n, a) ; lintfmpol(2.0, -l.O,n,a) ;

1

E. grnnew

Given the coefficients ai occurring in the polynomial

n

and the tabulation points x,, computes the divided differences in the equivalent Newton series representation

Function Parameters: void grnnew (n,x,a)

n: int; the degree of the polynomial; x: float x[O:n-I];

entry: the interpolation points, values of x, above; a: float a[O:n];

entry: the coefficients of the power sum; exit: the coefficients of the Newton sum, values of 6, above.

Method: see the function polchs.

void grnnew (int n, float x [I , float a [I ) l

int k, 1;

for (k=n-1; k>=O; k--) for (l=n-1; l>=n-1-k; I--) a [ll += a [l+ll *x [n-1-kl ;

1

F. newgrn

Given the coefficients Gf(x,J, together with the values of the arguments xi from which they are formed, in the truncated Newton interpolation series computes the coefficients c , i=O, ..., n, in the equivalent polynomial form

Copyright 1995 by CRC Press, Inc

Page 92: Numerical Library in C for Scientists and Engineers A

Function Parameters: void newgrn (n,x,a)

n: int; the degree of the polynomial; x: float x[O:n-I];

entry: the interpolation points, values of xi above; a: float a[O:n];

entry: the coefficients of the Newton sum, values of Gf(xJ; exit: the coefficients of the power sum, values of ci above.

Function used: elmvec.

Method: see the function polchs.

void newgrn (int n, float x [ I , float a [I )

void elmvec (int, int, int, float [I , float 11 , float) ; int k;

for (k=n-1; k>=O; k--) elmvec (k,n-l,l,a,a, -x[kl ) ;

1

G. lintfmpol

Given the ai occurring in the polynomial expression

and p, q, derives the b, occurring in the equivalent expression

where x=py+q.

Function Parameters: void lintfinpol (p,q,n,a)

Copyright 1995 by CRC Press, Inc

Page 93: Numerical Library in C for Scientists and Engineers A

n: int; the degree of the polynomial; p,q: float;

entry: defining the linear transformation of the independent variable x=py+q; p=O gives the value of the polynomial with argument q;

a: float a[O:n]; entry: the coefficients of the power sum in x, values of a, above; exit: the coefficients of the power sum in y, values of b, above.

Function used: norderpol.

Method: see the function polchs.

void lintfmpol(f1oat p, float q, int n, float a[]) I

void norderpol (int, int, float, float [I ) ; int k; float ppower;

norderpol (n,n, q, a) ; ppower=p; for (k=l; kc=n; k++) (

a [kl *= ppower; ppower *= p;

, I

2.7 Operations on orthogonal polynomials

intchs

Given the real coefficients a, in the expansion

where q(x) is the Chebyshev polynomial of the first kind of degree j, those in the expansion

are derived.

Function Parameters: void intchs (n,a,b)

n: int; the degree of the polynomial represented by the Chebyshev series; a, b: float a[O:n], b[l:n+l];

entry: the coefficients of the Chebyshev series, values of a, above; exit: the coefficients of the integral Chebyshev series, values of b, above.

Method: For a description of the algorithm see [Cle62, FoP681.

Copyright 1995 by CRC Press, Inc

Page 94: Numerical Library in C for Scientists and Engineers A

void intchs (int n, float a [I , float b [I ) {

int i; float h, 1, durn;

if (n == 0) ( b [ll =a [Ol ; return;

b[21 =a[l] /4.0; b [ll =a [Ol ; return;

I h=a [nl ; duma [n- 11 ; b [n+ll =h/ ( (n+l) *2) ; b 11-11 =durn/ (n*2) ; for (i=n-1; i>=2; i--) (

l=a [i-11 ; b [il = (1-h) / (2*i) ; h=dum; dum=l ;

I b [I] =a [O] -h/2.0;

1

Copyright 1995 by CRC Press, Inc

Page 95: Numerical Library in C for Scientists and Engineers A

3. Linear Algebra

3.1 Full real general matrices

3.1.1 Preparatory procedures

A. dec

Decomposes the nxn matrix A in the form LU=PA, where L is lower triangular, U is unit upper triangular and P is a permutation matrix.

Function Parameters: void dec (a,n,aux,p)

a : float a[l:n,l:n]; entry: the matrix to be decomposed; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int; the order of the matrix; aux: float aux[l:3];

entry: aux[2]: a relative tolerance: a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

exit: awc[l]: if R is the number of elimination steps performed (see aux[3J), then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] equals -1;

aux[3]: the number of elimination steps performed; if aux[3]<n then the process has been broken off because the selected pivot is too small relative to the maximum of the Euclidean norms of the rows of the given matrix;

p: int p[l:n]; exit: the pivot indices; row i and row p[i] are interchanged in the i-th iteration.

Functions used: matmat, mattam, ichrow.

Method: The decomposition uses only partial pivoting [Dek68, Wi63, Wi651. Since, in exceptional cases, partial pivoting may yield useless results, even for well- conditioned matrices, the user is advised to use the function gsselm. However, if the number of variables is small relative to the number of binary digits in the mantissa of the number representation then the function dec may also be used. Refer to the function gsselm for more details.

void dec(f1oat **a, int n, float aux[l , int p [ I ) 1

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); float matmat (int, int, int, int, float ** , float * * ) ;

Copyright 1995 by CRC Press, Inc

Page 96: Numerical Library in C for Scientists and Engineers A

float mattam(int, int, int, int, float **, float * * ) ; void ichrow(int, int, int, int, float * * ) ; int i,k,kl,pk,d; float r,s,eps,*v;

v=allocate-real-vector(1,n); r = -1.0; for (i=l; i<=n; i++) {

s=sqrt (mattam(l,n,i,i,a,a)) ; if (S > r) r=s; v[il =l.O/s;

1 eps=aux [21 *r; dd.0; for (k=l; k<=n; k++) (

r = -1.0; kl=k-1; for (i=k; ic=n; i++) (

a[i] [k] - = matmat(l,kl,i,k,a,a) ; s=fabs (a [il [kl ) *v [il ; if (S > r) {

r=s; pk=i ;

1 1

p [kl =pk; v [pkl =v [kl ; s=a [pkl [kl ; if (fabs(s) < eps) break; if (S < 0.0) d = -d; if (pk ! = k) {

d = -d; ichrow(l,n,k,pk,a) ;

I

aux [ll =d; aux[3] =k-1; free-real-vector (v, 1) ;

I

B. gsselm

Decomposes the nxn matrix A in the form LU=P,AP,, where L is lower triangular, U is unit upper triangular and P, and P, are permutation matrices. This function uses partial pivoting, with complete pivoting if the former does not yield stable results.

Function Parameters: void gsselm (a, n, aux,ri, ci)

a: float a[l:n,l:n]; entry: the matrix to be decomposed; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int; the order of the matrix; am: float aux[l: 71;

entry: aux[2]: a relative tolerance: a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value which is used for controlling pivoting, usually aux[4]=8 will give good results;

exit:

Copyright 1995 by CRC Press, Inc

Page 97: Numerical Library in C for Scientists and Engineers A

aux[l]: if R is the number of elimination steps performed (see aux[3J, then awc[l] equals I if the determinant of the principal submatrix of order R is positive, else aux[l] equals -1;

aux[3]: the number of elimination steps performed; if awc[3]<n then the process has been broken off because the selected pivot is too small relative to the maximum of the moduli of elements of the given matrix;

aux[5]: the modulus of an element which is of maximum absolute value for the matrix which had been given in a;

awc[7]: an upper bound for the growth (the modulus of an element which is of maximum absolute value for the matrices occurring during elimination);

ri: int ri[l:n]; exit: the pivotal row-indices; see ci below;

ci: int ci[l:n]; exit: the pivotal column-indices; in the i-th iteration, row i is interchanged with row

ri[i] and column j is interchanged with column cib].

Functions used: rowcst, elmrow, maxelmrow, ichcol, ichrow, absmaxmat.

Method: The process of Gaussian elimination is performed in at most n steps, where n denotes the order of the matrix. Partial pivoting is used as long as the calculated upper bound for the growth [Busi71] is less than a critical value that equals aux[4]*n times the modulus of an element which is of maximum absolute value for the given matrix. In the partial pivoting strategy, that element is chosen as pivot in the k-th step whose absolute value is maximal for the k-th column of the lower triangular matrix L. However, if the upper bound for the growth exceeds this critical value in the k-th step then a pivot is selected in the j-th step, j=k, ..., n, in such a way that its absolute value is maximal for the remaining submatrix of order n-k+l (complete pivoting). Since in practice, if we choose aux[4] properly, the upper bound for the growth rarely exceeds this critical value [Busi71, Wi631, we usually take advantage of the greater speed of partial pivoting (order n-k+l in the k-th step), while in a few doubtful cases numerical difficulties will be recognized and the process will switch to complete pivoting (order (n-k+l)' in the k-th step). Using the function gsselm, the upper bound for the relative error in the solution of a linear system [Wi63, Wi651 will be at most aux[4]*n times the upper bound using Gaussian elimination with complete pivoting only. Usually this will be a crude overestimate. The choice a d 4 1 < I/n will result in complete pivoting only, while partial pivoting will be used in every step if we choose aux[4] > 2"-'/n. Usually aux[4]=8 will give good results [Busi71]. The process will also switch to complete pivoting if the modulus of the pivot obtained with partial pivoting is less than a certain tolerance which equals the given relative tolerance aux[2] times the modulus of an element which is of maximum absolute value for the given matrix. If all elements in the remaining submatrix are smaller in absolute value than this tolerance then the process is broken off and the previous step number is delivered in awc[3]. In contrast with the method used in the function dec, no equilibrating is done in this pivoting strategy. The user has to take care for a reasonable scaling of the matrix elements.

Copyright 1995 by CRC Press, Inc

Page 98: Numerical Library in C for Scientists and Engineers A

void gsselm(f1oat **a, int n, float aux[l , int ri [I, int ci [I )

I void elmrow(int, int, int, int, float **, float **, float) ; int rnaxelmrow(int, int, int, int, float ** , float ** , float); void ichcol (int, int, int, int, float * * ) ; void ichrow(int, int, int, int, float * * ) ; void rowcst (int, int, int, float ** , float) ; float absmaxmat (int, int, int, int, int * , int *, float * * ) ; int i,j,p,q,r,rl,jpiv,rank,signdet,partial; float crit,pivot, rgrow,max, aid,maxl, eps;

aux [S] =rgrow=absmaxmat (l,n, 1, n, &i, &j, a) ; crit=n*rgrow*aux [41 ; eps=rgrow*aux [21 ; max=O. 0 ; rank=n; signdet=l; partial = rgrow ! = 0; for (q=1; qc=n; q++)

if (q ! = j) { aid=fabs (a [il [sl ; if (aid > max) -max=aid;

1 I

rgrow += max; for (r=l; r<=n; r++) {

rl=r+l; if (i ! = r) (

signdet = -signdet; ichrow(l,n,r,i,a) ;

if (j ! = r) ( signdet = -signdet; ichcol(l,n,r, j,a) ;

ri [rl =i; ci [rl = j ; pivot=a [rl [rl ; if (pivot < 0.0) signdet = -signdet; if (partial) {

max=maxl=O.O; j=rl; rowcst (rl,n, r,a, l.O/pivot) ; for

1 for

(p=rl; p<=n; p++) { elrnrow(rl,n,p,r,a,a, -a[pl [rl); aid=fabs (a [pl [rll ) ; if (max < aid) {

max=aid;

(q=rl+l; q<=n; q++) { aid=fabs (a [il [ql ) ; if (maxl < aid) rnaxl=aid;

1 aid=rgrow; rgrow += maxl; if ( (rgrow > crit) I I (max < eps) ) {

partial=O; rgrow=aid; max=absmaxmat (rl,n,rl,n,&i,&j,a) ;

1 ) el'se {

if (rnax <= eps) { rank=r- 1; if (pivot < 0.0) signdet = -signdet; break;

1 rnax = -1.0; rowcst(rl,n,r,a,l.O/pivot) ; for (p=rl; p<=n; p++) {

jpiv=maxelmrow(rl,n,p,r,a,a, -a[pl [rl ) ; aid=fabs (a [pl [ jpivl ) ;

Copyright 1995 by CRC Press, Inc

Page 99: Numerical Library in C for Scientists and Engineers A

if (max < aid) { max=aid; 1=p; j = jpiv;

. 1 if (rgrow < max) rgrow=max;

, I aux [I] =signdet; aux [31 =rank; aux [71 =rgrow;

1

C. onenrminv

Computes 11 6' 11 ,, a being an nxn matrix assumed to have been triangularly decomposed by the function dec or gsselm, a-' is first computed by forward and back substitution [Dek68, Wi63, Wi651, and 11 6' 11 , is then determined.

Function Parameters: float onenrminv (a,n)

onenrminv: given the 1-norm of the calculated inverse of the matrix whose triangularly decomposed form is given in array a;

a: float a[l:n,l:n]; entry: the triangularly decomposed form of a matrix, as delivered by the function dec

or gsselm; the elements of a remain unaltered on exit of the function; n: int; the order of the matrix.

Function used: matvec.

float onenrminv(f1oat **a, int n) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float matvec (int, int, int, float ** , float [I ) ; int i, j; float norm,max,aid,*y;

y=allocate-real-vector (1, n) ; norm=O .0 ; for (j=l; j<=n; j++) {

for (i=l; i<=n; i++) y[il=(i < j) ? 0 :

((i == j) ? l.O/a[il [i] : -matvec(j,i-l,i,a,y) /a[il [il ) ; max=O. 0 ; for (i=n; i>=l; i--) {

aid = y [il - = matvec (i+l,n, i,a, y) ; max += fabs (aid) ;

1 if (norm c max) normmax;

1 free-real-vector (y, 1) ; return (norm) ;

1

D. erbelm

Computes a rough error bound r for the relative error 11 AX 11 ,/ 11 x 11 in the solution of a linear

Copyright 1995 by CRC Press, Inc

Page 100: Numerical Library in C for Scientists and Engineers A

system of n-equations Ax = b; it is assumed that A has been triangularly decomposed by the function gsselm [Dek68, Wi63, Wi651, and that an upper bound for I I A - ' 11 , (possibly determined by the function onenrminv) is available (r is a function of A alone). With eps the machine precision, n the order of A, epsa an upper bound for the relative error in the elements of A, g the upper bound for the growth of auxiliary numbers produced during Gauss elimination (see the function gsselm: aux[7A, C the calculated inverse of A-I, and

q = g * (0.75*n3 + 4.5*n2) * eps + epsa P = 4 * IIcIIJ(1 -q*IIc113

r is given by r = p/(l-p). If A is very badly conditioned, it may occur that the above formula becomes unusable.

Function Parameters: void erbelm (n,am,nrminv)

n: int; the order of the linear system in consideration; am: float am[O: I I];

entry: am[O]: the machine precision; ~ 2 4 5 1 : the modulus of an element which is of maximum absolute value for the matrix

of the linear system, this value is delivered by the function gsselm; aux[d]: an upper bound for the relative error in the elements of the matrix of the linear

system; am[7]: an upper bound for the growth during Gaussian elimination, this value is

delivered in awr[7] by the function gsselm; exit: am[9]: the value of nrminv; aux[ll]: a rough upper bound for the relative error in the solution of

a linear system when Gaussian elimination is used for the calculation of this solution, if no use can be made of the formula for the error bound because of a very bad condition of the matrix then aux[l I] = -I;

nrminv: float; entry: the 1-norm of the inverse of the matrix of the linear system must be given in

nrminv, this value may be obtained by the function onenrminv.

void erbelm (int n, float aux [I , float nrminv) I

float aid, eps;

eps=aux [O] ; aid= (1.06*eps* (0.75*n+4.5) * (n*n) *aux I71 +aux 151 *aux [61 ) *nrminv; aux[lll=(2.0*aid >= (1.0-eps)) ? -1.0 : aid/(l.0-2.0*aid) ; aux [ 9 I =nrminv;

1

E. gsserb

Performs a triangular decomposition of the nxn matrix A and calculates an upper bound for the relative error in the solution of linear systems of the form Ax = b.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 101: Numerical Library in C for Scientists and Engineers A

void gsserb (a, n,aux,ri,ci) a : float a[l:n, l:n];

entry: the matrix to be decomposed; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int; the order of the matrix; aux: float awc[0:ll];

entry: aux[0]: the machine precision; aux[2]: a relative tolerance; aux[4]: a value which is used for controlling pivoting; aux[6]: an upper bound for the relative precision of the matrix elements; exit: aux[l]: if R is the number of elimination steps performed, then aux[l] equals 1 if the

determinant of the principal submatrix of order R is positive, otherwise aux[l] = -1;

aux[3]: the number of elimination steps performed; aux[5]: the modulus of an element which is of maximum absolute value for the matrix

which has been given in array a; aux[7]: an upper bound for the growth; aux[9]: if awc[3]=n then aux[9] will be equal to the 1-norm of the inverse matrix, else

aux[9] will be undefined; aux[lI]: if aur[3]=n then the value of aux[ll] will be a rough upper bound for the

relative error in the solution of linear systems with a matrix as given in array a, else aux[ll] will be undefined. If no use can be made of the formula for the error bound as given above because of a very bad condition of the matrix then aux[ll] = -1;

ri: int ri[l:n]; exit: the pivotal row-indices; see gsselm; ci: int ci[l:n]; exit: the pivotal column-indices.

Functions used: gsselm, onenrminv, erbelm.

void gsserb (f loat **a, int n, float aux [I , int ri [I , int ci [I ) 1

void gsselm (f loat **, int, float [I , int [I , int [I ; float onenrminv(f1oat **, int); void erbelm(int, float [I , float) ;

gsselm (a, n, aux, ri, ci) ; if (aux[3] == n) erbelm(n,aux,onenrminv(a,n));

I

F. gssnri

Performs a triangular decomposition of the nxn matrix A and calculates 11 A-' 11 ,.

Function Parameters: void gssnri (a, n,aux,ri,ci)

a: float a[l:n,l:n]; entry: the matrix to be decomposed; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

Copyright 1995 by CRC Press, Inc

Page 102: Numerical Library in C for Scientists and Engineers A

unit diagonal omitted; n: int; the order of the matrix; aux: float aux[l:9];

entry: aux[2]: a relative tolerance; aux[4]: a value used for controlling pivoting; exit: aux[l]: if R is the number of elimination steps performed, then aux[l] equals 1 if the

determinant of the principal submatrix of order R is positive, otherwise awcJI] = -1;

aux[3]: the number of elimination steps performed; aux[5]: the modulus of an element which is of maximum absolute value for the matrix

which has been given in array a; aux[7]: an upper bound for the growth; aux[9]: if aux[3]=n then aux[9] will be equal to the 1-norm of the inverse matrix, else

aux[9] will be undefined; ri: int ri[l :n];

exit: the pivotal row-indices; see gsselm; ci: int ci[l:n];

exit: the pivotal column-indices.

Functions used: gsselm, onenrminv.

void gssnri (float **a, int n, float aux [ ] , int ri [I , int ci [ I )

3.1.2 Calculation of determinant

determ

Calculates the determinant of a triangularly decomposed matrix. The calculation of the determinant is done directly by calculating the product of the diagonal elements of the lower triangular matrix given in array a. The user is warned that overflow may occur if the order of the matrix is large.

Function Parameters: float determ (a,n,sign)

determ: delivers the calculated value of the determinant of the matrix; a: float a[l:n,l:n];

entry: the diagonal elements of the lower triangular matrix, obtained by triangular decomposition of the matrix, has to be given in a,,,, i=l , ..., n;

n: int; the order of the matrix whose determinant has to be calculated; sign: int;

entry: if the determinant of the matrix is positive then the value of sign should be +I ,

Copyright 1995 by CRC Press, Inc

Page 103: Numerical Library in C for Scientists and Engineers A

else -1; this value is delivered by the function gsselm or dec in awc[l].

float determ(f1oat **a, int n, int sign)

int i; float det;

det=l. 0; for (i=l; i<=n; i++) det *= a [il [il ; return (sign*fabs (det) ) ;

I

3.1.3 Solution of linear equations

A. sol

Solves the linear system whose matrix has been triangularly decomposed. sol should be called after the function dec and solves the linear system with a matrix whose triangularly decomposed form as produced by dec is given in array a and a right hand side as given in array b. sol leaves the array a and the permutation array p unaltered. After one call of dec, several calls of sol may follow for solving several systems having the same matrix but different right hand sides.

Function Parameters: void sol (a,n,p, b)

a: float a[l:n,I:n]; entry: the triangularly decomposed form of the matrix of the linear system as

produced by the function dec; n: int; the order of the matrix; p: intp[l:n];

exit: the pivotal indices, as produced by dec; b: float b[l:n];

entry: the right hand side of the linear system; exit: the solution of the linear system.

Function used: matvec.

void sol (float **a, int n, int p [I, float b [I ) I '

float matvec (int, int, int, float **, float [I 1 ; int k,pk; float r;

for (k=l; k<=n; k++) { r=b [kl ; pk=p [kl ; b [k] = (b [pk] -matvec (1, k-1, k, a,b) )/a [kl [kl ; if (pk != k) b[pkl=r;

I ;or (k=n; k>=l; k--) b [kl -= matvec (k+l,n, k,a,b) ;

1

B. decsol

Copyright 1995 by CRC Press, Inc

Page 104: Numerical Library in C for Scientists and Engineers A

Solves a well-conditioned linear system of equations Ax = b whose order is small relative to the number of binary digits in the number representation.

Function Parameters: void decsol (a, n,am, b)

a: float a[l:n,l:n]; entry: the n-th order matrix; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int; the order of the matrix; am: float aux[l:3];

entry: am[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

exit: a w l : if R is the number of elimination steps performed (see am[3n, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else a d ] = -I;

am[3]: the number of elimination steps performed, if awc[3] < n then the process is terminated and no solution will be calculated;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if am[3] = n, then the calculated solution of the linear system is overwritten

on b, else b remains unaltered.

Functions used: dec, sol.

void decsol (float **a, int n, float aux [I , float b [I ) 1

int *allocate-integer-vector(int, int); void free-integer-vector(int *, int); void sol (float **, int, int [I , float [I ) ; void dec(f1oat **, int, float [I, int [ I ) ; int *p;

Solves the nxn system of equations Ax = b whose matrix has been triangularly decomposed by the function gsselm or gsserb. solelm leaves the matrix a and permutation arrays ri and ci unaltered. After one call of gsselm or gsserb, several calls of solelm may follow for solving several systems having the same matrix but different right hand sides.

Function Parameters: void solelm (a,n,ri,ci,b)

a: float a[l:n, l:n];

Copyright 1995 by CRC Press, Inc

Page 105: Numerical Library in C for Scientists and Engineers A

n: ri:

ci:

b:

entry: the triangularly decomposed form of the matrix of the linear system as produced by gsselm;

int; the order of the matrix; int ri[l :n]; entry: the pivotal row indices, as produced by gsselm; int ci[l:n]; entry: the pivotal column indices, as produced by gsselm; float b[l:n]; entry: the right hand side of the linear system; exit: the solution of the linear system.

Function used: sol.

void solelm(float **a, int n, int ri[] , int ci [I, float b[l) I

void sol (float ** , int, int [I, float 11) ; int r, cir; float w;

sol(a,n,ri,b) ; for (r=n; r>=l; r--) {

cir=ci [rl ; if (cir != r) {

w=b [rl ; b [rl =b [cirl ; b [cirl =w;

1 1

1

D. gsssol

Solves a linear system. gsssol first calls gsselm to decompose the matrix and then solelm to solve the linear system.

Function Parameters: void gsssol (a,n,aux, b)

a: float a[l:n, l:n]; entry: the n-th order matrix; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int; the order of the matrix; am: float a d l : 71;

entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; exit: aux[l]: if R is the number of elimination steps performed (see aux[3J, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] = -I;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process is

Copyright 1995 by CRC Press, Inc

Page 106: Numerical Library in C for Scientists and Engineers A

terminated and no solution will be calculated; am[5]: the modulus of an element which is of maximum absolute value for the matrix

given in array a; am[7]: an upper bound for the growth, see gsselm;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if awc[3] = n, then the calculated solution of the linear system is overwritten

on b, else b remains unaltered.

Functions used: solelm, gsselm.

void gsssol (float **a, int n, float aux[l , float b [ l ) t

int *allocate-integer-vector(int, int) ; void free-integervector(int *, int); void solelrn(f1oat **, int, int [I, int [I, float [ I ; void gsselrn(f1oat **, int, float [ I , int [ I , int [ I ) ; int *ri, *ci;

ri=allocate-integer-vector(1,n); ci=allocate-integer-vector(1,n) ; gsselm(a,n, aux, ri, ci) ; if (aux[3] == n) solelrn(a,n, ri, ci,b) ; free-integer-vector(ri,l); free-integer-vector(ci,l);

1

E. gsssolerb

Solves the nxn system of equation Ax = b, and provides an upper bound for the relative error in x. gsssolerb calls gsserb to perform the triangular decomposition and to calculate an upper bound for the relative error, and then calls solelm to calculate x.

Function Parameters: void gsssolerb (a,n,aux, b)

a: float a[l : n, I: n]; entry: the n-th order matrix; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int;

entry: the order of the matrix; am: float aux[O: 1 I];

entry: auQ]: the machine precision; awc[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; am[6]: an upper bound for the relative precision of the given matrix elements; exit: aux[l]: if R is the number of elimination steps performed (see am[3A, then am[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else am[l] = -1;

Copyright 1995 by CRC Press, Inc

Page 107: Numerical Library in C for Scientists and Engineers A

awc[3]: the number of elimination steps performed, if a2431 < n then the process is terminated and no solution will be calculated;

ax@]: the modulus of an element which is of maximum absolute value for the matrix given in array a;

aux[7]: an upper bound for the growth, see gsselm; aux[9]: if aux[3] = n then aux[9] will be equal to the 1-norm of the inverse matrix,

else a2491 will be undefined; am[l I]: if aux[3] = n then the value of aux[l I] will be a rough upper bound for

the relative error in the calculated solution of the given linear system, else aux[ll] will be undefined; if no use can be made of the formula for the error bound because of a very bad condition of the matrix, otherwise aux[ll] = -1.

b: float b[l:n]; entry: the right hand side of the linear system; exit: if aux[3] = n, then the calculated solution of the linear system is overwritten

on b, else b remains unaltered.

Functions used: solelm, gsserb.

void gsssolerb (float **a, int n, float aux [I , float b [ I ) I

int *allocate-integer-vector(int, int); void free-integer-vector(int *, int); void solelm(f1oat **, int, int [ I , int [ I , float 11); void gsserb (float **, int, float [I, int [I, int 11 ) ; int *ri,*ci;

3.1.4 Matrix inversion

A. inv

Calculates the inverse of a matrix that has been triangularly decomposed by dec.

Function Parameters: void inv (u,n,p)

a: float a[l:n,l:n]; entry: the triangularly decomposed form of the matrix as produced by the function

dec; exit: the calculated inverse matrix;

n: int; the order of the matrix; p: int p[l:n];

entry: the pivotal indices, as produced by dec.

Functions used: matmat, ichcol, dupcolvec.

Copyright 1995 by CRC Press, Inc

Page 108: Numerical Library in C for Scientists and Engineers A

void inv(f1oat **a, int n, int p[l) I L

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float matmat(int, int, int, int, float **, float * * ) ; void ichcol (int, int, int, int, float **) ; void dupcolvec (int, int, int, float **, float [I ) ; int j,k,kl; float r,*v;

v=allocate~real~vector(l,n); for (k=n; k>=l; k--) (

kl=k+l; for (j=n; j>=kl; j--) {

a[jl [kll=vfjl ; ~ [ j ] = -matmat(kl,n,k,j,a,a) ;

I

:=a [kl I ~ I ; for (j=n; j>=kl; j--) {

a[kl [jl=v[jl ; v[j] = -matmat (kl,n, j,k,a,a)/r;

1

dupcolvec(l,n,l,a,v) ; for (k=n-1; k>=l; k--) {

kl=p [kl ; if (kl ! = k) ichcol(l,n,k,kl,a);

B. decinv

Obtains the inverse of the nxn matrix by partial pivoting using successive calls of the functions dec and inv.

Function Parameters: void decinv (a, n, am)

a: float a[I:n, l:n]; entry: the matrix whose inverse has to be calculated; exit: if aux[3] = n, then the calculated inverse matrix;

n: int; the order of the matrix; aux: float aux[i:3];

entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

exit: aux[l]: if R is the number of elimination steps performed (see aux[3B, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] = -1;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process is terminated and no inverse will be calculated.

Functions used: dec, inv.

yoid decinv(f1oat **a, int n, float aux[l) I

int *allocate-integer-vector(int, int);

Copyright 1995 by CRC Press, Inc

Page 109: Numerical Library in C for Scientists and Engineers A

void free-integer-vector(int *, int); void dec (float: **, int, float [ I , int [I ) ; void inv(f1oat **, int, int [I ) ; int *p;

p=allocate~integer~vector(l,n); dec (a.n,aux,p) ; if (aux[3] == n) inv(a,n,p) ; free-integer-vector(p,l);

1

C. invl

Calculates the inverse of a matrix that has been triangularly decomposed by the function gsselm or gsserb. The I-norm of the inverse matrix might also be calculated.

Function Parameters: float invl (a,n,ri,ci,withnorm)

invl: if the value of withnorm is nonzero then the value of invl will be equal to the 1- norm of the calculated inverse matrix, else invl = 0;

a: float a[l:n,l:n]; entry: the triangularly decomposed form of the matrix as produced by gsselm; exit: the calculated inverse matrix;

n: int; the order of the matrix; ri: int ri[l:n];

entry: the pivotal row indices, as produced by gsselm; ci: int ci[l:n];

entry: the pivotal column indices, as produced by gsselm; withnorm: int;

entry: if the value of withnorm is nonzero then the 1-norm of the inverse matrix will be calculated and assigned to invl, else invl = 0.

Functions used: ichrow, inv.

void ichrow(int, int, int, int, float * * ) ; void inv(f1oat ** , int, int [ I ) ; int l,k,kl; float aid, nrminv;

inv(a,n,ri) ; nrmiwk0.0; if (withnorm)

for (1=1; l<=n; I++) nrminv += fabs (a [ll [nl ) ; for (k=n-1; k>=l; k--1 {

if (withnorm) { aid=O. 0 ; for (1=1; l<=n; 1++) aid t= f abs (a f l l [kl ) ; if (nrminv < aid) nrminv=aid;

) k=ci [kl ; if (kl ! = k) ichrow(l,n,k,kl,a) ;

1 return (nrminv) ;

1

Copyright 1995 by CRC Press, Inc

Page 110: Numerical Library in C for Scientists and Engineers A

D. gssinv

Uses the function gsselm to perform a triangular decomposition of the matrix and the function invl to calculate the inverse matrix.

Function Parameters: void gssinv (a,n,aux)

a: float a[l:n,l:n]; entry: the matrix whose inverse has to be calculated; exit: if aux[3] = n then the calculated inverse matrix;

n: int; entry: the order of the matrix;

a m : float aux[l:9]; entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; exit: aux[l]: if R is the number of elimination steps performed (see aux[3fi, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] = -1;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process is terminated and no solution will be calculated;

aux[5]: the modulus of an element which is of maximum absolute value for the matrix given in array a;

aux[7]: an upper bound for the growth, see gsselm; ax@]: if aux[3] = n then aux[9] will be equal to the 1-norm of the calculated inverse

matrix, else a*] will be undefined.

Functions used: invl, gsselm.

void gssinv(f1oat **a, int n, float aux[l)

int *allocate-integer-vector(int, int); void free-integer-vector(int *, int); void gsselm (float **, int, float [ I , int [I , int [I ) ; float invl(f1oat ** , int, int [I, int [ I , int) ; int *ri,*ci;

E. gssinverb

Uses the function gsselm to perform the triangular decomposition of the matrix a , the function invl to calculate the inverse matrix and its 1-norm and the function erbelm to calculate an upper bound for the relative error in the calculated inverse.

Copyright 1995 by CRC Press, Inc

Page 111: Numerical Library in C for Scientists and Engineers A

Function Parameters: void gssinverb (a,n,aux)

a: float a[l:n,I:n]; entry: the matrix whose inverse has to be calculated; exit: if aux[3] = n then the calculated inverse matrix;

n: int; entry: the order of the matrix;

a m : float aux[O: 1 I]; entry: a@]: the machine precision; aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; aux[6]: an upper bound for the relative precision of the given matrix elements; exit: am[l]: if R is the number of elimination steps performed (see am[3B, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] = -1;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process is terminated and no solution will be calculated;

aux[5]: the modulus of an element which is of maximum absolute value for the matrix given in array a;

aux[7]: an upper bound for the growth, see gsselm; aux[9]: if aux[3] = n then aux[9] will be equal to the 1-norm of the inverse matrix,

else am[9] will be undefined; aux[ll]: if aux[3] = n then the value of aux[ll] will be a rough upper bound for

the relative error in the calculated inverse matrix, else aux[ll] will be undefined; if no use can be made of the formula for the error bound because of a very bad condition of the matrix, otherwise aux[l I] = -1.

Functions used: invl, gsselm, erbelm.

void gssinverb(f1oat **a, int n, float am[])

' int *allocate-integer-vector(int, int); void free-integer-vector(int *, int); void gsselm(f1oat ** , int, float [ I , int [I , int [ I ) ; float invl(f1oat ** , int, int [I, int [I, int) ; void erbelm (int, float [I , float) ; int *ri,*ci;

ri=allocate-integer-vector(1,n); ci=allocate-integer-vector(1,n); gsselm(a,n,aux,ri,ci) ; if (aux[3] == n) erbelm(n,am,invl (a,n,ri,ci, 1) ) ; free-integer-vector(ri,l); f ree-integer-vector (ci, 1) ;

1

3.1.5 Iteratively improved solution

A. itisol

Copyright 1995 by CRC Press, Inc

Page 112: Numerical Library in C for Scientists and Engineers A

Solves a linear system Ax = b whose matrix has been triangularly decomposed by the function gsselm or gsserb. This solution will be refined iteratively until the calculated relative correction to this solution will be less than a prescribed value (see aux[lOn. Each iteration of the refinement process consists of the following three steps [Bus72a, Dek71, Wi651:

(a) calculate in double precision, the residual vector r defined by r = AXk - b, where xk denotes the solution obtained in the k-th iteration;

(b) calculate the solution c of the linear system Ac = r, with the aid of the triangularly decomposed matrix as given in the array lu;

(c) calculate the new solution $'' = Xk - C.

Function Parameters: void itisol (a, lu,n,aux,ri,ci, b)

a: float a[l:n,l:n]; entry: the matrix of the linear system;

lu: float lu[l :n, 1 :n]; entry: the triangularly decomposed form of the matrix given in a , as delivered by

gsselm; n: int; the order of the matrix; a m : float aux[lO: 131;

entry: aux[lO]: a relative tolerance for the solution vector; if the 1-norm of the vector of

corrections to the solution divided by the 1-norm of the calculated solution is smaller than aux[lO], then the process will stop; the user should not choose the value of aux[lO] smaller than the relative precision of the elements of the matrix and the right hand side of the linear system;

aux[l2]: the maximum number of iterations allowed for the refinement of the solution; if the number of iterations exceeds the value of aux[l2] then the process will be broken off; usually aux[l2] = 5 will give good results;

exit: aux[ll]: the 1-norm of the vector of corrections to the solution in the last iteration

step divided by the 1-norm of the calculated solution; if awc[l I] > aux[lO] then the process has been broken off because the number of iterations exceeded the value given in aux[l2];

aux[l3]: the 1-norm of the residual vector r above; ri: int ri[l:n];

entry: the pivotal row-indices, as produced by gsselm; ci: int ci[l:n];

entry: the pivotal column-indices, as produced by gsselm; b: float b[l:n];

entry: the right hand side of the linear system; exit: the calculated solution of the linear system.

Functions used: solelm, inivec, dupvec.

Method: If the condition of the matrix is not too bad then the precision of the calculated solution will be of the order of the precision asked for in a d l o ] . If the condition of the matrix is very bad then this process will possibly not converge

Copyright 1995 by CRC Press, Inc

Page 113: Numerical Library in C for Scientists and Engineers A

or, in exceptional cases, converge to a useless result. If the user wants to make certain about the precision of the calculated solution then the function itisolerb should be used. itisol leaves a, lu, ri and ci unaltered, so after one call of gsselm several calls of itisol may follow to calculate the solution of several linear systems with the same matrix but different right hand sides.

void itisol(f1oat **a, float **lu, int n, float aux[l, int ri[], int ci[], float b[l)

( float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); void solelm(f1oat ** , int, int [I, int [I, float [I ) ; void inivec (int, int, float [ I , float) ; void dupvec (int, int, int, float [I , float [I ) ; int i,j,iter,maxiter; float maxerx,erx,nrmres,nrms~l,r,rr,*res,*sol; double dtemp;

res=allocate~real~vector(l,n); sol=allocate-real-vector(1,n) ; maxerx=erx=aux [lo1 ; maxiter=aux [l21 ; inivec(l,n,sol,O.O); dupvec(l,n,O,res,b); iter=l; do {

solelm(lu,n,ri,ci, res) ; erx=nrmsol=nrmres=O.O; for (i=l; i<=n; i++) {

r=res [il ; erx += fabs(r); rr=sol [il +r; sol [il =rr; nrmsol += fabs (rr) ;

1 J erx /= nrmsol; for (i=l; i<=n; i++) {

dtemp = - (double) b [il ; for (j=l; j<=n; j++)

dtemp += (double) a [il [jl (double) sol [jl ; r = -dtemp; res [il =r; nrmres += fabs(r);

1 iter++;

} while ((iter <= maxiter) && (maxerx c erx)) ; dupvec(l,n,O,b,sol); aux [lll =erx; aux [l3 1 =nrmres ; free-real-vector(res,l); f ree-real-vector (sol, 1) ;

1

B. gssitisol

Uses the function gsselm to perform a triangular decomposition of the matrix and the function itisol to calculate an iteratively refined solution of the given linear system.

Function Parameters: void gssitisol (a,n,aux, b)

a: float a[l:n, 1 :n]; entry: the n-th order matrix;

Copyright 1995 by CRC Press, Inc

Page 114: Numerical Library in C for Scientists and Engineers A

exit: the calculated lower triangular matrix and unit upper triangular matrix with its unit diagonal omitted;

n: int; entry: the order of the matrix; aux: float aux[l:13];

entry: aux[2]: a relative tolerance for the process of triangular decomposition; a reasonable

choice for this value is an estimate of the relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; aux[lO]: a relative tolerance for the solution vector; if the I-norm of the vector of

corrections to the solution divided by the I-norm of the calculated solution is smaller than aux[lO], then the process will stop; the user should not choose the value of aux[10] smaller than the relative precision of the elements of the matrix and the right hand side of the linear system;

aux[l2]: the maximum number of iterations allowed for the refinement of the solution; if the number of iterations exceeds the value of aux[l2] then the process will be broken off; usually aux[l2] = 5 will give good results;

exit: aux[l]: if R is the number of elimination steps performed (see aux[3fi, then aux[l]

equals 1 if the determinant of the principal submatrix of order R is positive, else aux[l] = -1;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process has been broken off and no solution will have been calculated;

aux[5]: modulus of an element which is of maximum absolute value for array a ; aux[7]: an upper bound for the growth, see gsselm; aux[ll]: if aux[3] < n then aux[ll] will be undefined, else aux[ll] will be equal

to the 1-norm of the vector of corrections to the solution in the last step divided by the 1-norm of the calculated solution; if aux[ll] > aux[lO] then the process has been broken off because the number of iterations exceeded the value given in aux[l2];

aux[l3]: if aux[3] = n then the value of aux[l3] will be equal to the I-norm of the residual vector (see itisol), else aux[l3] will be undefined;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if aux[3] = n, then the calculated solution of the linear system is overwritten

on b. else b remains unaltered.

Functions used: dupmat, gsselm, itisol.

void gssitisol(f1oat **a, int n, float auxll, float b [ l ) I 1

int *allocate-integer-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int *, int); void free-real-matrix(f1oat ** , int, int, int); void gsselm(f1oat ** , int, float [I, int [I, int [I ) ; void itisol(f1oat **, float ** , int, float 11,

int [I, int [I, float [I); void dupmat (int, int, int, int, float ** , float * * ) ; int *ri,*ci; float **aa;

Copyright 1995 by CRC Press, Inc

Page 115: Numerical Library in C for Scientists and Engineers A

dupmat (l,n, l,n,aa,a) ; gsselm(a,n, aux, ri,ci) ; if (aux 131 == n) itisol (aa, a,n, aux, ri, ci, b) ;

free-integer-vector (ri, 1) ; free-integer-vector(ci,l); free-real-matrix (aa, 1, n, 1) ;

1

C. itisolerb

Solves a linear system Ax = b whose matrix has been triangularly decomposed by the function gssnri (the function gssnri also delivers the proper values for the odd elements of the array am). itisolerb calculates, with the use of the function itisol, an iteratively improved solution of the linear system. Moreover, with values of the machine precision E

and of I(A- ' (1 , available, and also with upper bounds q, for 11 AA (1 ,I ( (A (1 ,, AA being the matrix of errors in A, and q, for 11 ab 11 ,/ 11 b 11 ,, ab being the vector of errors in b available, itisolerb calculates a realistic upper bound for the relative error 11 AX 11 ,I 11 x 11 I in the calculated solution [Bus72a, Dek711. The latter bound is given by

where

C being the computed inverse of A, and

a being the upper bound for the growth of auxiliary numbers during Gauss elimination (the value allocated to awc[7] at exit from the function gssnri). itisolerb leaves a, lu, ri and ci unaltered, so after one call of gssnri several calls of itisolerb may follow, to calculate the solution of several linear systems with the same matrix but different right hand sides.

Function Parameters: void itisolerb (a, lu,n,am, ri, ci, b)

a: float a[l:n,l:n]; entry: the matrix of the linear system;

lu: float lu[l:n,l:n]; entry: the triangularly decomposed form of the matrix given in a, as delivered by

gssnri; n: int;

entry: the order of the matrix; aux: float am[0:13];

entry:

Copyright 1995 by CRC Press, Inc

Page 116: Numerical Library in C for Scientists and Engineers A

aux[O]: the machine precision; aux[5]: the modulus of an element which is of maximum absolute value for the matrix

of the linear system, this value is delivered by gssnri in aux[5]; aux[6]: an upper bound for the relative error in the elements of the matrix of the linear

system; the value of q, above; aux[7]: an upper bound for the growth during Gaussian elimination, this value is

delivered by gssnri in aux[7]; the value of a above; aux[8]: an upper bound for the relative error in the elements of the right hand side of

the linear system; the value of q, above; aux[9]: the 1-norm of the inverse matrix, this value is delivered by gssnri in a@];

the value of 11 C 11 , above; aux[IO]: a relative tolerance for the solution vector; if the 1-norm of the vector of

corrections to the solution divided by the 1-norm of the calculated solution is smaller than aux[lO], then the process will stop; the user should not choose the value of aw;[lO] smaller than the relative precision of the elements of the matrix and the right hand side of the linear system, given in aux[6] and aux[8];

aux[12]: the maximum number of iterations allowed for the refinement of the solution; if the number of iterations exceeds the value of aux[l2] then the process will be broken off; usually aux[l2] = 5 will give good results;

exit: aux[lI]: a realistic upper bound (the value of p/(I-p) above) for the relative error

in the calculated solution; if no use can be made of the error formula then aux[ll] = -1;

aux[l3]: the 1-norm of the residual vector; the value of 11 AX-b 11 , for which the last iterative scheme operates.

ri: int ri[l:n]; entry: the pivotal row-indices, as produced by gssnri;

ci: int ci[l:n]; entry: the pivotal column-indices, as produced by gssnri;

b: float b[l:n]; entry: the right hand side of the linear system; exit: the calculated solution of the linear system.

Function used: itisol.

void itisolerb(f1oat **a, float **lu, int n, float aux[l, int ri [ I , int ci [I, float b [I )

1 void itisol(f1oat ** , float **, int, float [I,

int [I, int [I, float [I 1 ; int i; float nrmsol,nrminv,nrmb,alfa,tola,eps;

eps=aux [O] ; nrminv=aux [ 9 I ; tola=aux [51 *aux [61 ; nrmb=nrmsol=O.O; for (i=l; i<=n; i++) nrmb += fabs (b [il ) ; itisol (a, lu,n,aux,ri,ci,b) ; for (i=l; ic=n; i++) nrmsol += fabs(b[il); alfa=l. 0- (1.06*eps*aux[7] * (0.75*n+4.5) *n*n+tola) *nrminv; if (alfa < eps)

Copyright 1995 by CRC Press, Inc

Page 117: Numerical Library in C for Scientists and Engineers A

D. gssitisolerb

Uses the function gssnri to perform a triangular decomposition of the matrix and the function itisolerb to calculate an iteratively refined solution of the given linear system and a realistic upper bound for the relative error in the solution.

Function Parameters: void gssitisolerb (u,n,aux,b)

a : float a[l:n,l:n]; entry: the n-th order matrix; exit: the calculated lower triangular matrix and unit upper triangular matrix with its

unit diagonal omitted; n: int;

entry: the order of the matrix; aux: float aux[0:13];

entry: aux[O]: the machine precision; aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

aux[4]: a value used for controlling pivoting, see gsselm; aux[6]: an upper bound for the relative error in the matrix elements of the linear

system; aux[8]: an upper bound for the relative error in the elements of the right hand side; aux[lO]: a relative tolerance for the solution vector; if the 1-norm of the vector of

corrections to the solution divided by the 1-norm of the calculated solution is smaller than aux[lO], then the process will stop; the user should not choose the value of awc[lO] smaller than the relative precision of the elements of the matrix and the right hand side of the linear system (aux[lO] 1 aux[2A;

aux[l2]: the maximum number of iterations allowed for the refinement of the solution; if the number of iterations exceeds the value of aux[l2] then the process will be broken off; usually alur[l2] = 5 will give good results;

exit: aux[l]: if R is the number of elimination steps performed (see aux[3J, then ~ ~ $ 1 1

equals 1 if the determinant of the principal submatrix of order R is positive, else awl = -I;

aux[3]: the number of elimination steps performed, if aux[3] < n then the process has been broken off and no solution will have been calculated;

aux[5]: the modulus of an element which is of maximum absolute value for the matrix which had been given in array a;

aux[7]: an upper bound for the growth, see gsselm; aux[9]: if aux[3] = n then aux[9] will be equal to the 1-norm of the calculated inverse

Copyright 1995 by CRC Press, Inc

Page 118: Numerical Library in C for Scientists and Engineers A

matrix, else a d 9 1 will be undefined; aux[ll]: if a2431 < n then aux[ll] will be undefined, else awc[ll] will be equal

to a realistic upper bound for the relative error in the calculated solution; however, if no use can be made of the error formula (see itisolerb) then aux[ll] = -1;

aux[l3]: if aux[3] = n then the value of aux[l3] will be equal to the 1-norm of the residual vector (see itisol), else aux[l3] will be undefined;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if aux[3] = n, then the calculated solution of the linear system is overwritten

on b, else b remains unaltered.

Functions used: dupmat, gssnri, itisolerb.

void gssitisolerb (f loat **a, int n, float aux [I , float b [I )

{ int *allocate-integer-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-integer-vector(int *, int); void free-real-matrix(f1oat **, int, int, int); void gssnri(f1oat **, int, float [I, int [I, int [ I ) ; void itisolerb(f1oat **, float **, int, float [I,

int [I, int [I, float 11 1 ; void dupmat (int, int, int, int, float **, float **) ; int *ri, *ci; float **aa;

dupmat (l,n, l,n,aa,a) ; gssnri (a,n,aux, ri, ci) ; if (auxI31 == n) itisolerb(aa,a,n,aux,ri,ci,b) ;

free-integer-vector (ri, 1) ; free-integer-vector (ci, 1) ; free-real-matrix(aa, l,n, 1) ;

1

3.2 Real Symmetric positive definite matrices

3.2.1 Preparatory procedures

Calculates the Cholesky decomposition of a positive definite symmetric matrix whose upper triangle is given in a two-dimensional array. For a given symmetric positive definite matrix A, it computes the upper triangular matrix U for which u*U=A. The columns uF, (k=l , ..., n) of U are determined in succession. The decomposition process is broken off at stage k if

T a@ - < z * B, with B = rnax aiPiy 1 &n,

where .r is a tolerance supplied by the user. In this case the matrix, possibly modified by rounding errors, is not positive definite.

Copyright 1995 by CRC Press, Inc

Page 119: Numerical Library in C for Scientists and Engineers A

Function Parameters: void chldec2 (a, n, am)

a: float a[l:n,l:n]; entry: the upper triangle of the positive definite symmetric matrix must be given in

the upper triangular part of a (the elements a[i,j], i s j ) ; exit: the Cholesky decomposition of the matrix is delivered in the upper triangle of

a ; n: int; entry: the order of the matrix;

a m : float am[2:3]; entry: aux[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: am[3]: normal exit: aux[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then am[3] = k-1, where k is the last stage number.

Function used: tammat.

Method: The method used is Cholesky's square root method without pivoting [Dek68, Wi651.

void chldec2(float **a, int n, float aux[l)

float tarnmat (int, int, int, int, float ** , float * * ) ; int k, j; float r, epsnorrn;

r=O . 0; for (k=l; kc=n; k++)

if (a [k] [kl > r) r=a [kl [kl ; epsnorrn=aux [21 *r ; for (k=l; k<=n; k++) {

r=a[k] [k] -tarnmat (1,k-l,k,k,a,a) ; if (r <= epsnorrn) {

aux[3] =k-1; return;

1 a [k] [kl =r=sqrt (r) ; for (j=k+l; jc=n; j++)

a[kl [jl=(a[kl [jl-tammat(1,k-l,j,k,a,a))/r; \ aux [3l =n;

1

B. chldecl

Performs the Cholesky decomposition of a positive definite symmetric matrix whose upper triangle is given columnwise in a one-dimensional array, by Cholesky's square root method without pivoting (see the description of the function chldec2).

Function Parameters: void chldecl (a,n,aux)

a: float a[l :(n+l)d2];

Copyright 1995 by CRC Press, Inc

Page 120: Numerical Library in C for Scientists and Engineers A

entry: the upper triangular part of the positive definite symmetric matrix must be given colurnnwise in array a (the (i j)-th element of the matrix should be given in array a[&l)j/2+i], 1 S i Sj S n);

exit: the Cholesky decomposition of the matrix is delivered columnwise in a ; n: int;

entry: the order of the matrix; aux: float aux[2:3];

entry: aux[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: aux[3]: normal exit: aux[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then awc[3] = k-I , where k is the last stage number.

Function used: vecvec.

void chldecl(f1oat a[], int n, float aux[l) I

float vecvec (int, int, int, float [ I , float [I ) ; int j,k,kk,kj,low,up; float r, epsnorm;

kk=O ; for (k=l; kc=n; k++) {

kk += k; if (a [kkl > r) r=a [kkl ;

\ J epsnorm=aux [21 *r; kk=O ; for (k=l; k<=n; k++) (

kk += k; low=kk-k+l; up=kk-1; r=a [kkl -vecvec (low,up, 0, a,a) ; if (r <= epsnorm) (

auxr31 =k-1; return;

I a [kkl =r=sqrt (r) ; kj=kk+k; for (j=k+l; j<=n; j++) (

a[kj]=(a[kj] -vecvec(low,up,kj-kk,a,a) )/r; kj + = j ;

. I ) aux [31 =n;

1

3.2.2 Calculation of determinant

Calculates the determinant of a symmetric positive definite matrix whose Cholesky matrix is given in the upper triangle of a two-dimensional array. chldeterm2 should be called after a successful call of chldec2 or chldecsol2. chldeterm2 should not be called if overflow is

Copyright 1995 by CRC Press, Inc

Page 121: Numerical Library in C for Scientists and Engineers A

to be expected.

Function Parameters: float chldeterm2 (a, n)

a : float a[l:n,l:n]; entry: the upper triangular part of the Cholesky matrix as produced by chldec2 or

chldecsol2 must be given in the upper triangle of a; exit: the contents of a are not changed;

n: int; entry: the order of the matrix.

float chldeterrn2(float **a, int n) 1

int k; float d;

d=1.0; for (k=l; k<=n; k++) d *= a[kl [kl; return (d*d) ;

1

B. chldeterml

Calculates the determinant of a symmetric positive definite matrix whose Cholesky matrix is given columnwise in a one-dimensional array. chldeterml should be called after a successful call of chldecl or chldecsoll. chldeterml should not be called if overflow is to be expected.

Function Parameters: float chldeterml (a,n)

a: float a[l:(n+l)n/2]; entry: the upper triangular part of the Cholesky matrix as produced by chldecl or

chldecsoll must be given colurnnwise in array a; exit: the contents of a are not changed;

n: int; entry: the order of the matrix.

float chldeterml(f1oat a[], int n) I

int k,kk; float d;

d=1.0; kk=O ; for (k=l; k<=n; kc+) (

kk += k; d *= a [kkl ;

return (d*d) ; I

3.2.3 Solution of linear equations

Copyright 1995 by CRC Press, Inc

Page 122: Numerical Library in C for Scientists and Engineers A

Calculates the solution of a system of linear equations, provided that the coefficient matrix has been decomposed by a successful call of the function chldec2 or chldecsol2. The solution is obtained by carrying out the forward and back substitution with the Cholesky matrix and the right hand side. The elements of the Cholesky matrix are not changed. Several systems of linear equations with the same coefficient matrix but different right hand sides can be solved by successive calls of chlsol2 [Dek68].

Function Parameters: void chlsol2 (a,n, b)

a: float a[l:n, l:n]; entry: the upper triangular part of the Cholesky matrix as produced by chldec2 or

chldecsol2 must be given in the upper triangle of a; exit: the contents of a are not changed;

n: int; entry: the order of the matrix;

b: float b[l:n]; entry: the right hand side of the system of linear equations; exit: the solution of the system.

Functions used: matvec, tamvec.

void chlsol2(float **a, int n, float b[l) i

float matvec (int, int, int, float **, float 11) ; float tamvec (int, int, int, float ** , float [I ) ; int i;

for (i=l; ic=n; i++) b[il =(b[il -tamvec(l,i-l,i,a,b) )/a[il [il ; for (i=n; i>=l; i--) b[i]=(b[i] -matvec(i+l,n,i,a,b) )/a[il [il ;

1

B. chlsoll

Calculates the solution of a system of linear equations, provided that the coefficient matrix has been decomposed by a successful call of the function chldecl or chldecsoll. The solution is obtained by carrying out the forward and back substitution with the Cholesky matrix and the right hand side. The elements of the Cholesky matrix are not changed. Several systems of linear equations with the same coefficient matrix but different right hand sides can be solved by successive calls of chlsoll.

Function Parameters: void chlsoll (a,n, b)

a: float a[l:(n+l)n/2]; entry: the upper triangular part of the Cholesky matrix as produced by chldecl or

chldecsoll must be given columnwise in array a; exit: the contents of a are not changed;

n: int; entry: the order of the matrix;

b: float b[l:n]; entry: the right hand side of the system of linear equations; exit: the solution of the system.

Copyright 1995 by CRC Press, Inc

Page 123: Numerical Library in C for Scientists and Engineers A

Functions used: vecvec, seqvec.

void chlsoll (float a [I , int n, float b [I ) I

float vecvec (int, int, int, float [I, float [I ) ; float seqvec (int, int, int, int, float [ I , float [I ; int i,ii;

ii=O; for (i=l; ic=n; i++) {

ii += i; b[i] = (b[i] -vecvec(l,i-1,ii-i,b,a) ) /a[iil ;

1 for (i=n; i>=l; i--) (

b [i] = (b [i] -seqvec (i+l,n, ii+i, 0, a, b) ) /a [iil ;

Solves a system of linear equations with a symmetric positive definite coefficient matrix by calling chldec2 and, if the call is successful, chlsol2. The coefficient matrix must be given in the upper triangle of a two-dimensional array.

Function Parameters: void chldecsol2 (a,n,aux, b)

a: float a[l:n, l:n]; entry: the upper triangle of the symmetric positive definite matrix must be given in

the upper triangular part of a (the elements a[i,j], i Sj); exit: the Cholesky decomposition of the matrix is delivered in the upper triangle of

a; n: int; entry: the order of the matrix;

am: float aux[2:3]; entry: aux[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: aux[3]: normal exit: aux[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then aux[3] = k-I, where k is the last stage number.

b: float b[l:n]; entry: the right hand side of the system of linear equations; exit: the solution of the system.

Functions used: chldec2, chlsol2.

void chldecsol2 (float **a, int n, float aux [I , float b [I ) l

void chldec2 (float **, int, float [ I ) ; void chlsol2 (float **, int, float [I ) ;

chldec2 (a,n, a=) ; if (aux [3] == n) chlsol2 (a,n, b) ;

1

Copyright 1995 by CRC Press, Inc

Page 124: Numerical Library in C for Scientists and Engineers A

D. chldecsoll

Solves a system of linear equations with a symmetric positive definite coefficient matrix by calling chldecl and, if the call is successful, chlsoll. The upper triangle of the coefficient matrix must be stored columnwise in a one-dimensional array.

Function Parameters: void chldecsoll (a,n,aux, b)

a: float a[l:(n+l)n/2]; entry: the upper triangular part of the symmetric positive definite matrix must be

given columnwise in array a (the elements (ij)-th element of the matrix must be given in a[&l)*j/2+i], I s i s j s n ) ;

exit: the Cholesky decomposition of the matrix is delivered columnwise in a; n: int;

entry: the order of the matrix; a m : float aux[2:3];

entry: aux[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: am[3]: normal exit: aux[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then aux[3] = k-1, where k is the last stage number.

b: float b[l:n]; entry: the right hand side of the system of linear equations; exit: the solution of the system.

Functions used: chldecl, chlsoll.

void chldecsoll (float a [ I , int n, float aux [ I , float b [ I ) I ' void chldecl (float [ I , int, float [ I ) ;

void chlsoll(f1oat [ I , int, float [ I ) ;

3.2.4 Matrix inversion

Calculates the inverse X of a symmetric positive definite matrix A, provided that the matrix has been decomposed (A = uTU, where U is the Cholesky matrix) by a successful call of chldec2 or chldecsol2. The Cholesky matrix must be given in the upper triangle of a two- dimensional array. The inverse X i s obtained from the conditions that X be symmetric and UX be a lower triangular matrix whose main diagonal elements are the reciprocals of the diagonal elements of U. The upper triangular elements of X are calculated by back substitution [Dek68].

Copyright 1995 by CRC Press, Inc

Page 125: Numerical Library in C for Scientists and Engineers A

Function Parameters: void chlinv2 (a,n)

a : float a[l:n,l:n]; entry: the upper triangular part of the Cholesky matrix as produced by chldec2 or

chldecsol2 must be given in the upper triangle of a; exit: the upper triangular part of the inverse matrix is delivered in the upper triangle

of a; n: int;

entry: the order of the matrix.

Functions used: matvec, tamvec, dupvecrow.

void chlinv2(float **a, int n) I

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void dupvecrow(int, int, int, float [I, float * * ) ; float matvec(int, int, int, float **, float [I ) ; float tamvec (int, int, int, float ** , float [I ) ; int i,j,il; float r, *u;

u=allocate-realvector(1,n) ; for (i=n; i>=l; i--) {

r=l.O/a Iil [il ; il=i+l: dupvecrow(il,n,i,u,a) ; for (j=n; js=il; j--)

a[i] [j] = -(tamvec(il, j, j,a,u)+matvec(j+l,n, j,a,u) )*r; a[i] [i] =(r-matvec(il,n,i,a,u)) *r;

B. chlinvl

Calculates the inverse X of a symmetric positive definite matrix A, provided that the matrix has been decomposed (A = UTu, where U is the Cholesky matrix) by a successful call of chldecl or chldecsoll. The upper triangular part of the Cholesky matrix must be given columnwise in a one-dimensional array. The inverse X i s obtained from the conditions that X be symmetric and UX be a lower triangular matrix whose main diagonal elements are the reciprocals of the diagonal elements of U. The upper triangular elements of Xare calculated by back substitution.

Function Parameters: void chlinvl (a,n)

a : float a[l:(n+l)d2]; entry: the upper triangular part of the Cholesky matrix as produced by chldecl or

chldecsoll must be given colurnnwise in array a; exit: the upper triangular part of the inverse matrix is delivered columnwise in array

a; n: int;

entry: the order of the matrix.

Functions used: seqvec, symmatvec.

Copyright 1995 by CRC Press, Inc

Page 126: Numerical Library in C for Scientists and Engineers A

void chlinvl (float a [I , int n) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float seqvec (int, int, int, int, float [ I , float [I ; float symmatvec (int, int, int, float [I , float [I ) ; int i,ii,il, j,ij; float r, *u;

u=allocate-real-vector (1,n) ; ii= ( (n+l) *n) /2; for (i=n; i>=l; i--) {

r=l. 0/a [iil ; il=i+l; i j=ii+i ; for (j=il; j<=n; j++) {

u[jl=a[ijl ; ij += 1;

1

Calculates the inverse of a symmetric positive definite coefficient matrix by calling chldec2 and, if the call is successful, chlinv2. The coefficient matrix must be given in the upper triangle of a two-dimensional array.

Function Parameters: void chldecinv2 (a, n, am)

a: float a[l:n,l:n]; entry: the upper triangle of the symmetric positive definite matrix must be given in

the upper triangular part of a (the elements a[i,j], i Sj); exit: the upper triangular part of the inverse matrix is delivered in the upper triangle

of a; n: int;

entry: the order of the matrix; aux: float am[2:3];

entry: am[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: am[3]: normal exit: am[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then am[3] = k-I, where k is the last stage number.

Functions used: chldec2, chlinv2.

void chldecinv2(float **a, int n, float aux[l) I ' void chldec2 (float **, int, float' [I ;

void chlinv2(float **, int);

Copyright 1995 by CRC Press, Inc

Page 127: Numerical Library in C for Scientists and Engineers A

D. chldecinvl

Calculates the inverse of a symmetric positive definite matrix by calling chldecl and, if the call is successful, chlinvl. The upper triangle of the coefficient matrix must be stored columnwise in a one-dimensional array.

Function Parameters: void chldecinvl (a,n,aux)

a: float a[]: (n+ l)n/2]; entry: the upper triangular part of the symmetric positive definite matrix must be

given columnwise in array a (the elements (ij)-th element of the matrix must be given in a[&l)j/2+i], 1 l i l j l n ) ;

exit: the upper triangular part of the inverse matrix is delivered columnwise in a ; n: int;

entry: the order of the matrix; a m : float aux[2:3];

entry: am[2]: a relative tolerance used to control the calculation of the diagonal elements; exit: aux[3]: normal exit: aux[3] = n;

abnormal exit: if the decomposition fails because the matrix is not positive definite then aux[3] = k-1, where k is the last stage number.

Functions used: chldecl, chlinvl.

void chldecinvl(f1oat a[], int n, float aux[l) {

void chldecl(f1oat [I, int, float [ I ) ; void chlinvl(f1oat [ I , int) ;

chldecl (a, n, aux) ; if (auxL31 == n) chlinvl(a,n) ;

f

3.3 General real symmetric matrices

3.3.1 Preparatory procedure

Calculates the L D L ~ decomposition of a symmetric matrix which may be indefinite andfor singular. Before the decomposition is performed, a check is made to see whether the matrix is symmetric. If the matrix is asymmetric then no decomposition is performed. Given a real symmetric nxn matrix A, it attempts to obtain the pivot reference integers p(i) associated with a permutation matrix P, a unit lower triangular matrix L and a block diagonal matrix D with 1x1 or 2x2 blocks of elements on its principal diagonal and zeros

Copyright 1995 by CRC Press, Inc

Page 128: Numerical Library in C for Scientists and Engineers A

elsewhere, such that P ~ A P = LDL~. The decomposition process used involves the recursive construction of a system of i x i matrices Ao) (i=n, ..., k) with A'") = AA"), where s=l or s=2 is determined from A@, by use of the decomposition

where P(" is an i x i permutation matrix and E is sxs nonsingular, and of the reduction formula

In the following I,,,, is the permutation matrix obtained by interchanging rows m and r of the i x i identity matrix I; a = (I + 171'2)/8 = 0.6404 is a fixed parameter; the determinations of P(') and s at each stage result from computations of a sequence of steps which may terminate at the stages a2, b2, cl or dl (thus if termination at stage a2 does not take place, b l and b2 are embarked upon, etc.).

a l : obtain A = max 1~:: 1 (2 sksi) and r for which A = l~,!;': 1 ;

a2: if /A:f),l > a h , set P(')=Z, s= l .

bl: obtain a =max /A:: 1 (1 sk,rsC k+;

b2: if ~A, ( f ) , l o>ah~ , set P ( ~ = I , s = l .

c l : if ~A;,!l>ao, set P("z~,~, s = l .

dl: set P(~=I , ,~ , s = 2 .

Copyright 1995 by CRC Press, Inc

Page 129: Numerical Library in C for Scientists and Engineers A

With

the choice of a = (1 + 171'2)/8 above leads to the element growth inequality

When Di,i+l=O, L,+l,i=O, so that if the block structure of D is known, the elements of D and L may be stored in the closed upper triangular part of the two dimensional array in which the elements of A are stored at entry. At exit from decsym2, the successive locations of the one-dimensional integer array p in the parameter list of decsym2 contain not only the pivot reference integers associated with the PO) above, but also information concerning the block structure of D: if p[i]>O and p[i+l]=O, D,,,#O and L,+,,=O. Upon successful exit from decsym2, the successive locations of the one-dimensional real array detaux contains numbers which are of use in computing the determinant of A. If p[i], p[i+l] > 0, detaux[i] = Di,i; if p[i] > 0, p[i+l] = 0, detaux[i] = 1 and detaux[i+l] is the determinant of

(", " j . 1

If g is the number of 1x1 blocks in D, so that h=(n-g)/2 is the number of 2x2 blocks, and u, v and w are respectively the numbers of positive, negative and zero 1x1 blocks, then u+h is the number of positive eigenvalues of A, v+h the number of negative eigenvalues, and w the number of zero eigenvalues (these numbers are delivered in successive locations of aux at exit from decsym2). The decision as to whether a 1x1 block D,, is zero is governed by the small real number z allocated to the real variable to1 upon call of decsym2: if I D,,, I < T, D,, is taken to be zero.

Function Parameters: void decsym2 (a, n, tol, aux,p,detaux)

a: float a[l :n, l:n]; entry: the symmetric coefficient matrix; exit: the elements of the LDLT decomposition of a are stored in the upper triangular

part of a; D is a block diagonal matrix with blocks of order 1 or 2, for a block of order 2 we always have D,,,+, # 0 and L,+,,i=O, so that D and L~ fit in the upper triangular part of a, the strictly lower triangular part of a is left undisturbed;

n: int; entry: the order of the matrix;

tol: float; entry: a relative tolerance used to control the calculation of the block diagonal

elements, the value of z above; aux: int aux[2:5];

exit: aux[2]: if the matrix is symmetric then 1; otherwise 0, and no decomposition of a is

performed; aux[3]: if the matrix is symmetric then the number of its positive eigenvalues,

Copyright 1995 by CRC Press, Inc

Page 130: Numerical Library in C for Scientists and Engineers A

otherwise 0; if aux[3]=n then the matrix is positive definite; aux[4]: if the matrix is symmetric then the number of its negative eigenvalues,

otherwise 0; if am[4]=n then the matrix is negative definite; am[5]: if the matrix is symmetric then the number of its zero eigenvalues, otherwise

0; if aux[5]=0 then the matrix is symmetric and non-singular; p: int p[l:n];

exit: a vector recording (1) the interchanges performed on array a during the computation of the decomposition and (2) the block structure of D; if p[i] > 0 and p[i+l] = 0 a 2x2 block has been found (Di,i+,#O and Li+,,;=O);

detaux: float detaux[l :n]; exit: ifp[i]>O and p[i+l]>O then detaux[i/ equals the exit value of a[i,i]; ifp[i]>O

and p[i+I]=O then detaux[i/=l and detaux[i+l] equals the value of the determinant of the corresponding 2x2 diagonal block as determined by decsym2.

Functions used: elmrow, ichrow, ichrowcol.

Method: The function decsym2 computes the LDL' decomposition of a symmetric matrix according to a method due to Bunch, Kaufinan and Parlett [BunK77, BunKP761. For the inertia problem it is important that decsym2 can accept singular matrices. However, in order to find the number of zero eigenvalues of singular matrices, the singular value decomposition might be preferred.

void decsym2(float **a, int n, float tol, int aux[l , int p [I , float detaux [I )

i void elmrow(int, int, int, int, float **, float **, float) ; void ichrow(int, int, int, int, float * * ) ; void ichrowcol (int, int, int, int, float **) ; int i,j,m,ipl,ip2,onebyone,sym; float det,s,t,alpha,lambda,sigma,aii,aipl,aipli,temp;

aux[3] =aux[41 =O; sym=1; i=O; while (sym && (i s n)) {

i++; j=i; while (sym && (j < n)) {

j++; sym = sym && (a[il [jl == a[jl [il);

, I I if (sym)

aux[2] 4 ; else {

auxl21 =O; aux [51 =n; return;

\ alpha=(l.O+sqrt(17.0))/8.0; p In1 =n; i=l; while (i s n) {

ipl=i+l; ip2=i+2 ; aii=fabs (a [il [il ) ; p [il =i; lambda=fabs (a [il [ipll ) ; j=ipl;

Copyright 1995 by CRC Press, Inc

Page 131: Numerical Library in C for Scientists and Engineers A

for (m=ip2; m<=n; m++) if (fabs (a [i] [ml ) > lambda) (

j=m; lambda=fabs (a [il [ml ) ;

\ t=alpha*lambda; onebyone=l; if (aii c t) (

sigma=lambda; for (m=ipl; mc=j-1; m++)

if (fabs (a [ml [jl ) > sigma) sigma=fabs (ah1 [jl ) ; for (m=j+l; mc=n; m++)

if (fabs (a [j] [m] ) > sigma) sigma=fabs (a [jl [ml ) ; if (sigma*aii c lambda) (

if (alpha*sigma c fabs(aCj1 [jl)) ( ichrow(j+l,n,i,, ],a) ; ichrowcol(ip1, J-l,i, j,a) ; t=a [i] [i] ; a[il [il=a[jl [jl; a[jl [jl=t; p [il =j ;

) else ( if (j > ipl) (

ichrow(j+l,n,ipl, j,a); ichrowcol(ip2, j-l,ipl, j,a) ; t=a [il [il ; a[il [il=a[jl [jl ; a[jl [jl=t; t=a[il [jl ; a [i] [j] =a [il [ipll ; a [il [ipll =t;

temp=a [il Lip11 ; det=a [il [il *a [ipll [ipll -temp*temp; aipli=a [il [ipll /det; aii=a [il [il /det; aipl=a [ipll Lip11 /det; p [il =j ; p [ipl] =O; detaux [il =l. 0; detaux[ipll =det; for (j=ip2; jc=n; j++) {

s=aipli*a [ipll jl -aipl*a [il [j I ; t=aipli*a[il [jl -aii*a Lip11 [jl ; elmrow(j,n, j,i,a,a,s); elmrow(j,n, j,ipl,a,a,t); a[il [jl=s; a[ipll [jl=t;

1

if (onebyone) { if (to1 < fabs (a [il [il ) ) (

aii=a [il [il ; detaux lil =a [il [il ; if (aii > 0.0)

aux I31 ++; else

aux Ill ++; for (j=ipl; j<=n; j++) {

s = -a [il [jl /aii; elmrow(j,n, j,i,a,a,s); a[il [jl=s;

1 1

i=ipl;

1 1

if (i == n) (

Copyright 1995 by CRC Press, Inc

Page 132: Numerical Library in C for Scientists and Engineers A

if (to1 < fabs (a [nl [nl ) ) { if (a[nl [nl > 0.0)

aux [31++; else

aux [41++;

3.3.2 Calculation of determinant

Calculates the determinant of a symmetric matrix A, det(A). The function decsyrn2 should be called to perform the L D L ~ decomposition of the symmetric matrix. Given the values of the determinants of the blocks of the nxn block diagonal matrix D (which has I x l or 2x2 blocks of elements on its principal diagonal and zeros elsewhere) and the number rn of zero eigenvalues of A, deterrnsyrn2 evaluates det(A). If rn # 0 then det(A)=O, otherwise det(A) is simply the product of the above determinants of blocks.

Function Parameters: float determsym2 (detaux, n, aux)

deterrnsyrn2: delivers the calculated value of the determinant of the matrix; detaux: float detaux[l:n];

entry: the array detaux as produced by decsyrn2; n: int; the order of the array detaux ( = the order of the matrix ); aux: int aux[2: 51;

entry: the array a m as produced by decsyrn2.

float determsym2(float detaux[l, int n, int aux[l) {

int i; float det;

if (aux[5] > 0) det=O. 0;

else ( det=l. 0; for (i=l; i<=n; i++) det *= detaux[il;

1

3.3.3 Solution of linear equations

Solves a symmetric system of linear equations, assuming that the matrix has been decomposed into LDLT form by a call of decsyrn2.

Function Parameters: void solsym2 (a,n, b,p,detaux)

a: float a[l :n, Z:n];

Copyright 1995 by CRC Press, Inc

Page 133: Numerical Library in C for Scientists and Engineers A

entry: the L D L ~ decomposition of A as produced by decsym2; n: int;

entry: the order of the matrix; b: float b[l:n];

entry: the right hand side of the system of linear equations; exit: the solution of the system;

p: int p[l:n]; entry: a vector recording the interchanges performed on the matrix by decsym2, p

also contains information on the block structure of the matrix as decomposed by decsym2;

detaux: float detaux[l:n]; entry: the array detaux as produced by decsym2.

Functions used: matvec, elmvecrow.

void solsym2(float **a, int n, float b[l, int p[l, float detaux[l) 1

float matvec(int, int, int, float ** , float [I) ; void elmvecrow (int, int, int, float [I , float ** , float) ; int i,ii,k,ipl,pi,pii; float det, temp, save;

i=l; while (i < n) {

ipl=i+l; pi=p [il ; save=b [pi] ; if (p[ipll s 0) {

b [pi] =b [il ; b [i] =save/a [il [il ; elmvecrow(ipl,n, i, b, a, save) ; i=ipl;

) else { temp=b [il ; b [pi] =b [ipll ; det=detaux [ipll ; b [i] = (tempfa [ipll [ipll -save*a [il [ipll ) /det; b [ipl] = (save*a [il [il -temp*a [il [ipll ) /det; elmvecrow(i+2,n,i,b,a, temp) ; elrnvecrow(i+2,n,ipl,b,a, save) ; i += 2;

1 if (i == n) (

b [il /= a [il [il ; i=n-1;

} else i=n-2;

while (i > 0 ) ( if (p[il == 0)

ii=i-1; else

ii=i; for (k=ii; k<=i; k++) (

save=b [kl ; save += rnatvec (i+l,n,k,a,b) ; b [kl =save;

pii=p [iil ; b [il =b [piil ; b [piil =save; i=ii-1;

Copyright 1995 by CRC Press, Inc

Page 134: Numerical Library in C for Scientists and Engineers A

Computes the solution of a symmetric system of linear equations by first calling decsym2 to compute the L D L ~ decomposition of the symmetric matrix. If the matrix is found to be non-singular then the function solsym2 is called to compute the solution vector, otherwise the function solsym2 is not called.

Function Parameters: void decsolsym2 (a,n, b,tol,awc)

a: float a[l:n,l:n]; entry: see decsym2; exit: see decsym2;

n: int; entry: the order of the matrix;

b: float b[l:n]; entry: the right hand side of the system of linear equations; exit: if the matrix a is non-singular then b contains the solution of the system,

otherwise b is left undisturbed; tol: float;

entry: see decsym2; am: int aux[2:5];

exit: see decsym2.

Functions used: decsym2, solsym2

void decsolsym2(float **a, int n, float b[l , float tol, int aux[l) {

int *allocate integer vector(int, int); float *allocate-real-?ector(int, int); void free-integer-vector(int *, int) ; void free-real-vector(f1oat *, int); void decsym2 (float ** , int, float, lnt [I, int [I, float [I ) ; void solsym2 (float ** , int, float [I, int [ I , float [I) ; int *p; float *detaux;

3.4 Real full rank overdetermined systems

3.4.1 Preparatory procedures

A, lsqortdec

Reduces an nxm matrix A (n 2 m) to the column permuted form A', where R = QA', R being an nxm upper triangular matrix, and Q being an nxm orthogonal matrix having the form

Copyright 1995 by CRC Press, Inc

Page 135: Numerical Library in C for Scientists and Engineers A

Q is the product of at most m Householder matrices which are represented by their generating vectors. A is reduced to R in at most m stages. At the k-th stage the k-th column of the (already modified) matrix is interchanged with the column of maximum Euclidean norm (the pivot column). Then the matrix is multiplied by a Householder matrix such that the subdiagonal elements of the k-th column become zero while the first k-1 columns remain unchanged. The process terminates prematurely if at some stage the Euclidean norm of the pivotal column is less than some tolerance (a given tolerance aux[2] times the maximum of the Euclidean norms of the columns of the given matrix).

Function Parameters: void lsqortdec (a, n, m, aux,aid, ci)

a: float a[l:n,l:m]; entry: the coefficient matrix of the linear least square problem; exit: in the upper triangle of a (the elements a[i,j] with i<j) the superdiagonal

elements of the upper triangular matrix (matrix R above) produced by the Householder transformation; in the other part of the columns of a the significant elements of the generating vectors of the Householder matrices used for the Householder triangularization (values of dV) above);

n: int; entry: the number of rows of the matrix;

m: int; entry: the number of columns of the matrix (n 2 m);

aux: float aux[2:5]; entry: aux[2]: contains a relative tolerance used for calculating the diagonal elements of the

upper triangular matrix; exit: aux[3]: delivers the number of the diagonal elements of the upper triangular matrix

which are found not negligible, normal exit awc[3] = m; aux[5]: the maximum of the Euclidean norms of the columns of the given matrix;

aid: float aid[l:m]; exit: normal exit (aux[3] = m) aid contains the diagonal elements of the upper

triangular matrix produced by the Householder triangularization; ci: int ci[l:m];

exit: contains the pivotal indices of the interchanges of the columns of the given matrix.

Functions used: tammat, elmcol, ichcol.

Method: The method is Householder triangularization with column interchanges. It is a modification of [Dek68] where a derivation is given by [BusiG65].

#include cmath.h>

void lsqortdec(f1oat **a, int n, int m, float auxrl,

Copyright 1995 by CRC Press, Inc

Page 136: Numerical Library in C for Scientists and Engineers A

float *allocate~real~vector(int, int); void free-real-vector(f1oat *, int); float tammat (int, int, int, int, float ** , float * * ) ; void elmcol(int, int, int, int, float **, float **, float); void ichcol (int, int, int, int, float **) ; int j , k, kpiv; float beta,sigma,norm,w,eps,akk,aidk,temp,*sum;

sum=allocate~real~vector(l,m); norm=O .0 ; aux 131 =m; for (k=l; kc=m; k++) (

w=sum [kl =tammat (l,n,k,k,a,a) ; if (W > norm) norm=w;

1 &aux [51 =sqrt (norm) ; eps=aux 121 *w; for (k=l; k<=m; k++) {

sigma=sum [kl ; kpiv=k; for (j=k+l; jc=m; j++)

if (sum[jl > sigma) { sigma=sum [ j I ; kpiv= j ;

I

if (fcpiv != k) sum [kpiv] =sum [kl ; ichcol (l,n,k, kpiv,a) ;

1 ci [kl =kpiv; akk=a [kl [kl ; sigma=tammat (ken, k, k, a, a) ; w=sqrt (sigma) ; aidk=aid[k] = ( (akk c 0.0) ? w : -w) ; if (W c eps) {

aux[3] =k-1; break;

1 beta=l. 0/ (sigma-akk*aidk) ; a [k] [k] =akk-aidk; for (j=k+l; jc=m; j++) {

elmcol (k,n, j, k, a, a, -beta*tammat (k,n, k, j ,a, a) ) ; temp=a [kl [ j I ; sum[j] -= temp*temp;

1 1

free-real-vector(sum,l); 1

B. lsqdglinv

Computes the principal diagonal elements of the inverse of ATA, where A is the coefficient matrix of a linear least squares problem. It is assumed that A has been decomposed after calling lsqortdec successfully. These values can be used for the computation of the standard deviations of least squares solutions.

Function Parameters: void lsqdglinv (a, m, aux, ci, diag)

a,m,aid,ci: see Isqortdec; the contents of a, aid and ci should be produced by a successful call of Isqortdec;

diag: float diag[l :m]; exit: the diagonal elements of the inverse of ATA, where A is the matrix of the

linear least squares problem.

Copyright 1995 by CRC Press, Inc

Page 137: Numerical Library in C for Scientists and Engineers A

Functions used: vecvec, tamvec.

void lsqdglinv(f loat **a, int m, float aid[] , int ci [I , float diag [I ) 1

float vecvec(int, int, int, float [I, float 11 ) ; float tamvec (int, int, int, float **, float [I ) ; int j, k, cik; float w;

for (k=l; k<=m; k++) { diag [kl =l. 0/aid [kl ; for (j=k+l; j<=m; j++) diag [j] = -tamvec (k, j-1, j, a,diag) /aid[jl ; diag [kl =vecvec (k,m, 0, diag, diag) ;

I I for (k=m; k>=l; k--) {

cik=ci [kl ; if (cik ! = k) {

w=diag [kl ; diag [kl =diag [cikl ; diag [cikl =w;

1 1

1

3.4.2 Least squares solution

A. lsqsol

Determines the least squares solution of the overdetermined system Ax = b, where A is an nxm matrix (n 2 m). It is assumed that A has been decomposed by calling lsqortdec successfully. The least squares solutions of several overdetermined systems with the same coefficient matrix can be solved by successive calls of lsqsol with different right hand sides.

Function Parameters: void lsqsol (a, n,m,aid,ci, b)

u,n,m,aid,ci: see lsqortdec; the contents of the arrays a, aid and ci should be produced by a successful call of Isqortdec;

b: float b[l:n]; entry: contains the right hand side of a linear least squares problem; exit: b[l:m] contains the solution of the problem;

b[m+l:n] contains a vector with Euclidean length equal to the Euclidean length of the residual vector.

Functions used: matvec, tarnvec, elmveccol.

void lsqsol(f1oat **a, int n, int m, float aid[], int ci[l, float b[l) I

float matvec(int, int, int, float **, float [I ) ; float tamvec(int, int, int, float **, float [I); void elmveccol(int, int, int, float [I, float **, float); int k, cik; float w;

for (k=l; kc=m; k++) elmveccol (k,n,k,b,a, tamvec (k,n, k,a,b) / (aidlkl *a [kl [kl ) ) ;

for (k=m; k>=l; k--) b [kl = (b [kl -matvec (k+l,m,k,a, b) ) /aid[k] ; for (k=m; k>=l; k--1 {

cik=ci [kl ; if (cik != k) {

w=b [kl ;

Copyright 1995 by CRC Press, Inc

Page 138: Numerical Library in C for Scientists and Engineers A

b [kl =b [cikl ; b [cikl =w;

B. lsqortdecsol

Computes the least squares solution of an overdetermined system Ax = b (n linear equations in m unknowns), and computes the principal diagonal elements of the inverse of ATA. The matrix A is first reduced to the column permuted form A', where R = QA' (see Isqortdec) by calling Isqortdec and, if this call is successful, the least squares solutions are determined by lsqsol and the principal diagonal elements are calculated by Isqdglinv.

Function Parameters: void lsqortdecsol (a,n, rn, am,diag, b)

a: float a[l:n,l:m]; entry: the coefficient matrix of the linear least square problem; exit: in the upper triangle of a (the elements a[i,j] with i<j) the superdiagonal

elements of the upper triangular matrix (matrix R above) produced by the Householder transformation; in the other part of the columns of a the significant elements of the generating vectors of the Householder matrices used for the Householder triangularization;

n: int; entry: the number of rows of the matrix;

m: int; entry: the number of columns of the matrix (n 2 m);

am: float am[2:5]; entry: aux[2]: contains a relative tolerance used for calculating the diagonal elements of the

upper triangular matrix; exit: aux[3]: delivers the number of the diagonal elements of the upper triangular matrix

which are found not negligible, normal exit aux[3] = m; aux[5]: the maximum of the Euclidean norms of the columns of the given matrix;

diag: float diag[l:m]; exit: the diagonal elements of the inverse of ATA, where A is the matrix of the linear

least squares problem; b: float b[l:n];

entry: contains the right hand side of a linear least squares problem; exit: b[l:m] contains the solution of the problem;

b[m+l:n] contains a vector with Euclidean length equal to the Euclidean length of the residual vector.

Functions used: lsqortdec, lsqdglinv, lsqsol.

void lsqortdecsol (float **a, int n, int m, float aux[l , float diag [ I , float b [I)

l int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int); void free-integer-vector(int *, int);

Copyright 1995 by CRC Press, Inc

Page 139: Numerical Library in C for Scientists and Engineers A

void free-real-vector(f1oat *, int); void lsqortdec(f1oat ** , int, int, float [I, float [ I , int [I); void lsqdglinv(f1oat **, int, float [I, int [I, float [I ) ; void lsqsol (float ** , int, int, float [ I , int [ I , float 11 ) ; int *ci; float *aid;

ci=allocate integer-vector(1,rn); aid=allocat-real-vector(1,rn) ; lsqortdec (a,n,rn, aux,aid, ci) ; if (auxL31 == rn) {

lsqdglinv(a,rn, aid, ci, diag) ; lsqsol (a,n,m, aid, ci, b) ;

kree-integer-vector (ci, 1) ; free-real-vector (aid, 1) ;

I

3.4.3 Inverse matrix of normal equations

lsqinv

Calculates the inverse of the matrix A ~ A , where A is the coefficient matrix of a linear least squares problem. lsqinv can be used for the calculation of the covariance matrix of a linear least squares problem. Given the mxm upper triangular matrix U and the pivot reference integers pi, i=l, ..., m, associated with the permutation matrix P, both occurring in the decomposition QTU=AP of the nxm matrix A (nzm), where Q is nxn orthogonal, lsqinv constructs the mxm inverse matrix X = (ATA)". lsqinv is to be called after a successful call of lsqortdec which obtains the decomposition in question. Since UTU = PTATAP, Xmay be obtained by inverting UTu in a call of chlinv2. Afterwards the covariance matrix is obtained by interchanges of the columns and rows of the inverse matrix.

Function Parameters: void lsqinv (a,m,aid,c)

a: float a[l:m,l:m]; entry: in the upper triangle of a (the elements a[i,j] with 1 5 i<j Sm) the superdiagonal

elements should be given of the upper triangular matrix (U above) that is produced by the Householder triangularization in a call of the function lsqortdec with normal exit (aux[3]=m);

exit: the upper triangle of the symmetric inverse matrix is delivered in the upper triangular elements of the array a (a[i,j], 1 5 i Sj Sm);

m: int; entry: the number of columns of the matrix of the linear least squares problem;

a i d float aid[l:m]; entry: contains the diagonal elements of the upper triangular matrix produced by

Isqortdec; ci: int ci[l:m];

entry: contains the pivotal indices produced by a call of Isqortdec.

Functions used: chlinv2, ichcol, ichrow, ichrowcol.

void lsqinv(f1oat **a, int rn, float aid [I , int c [I ) I

void chlinv2 (float ** , int) ; void ichcol (int, int, int, int, float **) ;

Copyright 1995 by CRC Press, Inc

Page 140: Numerical Library in C for Scientists and Engineers A

void ichrow(int, int, int, int, float * * ) ; void ichrowcol (int, int, int, int, float * * ) ; int i,ci; float w;

for (i=l; ic=m; i++) a [il [il =aid [il ; chlinv2 (a, rn) ; for (i=rn; i>=l; i--) {

ci=c [il ; if (ci ! = i) {

ichcol(1,i-l,i,ci,a) ; ichrow(i+l,ci-1, i, ci,a) ; ichrow(ci+l,m, i, ci, a) ; w=a [il [il ; a [il [il =a [cil [cil ; a [cil [cil =w;

1 1

1

3.4.4 Least squares with linear constraints

A. lsqdecomp

Let A denote the given matrix. lsqdecomp produces an n-th order orthogonal matrix Q and an nxm upper triangular matrix U such that U=QA with permuted columns.

The constrained least squares problem considered is that of determining xeRm which minimizes 11 r2 11 where

and A, is an n,xm matrix, subject to the condition that

A , x = b where b l ~ R n l ,

A, being n,xm (n,+n,=n). The required solution satisfies the equation

A is a vector of Lagrange multipliers and c e P is zero. In the following,

A (A,B)' denotes the compound matrix B.

Let P be an mxm permutation matrix such that (A,,A,)' = (E,F)' where E=(G,,, ,G,,J, F=(G, , , ,G,J , G I , , being an n,xn, nonsingular matrix and, for example, G , , being (n-n,)x(m- n,). Determine an n,xn, orthogonal matrix Q , such that Q,E=(U,,RJ where U, is an n,xn, upper triangular matrix, and R, is n,x(m-n,). Determine a further (n-n,)x(n-n,) orthogonal

Copyright 1995 by CRC Press, Inc

Page 141: Numerical Library in C for Scientists and Engineers A

matrix Q, such that

Q2(G2, - G ~ , ~ ( I ; ~ R ~ ) = (u2,o)'

where U, is an (m-n,)x(m-n,) upper triangular matrix, and 0 represents an (n-m)x(m-n,) matrix of zeros. With

B = U ~ - ~ G , , and R = (I,0T)Q2,

I representing the (m-n,)x(m-n,) unit matrix, the two formulae

are valid. Thus, setting

Y = 011,y2>: d = (d1,d2)' where y,,dl E R"', y2,d2e R ~ - " I

equation (1) may be rewritten as

These equations may be solved: successively

y1 = Qlb,, y2 = g1 - dl

where

x may be obtained from y by use of the first of relationships (2). The orthogonal matrices Q, and Q, and permutation matrix P are obtained recursively

Copyright 1995 by CRC Press, Inc

Page 142: Numerical Library in C for Scientists and Engineers A

by means of a process which may be explained as follows. Starting with a matrix G and setting G=A('), A@") is obtained from A@) by use of the relationship

A (k+ 1) = ( I - JRU WU (k) T)A ( 8

where, with n(k) =n, if k<n, and n(k) =n if k>n, and j so chosen that

is a maximum,

= 0 for i = k + l , ..., n(k) . ' J

(The k-th pivot reference integer p(k) associated with P is j.)

A&'" is rendered zero as desired by setting

Copyright 1995 by CRC Press, Inc

Page 143: Numerical Library in C for Scientists and Engineers A

With G=A, in the above, Q, is the product

( I - J ~ ~ U " " ~ " " ~ ) ...(I - ~ ~ u ( ' ) u ( ~ ) ~ ) and ~$1) = (U,,R,) .

Setting

where

The user must prescribe a small real tolerance tol. If in the above (sj)'I2 is less than to1 multiplied by the maximum Euclidean norm over the columns of A ~ , the decomposition process is broken off.

Function Parameters: void lsqdecomp (a, n, m, nl, am, aid, ci)

a: float a[l:n, l:m]; entry: the original least squares matrix, where the first n l rows should form the

constraint matrix (i.e. the first n l equations are to be strictly satisfied); exit: in the upper triangle of a (the elements a[i,j] with i<j) the superdiagonal part

of the upper triangular matrix produced by the Householder transformation; in the other part of the columns of a the significant elements of the generating vectors of the Householder matrices used for the Householder triangularization;

n: int; entry: the number of rows of the matrix;

m: int; entry: the number of columns of the matrix;

n l : int; entry: number of linear constraints, i.e. the first n l rows of a set up a system of n l

linear equations that must be strictly satisfied (if there are no constraints, n l must be chosen zero);

am: float am[2:7]; entry: am[2]: contains a relative tolerance used for calculating the diagonal elements of the

upper triangular matrix; exit: am[3]: delivers the number of the diagonal elements which are not negligible, normal

exit am[3] = m; am[5]: the maximum of the Euclidean norms of the columns of the given matrix;

a i d float aid[l :m]; exit: normal exit (am[3] = m) aid contains the diagonal elements of the upper

triangular matrix produced by the Householder transformation; ci: int ci[l:m];

Copyright 1995 by CRC Press, Inc

Page 144: Numerical Library in C for Scientists and Engineers A

exit: contains the pivotal indices of the interchanges of the columns of the given matrix.

Functions used: matmat, tarnmat, elmcol, ichcol.

Method: See [BjG67] for the QR decomposition of a least squares matrix.

void lsqdecomp(f1oat **a, int n, int rn, int nl, float aux[l, float aid [I , int ci [I )

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); float matmat (int, int, int, int, float ** , float * * ) ; float tammat (int, int, int, int, float ** , float * * ) ; void elmcol (int, int, int, int, float **, float ** , float) ; void ichcol (int, int, int, int, float * * ) ; int j,k,kpiv,nr,s,fsum; float beta,sigma,norm,aidk,akk,w,eps,temp,*sum;

sum=allocate~real~vector(l,m); norm=O. 0 ; aux[3] =m; nr=nl ; f sum=l; for (k=l; kc=m; k++) {

if (k == nl+l) { f sum=l; nr=n;

1 1 if (fsum)

for (j=k; jc=m; j++) ( w=sum[jl=tammat(k,nr, j, j,a,a); if (W > norm) norm=w;

fsum=O ; eps=aux [21 *sqrt (norm) ; sigma=sum [kl ; kpiv=k ; for (j=k+l; jc=m; j++)

if (sum[jl > sigma) ( sigma=sum [j I ; kpiv= j ;

if (kpiv ! = k) { sum [kpiv] =sum [kl ; ichcol(l,n,k,kpiv,a) ;

1 1

ci [kl =kpiv; akk=a [kl [kl ; sigma=tammat (k,nr, k,k,a,a) ; w=sqrt (sigma) ; aidk=aid[k] = ( (akk c 0.0) ? w : -w) ; if (W c eps) {

aux [31 =k-1; break;

1 J beta=l. 0/ (sigma-akk*aidk) ; a [kl [kl =akk-aidk; for (j=k+l; jc=m; j + + ) (

elmcol (k,nr, j, k, a, a, -beta*tammat (k,nr, k, j ,a, a) ) ; temp=a [kl [ j I ; sum[jl - = temp*temp;

1 I if (k == nl)

for (j=nl+l; jc=n; j++) for (s=l; sc=m; s++) {

nr = (s > nl) ? nl : s-1; w=a[jl [sl-matmat(l,nr, j,s,a,a);

Copyright 1995 by CRC Press, Inc

Page 145: Numerical Library in C for Scientists and Engineers A

a [j] [sl = (s > nl) ? w : w/aid [sl ; I

1 f ree-real-vector (sum, 1) ;

1

B. lsqrefsol

Solves a constrained least squares problem consisting of the determination of that xeRm which minimizes

llr211E where r2 = b2 -A2x, b2eRnZ

and A, is an n,xm matrix, subject to the condition that

Alx = bl where b 1 ~ R n 1 ,

A, being n,xm (n,+n,=n). The required solution satisfies the equation Bz=h where

X being a vector of Lagrange multipliers. It is assumed that the components of the vectors uw associated with the elementary reflectors defining orthogonal matrices Q, and Q, and those of an upper triangular matrix R, together with pivot reference integers associated with a permutation matrix P, have all been obtained by means of a successful call of Isqdecomp.

lsqrefsol first obtains a numerical solution z'" of the equation Bz=h, and then uses an iterative scheme of the form f) =h-BdS), BGz@)=J'S', z~s~f / '=z(s~+~z(s~ , s=1,2, ... to obtain a refined solution to this equation, and in so doing a refined estimate of x, z(') and, at each state, Gz@) are derived by the solution process outlined in the documentation to Isqdecomp. The above iterative scheme [BjG67] is terminated if either (a) 1) 6~'") 11, I E 11 zfS) 11 where c is a small real tolerance prescribed by the user or (b) s=smm where the integer smm is also prescribed by the user. The least squares solutions of several overdetermined systems with the same constraints and coefficient matrix can be solved by successive calls of lsqrefsol with different right hand sides.

Function Parameters: void lsqrefsol (a,qr,n,m,nl,aux,aid,ci, b,ldx,x,res)

a : float a[l:n,/:m]; entry: the original least squares matrix, where the first n l rows should form the

constraint matrix (i.e. the first n l equations are to be strictly satisfied);

Copyright 1995 by CRC Press, Inc

Page 146: Numerical Library in C for Scientists and Engineers A

qr: float qr[l:n,l:m]; entry: the QR decomposition of the original least squares matrix as delivered by a

successful call of lsqdecomp; n: int;

entry: the number of rows of the matrices a and qr; m: int;

entry: the number of columns of the matrices a and qr; nl : int;

entry: number of linear constraints; am: float am[2: 71;

entry: am[2]: contains a relative tolerance (value of E above) as a criterion to stop iterative

refining, if the Euclidean norm of the correction is smaller than am[2] times the current approximation of the solution then the iterative refining is stopped;

awc[d]: maximum number of iterations allowed (value of smax above), usually aux[d]=5 will be sufficient;

exit: a*]: the number of iterations performed (the last value of s for which a correction

term 6z") is determined in the above); a i d floataid[l:m];

entry: the diagonal elements of the upper triangular matrix as delivered by a successful call of lsqdecomp;

ci: int ci[l :m]; entry: the pivotal indices as produced by lsqdecomp;

b: float b[l:n]; entry: the right hand side of the least squares problem; first n l elements form the

right hand sides of the constraints; I&: float *;

the Euclidean norm of the last correction of the solution (the value of )I axfs) 11, for the last &dd determined in the above, x(") being formed from the last m components of z(S');

x: float x[l:m]; exit: the solution vector;

res: float res[l:n]; exit: the residual vector (f) in the above) corresponding to the solution.

Functions used: vecvec, matvec, tamvec, elmveccol, ichcol.

void lsqrefsol(f1oat **a, float **qr, int n, int m, int nl, float aux[l, float aid[], int ci [I, float b[l , float *ldx, float x [I , float res [I )

I float *allocate-real-vector (int, int) ; void free-real-vector(f1oat *, int) ; float vecvec (int, int, int, float [ I , float [I ) ; float matvec (int, int, int, float **, float [I ) ; float tamvec(int, int, int, float **, float [ I ) ; void ichcol (int, int, int, int, float * * ) ; void elmveccol(int, int, int, float [I, float **, float); int i,j,k,s,startup; float cl,nexve,ndx,ndr,d,corrnorm,*f,*g; double dtemp;

Copyright 1995 by CRC Press, Inc

Page 147: Numerical Library in C for Scientists and Engineers A

g=allocate-real-vector(1,m); for (j=l; jc=m; j++) {

s=ci [jl ; if (s != j) ichcol(l,n,j,s,a);

1 for (j=l; jc=m; j++) x[jl=g[jI=O.O; for (i=l; ic=n; i++) {

res[il=0.0; f [il =b [il ;

startup = (k c= 1) ; ndx=ndr=O.O; if (k ! = 0) {

for (i=l; ic=n; i++) res[il += f [il; for (s=l; sc=m; s++) (

x[sI += g [sl ; dtemp=O.O; for (i=l; ic=n; i++)

dtemp += (double) a [il [s] (double) res Iil ; d=dtemp; g[sl =(-d-tamvec(1,s-l,s,qr,g)) /aid[sl ;

:or (i=l; i<=n; i++) { dtemp = (i > nl) ? res [il : 0 .O; for (s=l; sc=m; s++)

dtemp += (double) a [il [sl * (double) x [sl ; f [il =(double) b [il -dtemp;

I 1

Aexve=sqrt (vecvec (l,m, 0 ,x,x) +vecvec (l,n, 0, res, res) ) ; for (s=l; sc=nl; s++)

elmveccol (s,nl,s, f ,qr, tamvec(s,nl, s,qr, f) / (qr [sl [sl *aid[sl ) ) ; for (i=nl+l; ic=n; i++)

f [il - = matvec(l,nl,i,qr,f) ; for (s=nl+l; sc=m; s++)

elmveccol(s,n,s,f ,qr, tamvec(s,n,s,qr,f)/(qr[sl [sl *aid[sl 1 ) ; for (i=l: 1c=m: i++) /

g [s] = (gls] -matvec (s+l,m, s,qr,g) ) /aid[sl ; ndx += g [sl *gIsl ;

1 for (s=m; s>=nl+l; s--)

elmveccol(s,n,s,f,qr,tamvec(s,n,s,qr,f)/(qr~sl [sl*aid[sl) for (s=l; sc=nl; s++)

f Is1 - = tamvec(nl+l,n,s,qr,f); for (s=nl; s>=l; s--)

elmveccol (s,nl,s,f,qr, tamvec(s,nl,s,qr,f)/(qr[sl [sl *aidIs aux [7] =k; for (i=l; ic=n; i++) ndr += f [il *f[il ; corrnorm=sqrt (ndx+ndr) ; k++ ;

) while (startup I / (corrnorm>aux [21 *nexve && kc=aux [61) ) ; *ldx=sqrt (ndx) ; for (s=m; s>=l; s--) (

j=ci [s] ; if (j != s) {

cl=x[jl ; x[jl=x[sl ; x [sl =c1; ichcol(l,n,j,s,a);

1 1

f ree-real-vector (f , 1) ; f ree-real-vector (g, 1) ;

1

Copyright 1995 by CRC Press, Inc

Page 148: Numerical Library in C for Scientists and Engineers A

3.5 Other real matrix problems

3.5.1 Solution of overdetermined systems

A. solsvdovr

Solves an overdetermined system of linear equations. solsvdovr determines that xcRn with minimum 11 x 11, which minimizes 11 Ax-b 11 ,, where A is a real mxn matrix, bcRm (m Tn), the matrices U,A, V occurring in the singular value decomposition A=UAVT being available, where U is an mxn column orthogonal matrix (uTu=I), A is an nxn diagonal matrix whose diagonal elements are the singular values of A (hi, i=l, ..., n), and V is an nxn orthogonal matrix (vTv=VVT=I). The analytic solution of the above problem is x=A'b, where A' is the pseudo-inverse of A: numerically, X = V A ~ ' ) U ~ ~ , where A6') is a diagonal matrix whose successive diagonal elements are (hi)-' if hi > 6, and 0 otherwise, 6 being a small positive real number prescribed by the user. The two stages in the determination of x are the formation of b '=A(- ' )~~b' and that of x= Vb ' .

Function Parameters: void solsvdovr (u, val, v, m,n,x, em)

u: float u[l:m,l:n]; entry: the matrix U in the singular values decomposition UAVT;

val: float val[l:n]; entry: the singular values (diagonal elements hi of A);

v: float v[l:n,l:n]; entry: the matrix V in the singular values decomposition;

m: int; entry: the length of the right hand side vector;

n: int; entry: the number of unknowns, n should satisfy n Sm;

x: float x[l:m]; entry: the right hand side vector; exit: the solution vector;

em: float em[6:6]; entry: the minimal non-neglectable singular value (value of 6 in the above).

Functions used: matvec, tarnvec.

Method: See [WiR71] for the solution of an overdetermined system of linear equations.

void solsvdovr(float **u, float val[l, float **v, int m, int n, float x[], float ern[])

{ float *allocate real vector(int, int); void free-real-?ecto?(float *, int) ; float matvec(int, int, int, float ** , float [I); float tarnvec(int, int, int, float ** , float [I ) ; int i; float min,*xl;

Copyright 1995 by CRC Press, Inc

Page 149: Numerical Library in C for Scientists and Engineers A

for (i=l; ic=n; i++) xl [i] = (val [i] <= min) ? 0.0 : tamvec(l,m, i,u,x)/val [il ;

for (i=l; i<=n; i++) x[i] =matvec(l,n,i,v,xl) ; free-real-vector (XI, 1) ;

I

B. solovr

Solves an overdetermined system of linear equations. solovr determines that xeRn with minimum 11 x 11, which minimizes 11 AX-b 11 ,, where A is a real mxn matrix, beRm (m Zn). solovr first calls qrisngvaldec to obtain the matrices U,A, V occurring in the singular value decomposition A=UAV* and, if all singular values of A can be determined by use of this function, calls solsvdovr to obtain x.

Function Parameters: int solovr (a, m, n,x, em)

solovr: given the number of singular values of a which cannot be found by qrisngvaldec; a : float a[l:m, l:n];

entry: the matrix of the system; m: int;

entry: the number of rows of a ; n: int;

entry: the number of columns of a, n < m; x: float x[l:m];

entry: the right hand side vector; exit: the solution vector;

em: float em[0:7]; entry: em[O]: the machine precision; em[2]: the relative precision of the singular values; em[4]: the maximal number of iterations to be performed in the singular values

decomposition; em[6]: the minimal non-neglected singular value; exit: em[l]: the infinity norm of the matrix; em[3]: the maximal neglected superdiagonal element; emr.51: the number of iterations performed in the singular values decomposition; em[7]: the numerical rank of the matrix,

i.e. the number of singular values 2 em[6].

Functions used: qrisngvaldec, solsvdovr.

int solovr(f1oat **a, int m, int n, float x[l, float em[] I

float *allocate-real-vector(int, int); float **allocate real matrix (int , int, int, int) ; void free-real-vEctorTfloat * , int) ; void free-real-matrix(f1oat **, int, int, int); int qrisngvaldec(f1oat ** , int, int, float [I, float ** , float 11 ) ; void solsvdovr(float ** , float [ I , float ** , int, int,

float [I, float [ I ) ; int i; float *val,**v;

Copyright 1995 by CRC Press, Inc

Page 150: Numerical Library in C for Scientists and Engineers A

val=allocate-real-vector(1,n); v=allocate-real-matrix(l,n,l,n) ; i=qrisngvaldec (a,m,n,val,v, em) ; if (i == 0) solsvdovr (a,val,v,m,n,x, em) ; f ree-real-vector (val , 1) ; free-real-matrix (v, 1, n, 1) ; return i;

1

3.5.2 Solution of underdetermined systems

A. solsvdund

Solves an underdetermined system of linear equations [WiR71]. solsvdund determines that XER" with minimum 11 x 11 , which minimizes 11 ATx-b 11 , where A is a real mxn matrix, ~ E R " (m I n ) , the matrices U,A, V as described in the documentation to solsvdovr being available. The analytic solution of the above problem is x=(A+)~~, where A+ is the pseudo-inverse of A. The two stages in the determination of x are the formation of b ' = ~ ~ ' ) V ~ b and that of x=Ub:

Function Parameters: void solsvdund (u,val,v,m,n,x,em)

u: float u[l:m,l:n]; entry: the matrix U in the singular values decomposition UAvT;

val: float val[l:n]; entry: the singular values (diagonal elements of A);

v: floatv[l:n,l:n]; entry: the matrix V in the singular values decomposition;

m: int; entry: the number of unknowns;

n: int; entry: the length of the right hand side vector, n should satisfy n s m ;

x: float x[l:m]; entry: the right hand side vector in x[l:n]; exit: the solution vector in x[l:m];

em: float em[6:6]; entry: the minimal non-neglectable singular value.

Functions used: matvec, tamvec.

void solsvdund(f1oat **u, float val[l, float **v, int m, int n, float x [ I , float em [ I

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float matvec(int, int, int, float **, float 11) ; float tamvec(int, int, int, float **, float 11 ) ; int i; float min,*xl;

xl=allocate-real-vector(1,n); min=em 161 ; for (i=l; i<=n; i++)

xl[i] = (val [i] <= min) ? 0.0 : tamvec(l,n,i,v,x)/val [il ; for (i=l; i<=m; i++) x[i] = matvec(l,n,i,u,xl) ; f ree-real-vector (xl, 1) ;

Copyright 1995 by CRC Press, Inc

Page 151: Numerical Library in C for Scientists and Engineers A

B. solund

Solves an underdetermined system of linear equations. solund determines that xeRm with minimum 11 x 11, which minimizes 11 ~ ~ x - b 11 ,, where A is a real mxn matrix, beR" (m 2 n). solund first calls qrisngvaldec to obtain the matrices U,A, V occurring in the singular value decomposition A=UAVT and, if all singular values of A may be obtained by use of this function, calls solsvdund to obtain x.

Function Parameters: int solund (a, m, n,x, em)

solund: given the number of singular values of a which cannot be found by qrisngvaldec; a: float a[l:m, I:n];

entry: the transpose of the matrix; m: int;

entry: the number of rows of a; n: int;

entry: the number of columns of a, n s m ; x: float x[l:m];

entry: the right hand side vector in x[l:n]; exit: the solution vector;

em: float em[0:7]; entry: em[O]: the machine precision; em[2]: the relative precision for the singular values; em[4]: the maximal number of iterations to be performed in the singular values

decomposition; em[6]: the minimal non-neglected singular value; exit: em[l]: the infinity norm of the matrix; em[3]: the maximal neglected superdiagonal element; em[5]: the number of iterations performed in the singular values decomposition; em[7]: the numerical rank of the matrix,

i.e. the number of singular values 1 em[6].

Functions used: qrisngvaldec, solsvdund.

int solund(f1oat **a, int m, int n, float x[l , float em[]) (

float *allocate-real-vector(int, int) ; float **allocate-real-rnatrix(int, int, int, int); void free-real-vector(f1oat * , int); void free-real-rnatrix(f1oat ** , int, int, int); int qrisngvaldec (float **, int, int, float [I , float ** , float [I ) ; void solsvdund(f1oat ** , float [I , float * * , int, int,

float [ I , float [I) ; int i; float *val,**v;

val=allocate-real-vector(1,n) ; v=allocate-real-matrix (1, n, 1,n) ; i=qrisngvaldec (a,m,n,val,v, ern) ; if (i == 0) solsvdund(a,val,v,m,n,x,em) ;

Copyright 1995 by CRC Press, Inc

Page 152: Numerical Library in C for Scientists and Engineers A

free real vector (val , 1) ; free~real~matrix(v, 1, n, 1) ; return i ;

1

3.5.3 Solution of homogeneous equation

A. homsolsvd

Given the matrices U,A, V occurring in a real singular value decomposition A=UAV~ where A is an mxn matrix (m 2 n), the diagonal elements hi of A are reordered in such a way that, for the new order, hi 2 hi+,; the columns of U and V are simultaneously reordered to preserve the correspondence between the hi and the columns.

With ui being the successive columns of U, vi those of V, and hi the diagonal elements of A (all in the new ordering)

If, for some r<n, Xi<6 (i=r+l, ..., n), 6 being a small positive real number, then approximately

for any xeR",

i.e. Ax lies in the column subspace in K" spanned by ui (i=l, ..., r); any vector x in the complementary column subspace in Rn spanned by v,,,, ..., vn satisfies the equation Ax= 0; for any xTe~", xTA lies in the column subspace in R" spanned by vi (i=l, ..., r); any vector x in the complementary row subspace in K" spanned by (u,+J? ...,(u J T satisfies the equation xTA=0.

After a call of homsolsvd, the reordered columns of U and V and reordered hi are available in the two dimensional arrays u and v, and the one dimensional array val, respectively. The latter elements hi may thus be inspected, and the vector sets v,, ..., v,; vr+, ,.,., v,; U, ,..., U, and u,, ,,..., un defining the above four subspaces may be extracted [WiR71].

Function Parameters: void homsolsvd (u, val,v,m,n)

u: float u[l:m,l:n]; entry: the matrix U in the singular values decomposition uAv~; exit: the components u[i,j] of U occurring in a reordered decomposition A=uAV~

in which the diagonal elements of A are set in nonascending order; val: float val[l:n];

entry: the singular values;

Copyright 1995 by CRC Press, Inc

Page 153: Numerical Library in C for Scientists and Engineers A

exit: the array will be ordered in such a way that val[i]<val~] i f j<i ; v: float v[l:n, l:n];

entry: the matrix V in the singular values decomposition; exit: the components v[i,j] of V in the reordered decomposition above;

m: int; entry: the number of rows of u;

n: int; entry: the number of columns of u;

Function used: ichcol.

void homsolsvd(f1oat **u, float val[l, float **v, int m, int n)

void ichcol (int, int, int, int, float * * ) ; int i,j; float x;

for (i=n; i>=2; i--) for (j=i-1; ]>=I; ] - - I

if (val [il > val [jl ) { x=val [il ; val [il =val [ j I ; val [ j I =x; ichcol(l,m,i, j,u) ; ichcol(l,n,i, j,v) ;

I 1

B. homsol

Given an mxn matrix A (m Tn), capable of real singular value decomposition, homsol determines the vectors u,tRm (j=r, ..., n) defining the column subspace in which Ax lies for all xeR', the vectors vjtRn (j=r+l, ..., n) defining the complementary column subspace in which xeR' must lie for the condition Ax=O to hold, the vectors v, (j=l, ..., r) defining the column subspace in which X ~ A lies for all xeRm and the vectors (uJT (j=r+l, ..., n) defining the complementary row subspace in which xTtRm must lie for the condition x T ~ = O to hold.

homsol first calls qrisngvaldec to obtain the matrices U,A, V occurring in the singular value decomposition A = U A V ~ and, if all singular values of A can be determined by use this function, calls homsolsvd to reorder the columns of U and V and the diagonal elements of A. The numerical rank (r in the above) of A is determined by the conditions hi>6 (i=l, ..., r) hi<6 (i=r+l, ..., n) for the reordered hi, where 6 is a small positive real number supplied by the user.

Function Parameters: int homsol (a,m, n,v,em)

homsol: given the number of singular values of a which cannot be found by qrisngvaldec;

a: float a[l:m, l:n]; entry: the matrix of the system; exit: the value of the components (uJfi) of u,, i=l, ..., m; j = I ,..., n;

m: int; entry: the number of rows of a;

n: int;

Copyright 1995 by CRC Press, Inc

Page 154: Numerical Library in C for Scientists and Engineers A

entry: the number of columns of a; v: float v[l:n,l:n];

exit: the value of the components (vj0) of v,, i,j=l, ..., n; em: float em[0: 71;

entry: em[O]: the machine precision; em[2]: the relative precision of the singular values; em[4]: the maximal number of iterations to be performed in the singular values

decomposition; em[6]: the minimal non-neglected singular value; exit: em[l]: the infinity norm of the matrix; em[3]: the maximal neglected superdiagonal element; em[5]: the number of iterations performed in the singular values decomposition; em[7]: the numerical rank of the matrix,

i.e. the number of singular values 2 em[d].

Functions used: qrisngvaldec, homsolsvd.

jnt homsol(f1oat **a, int m, int n, float **v, float em[])

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); int qrisngvaldec (float ** , int, int, float [ I , float ** , float [ I ) ; void homsolsvd (float ** , float [ I , float **, int, int) ; int i; float *val;

val=allocate-real-vector(1,n); i=qrisngvaldec (a,m, n, val, v, em) ; if (i == 0) homsolsvd(a,val,v,m,n) ; free-real-vector(va1,l); return i;

1

A. psdinvsvd

Calculates the pseudo-inverse of a matrix [WiR71]. Given the matrices U,A, V occurring in a real singular value decomposition A=uAvT of the mxn matrix A (mzn) , psdinvsvd determines the generalized inverse A' of A ( which satisfies and is defined by the relationships AA+A=A, A+AA+=A', AA' and A'A symmetric in the real case). With hi (i=l, ..., n) being the diagonal elements of A, the successive diagonal elements of the diagonal matrix A(-') are determined by taking them to be (hi)-' if hi>6, and 0 otherwise, 6 being a small positive real number prescribed by the user. Thereafter A+= vA(-')uT. The matrix X=Af- ')uT is first constructed, and then A+=VX.

Function Parameters: void psdinvsvd (u, val,v, m, n, em)

u: float u[l :m,l:n]; entry: the matrix U in the singular values decomposition UAVT; exit: the transpose of the pseudo-inverse;

Copyright 1995 by CRC Press, Inc

Page 155: Numerical Library in C for Scientists and Engineers A

val: float val[l :n]; entry: the singular values;

v: float v[l:n,l:n]; entry: the matrix V in the singular values decomposition;

m: int; entry: the number of rows of U;

n: int; entry: the number of columns of V;

em: float em[6:6]; entry: the minimal non-neglectable singular value.

Function used: matvec.

void psdinvsvd(f1oat **u, float val[l, float **v, int m, int n, float em [I )

I float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int) ; float matvec(int, int, int, float ** , float 11 ) ; int i, j; float min,vali,*x;

x=allocate-real-vector(1,n); min=em [61 ; for (i=l; i<=n; i++)

if (val [il > min) ( vali=l. 0/val [il ; for (j=1; jc=m; j++) u[j] [i] *= vali;

) else for (j=l; j<=m; j++) u[jl [il=0.0;

for (i=l; i<=m; i++) ( for (j=l; jc=n; j++) x[jl =u[il [jl ; for (j=l; jc=n; j++) u[il [jl=matvec(l,n,j,v,x);

1 free-real-vector (x, 1) ;

1

B. psdinv

Determines the generalized inverse A' of the mxn matrix A (mkn). The singular value decomposition A=UAV~ is first carried out by a call of qrisngvaldec and, if all singular values have been obtained, psdinvsvd is then called to construct A'.

Function Parameters: int psdinv (a, m, n, em)

psdinv: given the number of singular values of a which cannot be found by qrisngvaldec; a: float a[l:m,l:n];

entry: the given matrix; exit: the transpose of the pseudo-inverse;

m: int; entry: the number of rows of a;

n: int; entry: the number of columns of a, n s m ;

em: float em[0:7]; entry: em[O]: the machine precision;

Copyright 1995 by CRC Press, Inc

Page 156: Numerical Library in C for Scientists and Engineers A

em[2]: em[4]: em[6]: exit: em[/: em[3]: em[5]: em[7]:

i.e.

the relative precision of the singular values; the maximal number of iterations to be performed; the minimal non-neglected singular value;

the infinity norm of the matrix; the maximal neglected superdiagonal element; the number of iterations performed in the singular values decomposition; the numerical rank of the matrix, the number of singular values 2 em[6].

Functions used: qrisngvaldec, psdinvsvd.

fnt psdinv(f1oat **a, int m, int n, float em[])

float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); int qrisngvaldec(f1oat **, int, int, float [ I , float ** , float 1 1 ) ; void psdinvsvd(f1oat **, float [I , float ** , int, int, float [ I ) ; int i; float *val,**v;

val=allocate-real-vector(1,n) ; v=allocate-realmatrix(l,n,l,n); i=qrisngvaldec (a, m,n,val,v, em) ; if (i == 0) psdinvsvd(a,val,v,m,n, em) ; free-real-vector(va1,l); free-real-matrix (v, 1, n, 1) ; return i;

)

3.6 Real sparse non-symmetric band matrices

3.6.1 Preparatory procedure

decbnd

Performs the decomposition of a matrix whose non-zero elements are in band form, and whose band elements are stored rowwise in a one-dimensional array [Dek68].

Given an nxn matrix A for whose elements Aij=O when i>j+lw or j>i+rw (i,j=l, ..., n), decbnd obtains (a) a unit lower triangular band matrix M for whose elements Mij=O when i>j+lw or j>i, and M,,i=l; (b) an upper triangular band matrix U with qj=O when j>i+lw+rw or i>j; and (c) a sequence of pivot reference integers p(i) (i=l, ..., n) associated with a permutation matrix P, such that MU=PA, by Gauss elimination using partial pivoting.

The method used involves the recursive construction of matrices AO), with A(")=A. At the i-th stage the elements (A, .)(') G=l, ..., i-1; k=j+l, ..., n) are zero and

(A,)(L(U~~)(~) (k=l, . . ., i-I; j=k, k+ 1,. . . , n). Then (a) the smallest integer I for which I (AI,,)(') 12 1 (A,,,)") I for k 2 i is determined; (b) p(i) is set equal to I; (c) rows i and I of Ao) are interchanged (the i-th row of A"+") has now been determined); (d) with Mk,,=(Ak,i)(i)/(Ai,i)(i+'), row(k) of Ao) is replaced by row(k) - M,,yow(i) to form row(k) of A"") (k=i+l, ..., min(n, i+lw)). (The elements (A~,,)(~+'), k>i, are thus zero.) The process is arrested if 6>6,, where 6,= I (A~,~)("') I / 11 i-th row of A(') I), and 6 is a small positive real number prescribed by the user.

Copyright 1995 by CRC Press, Inc

Page 157: Numerical Library in C for Scientists and Engineers A

Function Parameters: void decbnd (a, n, lw,rw, am, m,pi)

a: float a[I:(lw+rw)(n-I)+n]; entry: a contains rowwise the band elements of the band matrix in such a way that

the (i,j)-th element of the matrix is given in a[(lw+rw)(i-I)+j], i=I, ..., n and j=max(I,i-lw), ..., min(n,i+rw), the values of the remaining elements of a are irrelevant;

exit: the band elements of the Gaussian eliminated matrix, which is an upper triangular band matrix U with (Iw+rw) codiagonals, are rowwise delivered in a as follows: the (i,j)-th element of U is a[(lw+rw)(i-j)+j], i=I, ..., n and j=i, ..., min(n,i+lw+rw);

n: int; entry: the order of the band matrix;

Iw: int; entry: number of left codiagonals of a;

rw: int; entry: number of right codiagonals of a;

awc: float awc[l:5]; entry: aux[2]: a relative tolerance to control the elimination process (value of 6 above); exit: aux[l]: if successful, given the sign of the determinant of the matrix (+1 or -1); aux[3]: if successful then aux[3]=n; otherwise awc[3]=i-I, where the reduction process

was terminated at stage i; aux[5]: if successful, given the minimum absolute value of pivot(i) divided by the

Euclidean norm of the i-th row (value of min 6,, l l j l n , in the above); m: float m[I:lw(n-2)+ I];

exit: the Gaussian multipliers (values of Mij above) of all eliminations in such a way that the i-th multiplier of the j-th step is m[lw(&I)+i-j];

p : int p[l:n]; exit: the pivotal indices.

Functions used: vecvec, elmvec, ichvec.

void decbnd(f1oat a[], int n, int lw, int rw, float aux[l , float m[l , int p [I )

float *allocate-real-vector(int, int); void f ree-real-vector (float *, int) ; float vecvec(int, int, int, float [I , float [I ) ; void elmvec (int, int, int, float [I, float [I, float) ; void ichvec (int, int, int, float [I ) ; int i, j , k, kk, kkl,pk,mk, ik, lwl, f, q,w,wl, w2 ,nrw, iw, sdet; float r, s, eps, min, *v;

Copyright 1995 by CRC Press, Inc

Page 158: Numerical Library in C for Scientists and Engineers A

q=lw-1; for (i=2; ic=lw; i++) (

q--; iw += wl; for (j=iw-q; jc=iw; j++) a[jl=O.O;

iw = -w2; q = -1w; for (i=l; ic=n; i++) {

iw += w; if (i c= lwl) iw--; q += w; if (i > nrw) q--; v[i] =sqrt (vecvec (iw,q, O,a,a) ) ;

I eps=aux [21 ; min=l. 0; kk = -wl; mk = -1w; if (f > nrw) w2 += nrw-f; for (k=l; kc=n; k++) {

if (f c n) f++; ik = kk += w; mk += lw; s=fabs (a [kkl ) /v [kl ; pk=k ; kkl=kk+l ; for (i=k+l; ic=f; i++) {

ik += wl; m [mk+i-kl =r=a [ikl ; a[ikl=0.0; r=fabs (r) /v [il ; if (r > S) (

s=r; pk=i;

I (S c min) min=s; (S c eps) ( aux[31 =k-1; aux [SI =s; aux [I] =sdet; free-real-vector(v,l); return;

1 if (k+w2 >= n) w2--; p [kl =pk; if (pk ! = k) ( ;~&plcc=;,~kl ;

ichvec (kkl, kkl+w2,pk*wl, a) ; sdet = -sdet; r=m [mk+pkl ; m [mk+pkl =a [kkl ; a [kkl =r;

} else r=a [kkl ;

if (r c 0.0) sdet = -sdet; iw=kkl; lwl=f-k+mk; for (i=mk+l; is=lwl; i++) (

s = m[il /= r; iw += wl; elmvec(iw,iw+w2,kkl-iw,a,a, -s) ;

1 1

aux [31 =n; aux [51 =min; aux [ll =sdet; f ree-real-vector (v, 1) ;

1

Copyright 1995 by CRC Press, Inc

Page 159: Numerical Library in C for Scientists and Engineers A

3.6.2 Calculation of determinant

determbnd

Calculates the determinant of the Gaussian eliminated upper triangular matrix provided with the correct sign that is delivered by decbnd or decsolbnd. determbnd should not be called when overflow can be expected.

Function Parameters: float determbnd (a,n, lw,rw,sgndet)

determbnd: delivers the determinant of the band matrix; a: float a[l:(lw+rw) *(n-l)+n];

entry: the contents of a are produced by decbnd or decsolbnd; n: int;

entry: the order of the band matrix; Iw: number of left codiagonals of a; rw: number of right codiagonals of a; sgndet: int;

entry: the sign of the determinant as delivered in aux[l] by decbnd, if the elimination was successful.

float determbnd(f1oat a[], int n, int lw, int rw, int sgndet) (

int i,l; float p;

1=1; p=1.0 ; lw += rw+l; for (i=l; ic=n; i++) {

p=a Ill *p; 1 += lw;

1 return (f abs (p) *sgndet) ;

1

3.6.3 Solution of linear equations

A. solbnd

Calculates the solution of a system of linear equations, provided that the matrix has been decomposed by a successful call of decbnd. The solution of the linear system is obtained by carrying out the elimination, for which the Gaussian multipliers are saved, on the right hand side, and by solving the new system with the upper triangular band matrix, as produced by decbnd, by back substitution. The solutions of several systems with the same coefficient matrix can be obtained by successive calls of solbnd.

Function Parameters: void solbnd (a,n,lw,rw,m,p,b)

a,n,lw,rw,m,p: see decbnd; entry: the contents of the arrays a,m,p are as produced by decbnd;

Copyright 1995 by CRC Press, Inc

Page 160: Numerical Library in C for Scientists and Engineers A

b: float b[l:n]; entry: the right hand side of the system of linear equations.

Functions used: vecvec, elmvec.

void solbnd(f1oat a [I , int n, int lw, int rw, float m [I , int p [I, float b [I )

float vecvec (int, int, int, float 11 , float [I ) ; void elmvec (int, int, int, float [I , float [I , float) ; int f,i,k,kk,w,wl,w2,shift; float s;

f =lw; shift = -1w; wl=lw-1; for (k=l; kc=n; k++) {

if (f c n) f++; shift += wl; i=p [kl ; s=b [il ; if (i ! = k) (

b [il =b [kl ; b [kl =s;

1 elmvec (k+l, f, shift,b,m, -s) ;

1 wl=lw+rw ; w=w1+1; kk= (n+l) *w-wl; W2 = -1; shift=n*wl; for (k=n; k>=l; k--1 {

kk - = W; shift -= wl; if (w2 c wl) w2++; b [k] = (b [k] -vecvec (k+l, k+w2, shift,b, a) ) /a [kkl ;

I I

B. decsolbnd

Calculates the solution of a system of linear equations by Gaussian elimination with partial pivoting if the coefficient matrix is in band form and is stored rowwise in a one-dimensional array. decsolbnd performs Gaussian elimination in the same way as decbnd, meanwhile also carrying out the elimination with the given right hand side. The solution of the eliminated system is obtained by back substitution.

Function Parameters: void decsolbnd (a,n,lw,rw,aux, b)

a,n, lw,rw,aux: see decbnd; b: see solbnd.

Functions used: vecvec, elmvec, ichvec.

void decsolbnd(f1oat a[], int n, int lw, int rw, float ~ux[], float b[l) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); float vecvec (int, int, int, float [I, float [I ) ;

Copyright 1995 by CRC Press, Inc

Page 161: Numerical Library in C for Scientists and Engineers A

sdet=l; wl=lw+rw; w=Wl+l; w2=w-2; iw=O ; nrw=n-rw; lwl=lw+l; q=lw-1; for (i=2; ic=lw; i++) (

q--; iw += wl; for (j=iw-q; j<=iw; j++) a[jl=O.O;

1 iw = -w2; q = -1w; for (i=l; i<=n; i++) {

iw += w; if (i <= lwl) iw--; q += w; if (i > nrw) q--; v[i] =sqrt (vecvec (iw, q, 0, a, a) ) ;

eps=aux [21 ; min=l. 0 ; kk = -wl; if (f > nrw) w2 += nrw-f; for (k=l; k<=n; k++) (

if (f < n) f++; ik = kk += w; s=f abs (a [kkl ) /v [kl ; pk=k; kkl=kk+l; for (i=k+l; i<=f; i++) {

ik += wl; m [i-kl =r=a [ikl ; a[ikl=0.0; r=fabs(r) /v[il ; if (r > S) {

s=r; pk=i ;

(S < min) min=s; (S < eps) { aux[31 =k-1; aux 151 =s; aux [ll =sdet; free real vector (m, 0) ; free~real~vector (v, 1) ; return;

(k+w2 >= n) w2--; (pk ! = k) { v [pkl =v [kl ; pk - = k; ichvec (kkl, kkl+w2, pk*wl, a) ; sdet = -sdet; r=b [kl ; b [kl =b [pk+kI ;

r=h [pkl ; m [pkl =a [kkl ; a [kkl =r;

} else r=a [kkl ;

iw=kkl;

Copyright 1995 by CRC Press, Inc

Page 162: Numerical Library in C for Scientists and Engineers A

lwl=f -k; if (r c 0.0) sdet = -sdet; for (i=l; ic=lwl; i++) {

s = m[il /= r; iw += wl; elmvec (iw, iw+w2, kkl-iw,a, a, -s) ; b [k+il -= b [kl *s;

1 1

aux[3] =n; aux [51 =min; kk= (n+l) *w-wl; w2 = -1; shift=n*wl; for (k=n; k>=l; k--) {

kk - = W; shift -= wl; if (w2 c wl) w2++; b [k] = (b [kl -vecvec (k+l, k+w2, shift,b, a) ) /a [kkl ;

1 J

aux Ill =sdet; f ree-real-vector (m, 0) ; free-realvector (v, 1) ;

1

3.7 Real sparse non-symmetric tridiagonal matrices

3.7.1 Preparatory procedures

A. dectri

Given the nxn tridiagonal matrix T (T,=O for 1 i-j1>1) obtains a lower bidiagonal matrix L (L. {,I .=O for i>j+l and j>i) and unit upper bidiagonal matrix U (U,,=l, q j = O for i>j and j> i+l ) such that T=LU. The columns of L and rows of U are determined in succession. If at stage k, 1 L , , I <to]* 11 tk 11 ,, where to1 is a tolerance prescribed by the user and tk is the k-th row of T, the decomposition process is discontinued, and an integer K is given the value k- I ; otherwise K is given the value n at exit.

Function Parameters: void dectri (sub,diag,super, n,awc)

sub: float sub[l:n-I]; entry: the subdiagonal of the given matrix T, T,+,,, should be given in sub[i], i=l, ..., n-

1; exit: the lower bidiagonal matrix, the value L,,,, will be delivered in sub[i],

i=l, ..., aux[3]-I; diag: float diag[l :n];

entry: the diagonal of T, the value of T,,, in diag[i]; exit: L,, will be delivered in diag[i], i=l, ..., awc[3];

super: float super[l :n-I]; entry: the superdiagonal of T, value of T,,,, in super[i], i=l, ..., n-I; exit: U,,,, will be delivered in super[iJ i=l, ..., awc[3]-1;

n: int; entry: the order of the matrix;

aux: float aux[2:5]; entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

Copyright 1995 by CRC Press, Inc

Page 163: Numerical Library in C for Scientists and Engineers A

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision (the value of to1 above);

exit: ~ 2 4 3 1 : the number of elimination steps performed (value of K above); am[5]: if awc[3]=n then am[5] will be equal to the infinity norm of the matrix, else

a2451 is set equal to the value of that element which causes the breakdown of the decomposition (value of TK+,,K+,).

void dectri (float sub [I , float diag [I , float super [ I , int n, float aux[l )

I int i,nl; float d,r,s,u,norm,norml,tol;

tol=aux 121 ; d=diag [ll ; r=super 111 ; norm=norml=fabs (d) +£abs (r) ; if (fabs(d) <= norml*tol) {

aux[31=0.0; aux 151 =d; return;

1 u=super Ill =r/d; s=sub [ll ; nl=n-1; for (i=2; i<=nl; i++) {

d=diag [il ; r=super [il ; norml=fabs (s) +fabs (d) +£abs (r) ; diag[il = d -= u*s; if (fabs(d) <= norml*tol) (

aux[31 =i-1; aux [51 =d; return;

1 u=super [il =r/d; s=sub [il ; if (norml s norm) norm=norml;

1 d=diag [nl ; norml=fabs(d)+fabs(s) ; diag [n] = d -= u*s; if (fabs(d) <= norml*tolf {

aux [3 1 =nl ; aux [51 =d; return;

1 if (norml s norm) norm=norml; auxF31 =n; aux [5 I =norm;

1

B. dectripiv

Given the nxn tridiagonal matrix T (Tj=O for I i-j 1 >1) attempts to obtain a lower bidiagonal matrix L (Lij=O for i>j+l) and unit upper band matrix (with at most two codiagonals) U (U,,,=l, Uij=O for i>j and j>i+2) such that LU=PT where P is a permutation matrix resulting from either no interchange or interchange of consecutive rows at each stage in the LU decomposition. The columns of 1F' (k=l ,..., n) of L are determined in succession. If

1 (1,)" I <tol* 11 t") 11 ,, (lJF) is the i-th component of P) and to) is the i-th row of T and to1 is a tolerance prescribed by the user, then the decomposition process is discontinued, and an

Copyright 1995 by CRC Press, Inc

Page 164: Numerical Library in C for Scientists and Engineers A

integer K is given the value k-I; otherwise K is given the value n at exit.

Function Parameters: void dectripiv (sub, diag,super, n, aid, aux,piv)

sub: float sub[l:n-11; entry: the subdiagonal of the given matrix T, T+I,i should be given in sub[iJ i=l, ..., n-

1; exit: the lower bidiagonal matrix, the value L,,,, will be delivered in sub[i],

i=l, ..., aux[3]-I; diag: float diag[l :n];

entry: the diagonal of T, value of T,,, in diag[i]; exit: L,, will be delivered in diag[i], i=l, ..., aux[3];

super: float superr1 :n-11; entry: the superdiagonal of T, value of Ti,,,, in super[i], i=l, ..., n-I; exit: U,,,, will be delivered in super[i], i=l, ..., aux[3]-I;

n: int; entry: the order of the matrix;

aid: float aid[l :n-21; exit: the value of U,,,,, will be delivered in aid[i], i= l ,..., awc[3]-2;

aux: float aux[2:5]; entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements, however, it should not be chosen smaller than the machine precision (value of to1 above);

exit: aux[3]: the number of elimination steps performed (value of K above); aux[5]: if aux[3]=n then aux[5] will be equal to the infinity norm of the matrix, else

aux[5] is set equal to the value of that element which causes the breakdown of the decomposition (value of TK+l,K+I);

piv: int piv[l :+I]; exit: the value of piv[i] will be nonzero if the i-th and (i+l)-th row are

interchanged, i=l, ..., min(aux[3],n-1), else piv[i] will be zero.

void dectripiv(f1oat sub[], float diag[], float super[], int n, float aid [I , float aux [I , int piv[l )

{ int i,il,nl,n2; float d, r, s, u, t, q, v, w , norm, norml, norm2, tol;

tol=aux [21 ; d=diag [ll ; r=super [ll ; norm=norm2=fabs (d) +£abs (r) ; n2=n-2; for (i=l; i<=n2; i++) (

il=i+l; s=sub [il ; t=diag [ill ; q=super [ill ; norml=norm2; norm2zfabs (s) +fabs (t) +fibs (q) ; if (norm2 > norm) norm=norm2; if (fabs(d)*norm2 c fabs(s)*norml) {

if (fabs(s) c= tol*norm2) ( aux[3] =i-1;

Copyright 1995 by CRC Press, Inc

Page 165: Numerical Library in C for Scientists and Engineers A

aux 151 =s; return;

1 J diag [il =s; u=super [il =t/s; v=aid [il =q/s; sub [il =d; w = super[ill = -v*d; d=diag [ill =r-u*d; r=w; norm2=norml: piv [il =l;

} else ( if (fabs(d) C= tol*norml) (

aux[3] =i-1; aux [51 =d; return;

\ ;=super [i] =r/d; d=diag [ill =t-u*s; aid[i]=O.O; piv [il =O; r=q;

1 1

nl=n- 1 ; s=sub [nll ; t=diag [nl ; norml=norm2; norm2=fabs (s) +fabs (t) ; if (norm2 > norm) norm=norm2; if ( f abs (d) *norm2 c f abs (s) *norml) (

if (fabs(s) c = tol*norm2) ( aux [3l=n2; aux [51 =s; return;

\ diag [nll =s; u=super [nl] =t/s; sub [nl] =d; d=diag [nl =r-u*d; norm2=norml; piv [nl] =l;

} else ( if (fabs(d) c = tol*norml) (

aux[31 =n2; aux [51 =d; return;

u=super [nll =r/d; d=diag [nl =t-u*s; piv [nl]=O ;

1 if (fabs(d) c= tol*norm2) (

auxL31 =nl; aux [51 =d; return;

I I aux [31 =n; aux [51 =norm;

1

3.7.2 Solution of linear equations

A. soltri

Given the nxn lower bidiagonal matrix L (Lij=O for i>j+l or j>i) and unit upper bidiagonal matrix U (Uimi=l, Uij=O for i>j or j>i+l) solves the system of equations Tx-b by forward

Copyright 1995 by CRC Press, Inc

Page 166: Numerical Library in C for Scientists and Engineers A

and back substitution, where T=LU (this decomposition results from successful exit from dectri). One call of dectri followed by several calls of soltri may be used to solve several linear systems having the same tridiagonal matrix, but different right hand sides.

Function Parameters: void soltri (sub, diagwper, n, b)

sub: float sub[l:n-I]; entry: the subdiagonal of the lower bidiagonal matrix, as delivered by dectri;

diag: float diag[l :n]; entry: the diagonal of the lower bidiagonal matrix, as delivered by dectri;

super: float super[l:n-11; entry: the superdiagonal of the upper bidiagonal matrix, as delivered by dectri;

n: int; entry: the order of the matrix;

b: float b[l:n]; entry: the right hand side of the linear system; exit: the calculated solution of the linear system.

void s o l t r i ( f l o a t sub [ I , f l o a t diag [I , f l o a t super [ I , i n t n, f l o a t b [ I I

i n t i; f l o a t r ;

r = b [ l l /= diag [ l l ; f o r ( i = 2 ; i < = n ; i++) r=b [ i ] = ( b [ i l -sub [i-11 *r) /diag [ i l ; f o r ( i=n-1; i>=l; i - - ) r = b [ i l - = s u p e r [ i l * r ;

1

B. decsoltri

Given the nxn tridiagonal matrix T, attempts to obtain a lower bidiagonal matrix L and unit upper bidiagonal matrix U such that T=LU and, if successful in so doing, solves the system of equations Tx=b. The triangular decomposition of the given matrix is done b dectri and the forward and back substitution by calling soltri.

Function Parameters: void decsoltri (sub,diag,super,n,aux, b)

sub: float sub[l :n-I]; entry: the subdiagonal of the given matrix T, 7j.+,,, should be given in sub[i],

1;

calling

=I, ..., n-

exit: the lower bidiagonal matrix, the value L,,,, will be delivered in sub[i], i=l, ..., am[3]-I;

diag: float diag[l:n]; entry: the diagonal of T, value of T,,i in diag[i]; exit: L , , will be delivered in diag[i], i=l,. . ., aux[3];

super: float super[l:n-I]; entry: the superdiagonal of T, value of T,,+, in super[i], i=l, ..., n-I; exit: U,,,, will be delivered in super[i], i=l, ..., aux[3]-I;

n: int; entry: the order of the matrix; a i d float aid[l:n-21;

exit: the value of U,,,, will be delivered in aid[i], i=I, ..., awc[3]-2;

Copyright 1995 by CRC Press, Inc

Page 167: Numerical Library in C for Scientists and Engineers A

am: float aux[2:5]; entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

exit: awc[3]: the number of elimination steps performed; aux[5]: if aux[3]=n then aux[5] will be equal to the infinity norm of the matrix, else

au[5] is set equal to the value of that element which causes the breakdown of the decomposition;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if awc[3]=n then the solution of the linear system is overwritten on b, else b

remains unaltered.

Functions used: dectri, soltri.

void decsoltri (float sub [I , float diag [I , float super [ I , int n, float aux[l, float b[l)

dectri (sub,diag, super,n, aux) ; if (aux[3] == n) soltri (sub,diag,super,n,b) ;

1

C. soltripiv

Given the nxn lower bidiagonal matrix L (Lij=O for i>j+l and j>i) and the unit upper band matrix (with at most two codiagonals) U (U,,,=l, Uij=O for i>j and j>i+2) such that LU=PT (where P is a permutation matrix resulting from either no interchange or interchange of consecutive rows at each stage in the LU decomposition of T), solves the system of equations Tx=b (the above decomposition is produced at successful exit from dectripiv). One call of dectripiv followed by several calls of soltripiv may be used to solve several linear systems having the same tridiagonal matrix, but different right hand sides.

Function Parameters: void soltripiv (sub,diag,super,n,aid,piv,b)

sub: float sub[l:n-I]; entry: the subdiagonal of the lower-bidiagonal matrix, as delivered by dectripiv;

diag: float diag[l :n]; entry: the diagonal of the lower bidiagonal matrix, as delivered by dectripiv;

super: float super[l :n-I]; entry: the first codiagonal of the upper triangular matrix, as delivered by dectripiv;

n: int; entry: the order of the matrix; a i d float aid[l :n-21;

entry: the second codiagonal of the upper triangular matrix, as delivered by decfripiv; piv: int piv[l :n-I];

entry: the pivot information as delivered by dectripiv; b: float b[l:n];

Copyright 1995 by CRC Press, Inc

Page 168: Numerical Library in C for Scientists and Engineers A

entry: the right hand side of the linear system; exit: the calculated solution of the linear system.

void soltripiv (f loat sub [I , float diag [I , float super [I , int n, float aid [I , int piv[l , float b [I

I !

int i,nl; float bi,bil,r,s,t;

nl=n- 1 ; for (i=l; iz=nl; i++) {

if (piv[il ) { bi=b [i+ll ; bil=b [il ;

) else { bi=b [il ; bil=b [i+ll ;

I

1 r = b [nl /= diag [nl ; t = b [nll -= super [nll *r; for (i=n-2; i>=l; i--) {

s=r;

D. decsoltripiv

Given the nxn tridiagonal matrix T (qj=O for I i-j 1 >1) attempts to obtain a lower bidiagonal matrix L (Lij=O for i>j+l and j>i) and unit upper band matrix (with at most two codiagonals) U (Ui,,=l, Uij=O for i>j and j>i+2) such that LU=PT where P is a permutation matrix resulting from either no interchange or interchange of consecutive rows at each stage in the LU decomposition and, if successful in so doing, solves the system of equations Tx=b. One call of decsoltripiv is equivalent to calling consecutively dectripiv and soltripiv. However, decsoltripiv does not make use of dectripiv and soltripiv, to save memory space and time. This is only true in the case that linear systems with different matrices have to be solved.

Function Parameters: void decsoltripiv (sub,diag,super,n,aux, b)

sub: float sub[l:n-I]; entry: the subdiagonal of the given matrix T, T,+,,) should be given in sub[i], i=l, ..., n-

1; exit: the elements of sub will be destroyed;

diag: float diag[l :n]; entry: the diagonal of T, value of T,,i in diag[if; exit: the elements of diag will be destroyed;

super: float super[l :n-I]; entry: the superdiagonal of T, value of qSi+, in super[i], i=l, ..., n-I; exit: the elements of super will be destroyed;

n: int; entry: the order of the matrix;

am: float aux[2:5];

Copyright 1995 by CRC Press, Inc

Page 169: Numerical Library in C for Scientists and Engineers A

entry: aux[2]:

exit: awc[3]: aux[5]:

a relative tolerance; a reasonable choice for this value is an estimate of the relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

the number of elimination steps performed; if aux[3]=n then aux[5] will be equal to the infinity norm of the matrix, else a d 5 1 is set equal to the value of that element which causes the breakdown of the decomposition;

b: float b[l:n]; entry: the right hand side of the linear system; exit: if awc[3]=n then the solution of the linear system is overwritten on b, else b

remains unaltered.

void decsoltripiv(f1oat sub [I , float diag[l , float super [I , int n, float aux[l , float b [I )

{ int *allocate-integer-vector(int, int); void f ree-integer-vector (int * , int) ; int i,il,nl,n2,*piv; float d, r, s, u, t, q, v, w, norm, norml, norm2, tol, bi, bil, bi2 ;

piv=allocate-integer-vector(1,n); tol=aux [21 ; d=diag [ll ; r=super [ll ; bi=b [ll ; norm=norm2=f abs (d) +iabs (r) ; n2=n-2; for (i=l; i<=n2; i++) {

il=i+l; s=sub [il ; t=diag [ill ; q=super [ill ; bil=b [ill ; norml=norm2; norm2=fabs(s)+fabs (t) +fabs(q) ; if (norm2 > norm) norm=norm2; if (fabs(d)*norm2 < iabs(s)*norml) {

if (fabs (s) <= tol*norm2) { auxl31 =i-1; aux [5l =s; free-integer-vector (piv, 1) ; return;

\

:=super [il =t/s; b[il = bil /= s; bi -= bil*d; v=sub [il =q/s; w = super [ill = -v*d; d=diag [ill =r-u*d; r=w; norm2=norml; piv [il =l;

} eise ( if (fabs(d) c= tol*norml) {

aux [31 =i-1; aux [51 =d; free-integer-vector (piv, 1) ; return;

1 J

u=super [il =r/d; b[il = bi /= d; bi=bil-bi*s; d=diag [ill =t-u*s;

Copyright 1995 by CRC Press, Inc

Page 170: Numerical Library in C for Scientists and Engineers A

piv [il =O; r=q;

nl=n-1; s=sub [nll ; t=diag [nl ; norml=norm2; bil=b [nl ; norm2=fabs (s) +fabs (t) ; if (norm2 > norm) norm=norm2; if (fabs (d) *norm2 c fabs (s) *norml) {

if (fabs(s) c= tol*norm2) ( aux[3] =n2; aux [S] =s; free-integer-vector (piv, 1) ; return;

\ u=super [nll =t/s; b[nll = bil /= s; bi - = bil*d; d=r-u*d; norm2=norml;

) else { if (fabs(d) c= tol*norml) {

aux[31 =n2; aux [51 =d; f ree-integer-vector (piv, 1) ; return;

1 u=super [nll =r/d; b [nl] = bi /= d; bi=bil-bi*s; d=t-u*~;

if (fabs(d) c= tol*norm2) { aux[3] =nl; aux[5] =d; free-integer-vector(piv,l) ; return;

1 1 aux 131 =n; aux 151 =norm; bil=b [nl =bi/d; bi = b [nll -= super [nll *bil; for (i=n-2; i>=l; i--) (

bi2=bil; bil=bi ; bi = b [i] - = super [i] *bil + ( (piv[i] ) ? sub [il *bi2 : 0.0) ;

1

3.8 Sparse symmetric positive definite band matrices

3.8.1 Preparatory procedure

chldecbnd

Decomposes a symmetric positive definite band matrix A (Aij=O for I i-j I>w, i,j=l, ..., n) into the form A = u T u , where U is an upper triangular band matrix (Uij=O for j<i and j>i+w) by use of Cholesky's square root method. For j=l ,..., n, with j(w)=rnax(i,j-w) If when j=k, either 6,<0 or 6, < 6 max I I for I I i <j, 6 being a small positive real number prescribed by the user, then the above process is terminated, and the value of k-I is allocated to aux[3] as a failure indication [Dek68].

Copyright 1995 by CRC Press, Inc

Page 171: Numerical Library in C for Scientists and Engineers A

i - l

Function Parameters: void chldecbnd (a, n, w, am)

a : float a[l:w(n-l)+n]; entry: a contains columnwise the upper triangular band elements of the symmetric

band matrix (the (i,j)-th element of the matrix is in location a[&l)w+i], j = l ,..., n, i=max(l,j-w) ,... 4);

exit: the band elements of the Cholesky matrix, which is an upper triangular band matrix with w superdiagonals, are delivered columnwise in a;

n: int; entry: the order of the band matrix;

w: int; entry: number of superdiagonals of the matrix;

am: float awc[2:3]; entry: aux[2]: a relative tolerance to control the calculation of the diagonal elements of the

Cholesky matrix (value of 6 above); exit: aux[3]: if successful then am[3]=n; otherwise aux[3]=k-I, where k is the index of the

diagonal element of the Cholesky matrix that cannot be calculated.

Function used: vecvec.

void chldecbnd(f1oat a[], int n, int w, float aux[l) I

float vecvec(int, int, int, float [I, float [ I ) ; int j,k,jmax,kk,kj,wl,start; float r,eps,max;

max=O. 0 ; kk = -w; w1=w+1; for (j=l; jc=n; j++) {

kk += wl; if (a [kk] > max) max=a [kkl ;

1 jmax=w ; wl=w+l; kk = -w; eps=aux [21 *max; for (k=l; k<=n; k++) {

if (k+w > n) jmax--; kk += wl; start=kk-k+l; r=a [kkl -vecvec ( ( (k <= wl) ? start : kk-w) , kk-l,O,a, a) ; if (r <= eps) {

Copyright 1995 by CRC Press, Inc

Page 172: Numerical Library in C for Scientists and Engineers A

auxt31 =k-1; return:

1 a [kkl =r=sqrt (r) ; kj=kk; for (j=l; j<=jrnax; j++) (

kj += w; a[kj]=(a[kjl -vecvec( ((k+j <= wl) ? start : kk-w+j) ,

kk-1,kj-kk,a,a)) /r;

I 1

J

aux 131 =n; 1

3.8.2 Calculation of determinant

chldetermbnd

With the Cholesky decomposition A = U ~ U of the symmetric positive definite band matrix A for whose elements Aij=O for 1 i-jl>w, i,j=l ,..., n) available, chldetermbnd computes the determinant A of A,

chldetermbnd should not be called when overflow can be expected.

Function Parameters: float chldetermbnd (a,n, w)

chldetermbnd: delivers the determinant of symmetric positive definite band matrix whose Cholesky matrix is stored in a (value of A above);

a: float a[l:w(n-l)+n]; entry: the contents of a are as produced by chldecbnd or chldecsolbnd;

n: int; entry: the order of the band matrix;

w: int; entry: number of superdiagonals of the matrix.

float chldetermbnd(f1oat a[], int n, int w) {

int j,kk,wl; float p;

wl=w+l; kk = -w; p=l.O; for (j=l; j < = n ; j++) {

kk += wl; p *= a [kkl ;

1

3.8.3 Solution of linear equations

Copyright 1995 by CRC Press, Inc

Page 173: Numerical Library in C for Scientists and Engineers A

A. chlsolbnd

With the Cholesky decomposition A=UTu of the symmetric positive definite band matrix A for whose elements Aij=O for 1 i-j 1 >w, i,j=l, ..., n) available, chlsolbnd carries out the solution of the systems of equations Ax=b. The relationships

for j=l, . . .,n, where j(w)=rnax(l,j-w), J(w)=rnin(n J+w), are used (they follow from U?=b, Ux=y).

Function Parameters: void chlsolbnd (a,n, w, b)

float a[l: w(n-I) in]; entry: the contents of a are as produced by chldecbnd; int; entry: the order of the band matrix; int; entry: number of superdiagonals of the matrix; float b[l:n]; entry: the right hand side of the system of linear equations; exit: the solution of the system.

Functions used: vecvec, scaprdl.

void chlsolbnd(f1oat a[], int n, int w, float b[l)

float vecvec(int, int, int, float [I, float [I ) ; float scaprdl(int, int, int, int, int, float [I, float [I); int k, imax, kk, wl ;

kk = -w; wl=w+l; for (k=l; kc=n; k++) {

kk += wl; b [k] = (b [k] -vecvec ( ( (k c = wl) ? 1 : k-w) , k-1, kk-k, b, a) )/a [kkl ;

imax = -1; for (k=n; k>=l; k--) {

if (imax c w) imax++; b [kl = (b [k] -scaprdl (kk+w, w, k+l, 1, imax, a, b) ) /a [kkl ; kk - = wl;

I

B. chldecsolbnd

Solves the system of equations Ax=b where A is an nxn symmetric positive definite band matrix for whose elements Aij=O for li-jl>w, iJ=l , ..., n), by use of Cholesky's square root

Copyright 1995 by CRC Press, Inc

Page 174: Numerical Library in C for Scientists and Engineers A

method. The decomposition A = U ~ U is first obtained by means of chldecbnd and, if this was successful, chlsolbnd is then called to obtain x.

Function Parameters: void chldecsolbnd (a,n, w,am,b)

a,n, w,aux: see chldecbnd; b: float b[l:n];

entry: the right hand side of the system of linear equations; exit: the solution of the system.

Functions used: chldecbnd, chlsolbnd.

3.9 Symmetric positive definite tridiagonal matrices

3.9.1 Preparatory procedure

decsymtri

Given the nxn symmetric tridiagonal matrix T (T,,=O for I i j 1 >1) attempts to obtain a unit upper diagonal matrix U (Uiji=l, Uij=O for i>j and j> i+ l ) and unit upper bidiagonal matrix U (U,,i=l, Uij=O for i>j and j> i+ l ) and a diagonal matrix D such that UTDU=T. The rows of U and diagonal elements of D are determined in succession. If at stage k, I T,, 1 <tol* 11 tw 11 ,, where to1 is a tolerance prescribed by the user and p) is the k-th row of T, the decomposition process is discontinued, and an integer K is given the value k-I; otherwise K is given the value n at exit.

Function Parameters: void decsymtri (diag, co, n, a m )

diag: float diag[l :n]; entry: the diagonal of T, value of in diag[i], i=l, ..., n; exit: Dj,i will be delivered in diag[i], i=l, ..., aux[3];

co: float co[l:n-I]; entry: the codiagonal of T, value of T,,, in co[i], i=l, ..., n-I; exit: U,,,, will be delivered in co[i], i=l, ..., aux[3]-I;

n: int; entry: the order of the matrix;

aux: float aux[2:5]; entry: aux[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision (the value of to1 above);

Copyright 1995 by CRC Press, Inc

Page 175: Numerical Library in C for Scientists and Engineers A

exit: ~ 2 4 3 1 : the number of elimination steps performed (value of K above); awr[5]: if awc[3]=n then aux[5] will be equal to the infinity norm of the matrix, else

a2451 is set equal to the value of that element which causes the breakdown of the decomposition (value of T,,,,,,,).

void decsymtri (float diag [I , float co [I , int n, float aux [I ) (

int i,nl; float d,r,s,u,tol,norm,normr;

tol=aux [21 ; d=diag [ll ; r=co [ll ; norm=normr=fabs (dl +fabs (r) ; if (fabs(d) <= normr*tol) {

aux[3]=0.0; aux [SI =d; return;

1 &o [ll =r/d; nl=n- I. ; for (i=2; i<=nl; i++) (

s=r; r=co Iil ; d=diag [il ; normr=fabs (s) +fabs (d) +fabs (r) ; diag[il = d - = u*s; if (fabs(d) <= normr*tol) {

aux[3] =i-1; aux [Sl =d; return ;

1 ;=co [il =r/d; if (normr > norm) norm=normr;

I i d=diag [nl ; normr=f abs (d) +f abs (r) ; diag[nl = d -= u*s; if (fabs(d) <= normr*tol) {

aux[3] =nl; aux [S] =d; return;

1 I

if (normr > norm) norm=normr; aux [31 =n; aux [ 5 1 =norm ;

I

3.9.2 Solution of linear equations

A. solsymtri

Given the nxn unit upper bidiagonal matrix U (Ui,i=l, q j = O for i>j and j>i+I) and diagonal matrix D, solves the system of equations Tx=b, where T=UTDU (this decomposition results from successful exit from decsymtri). One call of decsymtri followed by several calls of solsymtri may be used to solve several linear systems having the same symmetric tridiagonal matrix, but different right hand sides.

Function Parameters: void solsymtri (diag, co,n, b)

Copyright 1995 by CRC Press, Inc

Page 176: Numerical Library in C for Scientists and Engineers A

diag: float diag[l :n]; entry: the diagonal matrix, as delivered by decsymtri;

co: float co[l:n-I]; entry: the codiagonal of the unit upper bidiagonal matrix, as delivered by decsymtri;

n: int; entry: the order of the matrix;

b: float b[l:n]; entry: the right hand side of the linear system; exit: the calculated solution of the linear system.

void solsymtri (float diag [I , float co [I , int n, float b [I ) I

int i; float r,s;

r=b [ll ; b [ll =r/diag [ll ; for (i=2: i<=n: i++)

s=b [nl ; for (i=n-1; i>=l; i--) s = b[il - = co[il*s;

1

B. decsolsymtri

Given the nxn symmetric tridiagonal matrix T (Tj=O for I i-j 1 >1) attempts to obtain a unit bidiagonal matrix U (Uiri=l, Uij=O for i>j and j> i+ l ) and a diagonal matrix D such that U T ~ u = ~ by calling decsymtri and, if successful in so doing, solves the system of equations Tx=b by calling solsymtri.

Function Parameters: void decsolsymtri (diag,co,n,am, b)

diag: float diag[l:n]; entry: the diagonal of T, value of Tri in diag[i], i=l, ..., n; exit: Di,i will be delivered in diag[i], i=l , ..., am[3];

co: float co[l:n-I]; entry: the codiagonal of T, value of I;,,, in co[i], i=l, ..., n-I; exit: U,i+, will be delivered in co[i], i=l, ..., am[3]-I;

n: int; entry: the order of the matrix;

am: float aux[2:5]; entry: am[2]: a relative tolerance; a reasonable choice for this value is an estimate of the

relative precision of the matrix elements; however, it should not be chosen smaller than the machine precision;

exit: am[3]: the number of elimination steps performed; am[5]: if aux[3]=n then aux[5] will be equal to the infinity norm of the matrix, else

aux[5] is set equal to the value of that element which causes the breakdown of the decomposition;

b: float b[l:n];

Copyright 1995 by CRC Press, Inc

Page 177: Numerical Library in C for Scientists and Engineers A

entry: the right hand side of the linear system; exit: if aux[3]=n then the solution of the linear system is overwritten on b, else b

remains unaltered.

Functions used: decsymtri, solsymtri.

void decsolsymtri (float diag [ I , float co [ I , int n, float aux [ I , float b [ I )

{ void decsymtri (float [ I , float [ I , int, float [ I ) ; void solsymtri (float [ I , float [ I , int, float [ I ) ;

decsymtri (diag, co, n , aux) ; if (aux [3 ] == n) solsymtri (diag, co,n, b) ;

1

3.10 Sparse real matrices - Iterative methods

conjgrad

Solves the system of equations Ax=b, where A is a nxn positive definite symmetric matrix, by the method of conjugate gradients [R71]. This method involves the construction of sequences of approximations xk to the solution, differences ak=xk+,-x,, and the associated residual vectors rW=b-Ax". With x, an initial approximation to x, and

pk = (rk,rJ vk = (rbArJ (k=0,1 ,...) the recursion is

qo=tldpo a o = r d q o and for k=1,2, ...

xk = Xk-, + a k k l

ek-I = qk-,pJpk-, qk = ( ~ P J + ek-, a k = (rk + ek-lak-3/qk '

Setting ak=l/qb b,=ek-,/q,,, pk=rk+ek-,akk,, the above formulae may be written as bk = p i p k - , Pa = rk + b#k-1' qk = A P ~

= ~d(Pk,qd Xk+, = X k + a#b rk+l = rk - akqk P k + l = (rk+llrk+b.

The computations are terminated if max( 11 rk 11 ,, 11 uk., 11 2)ltol, where to1 is a tolerance prescribed by the user.

Function Parameters: void conjgrad (matvec,~, r, I, n,goon, iterate, norm2)

matvec: void (*matvec)(p,q); this function defines the coefficient matrix A of the system as follows: at each call matvec delivers in q the matrix-vector product Ap, p and q are one-dimensional arrays, float p[l:n], q[l:n];

x: float x[l:n]; entry: an initial approximation to the solution; exit: the solution;

r: float r[l:n];

Copyright 1995 by CRC Press, Inc

Page 178: Numerical Library in C for Scientists and Engineers A

entry: the right hand side of the system; exit: the residual b-Ax;

1,n: int; entry: I and n are respectively the lower and upper bound of the arrays x,r,p,q;

goon: int (*goon)(iterate, norm2); this is a user supplied function, goon indicates the continuation of the process depending on the current values of iterate and norm2, if goon equals zero then the iteration process is stopped;

iterate: int *; exit: delivers the number of iteration steps already performed;

norm2: float *; exit: delivers the squared Euclidean norm of the residual.

Functions used: vecvec, elmvec.

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); float vecvec (int, int, int, float [ I , float [I ; void elmvec(int, int, int, float [I, float [I, float); int i; float a,b,prr,rrp, *P, *aP;

p=allocate-real-vector (1, n) ; ap=allocate-real-vector(1,n); *iterate=O; do (

if (*iterate == 0) { (*rnatvec) (x,p) ; for (i=l; ic=n; i++) p [il = r [il -= p [il ; prr=vecvec(l,n,O,r,r);

) else { b=rrp/prr; prr=rrp; for (i=l; ic=n; i++) p [il =r [il +b*p [il ;

I J

(*matvec) (p, ap) ; a=prr/vecvec(l,n,O,p,ap); elmvec(l,n,O,x,p,a) ; elmvec (l,n, O,r,ap, -a) ; *norm2=rrp=vecvec(l,n,O,r,r) ; (*iterate) ++;

} while ( (*goon) (*iterate, *norm2) ) ; free-real-vector(p,l); free-real-vector(ap,l) ;

1

3.1 1 Similarity transformation

3.1 1.1 Equilibration - real matrices

A. eqilbr

Equilibrates an nxn real matrix A by determining a real diagonal matrix D whose diagonal elements are integer powers of 2, and a permutation matrix P such that the Euclidean norms of the k-th row and the k-th column of A'=PDAD"P" are approximately equal (k=l, ..., n).

Copyright 1995 by CRC Press, Inc

Page 179: Numerical Library in C for Scientists and Engineers A

With j(k) =1,2 ,..., n, 1,2 ,... , (i.e. j(k) =(k-1 mod(n))+l, k=1,2 ,...) a sequence of diagonal matrices D,, where the j(k)-th diagonal element of Dk is p;' (pk being an integer power of 2) and all others 1, together with a sequence of matrices A,=DJ,,D;', A,=A are obtained. p, is determined by the condition that the Euclidean norms of the j(k)-th column and j(k)-th row of A, have approximately equal values. If all of diagonal elements of either the j(k)-th row or the j(k)-th column of A,, is nearly zero, the row and column in question are interchanged with the next pair for which this is not so. The process is terminated if either (a) 112 < p, < 2 for one whole cycle of the j(k) or (b) k=(n+l)n2. D is the product of the

Dk.

Function Parameters: void eqilbr (a,n,em,d, inter)

a: float a[l:n, l:n]; entry: the matrix to be equilibrated; exit: the equilibrated matrix;

n: int; entry: the order of the matrix;

em: float em[O:O]; entry: the machine precision;

d float d[l:n]; exit: the main diagonal of the transforming diagonal matrix;

inter: int inter[l :n]; exit: information defining the possible interchanging of some rows and the

corresponding columns.

Functions used: tammat, mattam, ichcol, ichrow.

Method: The method is equilibrated by means of Osborne's diagonal similarity transformation possibly with interchanges [DekHo68, 0~601.

eqilbr(float **a, int n, float em11 , float dIl , int inter[] ) I ' float tammat (int, int, int, int, float **, float **) ;

float mattam(int, int, int, int, float **, float * * ) ; void ichcol (int, int, int, int, float **) ; void ichrow(int, int, int, int, float **) ; int i,im,il,p,q,j,t,count,exponent,ni; float c, r, eps, omega, factor, di;

factor=l.O/ (2 .O*log(2.0) ) ; eps=em [OI ; omega=l.O/eps; t=p=l; q=ni=i=n; count= ( (n+l) *n) /2; for (j=l; jc=n; j++) {

d[jl =l.O; interIj1 =O;

1 I i = (i < q) ? i+l : p( while (count > 0 && ni > 0) {

count - - ; im=i-1; il=i+l; c=sqrt (tammat (p, im, i, i, a, a) +tammat (il,q, i, i, a, a) ) ; r=sqrt (mattam ( p , im, i, i, a, a) +mattam(il, q, i, i, a, a) ) ;

Copyright 1995 by CRC Press, Inc

Page 180: Numerical Library in C for Scientists and Engineers A

if (c*omega c= r*eps) ( inter [tl =i; ni=q-p; t++; if (p ! = i) {

ichcol(l,n,p,i,a) ; ichrow(l,n,p, i,a) ; di=d [il ; d [il =d [pl ; d [pl =di ;

1 p++;

) else if (r*omega c= c*eps) (

inter[tl = -i; ni=q-p; t++; if (q ! = i) (

ichcol (l,n,q,i,a) ; ichrow(l,n,q,i,a) ; di=d [il ; d [il =d [ql ; d [ql =di ;

1 q--;

) else ( exponent=log(r/c)*factor; if (fabs(exponent) > 1.0) (

nl=q-p; c=pow(2.0,exponent) ; r=l . O/c; d[il *= c; for (j=l; jc=im; j++) {

a[jl [il *=c; a[il [jl *= r;

1

B. baklbr

Given the diagonal elements of the nxn diagonal matrix D, the pivot reference integers associated with a permutation matrix P, and a set of column vectors vo) (i=nl, ..., n2), constructs the sequence of vectors utij=~LIvti) (i=nl ,..., n2). (If v m is an eigenvector of PDAD- 'P', uti) is an eigenvector of A.)

Function Parameters: void baklbr (n,nl,n2,d, inter,vec)

n: int; entry: the length of the vectors to be transformed; nl,n2: int;

entry: the serial numbers of the first and last vector to be transformed; d: float d[l:n];

entry: the main diagonal of the transforming diagonal matrix of order n, as produced by eqilbr;

inter: int inter[l:n]; entry: information defining the possible interchanging of some rows columns, as

Copyright 1995 by CRC Press, Inc

Page 181: Numerical Library in C for Scientists and Engineers A

produced by eqilbr; vec: floatvec[l:n,nl:n2];

entry: the n2-nl + I vectors of length n to be transformed; exit: the n2-nl+l vectors of length n resulting from the back transformation.

Function used: ichrow.

void ichrow(int, int, int, int, float * * ) ; int i,j,k.p,q; float di;

q=n; for (i=l; i<=n; i++) (

di=d [il ; if (di ! = 1)

for (j=nl; j<=n2; j++) vec[il [jl *= di; k=inter [il ; if (k > 0)

p++ ; else

if (k c 0) q--; 1 for (i=p-l+n-q; i>=l; i--) {

k=inter [il ; if (k > 0 ) {

) else (

3.1 1.2 Equilibration - complex matrices

A. eqilbrcom

Equilibrates an nxn complex matrix A by determining a real diagonal matrix D whose diagonal elements are integer powers of 2, and a permutation matrix P such that if c=PDAD-'P', the diagonal elements of C'C-CC' (C' denotes the conjugate transpose of C) are approximately zero. With j(k)=1,2 ,..., n, 1,2 ,..., (i.e. j(k)=(k-1 mod(n))+l, k=1,2 ,...) a sequence of diagonal matrices D,, where the j(k)-th diagonal element of D, is pi' (p, being an integer power of 2) and all others 1, together with a sequence of matrices C, for which C,=D,C,-,D,,-', C,=A are determined. p, is determined by the condition that the Euclidean norms of the j(k)-th column and j(k)-th row of C, have approximately equal values. If all off-diagonal elements of either the j(k)-th column or the j(k)-th row of Ck., are nearly zero, the row and column in question are interchanged with the next pair for which this is not so. The process is terminated if either (a) 112 < p, < 2 for one whole cycle of the j(k) or (b) k=kmax+l, where kmax is an integer prescribed by the user [DekHo68, Os60, PaR691.

Function Parameters: void eqilbrcom (al,a2,n,em,d, inter)

al ,a2: float al[l:n,l:n], a2[l:n,I:n]; entry: the real part and imaginary part of the matrix to be equilibrated must be given

Copyright 1995 by CRC Press, Inc

Page 182: Numerical Library in C for Scientists and Engineers A

in the arrays a1 and a2, respectively; exit: the real part and the imaginary part of the equilibrated matrix are delivered in

the arrays a1 and a2, respectively; int; entry: the order of the given matrix;

float em[O: 71; entry: em[O]: the machine precision; em[6]: the maximum allowed number of iterations (value of kmax above); exit: em[7]: the number of iterations performed; float d[l:n]; exit: the scaling factors of the diagonal similarity transformation;

inter: int inter[l :n]; exit: information defining the possible interchanging of some rows and the

corresponding columns.

Functions used: ichcol, ichrow, tammat, mattam.

void eqilbrcorn(f1oat **al, float **a2, int n, float em[], float d[l, int inter [I )

I void ichcol (int, int, int, int, float * * ) ; void ichrow (int, int, int, int, float * * ) ; float tammat(int, int, int, int, float **, float * * ) ; float mattam(int, int, int, int, float **, float * * ) ; int i,p,q,j,t,count,exponent,ni,im,il; float c,r,eps,di;

eps=em [O] *em [O] ; t=p=l; q=ni=i=n; count=em [61 ; for (j=l; jc=n; j++) {

d[jl=l.O; inter [ j I =0 ;

I I i = (i c q) ? i+l : pj while (count > 0 && ni > 0) (

count - - ; im=i-1; il=i+l; c=tammat (p, im, i, i, a1,al) +tammat (il,q, i, i, al, al) +

tammat (p, im, i, i,a2,a2) +tammat (il,q, i, i, a2,a2) ; r=mattam(p, im, i, i,al, al) +mattarn(il,q, i, i, al, al) +

mattam(p,im,i,i,a2,a2)+mattam(il,q,i,i,a2,a2) ; if (c/eps <= r) {

inter It1 =i; ni=q-p; t++; if (p ! = i) (

ichcol (l,n,p, i,al

p++; ) else

if (r/eps <= c) {

Copyright 1995 by CRC Press, Inc

Page 183: Numerical Library in C for Scientists and Engineers A

inter[tl = -i; ni=q-p; t++; if (q ! = i) {

ichcol (l,n, ichrow (1, n, ichcol (l,n, ichrow ( 1, n, di=d [il ; d [il =d [ql ; d [ql =di ;

1 q--;

} else ( exponent=ceil (log(r/c) *0.36067) ; if (abs (exponent) > 1) {

ni=q-p; c=pow (2.0, exponent) ; d[il *= c. for (j=l;'jc=im; j++) (

a1 [jl [il * = c; a1 [il [jl /= c; a2 [jl [il *= c; a2 [il [jl /= c;

B. baklbrcom

Given a real nxn diagonal matrix D, a permutation matrix P and a sequence of complex vectors vF) (k=nl, ..., n2), constructs the vectors uF)=~PvF) (k=nl ,..., n2). (If vM, k=nl, ..., n2, are eigenvectors of P'D-'ADP, u", k=nl, ..., n2, are corresponding eigenvectors of A.)

Function Parameters: void baklbrcom (n,nl,n2,d, inter,vr,vi)

n: int; entry: the order of the matrix of which the eigenvectors are calculated;

nl,n2: int; entry: the eigenvectors corresponding to the eigenvalues with indices nl, ..., n2 are to

be transformed; d float d[l:n];

entry: the scaling factors of the diagonal similarity transformation as delivered by eqilbrcom;

inter: int inter[l :n]; entry: information defining the interchanging of some rows and columns, as produced

by eqilbrcom; vr,vi: float vr[l:n,nl:n2], vi[l:n,nl:n2];

entry: the back transformation is performed on the eigenvectors with the real parts given in array vr and the imaginary parts given in array vi;

Copyright 1995 by CRC Press, Inc

Page 184: Numerical Library in C for Scientists and Engineers A

exit: the real parts and imaginary parts of the resulting eigenvectors are delivered in the columns of the arrays vr and vi, respectively.

Function used: baklbr.

void baklbrcom(int n, int nl, int n2, float d[l, int inter[], float **vr, float **vi)

1

baklbr (n, nl, n2, d, inter, vr) ; baklbr (n, nl, n2, d, inter, vi) ;

1

3.1 1.3 To Hessenberg form - real symmetric

Reduces an nxn symmetric matrix A to tridiagonal form T by setting A(J)=A and ~(j+J)=p(i)~p(i) (i=l , . . . , n-2) when T=A("-') (setting

(v'))~ = (Ak,,'), 0,0 ,...,o), and

(U'i,')T=(V(0)T+((V(i) )TV(Vlek,

where k=n-i+l and e, is the k-th unit vector, and + is the sign of A,,,, P ~ ) = I - ~ U ~ ) ( U ~ ) ) ~ / ( U ~ ) ) ~ U ~ ) in the above). The i-th transformation reduces the elements, in the (n-i+l)-th row and column of Afi) which do not also belong to the principal diagonal and the two adjacent diagonals, to zero; if all of these elements are already less in absolute value than 11 A 11 times the machine precision, the i-th transformation is skipped [DekHo68, Wi651.

Function Parameters: void tfmsymtri2 (a,n,d, b, bb,em)

a: float a[l:n,l:n]; entry: the upper triangle of the symmetric matrix must be given in the upper

triangular part of a (the elements a[i,j], i ilj); exit: the data for Householder's back transformation is delivered in the upper

triangular part of a, the elements a[i,j], i>j are neither used nor changed; n: int;

entry: the order of the given matrix; d float d[I:n];

exit: the main diagonal of the symmetric tridiagonal matrix T, produced by Householder's transformation;

b: float b[I:n]; exit: the codiagonal elements of T are delivered in b[l:n-I], b[n] is set equal to

zero; bb: float bb[l:n];

exit: the squares of the codiagonal elements of T are delivered in bb[l:n-I], bb[n] is set equal to zero;

em: float em[O:l]; entry: em[O]: the machine precision;

Copyright 1995 by CRC Press, Inc

Page 185: Numerical Library in C for Scientists and Engineers A

exit: em[l]: the infinity norm of the original matrix.

Functions used: tamvec, matmat, tammat, elmveccol, elmcolvec, elmcol.

void tfmsymtri2 (float **a, int n, float d[l , float b [I, float bb[l , float em [I )

float tammat (int, int, int, int, float **, float * * ) ; float matmat (int, int, int, int, float **, float * * ) ; void elrnveccol(int, int, int, float [ I , float ** , float); float tamvec(int, int, int, float ** , float [I ) ; void elmcol(int, int, int, int, float ** , float ** , float); void elmcolvec (int, int, int, float **, float [I , float) ; int i, j,r,rl; float w,x, al, bO, bbO ,machtol, norm;

norm=O. 0 ; for (j=l; jc=n; j++) {

w-0.0 ; for (i=l; ic=j ; i++) w += fabs (a [il [jl ; for (i=j+l; i<=n; i++) w += fabs(a[jl [il ) ; if (W > norm) norm=w;

I machtol=em [O] *norm; em [ll =norm; r=n; for (rl=n-1; rl>=l; rl--) {

d [rl =a [rl [rl ; xztammat (1, r-2,r,r,a,a) ; al=a [rll [rl ; if (sqrt (x) c = rnachtol) {

bO=b [rll =al; bb [rll =bO*bO; a [rl [rl =1.0;

) else ( bbO=bb [rl] =al*al+x; bO = (a1 > 0.0) ? -sqrt (bbO) : sqrt (bb0) ; al=a [rl] [rl =al-bO; w=a [rl [rl=l.O/ (al*bO) ; for (j=l; jc=rl; j++)

b [j] = (tamrnat (1, j, j, r,a,a) +matmat (j+l,rl, j ,r,a,a) ) *w; elmveccol(l, rl, r, b,a, tamvec (1, rl, r,a, b) * * 5 ; for (j=l; jc=rl; j++) {

elmcol(1, j, j,r,a,a,b[jl); elmcolvec(1, j, j,a,b,a[jl [rl ) ;

1 d [ll =a [ll [ll ; a [ll 111 =1.0; b [n] =bb [nl =O. 0 ;

1

Performs the back substitutions upon the intermediate numbers produced by tfmsymtri2.

Function Parameters: void baksymtri2 (a,n,nl,n2,vec)

a: float a[l:n, 1 :n]; entry: the data for the back transformation, as produced by tfmsymtri2, must be given

in the upper triangular part of a;

Copyright 1995 by CRC Press, Inc

Page 186: Numerical Library in C for Scientists and Engineers A

n: int; entry: the order of the given matrix;

nl,n2: int; entry: the lower and upper bound, respectively, of the column numbers of vec;

vec: float vec[l:n, nl:n2]; entry: the vectors on which the back transformation has to be performed; exit: the transformed vectors.

Functions used: tammat, elmcol.

void baksymtril(f1oat **a, int n, int nl, int n2, float **vet) I

float tammat (int, int, int, int, float * * , float * * ) . void elmcol (int, int, int, int, float ** , float ** , ;loat) ; int j,k; float w;

for (j=2; j<=n; j++) ( w=a[jl [jl ; if (W < 0.0)

for (k=nl; k<=n2; k++) elmcol(1, j -1, k, j ,vec, a, tammat (1, j -1, j, k,a,vec w ;

C. tfmprevec

Computes the matrix P for which P A P ~ = T where A is an nxn matrix, and the nxn matrix T is of tridiagonal form, using the intermediate results generated by tfmsymtri2.

Function Parameters: void tfinprevec (a,n)

a : float a[l:n,l:n]; entry: the data for the back transformation, as produced by tfmsymtri2, must be given

in the upper triangular part of a; exit: the matrix which transforms the original matrix into a similar tridiagonal one;

n: int; entry: the order of the given matrix.

Functions used: tammat, elmcol.

void tfmprevec(f1oat **a, int n) I

float tammat (int, int, int, int, float ** , float * * ) ; void elmcol (int, int, int, int, float **, float ** , float) ; int i, j, j1,k; float ab;

jl=l; for (j=2; j<=n; j++) {

for (i-1; i<=jl-1; i++) a[il [jll=0.0; for (i=j; ic=n; i++) a[il [jll=0.0; a[jll [jll=l.O; ab=a[jl [jl ; if (ab < 0)

for (k=l; k<=jl; k++) elmcol(l,jl,k,j,a,a,tammat(l,jl,j,k,a,a)*ab);

]I=]; 1

Copyright 1995 by CRC Press, Inc

Page 187: Numerical Library in C for Scientists and Engineers A

for (i=n-1; i>=l; i--) a[il [nl=0.0; a [nl 11-11 =I. 0;

1

D. tfmsymtril

Reduces an nxn symmetric matrix A to tridiagonal form T as in the implementation of tfmsymtri2. It is assumed that the upper triangular elements of A are given in a linear array.

Function Parameters: void tfmsymtri 1 (a,n,d, b, bb,em)

a : float a[l:(n+l)d2]; entry: the upper triangle of the given matrix must be given in such a way that the

(i,j)-th element of the matrix is a[&l)j/2+i], I I i 4j 4 n; exit: the data for Householder's back transformation as used by bahymtril;

n: int; entry: the order of the given matrix;

d float d[l:n]; exit: the main diagonal of the symmetric tridiagonal matrix T, produced by

Householder's transformation; b: float b[l:n];

exit: the codiagonal elements of T are delivered in b[l:n-I], b[n] is set equal to zero;

bb: float bb[l:n]; exit: the squares of the codiagonal elements of T are delivered in bb[l:n-I], bb[n]

is set equal to zero; em: float em[O:l];

entry: em[O]: the machine precision; exit: em[l]: the infinity norm of the original matrix.

Functions used: vecvec, seqvec, elmvec.

void tfmsymtril (float a[], int n, float d[l , float b [I, float bb [ I 1

float em11 ) I

float vecvec (int, int, int, float [I , float [I ) ; float seqvec (int, int, int, int, float [I , float [I ) ; void elmvec (int, int, int, float [I , float [I , float) ; int i,j,r,rl,p,q,ti,tj; float s,w,x,al,bO,bbO,norm,machtol;

norm=O . 0 ; tj=O; for (j=l; js=n; j++) (

w=o . 0 ; for (i=l; is=j; i++) w += fabs(a[i+tjl) ; tj += j; ti=tj+j; for (i=j+l; is=n; i++) (

w += fabs (a [ti1 ) ; ti += i;

1 I

if (W > norm) norm=w;

Copyright 1995 by CRC Press, Inc

Page 188: Numerical Library in C for Scientists and Engineers A

q= ( (n+l) *n) /2; r=n; for (rl=n-1; rl>=l; rl--) {

p=q-r; d [rl =a [ql ; x=vecvec (p+l, q-2,0, a, a) ; al=a [q-11 ; if (sqrt(x) <= machtol) (

bO=b [rll =al; bb [rll =bO*bO; a[q]=l.O;

} else { bbO=bb [rll =al*al+x; bo = (a1 > 0.0) ? -sqrt (bb0) : sqrt (bb0) ; al=a [q-11 =al-b0; w=a [ql =l .O/ (al*bO) ; tj=O; for (j=l; j<=rl; j++) {

ti=ti+i : - d .

s=vecvec(tj+l,ti,p-tj,a,a) ; tj=ti+j; b [jl= (seqvec (j+l,rl, tj ,p,a,a) +s) *w;

1

elrnvec (1, rl,p, b, a,vecvec (1, rl,p,b, a) *w*O. 5) ; tj=O; for (j=l; j<=rl; j++) (

E. baksymtril

Performs the back substitutions upon the intermediate numbers produced by tfmsymtril.

Function Parameters: void baksymtri 1 (a, n, nl , n2, vec)

a: float a[l:(n+ l)n/2]; entry: the data for the back transformation, as produced by tfmsymtril;

n: int; entry: the order of the given matrix;

nl,n2: int; entry: the lower and upper bound, respectively, of the column numbers of vec;

vec: float vec[l :n, n l :n2]; entry: the vectors on which the back transformation has to be performed; exit: the transformed vectors.

Functions used: vecvec, elmvec.

void baksymtril (float a [I , int n, int nl, int n2, float **vet) 1

float *allocate-real-vector(int, int);

Copyright 1995 by CRC Press, Inc

Page 189: Numerical Library in C for Scientists and Engineers A

void free-real-vector(f1oat *, int); float vecvec(int, int, int, float [I, float [I); void elmvec (int, int, int, float [I , float [ I , float) ; int j, jl,k, ti,tj; float w,*auxvec;

auxvec=allocate real vector(1,n) ; for (k=nl; k<=n2; k+S) {

for (j=l; j<=n; j++) auxvec[j]=vec[jl [kl ; tj=jl=l; for (j=2; jc=n; j++) {

ti=tj+j; w=a [ti] ; if (W < 0.0)

elmvec(1, jl,tj,auxvec,a,vecvec(l, jl,tj,auxvec,a)*w); ]I=]; tj=ti;

1 ;or (j=l; j<=n; j++) vec [jl [kl =auxvec [jl ;

1

3.1 1.4 To Hessenberg form - real asymmetric

A. tfmreahes

Given areal nxn matrix A, obtains a sequence ofpivot reference integers I Sp(i) I n (i=l, ..., n) associated with a permutation matrix P, a unit lower triangular matrix L with Li,,=O (i=2 ,..., n), I Lijl 4 (j=2 ,..., n; i=j+l, ..., n) such that PLH=APL, where H is an upper Hessenberg matrix (HiLi=O for i>j+l). For hrther details see [DekHof68, Wi651.

Function Parameters: void tfmreahes (a,n,em, index)

a: float a[l:n, l:n]; entry: the matrix to be transformed; exit: the upper Hessenberg matrix is delivered in the upper triangle and the first

subdiagonal of a, the transforming matrix L, in the remaining part of a, i.e. a[i,jJ=Lij+,, for i=3 ,..., n and j = l , ..., i-2;

n: int; entry: the order of the given matrix;

em: float em[O:l]; entry: em[O]: the machine precision; exit: em[l]: the infinity norm of the original matrix;

index: int inter[l :nJ; exit: the pivotal indices defining the stabilizing row and column interchanges.

Functions used: matvec, matmat, ichcol, ichrow.

yoid tfmreahes (float **a, int n, float em [I , int index [I ) t

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); float matvec(int, int, int, float ** , float [I ) ; float matmat (int, int, int, int, float **, float * * ) ; void ichcol(int, int, int, int, float * * ) ; void ichrow(int, int, int, int, float * * I ;

Copyright 1995 by CRC Press, Inc

Page 190: Numerical Library in C for Scientists and Engineers A

int i, j, jl,k,l; float s,t,machtol,macheps,norm,*b;

b=allocate-real-vector(0,n-1); macheps=em [Ol ; norm=O .0 ; for (i=l; i<=n; i++) {

s=o . 0 ; for (j=l; j<=n; j++) s += fabs(a[il [jl ) ; if ( S > norm) norm=s;

\ em [ll =norm; machtol=norm*macheps; index [ll =O; for (j=2; j<=n; j + + ) (

jl=j-1; 1=0; s=machtol; for (k=j+l; k<=n; k++) {

t=fabs (a [kl [jll ) ; if (t > S) {

l=k;

) if (1 ! = 0) {

if (fabs(a[jl [jll) < s) { ichrow(l,n, j,l,a); ichcol(l,n, j,l,a);

) else 1=j ;

t=a[jl [jll ; for (k=j+l; k<=n; k++) a[kl 1111 /=t;

) else for (k=j+l; k<=n; k++) a[kl [jll=0.0;

for (i=l; i<=n; i++) b[i-11 = a[il [jl +=

((1 == 0) ? 0.0 : matmat(j+l,n,i,jl,a,a)) - matvec(1, (jl < i-2) ? jl : i-2,i,a,b);

index t j I =l ; 1 free-real-vector(b,O);

)

B. bakreahesl

Given asequence of pivot reference integers p(i) (1 <p(i) I n , i = l ,..., n) associated with an nxn permutation matrix P, a unit lower triangular matrix L with L,,=O (i=2, ..., n) and a single column vector v, forms the vector u=PLv. (If v is an eigenvector of H, where PLH=APL, u is an eigenvector of A.)

Function Parameters: void bakreahes 1 (a, n, index, v)

a : float a[l:n,l:n]; entry: the transforming matrix L, as produced by tfmreahes must be given in the part

below the first subdiagonal of a, i.e. a[i,j]=LiJ+,, for i=3 ,..., n and j=l ,..., i-2; n: int;

entry: the length of the vector to be transformed; index: int index[l :n];

entry: the pivotal indices defining the stabilizing row and column interchanges as produced by tfmreahes;

v: float v[l:n]; entry: the vector to be transformed;

Copyright 1995 by CRC Press, Inc

Page 191: Numerical Library in C for Scientists and Engineers A

exit: the transformed vector.

Function used: matvec.

void bakreahesl (float **a, int n, int index [I , float v [I ) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int) ; float matvec(int, int, int, float ** , float [I) ; int i,l; float w, *x;

x=allocate-real-vector(1,n) ; for (i=2; ic=n; i++) x[i-ll=v[il; for (i=n; i>=2; i--) {

v[i] += matvec(1, i-2,i,a,x) ; l=index [il ; if (1 > i) {

w=v[il ; v [il =v [ll ; v[ll =w;

f ree-real-vector (x, 1) ; I

Given a sequence of pivot reference integers p(i) (1 Ip(i) S n, i=l, ..., n) associated with an nxn permutation matrix P, a unit lower triangular matrix L with L,,=O (i=2, ..., n) and a system of column vectors bw (k=nl, ..., n2) forms the vectors vW=P~bF) (k=nl, ..., n2). (If bF) is an eigenvector of H, where PLH=APL, vM is an eigenvector of A , )

Function Parameters: void bakreahes2 (a, n, nl , n2, index,vec)

a: float a[l:n, l:n]; entry: the transforming matrix L, as produced by tjmreahes must be given in the part

below the first subdiagonal of a, i.e. a[i,j]=Lij+,, for i=3 ,..., n and j = l , ..., i-2; n: int;

entry: the length of the vectors to be transformed; nl,n2: int;

the column numbers of the first and last vector to be transformed; index: int index[l :n];

entry: the pivotal indices defining the stabilizing row and column interchanges as produced by tjmreahes;

vec: float vec[l:n,nl :n2]; entry: the n2-nl+l vectors of length n to be transformed; exit: the n2-nl+l vectors of length n resulting from the back transformation.

Functions used: tarnvec, ichrow.

void bakreahes2(float **a, int n, int nl, int n2, int index[], float **vet)

' float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int) ; float tamvec(int, int, int, float * * , float [ I ) ; void ichrow(int, int, int, int, float * * ) ;

Copyright 1995 by CRC Press, Inc

Page 192: Numerical Library in C for Scientists and Engineers A

int i,l,k; float *u;

u=allocate-real vector(1,n) ; for (i=n; i>=2;-i--) {

for (k=i-2; k>=l; k--) u[k+ll=a[il [kl ; for (k=nl; k<=n2; k++) vec [i] [kl += tamvec ( 2 , i-1, k,vec,u) ; l=index [il ; if (1 > i) ichrow(nl,n2,i,l,vec) ;

1 f ree-real-vector (u , 1) ;

3.1 1.5 To Hessenberg form - complex Hermitian

A. hshhrmtri

Given an nxn Hermitian matrix A, obtains a complex diagonal matrix C and k (k In-2) vectors uW such that with

S=C'EAEC (E' denotes the conjugate transpose of E) is a real symmetric tridiagonal matrix (Sij=O if I i-j 1 >I and S,,i+l =Si+l,r).

Function Parameters: void hshhrmtri (a,n,d, b,bb,em,tr,ti)

a: float a[I:n,I:n]; entry: the real part of the upper triangle of the Hermitian matrix must be given in the

upper triangular part of a (the elements a[i,j], i q ) ; the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], i>j);

exit: the components of the uo) and C; n: int;

entry: the order of the matrix; d float d[l:n];

exit: the main diagonal of the resulting symmetric tridiagonal matrix (Si,i above); b: float b[l:n-I];

exit: the codiagonal elements of the resulting symmetric tridiagonal matrix (the values S,,i+I, i=l, ..., n-I, in the above);

bb: float bb[l:n-I]; exit: the squares of the moduli of the codiagonal elements of the resulting

symmetric tridiagonal matrix (the values i=l, ..., n-1, in the above); em: float em[O:l];

entry: em[O]: the machine precision; exit: em[]]: an estimate for a norm of the original matrix;

tr,ti: float tr[l:n-I], ti[l:n-I]; exit: data for subsequent back transformations.

Functions used: matvec, tamvec, matmat, tarnmat, mattam, elmveccol, elmcolvec,

Copyright 1995 by CRC Press, Inc

Page 193: Numerical Library in C for Scientists and Engineers A

elmcol, elmrow, elmvecrow, elmrowvec, elmrowcol, elmcolrow, carpol.

Method: see hshhrmtrival.

void hshhrmtri (float **a, int n, float d [I , float b [I , float bb [I , float em [I , float tr [I , float ti [I )

I float matvec (int, int, int, float ** , float [I ) ; float tamvec(int, int, int, float ** , float [ I ) ; float matmat (int, int, int, int, float ** , float * * ) ; float tammat (int, int, int, int, float * * , float * * ) ; float mattam(int, int, int, int, float **, float * * ) ; void elmveccol (int, int, int, float 11 , float ** , float) ; void elmcolvec (int, int, ,int, float * * , float [I , float) ; void elmcol(int, int, int, int, float ** , float ** , float) ; void elmrow(int, int, int, int, float ** , float ** , float) ; void elmvecrow(int, int, int, float [I, float **, float); void elmrowvec (int, int, int, float ** , float [I , float) ; void elmrowcol (int, int, int, int, float **, float ** , float) ; void elmcolrow(int, int, int, int, float **, float ** , float) ; void carpol(float, float, float * , float *, float * ) ; int i,j,jl,jml,r,rml; float nrm,w,tol2,x,ar,ai,mod,~,s,h,k,t,q,ajr,a~1~bj,bbj;

nrm=O. 0 ; for (i=l; i<=n; i++) (

w=fabs (a [il [il ) ; for (j=i-1; j>=l; j--) w += fabs(a[i] [jl )+fabs(a[jl [il ) ; for (j=i+l; jc=n; j++) w += fabs(a[i] [jl )+fabs(a[jl [il); if (W > nrm) nrm=w;

t=em [Ol *nrm; tol2=t*t; em [ll =nrm; r=n; for (rml=n-1; rml>=l; rml--) {

x=tammat (1,r-2,r,r,a,a) +mattam(l,r-2,r,r,a,a) ; ar=a [rmll [rl ; ai = -a [rl [rmll ; d [rl =a [rl [rl ; carpol (ar, ai, &mod, &c, &s) ; if (X c t012) {

a[rl [rl = -1.0; b [rmll =mod; bb [rml] =mod*mod;

} else { h=mod*mod+x; k=sqrt (h) ; t=a [r] [rl =h+mod*k; if (ar == 0.0 && ai == 0.0)

a [rmll [rl =k; else {

a [rmll [r] =ar+c*k; a[rl [rmll = -ai-s*k; s = - s ;

1 C = -c; j=l; jml=O; for (jl=2; jlc=r; jl++) {

b [j] = (tammat (1, j, j ,r,a,a) +matmat (jl, rml, j ,r,a,a) + mattam(1, jml, j ,r,a,a) -matmat (jl,rml,r, j ,a,a) )/t;

bb[j]=(matmat(l, jml,],r,a,a) -tammat(jl,rml, j,r,a,a) - matmat (1, j ,r, j ,a,a) -mattam(jl, rml, j ,r,a,a) )It;

jml=j; ]=]I;

1 q= (tamvec (1, rml, r, a, b) -matvec (1, rml, r, a, bb) ) /t/2.0 ;

Copyright 1995 by CRC Press, Inc

Page 194: Numerical Library in C for Scientists and Engineers A

bb [ r m l l =h; b [ r m l l =k ;

J t r [ r m l l = c ; t i [ r m l l = s ; r = r r n l ;

B. hshhrmtrival

Given an nxn Hermitian matrix A, obtains m complex vectors cW (m 511-2) such that with E=E,,,E,,. . . El, where

Ek = I - 2 ~ ' ~ ) C 7 ~ ) ~ / 2 ~ ) ~ ' ~ ) , EAET=s, (ET: conjugate and transpose of E)

where S is a Hermitian tridiagonal matrix and delivers the values S,,, ( i=l ,..., n) and of 1 r,i+l 1 (i=l, ..., n-1).

Function Parameters: void hshhrmtrival (a, n, d, bb,em)

a: float a[l:n,l:n]; entry: the real part of the upper triangle of the Hermitian matrix must be given in the

upper triangular part of a (the elements a[i,j], i i j ) ; the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], i>j);

exit: the elements of a are altered; n: int;

entry: the order of the given matrix; d: float d[l:n];

exit: the main diagonal of the resulting Hermitian tridiagonal matrix (Si,i above); bb: float bb[l:n-11;

exit: the squares of the moduli of the codiagonal elements of the resulting Hermitian tridiagonal matrix (the values (S,,,,)', i=l , ..., n-1, in the above);

em: float em[O:l]; entry: em[O]: the machine precision; exit: em[l]: an estimate for a norm of the original matrix.

Copyright 1995 by CRC Press, Inc

Page 195: Numerical Library in C for Scientists and Engineers A

Functions used: matvec, tamvec, matmat, tammat, mattam, elmveccol, elmcolvec, elmcol, elmrow, elmvecrow, elmrowvec, elrnrowcol, elmcolrow.

Method: hshhrmtrival transforms a Hermitian matrix into a similar Hermitian tridiagonal matrix by means of Householder's transformation. hshhrmtri transforms a Hermitian matrix into a similar real tridiagonal matrix by means of Householder's transformation followed by a complex diagonal unitary similarity transformation in order to make the resulting tridiagonal matrix real symmetric. Householder's transformation for complex Hermitian matrices is a unitary similarity transformation, transforming a Hermitian matrix into a similar complex tridiagonal one [Mu66, Wi651.

void hshhrmtrival(f1oat **a, int n, float d[l, float bb[l, float em[])

float matvec (int, int, int, float ** , float [I ) ; float tamvec(int, int, int, float ** , float [I); float matmat(int, int, int, int, float ** , float * * ) ; float tammat(int, int, int, int, float ** , float * * ) ; float mattam(int, int, int, int, float ** , float * * ) ; void elmveccol (int, int, int, float [I , float **, float) ; void elmcolvec (int, int, int, float ** , float [I , float) ; void elmcol(int, int, int, int, float ** , float **, float); void elmrow(int, int, int, int, float **, float **, float); void elmvecrow (int, int, int, float [I , float ** , float) ; void elmrowvec (int, int, int, float **, float [ I , float) ; void elmrowcol (int, int, int, int, float **, float ** , float) ; void elmcolrow(int, int, int, int, float **, float ** , float) ; int i, j, jl, jml,r,rml; float nrm,w,tol2,x,ar,ai,h,t,q,ajr,arj,dj,bbj,mod2;

nrm=O. 0 ; for (i=l; i<=n; i++) {

w=fabs (a lil lil ) ; for (j=i-1; j>=l; j--) w += fabs(a[il [jl)+fabs(a[jl [il); for (j=i+l; j<=n; j++) w += fabs(a[il [jl)+fabs(a[jl [il); if (W > nrm) nrm=w;

J

t=em [O] *nrm; tol2=t*t; em [ll =nrm; r=n; for (rml=n-1; rml>=l; rml--1 (

x=tammat (1,r-2, r,r, a, a) +mattam(l,r-2, r,r, a,a) ; ar=a [rmll [rl ; ai = -a [rl [rmll ; d [TI =a lr1 [rl ; if (X < tol2)

bb [rml] =ar*ar+ai*ai ; else {

mod2=ar*ar+ai*ai; if (mod2 == 0.0) (

a [rmll [rl =sqrt (x) ; t=x;

} else ( x += mod2; h=sqrt (mod2*x) ; t=x+h; h=l.O+x/h; a[rl [rmll = -ai*h; a [rmll [rl =ar*h;

1 j=1; jml=O; for (jl=2; jl<=r; jl++) {

d[jl=(tammat(l,j,j,r,a,a)+matmat(jl,rml,j,r,a,a)+ mattam(1, jml, j,r,a,a) -matmat(jl,rml,r, j,a,a) )It;

Copyright 1995 by CRC Press, Inc

Page 196: Numerical Library in C for Scientists and Engineers A

bb[j] =(matmat (1, jml, j,r,a,a) -tammat (jl,rml, j ,r,a,a) - matmat(l,j,r,j,a,a)-mattam(jl,rml,j,r,a,a))/t;

jml= j ; j=jl;

I &(tamvec(l,rml,r,a,d) -matvec(l,rml,r,a,bb)) /t/2.0; elrnveccol(l,rml,r,d,a, -q) ; elmvecrow (1, rml, r, bb, a, q) ; j=1; for (jl=2; jl<=r; jl++) (

ajr=a[jl [rl ; arj=a[rl [jl ; dj=d[jl ; bbj=bb[jl ; elmrowvec(j,rml, j,a,d, -ajr) ; elmrowvec(j,rml, j,a,bb,arj),; elmrowcol(j,rml, j,r,a,a,-dl); elmrow(j,rml, j,r,a,a,bbj); elmcolvec(jl,rml,j,a,d,-arj); elmcolvec(jl,rml, j,a,bb,-ajr) ; elmcol(jl,rml, j,r,a,a,bbj); elmcolrow(jl,rml, j,r,a,a,dj); j=jl;

1 bb [rmll =x;

1

C. bakhrmtri

Given a complex nxn diagonal matrix C and m Sn-2 complex vectors uw (as produced, for example, at exit from hshhrmtri) and a set of complex vectors

vectors vO) (j=nl, ..., n2) forms the

(j=nl, ..., n2).

Function Parameters: void bakhrmtri (a, n, n l , n2, vecr,veci, tr, ti)

a: float a[l :n, l :n]; entry: the data for the back transformation as produced by hshhrmtri;

n: int; entry: the order of the matrix of which the eigenvectors are calculated;

nl,n2: int; entry: the eigenvectors corresponding to the eigenvalues with indices

n l , ..., n2 are to be transformed; vecr, veci: float vecr[l :n, n l :n2], veci[l :n, n l :n2];

entry: the back transformation is performed on the real eigenvectors given in the columns of array vecr;

exit: vecr and veci contain the real part and imaginary part of the transformed eigenvectors;

tr, ti: float tr[l :n-I], ti[l :n-I]; entry: data at exit from hshhrmtri.

Copyright 1995 by CRC Press, Inc

Page 197: Numerical Library in C for Scientists and Engineers A

Functions used: matmat, tammat, elmcol, elmcolrow, commul, comrowcst,

Method: see hshhrmtrival.

void bakhrmtri(f1oat **a, int n, int nl, int n2, float **vecr, float **veci, float tr [I, float ti [ I )

t float matmat (int, int, int, int, float ** , float * * ) ; float tammat (int, int, int, int, float ** , float * * ) ; void elmcol (int, int, int, int, float ** , float * * , float) ; void elmcolrow(int, int, int, int, float ** , float ** , float) ; void commul (float, float, float, float, float *, float * ) ; void comrowcst (int, int, int, float ** , float ** , float, float) ; int i,j,r,rml; float c,s,t,qr,qi;

for (i=l; i<=n; i++) for (j=nl; jc=n2; j++) veci[i] [j]s0.0;

c=1.0 ; s=o . 0 ; for (j=n-1; j>=l; j--) {

commul(c,s,tr[jl ,ti[jl ,&c,&s); comrowcst (nl, n2, j ,vecr,veci, c, s) ;

1 rml=2 ; for (r=3; rc=n; r++) {

t=a [rl [rl ; if (t > 0.0)

for (j=nl; jc=n2; j++) { qr=(tammat(l,rml,r, j,a,vecr) -matmat(l,rml,r, j,a,veci)) /ti qi=(tammat(l,rml,r, j,a,veci)+matmat(l,rml,r, j,a,vecr) )It; elmcol(1, rml, j , r,vecr, a, -qr) ; elmcolrow(l, rml, j, r,vecr, a, -qi! ; elmcolrow(l, rml, j ,r,veci,a:qr), elmcol(l,rml, j,r,veci,a, -ql) ;

1 rml=r;

3.11.6 To Hessenberg form - complex non-Hermitian

A. hshcomhes

Given an nxn complex matrix A, determines m complex vectors uo) (m Sn-2) and an nxn complex diagonal matrix D such that with E=EmE ,-,...El, where

D-'EAED=H where H is a complex upper Hessenberg matrix (Hij=O for i>j+l) with real nonnegative subdiagonal elements H,+lj. The uo) are determined by imposing the conditions that the first j elements uo) are zero and that with Afl)=A, A0")Ao)@) has zeros in positions i=j+2, ..., n of the j-th column G=I, ..., n-2). D is determined by imposing the condition that the elements of the subdiagonal of DIAfn- ' )~ are absolute values of those of A("-/). For further details see [Mu66, Wi651.

Function Parameters: void hshcomhes (ar,ai,n,em, b, tr,ti,del)

ar, ai: float ar[l : n, 1 : n], ai[l : n, 1 : n]; entry: the real part and the imaginary part of the matrix to be transformed must be

Copyright 1995 by CRC Press, Inc

Page 198: Numerical Library in C for Scientists and Engineers A

given in the arrays a r and ai, respectively; exit: the real part and the imaginary part of the upper triangle of the resulting upper

Hessenberg matrix are delivered in the corresponding parts of the arrays a r and ai, respectively; data for the Householder back transformation are delivered in the strict lower triangles of the arrays a r and ai;

n: int; entry: the order of the given matrix;

em: float em[O:I]; entry: em[O]: the machine precision;

em[l]: an estimate of the norm of the complex matrix (for example, the sum of the infinity norms of the real part and imaginary part of the matrix);

b: float b[l:n-I]; exit: the real nonnegative subdiagonal of the resulting upper Hessenberg matrix;

tr,ti: float tr[l :n], ti[l :n]; exit: the real part and the imaginary part of the diagonal elements of a diagonal

similarity transformation are delivered in the arrays tr and ti, respectively; del: float del[l :n-21;

exit: information concerning the sequence of Householder matrices.

Functions used: hshcomcol, matmat, elmrowcol, hshcomprd, carpol, cornmul, comcolcst, comrowcst.

void hshcomhes (float **ar, float **ai, int n, float em[], float b[l , float tr [I , float ti [I , float del [I )

I float matmat(int, int, int, int, float **, float * * ) ; void elmrowcol(int, int, int, int, float **, float **, float); void hshcomprd(int, int, int, int, int, float ** ,

float ** , float **, float **, float); void comcolcst(int, int, int, float **, float ** , float, float) ; void comrowcst (int, int, int, float **, float **, float, float) ; void carpol(float, float, float * , float * , float * ) ; void commul(float, float, float, float, float *, float * ) ; int hshcomcol(int, int, int, float **, float **, float,

float *, float *, float *, float * ) ; int r,rml,i,nml; float tol,t,xr,xi;

nml=n- 1 ; t=em [Ol *em [ll ; tol=t*t; rml=l; for (r=2; rc=nml; r++) {

if (hshcomcol (r,n,rml,ar,ai,tol,&(b[rmll) ,&(tr[rl) ,&(ti [rl) , &t) 1 { for (i=l; i<=n; i++) (

xr=(matmat(r,n,i,rml,ai,ai)-matmat(r,n,i,rml,ar,ar))/t; xi=(-matmat(r,n,i,rml,ar,ai)-matmat(r,n,i,ml,ai,ar))/t; elmrowcol (r,n,i,rml,ar,ar,xr) ; elmrowcol(r,n, i,rml,ar,ai,xi) ; elmrowcol (r, n, i, rml, ai, ar, xi) ; elmrowcol (r, n, i, rml, ai, ai, -xr) ;

1 hshcomprd (r, n, r, n, rml, ar, ai, ar, ai , t) ;

del [rmll =t; rml=r ;

1 if (n > 1) carpol (ar [nl [nmll , ai [n] [nmll , & (b [nmll ) , & (tr [nl ) , &(ti [nl ) ) ; rml=l; tr [ll =l. 0; ti[ll=O.O; for (r=2; rc=n; r++) {

Copyright 1995 by CRC Press, Inc

Page 199: Numerical Library in C for Scientists and Engineers A

commul (tr [rml] ,ti [rmll , tr [rl ,ti [rl , & (tr [rl ) , &(ti [rl ) ) ; comcolcst (l,rml,r,ar,ai,tr[rl ,ti[rl) ; comrowcst (r+l,n,r,ar,ai, trtrl ,-ti [rl) ; rml=r;

1 1

B. bakcomhes

Given m complex vectors uo) (m In-2) , an nxn complex diagonal matrix D and a sequence of complex column vectors v" (k=nl, ..., n2) computes the vectors WF'=EDV~ (k=nl, ..., n2) where

(If vM (k=nl, ..., n2) are eigenvectors of H=D-'EAED, wm (k=nl, ..., n2) are corresponding eigenvectors of A.) For further details see [Mu66, Wi651.

Function Parameters: void bakcomhes (ar, ai, tr,ti,del, vr,vi, n, nl,n2)

ar, ai, tr, ti, del: float ar[l :n, 1 : n], ai[l :n, 1 :n], tr[l :n], ti[l :n], del[l : n-21; entry: the data for the back transformation as produced by hshcomhes;

vr,vi: float vr[l:n,nl:n2]; entry: the back transformation is performed on the eigenvectors with the real

parts given in vr and the imaginary parts given in vi; exit: the real parts and imaginary parts of the resulting eigenvectors are

delivered in the columns of the vr and vi, respectively; n: int;

entry: the order of the matrix of which the eigenvectors are calculated; nl,n2: int;

entry: the eigenvectors corresponding to the eigenvalues with indices nl, ..., n2 are to be transformed.

Functions used: comrowcst, hshcomprd.

void bakcomhes (float **ar, float **ai, float tr [I , float ti [I , float del[l, float **vr, float **vi, int n, int nl, int n2)

( void hshcomprd(int, int, int, int, int, float **,

float ** , float **, float ** , float); void comrowcst(int, int, int, float **, float **, float, float); int i,r,rml; float h;

for (i=2; ic=n; i++) comrowcst (nl,n2, i,vr,vi, tr [il ,ti [il ) ; r=n- 1 ; for (rml=n-2; rml>=l; rml--) {

h=del [rmll ; if (h > 0.0) hshcomprd (r, n,nl,n2, rml,vr,vi, ar, ai, h) ; r=rml ;

1 1

Copyright 1995 by CRC Press, Inc

Page 200: Numerical Library in C for Scientists and Engineers A

3.12 Other transformations

3.12.1 To bidiagonal form - real matrices

A. hshreabid

Reduces an mxn symmetric matrix A to bidiagonal form B. With A=A,, u") is so chosen that all elements but the first in the first column of

are zero; v") is so chosen that all elements but the first two of the first row in

A; = A;(Z - 2v(l)v(l)T/v(l)Tv('))

are zero; the first row and column are stripped from A," to produce the (m-l)x(n-1) matrix A, and the process is repeated.

Function Parameters: void hshreabid (a,m,n,d, b,em)

a: float a[l:m,l:n]; entry: the given matrix; exit: data concerning the premultiplying and postmultiplying matrices;

m: int; entry: the number of rows of the given matrix;

n: int; entry: the number of columns of the given matrix;

d: float d[l:n]; exit: the diagonal of the bidiagonal matrix (diagonal of B above);

b: float b[l:n]; exit: the superdiagonal of the bidiagonal matrix is delivered in b[l:n-11;

em: float em[O:l]; entry: em[O]: the machine precision; exit: em[l]: the infinity norm of the original matrix.

Functions used: tammat, mattam, elmcol, elmrow.

Method: hshreabid slightly improves a part of a procedure (svd) of Golub and Reinsch [WiR71] by skipping a transformation if the column or row in already in the desired form, (i.e. if the sum of the squares of the elements that ought to be zero is smaller than a certain constant). In svd the transformation is skipped only if the norm of the full row or column is small enough. As a result, some ill-defined transformations are skipped in hshreabid. Moreover, if a transformation is skipped, a zero is not stored in the diagonal or superdiagonal, but the value that would have been found if the column or row were in the desired form already is stored.

Copyright 1995 by CRC Press, Inc

Page 201: Numerical Library in C for Scientists and Engineers A

void hshreabid(f loat **a, int m, int n, float d[l , float b [I , float em [I )

{ float tammat(int, int, int, int, float **, float **) ; float mattam(int, int, int, int, float **, float **) ; void elmcol (int, int, int, int, float **, float **, float) ; void elmrow(int, int, int, int, float **, float ** , float); int i,j,il; float norm,machtol,w,s,f,g,h;

norm=O .0 ; for (i=l; ic=m; i++) {

w=o . 0 ; for (j=i; jc=n; j++) w += fabs(a[il [jl); if (W > norm) norm=w;

Aachtol=em [Ol *norm; em Ill =norm; for (i=l; ic=n; i++) {

il=i+l; s=tammat (il,m,i,i,a,a) ; if (S c machtol)

d [il =a [il [il ; else {

f=a [il [il ; s += f*f; d[i] = g = (f c 0.0) ? Sqrt(S) : -sqrt(~) ; h=f *g-s; a [il [il =f -g; for (j=il; jc=n; j++)

elmcol(i,m, j,i,a,a, tammat(i,m,i,j,a,a)/h ; 1 if (i c n)

s=mattarn(il+l,n, i, i,a, a) ; if (s c machtol)

b ti] =a [il [ill ; else {

f=a [il [ill ; S += f*f; b[i] = g = (f c 0.0) ? sqrt(s) : -sqrt(S) ; h=f *g-s ; a [il [ill =f -g; for (j=il; jc=m; j++)

elmrow(il,n, j, i, a,a,mattarn(il,n, i, j ,a,a) /h) ;

B. psttfmmat

Computes the postmultiplying matrix from the intermediate results generated by hshreadbid.

Function Parameters: void psttfinmat (a,n,v,b)

a: float a[l:n,l:n]; entry: the data concerning the postmultiplying matrix, as generated by hshreabid;

n: int; entry: the number of columns and rows of a;

v: float v[l:n,l:n]; exit: the postmultiplying matrix;

b: float b[l :n]; exit: the superdiagonal as generated by hshreabid.

Copyright 1995 by CRC Press, Inc

Page 202: Numerical Library in C for Scientists and Engineers A

Functions used: matmat, elmcol.

void psttfmmat(f1oat **a, int n, float **v, float b[]) {

float matmat (int, int, int, int, float ** , float * * ) ; void elmcol (int, int, int, int, float **, float **, float) ; int i, il, j; float h;

il=n; v [nl In] =1.0 ; for (i=n-1; i>=l; i--) {

h=b [i] *a [il [ill ; if (h < 0.0) {

for (j=il; j<=n; j++) v[jl [il=a[il [jl/h; for (j=il; j<=n; j++)

elmcol (il, n, j , i , v, v, matmat (il , n, i , j , a, v) ) ; \

C. pretfmmat

Computes the premultiplying matrix fiom the intermediate results generated by hshreadbid.

Function Parameters: void pretfmmat (a,m, n,d)

a: float a[l:m,l:n]; entry: the exit: the

m: int; entry: the

n: int; entry: the

data concerning the premultiplying matrix, as generated by hshreabid; premultiplying matrix;

number of rows of a;

number of columns of a, n should satisfy n l m ; d: float d[l:n];

entry: the diagonal as generated by hshreabid.

Functions used: tammat, elmcol.

void pretfmmat (float **a, int m, int n, float d[l ) I

float tammat(int, int, int, int, float **, float * * ) ; void elmcol (int, int, int, int, float **, float **, float) ; int i,il,j; float g,h;

for (i=n; i>=l; i--) { il=i+l; g=d [il ; h=g*a [il [ i l ; for (j=il; j<=n; j++) a[il [jl=O.O; if (h < 0.0) {

for (j=il; j<=n; j++) elmcol (i,m, j, i,a,a, tammat (il,m, i, j ,a,a) /h) ;

for (j=i; jc=m; j++) a[jl [il /= g; } else

for (j=i; j<=m; j++) a[jl [il=0.0; a[i] [il += 1.0;

1

Copyright 1995 by CRC Press, Inc

Page 203: Numerical Library in C for Scientists and Engineers A

3.13 The (ordinary) eigenvalue problem

3.13.1 Real symmetric tridiagonal matrices

A. valsymtri

Calculates all or some consecutive eigenvalues in descending order of magnitude, of a symmetric nxn tridiagonal matrix T. With d, (i=l, ..., n) the values of the elements of the principal diagonal of T, b, (i=l, ..., n-I) the squares of the values of the codiagonal elements of T, 6 the product of the machine precision and 11 TII, the sequence f(k,x) given by

f(lJ)=d,-x, f(kx)=(dk-xbk-J/vk where vk=f(k-1,x) if I f(k-1,x) 1 >6, -6 if f(k-1,x) 5 0 , and 6 otherwise (k=2, ..., n), is determined,

f(nd =p(n,x)/p(n-Lx) where p(n,x) = determinant of T-XI, and the f(k,x) form a Sturm sequence. The zeros of f(n,x) (i.e. the eigenvalues of 2') are computed by a sophisticated mixture of linear interpolation and bisection (see zeroin). It is assumed that the values of 4, bi and 11 T I I above are available; these are generated as output from the tridiagonalization of a symmetric nxn matrix by both tfmsymtri2 and tfmsymtril. For further details see [DekHo68, Wi651.

Function Parameters: void valsymtri (d, bb, n,nl,n2,val,em)

d float d[l :n]; entry: the main diagonal of the symmetric tridiagonal matrix (values of di above);

bb: float bb[l:n-I]; entry: the squares of the codiagonal elements of the symmetric tridiagonal matrix (the

values of b, in the above); n: int;

entry: the order of the given matrix; nl,n2: int;

entry: the serial number of the first and last eigenvalue to be calculated, respectively; val: float val[nl:n2];

exit: the n2-nl+I calculated consecutive eigenvalues in nonincreasing order; em: float em[0:3];

entry: em[O]: the machine precision; em[l]: an upper bound for the moduli of the eigenvalues of the given matrix; em[2]: a relative tolerance for the eigenvalues;

exit: em[3]: the total number of iterations used for calculating the eigenvalues.

void valsymtri(f1oat d[l , float bb[] , int n, int nl, int n2, float val[l, float em[])

I float sturm(f1oat [I, float [ I , int, float, int, float,

float, int *, float *, float * ) ; int k,count,ext,extrapolate; float max,x,y,macheps,norm,re,machtol,ub,lb,lambda,

c,fc,b,fb,a,fa,dd,fd,fdb,fda,w,mb,tol,m,p,q;

Copyright 1995 by CRC Press, Inc

Page 204: Numerical Library in C for Scientists and Engineers A

macheps=em [Ol ; norm=em [ll ; re=em 121 ; machtol=norm*macheps; rnax=norm/macheps; count=O; ub=l.l*norm; lb = -ub; lambda=ub; for (k=nl; k<=n2; k++) {

y=ub; lb = -l.l*norm; x=lb;

/ * look for the zero of the polynomial function * /

b=x; fb=sturm(d,bb,n,x,k,machtol,max,&count,&lb,&ub~; a=x=y; fa=sturm(d,bb,n,x,k,machtol,max, &count, &lb, &ub) ; c=a; fc=fa; ext=o; extrapolate=l; while (extrapolate) {

if (fabs(fc) < fabs(fb)) { if (C ! = a) {

dd=a; fd=fa;

1 a=b ; fa=fb; b=x=c; fb=fc; c=a; fc=fa;

I I tol=fabs (x) *re+machtol; m= (c+b) *0.5; rnb=m-b; if (fabs(mb) > tol) {

if (ext > 2 ) w=mb ;

else { if (mb == 0.0)

tol=O .O; else

if (mb < 0.0) to1 = -tol; p= (b-a) *fb; if (ext <= 1)

q=fa-fb; else {

fdb= (fd-fb) / (dd-b) ; fda= (fd-fa) / (dd-a) ; p *= fda; q=fdb*fa-fda*fb;

1 if (p < 0.0) {

p = -p; q = -q;

1 W= (p<FLT-MIN I I p<=q*tol) ? to1 : ( (p<mb*q) ? p/q : mb) ;

1 dd=a ; fd=fa; a=b; fa=fb; x = b += W; fb=sturm(d,bb,n,x,k,machtol,max,&count,&lb,&ub~; if ((fc >= 0.0) ? (fb >= 0.0) : (fb <= 0.0)) {

c=a; fc=f a; ext=o;

) else

Copyright 1995 by CRC Press, Inc

Page 205: Numerical Library in C for Scientists and Engineers A

ext = ( w == mb) ? 0 : ext+l; } else

break;

/ * end of the zero finding procedure * /

val [kl = lambda = (x > lambda) ? lambda : x; if (ub > X)

ub = (x > y) ? x : y; 1

float sturm(f1oat d[l , float bb [I, int n, float x, int k, float machtol, float max, int *count, float *lb, float *ub)

/ * this sturm sequence procedure is used internally by VALSYMTRI * /

int p,i; float f;

(*count) ++; p=k; f =d [I] -x; for (i=2; i<=n; i++) {

if (f <= 0.0) ( p++; if (p > n) return ((p == n) ? f : (n-p) *max) ;

} else if (p < i-1) {

*lb = X; return ((p == n) ? f : (n-p) *rnax) ;

if (kabs (f) < machtol) f = (f <= 0.0) ? -machtol : machtol;

f=d[il -x-bb[i-11 /f; \ if (p == n I I f <= 0.0)

if (X < *ub) *ub = x; else

*lb = x; return ((p == n) ? f : (n-p) *rnax) ;

1

B. vecsymtri

Calculates, by use of inverse iteration, the eigenvectors xi corresponding to the given consecutive eigenvalues hi (in nonincreasing order) (i=nl ,..., n2) of the nxn symmetric tridiagonal matrix T. The inverse iteration procedure used involves the determination of the vectors xi" from the relationships ( T - x J , ) x ~ ~ ) = Y F ) x , F ' (k=O, I,...), where YF' is so chosen that

11 x,'k") 11 =I. The values of the machine precision m,, the norm of the given matrix m,, an orthogonalization parameter m,, the relative tolerance of the eigenvectors m,, and the maximum number of iterations allowed for the calculation of each eigenvector m8 must be provided. If I hi-$ I <m,*m, for any j in I I j I i - I , then hi is modified so that I &-Aj I =m,*m,. If I hi-h, I <m,*m, for any j in the range I Sj I i-1, then a Gram-Schmidt process is carried out at each iteration step, so that the eigenvectors are orthogonal to within working precision. The iteration terminates when either Ilx,, 11 2<mI*m6 or k>m8. vecsymtri may be called with nl=l (so that eigenvectors are already known). However, it may occur that from previous use of vecsymtri or some other procedure, the eigenvectors corresponding to the nl-1 largest eigenvalues h ,,..., A,,, are already known. In this case the eigenvalues h ,,..., h ,,-, must be provided (in array val) as well as the corresponding eigenvector (in array vec). Moreover,

Copyright 1995 by CRC Press, Inc

Page 206: Numerical Library in C for Scientists and Engineers A

if vecsymtri has been called previously, then the number m, of eigenvectors involved in the last Gram-Schmidt process used must be provided. For further details see [DekHo68].

Function Parameters: void vecsymtri (4 b,n,nl, n2,val,vec,em)

d: float d[l:n]; entry: the main diagonal of the symmetric tridiagonal matrix (values of T,,, above);

b: float b[l:n]; entry: the codiagonal of the symmetric tridiagonal matrix (the values of T,,,+,=T+,,,

in the above) followed by an additional element 0; n: int;

entry: the order of the given matrix; nl,n2: int;

entry: lower and upper bound of the array val; val: float val[nl:n2];

entry: a row of nonincreasing eigenvalues (values of A,&, ..., A,, above) as delivered by valsymtri;

vec: float vec[l :n, n l :n2]; entry: if n l> l then the components of the eigenvectors corresponding to A,, ..., A,,,-,

must be given in vec[l:n,l:nl-I]; exit: the eigenvectors corresponding with the given eigenvalues A,, ..., A,,,;

em: float em[0:9]; entry: em[O]: em[l/: em[4]: em[5]:

em[6]: em[8]: exit: emL.51:

em[7]: em[9]:

the machine precision (value of m, above); a norm of the given matrix (value of m, above); the orthogonalization parameter (value of m, above); if n P l then em[6] should be given the value of the number of eigenvectors involved in the last Gram-Schmidt process used in the determination of the eigenvectors corresponding to A,, ..., A,-, (value of m, above); a relative tolerance for the eigenvectors; maximum number of iterations allowed for calculating each eigenvector;

the number of eigenvectors involved in the last Gram-Schmidt orthogonalization; the maximum Euclidean norm of the residues; the largest number of iterations performed for the calculation of some eigenvector.

Functions used: vecvec, tamvec, elmveccol.

void vecsymtri (float d [ I , float b [I , int n, int nl, int n2, float val [ I , float **vec, float em[] )

int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int); void free-integer-vector(int * , int); void free-real-vector(f1oat * , int); float vecvec (int, int, int, float [I , float 11 ) ; void elrnveccol (int, int, int, float [ I , float **, float) ; float tamvec (int, int, int, float ** , float [I ) ; int i,j,k,count,maxcount,countlim,orth,ind,iterate,*index;

Copyright 1995 by CRC Press, Inc

Page 207: Numerical Library in C for Scientists and Engineers A

float bi,bil,u,w,y,mil,lambda,oldlambda,ortheps,valspread,spr, res,maxres,norm,newnorm,oldnorm,machtol,vectol, *m, *p, *q, *r, *x;

index=allocate-integer-vector(1,n) ; m=allocate-real-vector(1,n) ; p=allocate-real-vector(1,n); q=allocate-real-vector(1,n); r=allocate-real-vector(1,n); x=allocate-real-vector (1, n) ; norm=em [ll ; machtol=em [OI *norm; valspread=em 141 *norm; vectol=em [61 *norm; countlim=em [81 ; ortheps=sqrt (em [Ol ) ; maxcount=ind=O; maxres=O.O; if (nl > 1) {

orth=em [51 ; oldlambda=val [nl-orthl ; for (k=nl-orth+l; k<=nl-1; k++) {

lambda=val [kl ; spr=oldlambda-lambda; if (spr < machtol) lambda=oldlambda-machtol; oldlambda=lambda;

1 ) else

orth=l; for (k=nl: k<=n2: k++)

ii (spr < machtol). lambda=oldlambda-machtol; orth++;

} else orth=l;

1 count=O; u=d [ll -lambda; bi=w=b [ll ; if (fabs (bi) < machtol) bi=machtol; for (i=l; i<=n-1; i++) {

bil=b [i+ll ; if (fabs (bil) < machtol) bil=machtol; if (fabs(bi) >= fabs(u)) {

mil=m li+ll =u/bi:

u=w-mil*y; w = -mil*bil; index [il =l;

} else { mil=m [i+ll =bi/u; p [il =u; q [il =w; r[il=O.O; u=d [i+ll -lambda-mil*w; w=bil; index[il =O;

1 I x[il=l.O; bi=bil;

) / * transform * / p[nl = (fabs(u) < machtol) ? machtol : u; q [nl =r [nl =O . 0 ; x[nl=l.O; iterate=l; while (iterate) {

u=w=o . 0 ; for (i=n; i>=l; i--) {

y=u;

Copyright 1995 by CRC Press, Inc

Page 208: Numerical Library in C for Scientists and Engineers A

u=x [i] = (x [il -q [i] *u-r [il *w) /p [il ; w=y;

) / * next iteration * / newnorm=sqrt (vecvec (l,n, 0,x, x) ) ; if (orth > 1) (

oldnorm=newnorm; for (j=k-orth+l; j<=k-1; j++)

elmveccol (1, n, j , x, vec, -tamvec (1, n, j , vec, x) ) ; newnorm=sqrt (vecvec (l,n, O,x,x) ) ; if (newnorm c ortheps*oldnorm) (

ind++ ; count=l; for (i=l; ic=ind-1; i++) x[il =O.O; for (i=ind+l; i<=n; i++) x [il =O. 0; x[indl =l.O; if (ind == n) ind=O; w=x [ll ; for (i=2; i<=n; i++) (

if (index[i-11 ) { u=w; w=x[i-11 =x [il ;

} else u=x [il ;

w=x [il =u-m [il *w; 1 J continue; / * iterate on * /

) / * new start * / ) / * orthogonalization * / res=l.O/newnorm; if (res > vectol I I count == 0) {

count++; if (count c = countlim) (

for (i=l; i<=n; i++) x[il *= res; w=x[ll ; for (i=2; ic=n; i++) (

if (index[i-11) { u=w; w=x [i-11 =x [i] ;

) else u=x[i] ;

w=x [i] =u-m [il *w; 1

) else break;

) else break;

1 for (i=l; ic=n; i++) vec [il [kl =x [il *res; if (count > maxcount) maxcount=count; if (res > maxres) maxreszres; oldlambda=lambda;

1 em 151 =orth; em [71 =maxres; em [ 9 I =maxcount ; free integer vector(index,l); f reeIrea1-vector (m, 1) ; free-real-vector (p , 1) ; f ree-real-vector (q, 1) ; free-real-vector (r, 1) ; f ree-real-vector (x , 1) ;

I

C. qrivalsymtri

Calculates all eigenvalues of a symmetric tridiagonal matrix T using square-root-free QR iteration. Values of m,, the machine precision, a relative tolerance m,, and 1) T J J must be provided. The relative error in the computed eigenvalues is less than m,* (1 TI[, the absolute error is less than m,* 11 T I I . If some eigenvalues hi are very small, the absolute error in their

Copyright 1995 by CRC Press, Inc

Page 209: Numerical Library in C for Scientists and Engineers A

determination may be made smaller by prescribing a value of m, which is less than its true value. When this is done, the calculation of b,lmi should cause no overflow, and that of (m,* 11 T I ] )' no underflow, where bi is the i-th element of the codiagonal of T. For hrther details see [Re7 1, Wi6.51.

Function Parameters: int qrivalsymtri (4 bb,n,em)

qrivalsymtri: given the number of eigenvalues not calculated; d: float d[l :n];

entry: the main diagonal of the symmetric tridiagonal matrix; bb: float bb[l:n];

entry: the squares of the codiagonal elements of the symmetric tridiagonal matrix followed by an additional element 0;

exit: the squares of the codiagonal elements of the symmetric tridiagonal matrix resulting from the QR iteration;

n: int; entry: the order of the given matrix; em: float em[0:5];

entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[2]: a relative tolerance for the eigenvalues; em[4]: the maximum allowed number of iterations;

exit: em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: the number of iterations performed.

int qrivalsymtri (float d [I , float bb [I , int n, float em[] ) I

int i,il,low,oldlow,nl,count,max; float bbtol,bbmax,bbi,bbnl,machtol,dn,delta,f,num,shi£t,g,h,

t,p,r,s,c,oldg;

t=em [21 *em [ll ; bbtol=t*t; machtol=em 101 *em [ll ; max=em [ 4 1 ; bbmax=0.0; count=O; oldlow=n; nl=n-1; while (n > 0) {

i=n; do I

low=i ; I--.

) while ((i >= 1) ? bb[il > bbtol : 0) ; if (low > 1)

if (bb [low-11 > bbmax) bbmax=bb [low-11 ; if (low == n)

n=nl ; else {

dn=d [nl ; delta=d [nl] -dn; bbnl=bb [nil ; if (fabs (delta) c machtol)

r=sqrt (bbnl) ; else {

f=2.0/delta; nurn=bbnl*f; r = -num/ (sqrt (num*f+l. 0) +l. 0) ;

1

Copyright 1995 by CRC Press, Inc

Page 210: Numerical Library in C for Scientists and Engineers A

if (low == nl) { d [nl =dn+r ; d[nll - = r; n -= 2;

} else ( count++ ; if (count > max) break; if (low c oldlow) (

shift=O.O; oldlow=low;

) else shift=dn+r;

h=d [low] -shift; if (fabs (h) c machtol)

h = (h c= 0.0) ? -machtol : machtol; g=h; t=g*h; bbi=bb [low] ; p=t+bbi ; il=low; for (i=low+l; ic=n; i++) {

s=bbi/p; c=t/p; h=d [il -shift-bbi/h; if (fabs (h) c machtol)

h = (h c= 0.0) ? -machtol : machtol; oldg=g; g=h*c; t=g*h; d [ill =oldg-g+d [il ; bbi = (i == n) ? 0.0 : bb[il ; p=t+bbi; bb [ill =s*p; il=i;

em [3] =sqrt (bbmax) ; em 151 =count; return n;

1

D. qrisymtri

Calculates the eigenvalues and eigenvectors of a symmetric tridiagonal matrix T of order n simultaneously by QR iteration. The process requires input of an auxiliary matrix A. If T results from tridiagonalization by use of tfmprevec then A has precisely the form produced as output by that procedure. If T is simply given as a symmetric tridiagonal matrix then A must be set to be the unit matrix. The maximum allowed number of iterations must be prescribed. If this number is exceeded, and the eigenvalues A,, ..., A,, and their corresponding eigenvectors have been determined, qrisymtri is given the value k, A,, ..., A,, are to be found in locations k+ l , ..., n of an output array D, their eigenvectors are to be found in columns k+l, ..., n of an output array A, and the numbers found in the remaining positions of these arrays are rough approximations only. For further details see [DekHo68, Wi651.

Function Parameters: int qrisymtri (a,n,d, b, bb,em)

qrisymtri: given the number (k above) of eigenvalues and eigenvectors not calculated; a: float a[l :n, l:n];

entry: some input matrix, possibly the identity matrix;

Copyright 1995 by CRC Press, Inc

Page 211: Numerical Library in C for Scientists and Engineers A

exit: the eigenvectors of the original symmetric tridiagonal matrix, premultiplied by the input matrix a;

n: int; entry: the order of the given matrix; d float d[l:n];

entry: the main diagonal of the symmetric tridiagonal matrix; exit: the eigenvalues of the matrix in some arbitrary order;

b: float b[l:n]; entry: the codiagonal of the symmetric tridiagonal matrix followed by an additional

element 0; exit: the codiagonal of the symmetric tridiagonal matrix resulting from the QR

iteration, followed by an additional element 0; bb: float bb[l:n];

entry: the squared codiagonal elements of the symmetric tridiagonal matrix, followed by an additional element 0;

exit: the squared codiagonal elements of the symmetric tridiagonal matrix resulting from the QR iteration;

em: float em[0:5]; entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[2]: a relative tolerance for the QR iteration; em[4]: the maximum allowed number of iterations; exit: em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: the number of iterations performed.

Function used: rotcol.

void rotcol (int, int, int, int, float **, float, float) ; int j , j 1, k, m, ml, count, max; float bbmax,r,s,sin,t,cos,oldcos,g,p,w,tol,tol2,lambda,dkl;

tol=em [21 *em [ll ; tol2=tol*tol; count=O ; bbmax=0.0; max=em [41 ; m=n ; do I

k=m; ml=m- 1 ; while (1) {

k- - ; if (k <= 0) break; if (bb[kl < to12) {

if (bb [k] > bbmax) bbmax=bb [kl ; break:

1 I

if (k == ml) m=ml;

else { t=d [ml -d [mll ; r=bb [ m l l ;

Copyright 1995 by CRC Press, Inc

Page 212: Numerical Library in C for Scientists and Engineers A

if (fabs(t) < tol) s=sqrt (r) ;

else ( w=z.o/t; s=w*r/ (sqrt (w*w*r+l. 0) +l. 0) ;

dim] += s; d[mll - = s; t = -s/b [mll ; r=sqrt (t*t+l. 0) ; cos=l.O/r; sin=t/r; rotcol (l,n,ml,m,a,cos,sin) ; m -= 2 ;

] else { count++; if (count > max) break; lambda=d [ml +s; if (fabs(t) < tol) (

w=d [mll -s; if (fabs(w) < fabs(1ambda)) lambda=w;

I k++ ; t=d [k] -lambda; cos=1.0 ; w=b [kl ; p=sqrt (t*t+w*w) ; jl=k; for (j=k+l; j<=m; j++) (

oldcos=cos; cos=t/p; sin=w/p; dkl=d [ j I -lambda; t *= oldcos; d [j I] = (t+dkl) *sin*sin+lambda+t; t=cos*dkl-sin*w*oldcos; w=b[jl ; p=sqrt (t*t+w*w) ; g=b [ j 11 =sin*p; bb [ jll =g*g; rotcol(l,n, jl, j,a,cos,sin); ]I=];

I d [m] =cos*t+lambda; if (t < 0.0) bIml1 = -9;

1 1

) while (m > 0); em [3] =sqrt (bbmax) ; em 151 =count; return m;

I

3.1 3.2 Real symmetric full matrices

Computes the m largest eigenvalues of an nxn symmetric matrix A whose upper triangular part is stored in a two dimensional array, using linear interpolation on a function derived from a Sturm sequence. A is first reduced to similar tridiagonal form T by a call of tfmsymtri2, and valsymtri is then used to calculate the eigenvalues.

Function Parameters: void eigvalsym2 (a,n,numval,val,em)

a: float a[l:n,l:n];

Copyright 1995 by CRC Press, Inc

Page 213: Numerical Library in C for Scientists and Engineers A

entry: the upper triangle of the symmetric matrix must be given in the upper triangular part of a (the elements a[ij], i +);

exit: the data for the Householder's back transformation (which is not used by this procedure) is delivered in the upper triangular part of a;

n: int; entry: the order of the given matrix; numval: int; entry: the serial number of the last eigenvalue to be calculated; val: float val[l:numvaE];

exit: the numval largest eigenvalues in monotonically nonincreasing order; em: float em[0:3];

entry: em[O]: the machine precision; em[2]: a relative tolerance for the eigenvalues; exit: em[l]: the infinity norm of the original matrix; em[3]: the number of iterations used for calculating the numval eigenvalues.

Functions used: tfmsymtri2, valsymtri.

void eigvalsym2(float **a, int n, int numval, float val[l, float em[]) I

float *allocate~real~vector(int, int); void free-real-vector(f1oat *, kt); void tfmsymtri2 (float **, int, float [I, float 11, float [I,

float [I ) ; void valsymtri (float [I, float [I, int, int, int,

float [I , float [I ) ; float *b,*bb,*d;

b=allocate-real-vector(1,n); bb=allocate-real-vector(1,n); d=allocate-realvector(1,n); tfmsymtri2 (a,n,d,b,bb,em) ; valsymtri (d,bb,n,l,numval,val,em) ; free-real-vector (b, 1) ; free-real-vector(bb,l); f ree-real-vector (d, 1) ;

1

Computes the m largest eigenvalues and corresponding eigenvectors of an nxn symmetric matrix A whose upper triangular part is stored in a two-dimensional array, by means of inverse iteration. A is first reduced to similar tridiagonal form T by a call of tfmsymtri2, valsymtri is used to calculate the eigenvalues, vecsymtri is used to calculate the corresponding eigenvectors, and bakrymtri2 is then used to perform the necessary back transformation. eigsym2 requires, as does vecsymtri, the value of an orthogonalization parameter m,. When the distance between two consecutive eigenvalues is less than m,, the eigenvectors are orthogonalized by a Gram-Schmidt process. The number m, of eigenvectors involved in the last Gram-Schmidt process is given by eigsym2 as part of its output. If eigsym2 is called more than once (to compute successive sets of eigenvalues and eigenvectors), the value m, arising from the preceding call is required as input for the current call.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 214: Numerical Library in C for Scientists and Engineers A

void eigsym2 (a, n, numval, val, vec, em) a : float a[l:n, l:n];

entry: the upper triangle of the symmetric matrix must be given in the upper triangular part of a (the elements a[i,j], I Q);

exit: the data for Householder's back transformation is delivered in the upper triangular part of a; the elements a[i,j] for i>j are neither used nor changed;

n: int; entry: the order of the given matrix;

numval: int; entry: the serial number of the last eigenvalue to be calculated;

val: float val[l :numval]; exit: the numval largest eigenvalues in monotonically nonincreasing order;

vec: float vec[l:n, l:numval]; exit: the numval calculated eigenvectors, stored columnwise, corresponding to the

calculated eigenvalues; em: float em[0:9];

entry: em[O]: the machine precision; em[2]: the relative tolerance for the eigenvalues; em[4]: the orthogonalization parameter (value of m, above); em[6]: the relative tolerance for the eigenvectors; em[8]: the maximum number of inverse iterations allowed for the calculation of each

eigenvector; exit: em[I]: the infinity norm of the matrix; em[3]: the number of iterations used for calculating the numval eigenvalues; em[5]: the number of eigenvectors involved in the last Gram-Schmidt

orthogonalization; em[7]: the maximum Euclidean norm of the residues of the calculated eigenvectors; em[9]: the largest number of inverse iterations performed for the calculation of some

eigenvector.

Functions used: tfmsymtri2, valsymtri, vecsymtri, baksymtri2.

void eigsp2 (float **a, int n, int numval, float -la1 [I, float **vec, float em [I )

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void tfmsptri2 (float ** , int, float [I , float [I , float [I ,

float [ I ) : void valsymtri (float [I, £loat 11 , int, int, int,

float [ I , float [I); void vecsymtri(f1oat [I, float [I, int, int, int,

float [I, float ** , float [I); void baksymtri2(float ** , int, int, int, float * * ) ; float *b,*bb,*d;

b=allocate-real-vector(1,n); bb=allocate-real-vector(1,n); d=allocate-real-vector(1,n); tfmsymtri2 (a,n, d, b, bb, em) ; valsymtri (d, bb,n, l,numval,val,em) ; vecsymtri (d, b,n, l,numval,val,vec, em) ; baksptri2 (a,n, l,numval,vec) ; f ree-real-vector (b, 1) ;

Copyright 1995 by CRC Press, Inc

Page 215: Numerical Library in C for Scientists and Engineers A

f ree-real-vector (bb, 1) ; f ree-real-vector (d, 1) ;

1

C. eigvalsyml

Computes the m largest eigenvalues of an nxn symmetric matrix A whose upper triangular part is stored in a one dimensional array, using linear interpolation on a hnction derived from a Sturm sequence. A is first reduced to similar tridiagonal form T by a call of tfmsymtril, and valsymtri is then used to calculate the eigenvalues.

Function Parameters: void eigvalsym 1 (a, n, numval,val, em)

a: float a[l:(n+l)dZ]; entry: the upper triangle of the symmetric matrix must be given in such a way that

the (i,j)-th element of the matrix is a[&l)j/Z+i], I 4 i 4j S n ; exit: the data for the Householder's back transformation (which is not used by this

procedure) is delivered in a; n: int;

entry: the order of the given matrix; numval: int;

entry: the serial number of the last eigenvalue to be calculated; val: float val[l :numval];

exit: the numval largest eigenvalues in monotonically nonincreasing order; em: float em[0:3];

entry: em[O]: the machine precision; em[Z]: a relative tolerance for the eigenvalues; exit: em[l]: the infinity norm of the original matrix; em[3]: the number of iterations used for calculating the numval eigenvalues.

Functions used: tfmsymtril, valsymtri.

void eigvalsyml(f1oat a[], int n, int numval, float val[l, float em[])

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int) ; void tfmsymtril(f1oat [I, int, float [I, float [I, float [I,

float [ I ) ; void valsymtri (float [ I , float [ I , int, int, int,

float [I , float [I ) ; float *b,*bb,*d;

b=allocate-real-vector (1, n) ; bb=allocate-real-vector(1,n); d=allocate-real-vector (l,n) ; tfmsymtril (a,n, d, b,bb, em) ; valsymtri (d, bb,n, l,numval,val, em) ; free-real-vector (b, 1) ; f ree-real-vector (bb, 1) ; f ree-real-vector (d, 1) ;

I

D. eigsyml

Copyright 1995 by CRC Press, Inc

Page 216: Numerical Library in C for Scientists and Engineers A

Computes the m largest eigenvalues and corresponding eigenvectors of an nxn symmetric matrix A whose upper triangular part is stored in a one-dimensional array, by means of inverse iteration. A is first reduced to similar tridiagonal form T by a call of tfmsymtril, valsymtri is used to calculate the eigenvalues, vecsymtri is used to calculate the corresponding eigenvectors, and baksymtril is then used to calculate the necessary back transformation. The significances of an orthogonalization parameter m4 and a number m, of eigenvectors involved in a Gram-Schmidt process are as for eigsym2.

Function Parameters: void eigsym 1 (a, n, numval,val,vec, em)

a: float a[l:(n+l)n/2]; entry: the upper triangle of the symmetric matrix must be given in such a way that

the (i,j)-th element of the matrix is a[G;-l)j/2+i], I 5 i 5 j S n ; exit: the data for Householder's back transformation;

n: int; entry: the order of the given matrix;

numval: int; entry: the serial number of the last eigenvalue to be calculated;

val: float val[l:numval]; exit: the numval largest eigenvalues in monotonically nonincreasing order;

vec: float vec[l :n, 1 :numval]; exit: the numval calculated eigenvectors, stored columnwise, corresponding to the

calculated eigenvalues; em: float em[0:9];

entry: em[O]: the machine precision; em[2]: the relative tolerance for the eigenvalues; em[4]: the orthogonalization parameter (value of m4 above); em[6]: the relative tolerance for the eigenvectors; em[8]: the maximum number of inverse iterations allowed for the calculation of each

eigenvector; exit: em[l]: the infinity norm of the matrix; em[3]: the number of iterations used for calculating the numval eigenvalues; em[5]: the number of eigenvectors involved in the last Gram-Schmidt

orthogonalization; em[7]: the maximum Euclidean norm of the residues of the calculated eigenvectors; em[9]: the largest number of inverse iterations performed for the calculation of some

eigenvector.

Functions used: tfmsymtri 1, valsymtri, vecsymtri, baksymtril .

void eigsyml(f1oat a[], int n, int numval, float val[l, float **vec, float em[] )

I float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); void tfmsymtril(f1oat [I, int, float [I, float [I, float [I,

float I 1 ) : void valsymtri (float [I, flbat [I, int, int, int,

float [I, float [I ) ; void vecsymtri (float [I , float [I , k t , int, int,

Copyright 1995 by CRC Press, Inc

Page 217: Numerical Library in C for Scientists and Engineers A

float [I , float ** , float [I ) ; void baksymtril (float [I , int, int, int, float ** ) ; float *b,*bb,*d;

b=allocate-real-vector (1, n) ; bb=allocate-real-vector (1, n) ; d=allocate-real-vector(1,n); tfmsymtril (a,n, d, b, bb, em) ; valsymtri (d, bb,n, l,numval,val,em) ; vecsymtri (d, b, n, 1, numval, val,vec, em) ; baksymtril (a,n, 1, numva1,vec) ; free-real-vector (b, 1) ; free-real-vector (bb, 1) ; free-real-vector (d, 1) ;

Computes all eigenvalues of an nxn symmetric matrix A whose upper triangular part is stored in a two-dimensional array, by means of QR iteration. A is first reduced to similar tridiagonal form by a call of tfmsymtri2, and qrivalsymtri is then used to calculate the eigenvalues.

Function Parameters: int qrivalsym2 (a, n, va1,em)

qrivalsym2: given the number of eigenvalues not calculated; a : float a[l:n,l:n];

entry: the upper triangle of the symmetric matrix must be given in the upper triangular part of a (the elements a[i,j], i s j ) ;

exit: the data for Householder's back transformation (which is not used by this procedure) is delivered in the upper triangular part of a ; the elements a[i,j] for i>j are neither used nor changed;

n: int; entry: the order of the given matrix;

val: float val[l:n]; exit: the eigenvalues of the matrix in some arbitrary order;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance for the eigenvalues; em[4]: the maximum allowed number of iterations; exit: em[l]: the infinity norm of the matrix; em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: the number of iterations performed.

Functions used: tfmsymtri2, qrivalsymtri.

int qrivalsym2 (float **a, int n, float val [I, float em11 ) I

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void tfmsymtri2 (float * * , int, float [ I , float [I, float [I,

float [I) ; int qrivalsymtri (float (1 , float [ I , int, float [I ) ; int i;

Copyright 1995 by CRC Press, Inc

Page 218: Numerical Library in C for Scientists and Engineers A

float *b,*bb;

b=allocate-real-vector(1,n); bb=allocate-real-vector (1, n) ; tfrnsymtri2 (a,n,val,b, bb,ern) ; i=qrivalsymtri (val, bb, n, ern) ; f ree-real-vector (b, 1) ; free-real-vector(bb,l); return i;

}

F. qrisym

Computes all eigenvalues and corresponding eigenvectors of an nxn symmetric matrix A whose upper triangular part is stored in a two-dimensional array, by means of QR iteration. A is first reduced to similar tridiagonal form by a call of tfmsymtri2, the back transformation on the eigenvectors is prepared by a call of tfmprevec, and the eigenvalues and eigenvectors are then calculated by qrisymtri.

Function Parameters: int qrisym (a, n, val, em)

qrisym: given the number of eigenvalues and eigenvectors not calculated; a : float a[l:n, 1 :n];

entry: the upper triangle of the symmetric matrix must be given in the upper triangular part of a (the elements a[i,j], i s j ) ;

exit: the eigenvectors of the symmetric matrix, stored colurnnwise; n: int;

entry: the order of the given matrix; val: float val[l :n];

exit: the eigenvalues of the matrix corresponding to the calculated eigenvectors; em: float em[0:5];

entry: em[O]: the em[2]: the em[4]: the exit: em[]]: the em[3]: the em[5]: the

machine precision; relative tolerance for the QR iteration; maximum allowed number of iterations;

infinity norm of the matrix; maximum absolute value of the codiagonal elements neglected; number of iterations performed.

Functions used: tfmsymtri2, tfmprevec, qrisymtri.

int qrisym(f1oat **a, int n, float val [ I , float em [I ) I

float *allocate-realvector(int, int) ; void free-realvector(f1oat *, int); void tfmsymtri2(float **, int, float [I, float [I, float [ I ,

float [I ) ; void tfmprevec (float ** , int) ; int qrisymtri (float * * , int, float [I , float [I , float [I , float [I ) ; int i; float *b, *bb;

b=allocate-real-vector (1, n) ; bb=allocate-real-vector (1, n) ; tfmsymtri2 (a,n,val,b,bb,ern) ; tfrnprevec (a,n) ;

Copyright 1995 by CRC Press, Inc

Page 219: Numerical Library in C for Scientists and Engineers A

i=qrisymtri (a,n,val,b,bb,em) ; free-real-vector(b,l); free-real-vector (bb, 1) ; return i;

1

G . qrivalsyml

Computes all eigenvalues of an nxn symmetric matrix A whose upper triangular part is stored in a one-dimensional array, by means of QR iteration. A is first reduced to similar tridiagonal form by a call of tfmsymtril, and qrivalsymtri is then used to calculate the eigenvalues.

Function Parameters: int qrivalsym 1 (a, n,val, em)

qrivalsyml: given the number of eigenvalues not calculated; a: float a[l:(n+l)n/2];

entry: the upper triangle of the symmetric matrix must be given in such a way that the (i,j)-th element of the matrix is a[Q-l)j/2+i], I 5 i 5j 5 n;

exit: the data for Householder's back transformation (which is not used by this procedure);

n: int; entry: the order of the given matrix;

val: float val[l:n]; exit: the eigenvalues of the matrix in some arbitrary order;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance for the eigenvalues; em[4]: the maximum allowed number of iterations; exit: em[l]: the infinity norm of the matrix; em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: the number of iterations performed.

Functions used: tfinsymtril, qrivalsymtri.

int qrivalsyml (float a [I , int n, float val [I , float em [I ) I

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); void tfmsymtril(f1oat [I, int, float [I, float [I, float [I,

float [I ) ; int qrivalsymtri(f1oat [I, float [I, int, float [I); int i; float *b, *bb;

b=allocate-real-vector (1, n) ; bb=allocate-real-vector(1,n); tfmsymtril (a. n,val,b,bb,em) ; i=qrivalsymtri(val,bb,n,em) ; f ree-real-vector (b, 1) ; f ree-real-vector (bb, 1) ; return i;

I

Copyright 1995 by CRC Press, Inc

Page 220: Numerical Library in C for Scientists and Engineers A

3.13.3 Symmetric matrices - Auxiliary procedures

A. mergesort

Determines the permutation of p integers in the range 1% i % u, which rearranges the real numbers ai (i=l, ..., u) in nonincreasing order of magnitude, so that I a,,) 1 2 1 a,,,, I , i=l, ..., u-1. For sorting by merging see [AHU74, K731.

Function Parameters: void mergesort (a,p,low, up)

a: float a[low:up]; entry: the vector to be stored into nondecreasing order; exit: the contents of a are left invariant;

p: int p[low:up]; exit: the permutation of indices corresponding to sorting the elements of vecl into

nondecreasing order; low: int;

entry: the lower index of the arrays a and p (value of I above); up: int;

entry: the upper index of the arrays a and p (value of u above).

int *allocate-integer-vector(int, int); void free-integer-vector(int * , int) ; void merge (int, int, int, int [I, float [ I , int [I ) ; int i,lo,step,stap,umlpl,umspl,rest,restv,*hp;

hp=allocate~integer~vector(low,up) ; for (i=low; ic=up; i++) p[il =i; restv=O ; umlpl=up-low+l;

3='; stap=2*step; umspl=up-stap+l; for (lodow; loc=umspl; lo += stap)

merge(10, step, step,p,a,hp) ; rest=up-lo+l; if (rest > restv && restv > 0)

merge (lo, rest-restv, restv,p,a, hp) ; restv=rest; step *= 2;

} while (step c umlpl) ; free-integer-vector(hp,low);

1 void merge (int lo, int Is, int rs, int p [I , float a [I , int hp [ I ) {

/ * this procedure is used internally by MERGESORT * /

int l,r,lout,rout,i,pl,pr;

Copyright 1995 by CRC Press, Inc

Page 221: Numerical Library in C for Scientists and Engineers A

r++ ; rout = (r == lo+ls+rs) ;

) else { hp [il =pl; li+; -

lout = (1 == lo+ls); 1

} while' ( ! (lout / I rout) ) ; if (rout) {

for (i=lo+ls-1; i>=l; i--) p [i+rsl =p [il ;

J for (i=r-1; i>=lo; i--) p[il=hp[il;

1

B, vecperm

Given a sequence of distinct integers p(i), i=l, ..., u, in the range llp(i) l;u and the real numbers ai (i=l, ..., u), constructs the sequence of real numbers a,#, i=l, ..., u.

Function Parameters: void vecperm (perm,low, upp,vector)

perm: int perrn[low:upp]; entry: a given permutation (for example, as produced by mergesort) of the numbers

in the array vector; exit: the contents of a are left invariant;

low: int; entry: the lower index of the arrays perm and vector (value of 1 above);

upp: int; entry: the upper index of the arrays perm and vector (value of u above).

vector: float vector[low: upp]; entry: the real vector to be permuted; exit: the permuted vector elements.

void vecperm(int perm[], int low, int upp, float vector[]) I

int *allocate-integer-vector(int, int); void free-integervector(int *, int) ; int t,j,k,*todo; float a;

todo=allocate~integer~vector~1ow,upp) ; for (t=low; tc=upp; t++) todo[tl=l; for (t=low; tc=upp; t++)

if (todo[tl ) { k=t; a=vector [kl ; j =perm [kl ; while (j ! = t) {

vector [kl =vector [ j I ; todo [kl=0 ; k=j; j =perm [kl ;

1

Copyright 1995 by CRC Press, Inc

Page 222: Numerical Library in C for Scientists and Engineers A

C. rowperm

Given a sequence of distinct integers PO), j=l, ..., u, in the range 1 5pC;) 5 u and the elements M,j, j=l, ..., u, belonging to the i-th row of a real matrix, constructs the corresponding row elements Mi,po,, j=l, ..., u.

Function Parameters: void rowperm (perm, low, upp, ,i,mat)

perm: int perm[low:upp]; entry: a given permutation (for example, as produced by mergesort) of the numbers

in the array vector; low: int;

entry: the lower index of the arrays perm; upp: int;

entry: the upper index of the arrays perm; i: int;

entry: the row index of the matrix elements; mat: float mat[i:i, low:upp];

entry: mat[i,low:upp] should contain the elements to be permuted; exit: mat[i,low:upp] contains the row of permuted elements.

yoid rowperm(int perm[] , int low, int upp, int i, float **mat)

int *allocate-integer-vector(int, int) ; void free-integer-vector(int *, int) ; int t,j,k,*todo; float a;

todo=allocate~integer~vector(low,upp); for (t=low; ts=upp; t++) todo[tl=l; for (t=low;

if ( todo :;YYPf' ; t++)

k=t; a=mat [il [kl ; j =perm [kl ; while (j ! = t) (

mat [il [kl =mat [il [j I ; todo [kl=0 ;

mat [il [kl =a; todo [kl =O;

J f reelinteger-vector (todo, low) ;

1

3.13.4 Symmetric matrices - Orthogonalization

orthog

Given a system of linearly independent columns x, j=l, ..., u, of an n-rowed matrix X, determines an orthonormal system of columns ((xi:xj) equals 0 when i f j and equals 1 with i=j) of a corresponding matrix X' by the modified Gram-Schmidt orthogonalization [Wi65].

Copyright 1995 by CRC Press, Inc

Page 223: Numerical Library in C for Scientists and Engineers A

Function Parameters: void orthog (n, lc, uc,x)

n: int; entry: the order of the matrix x;

Ic: int; entry: the lower column index of the matrix x;

uc: int; entry: the upper column index of the matrix x;

x: float x[l:n, lc:uc]; entry: the matrix columns to be orthogonalized; exit: the orthogonalized matrix columns.

Functions used: tamrnat, elmcol.

void orthog(int n, int lc, int uc, float **x) I

int *allocate-integer-vector(int, int) ; void free integer-vector(int *, int); float tamKat(int, int, int, int, float ** , float * * ) ; void elmcol(int, int, int, int, float **, float ** , float); int i,j,k; float norm;

for (j=lc; j<=uc; j++) { norm=sqrt (tammat (1,n, j, j,x,x)) ; for (i=l; ic=n; i++) x[il [jl /=norm; for (k=j+l; k<=uc; k++) elmcol ( l , n , k , j,x,x, -tammat (l,n,k, j,x,x)) ;

I 1

3.13.5 Symmetric matrices - Iterative improvement

symeigimp

Given single precision estimates A,' of the eigenvalues A, and single precision estimates u,' of the eigenvectors u, (j=l, ..., n) of an nxn real symmetric matrix A, derives (a) ranges of the form [Aju-6,,h,"+qj] within which the A, lie, A," being an improved double precision estimate of A, and (b) improved single precision estimates u," of the corresponding eigenvector uj (j=l ,..., n). For further details see [GrK69].

Function Parameters: void symeigimp (n,a,vec,val, lbound, uboundaux)

n: int; entry: the order of the matrix a ;

a: float a[l :n, 1 :n]; entry: contains a real symmetric matrix whose eigensystem has to be

improved;

Copyright 1995 by CRC Press, Inc

Page 224: Numerical Library in C for Scientists and Engineers A

vec: float vec[l :n, l:n]; entry: contains a matrix whose columns are a system of approximate

eigenvectors of matrix a; initial approximations; exit: improved approximations;

val: float val[l :n]; entry: initial approximations of the eigenvalues of a; exit: improved eigenvalues of a;

Ibound, ubound: float Ibound[l:n], ubound[l:n]; exit: the lower and upper error bounds respectively for the eigenvalue

approximations in val such that the i-th exact eigenvalue lies between val[i]-lbound[i] and val[i]+ubound[i] (values of 6j and qj, j=l, ..., n, respectively, in the above);

a m : float aux[0:5]; entry: aux[O]: the relative precision of the elements of a; aux[2]: the relative tolerance for the residual matrix; the iteration ends when

the maximum absolute value of the residual elements is smaller than aux[2]*aux[l];

aux[4]: the maximum number of iterations allowed; exit: aux[l]: infinity norm of the matrix a; aux[3]: maximum absolute element of the residual matrix; aux[5]: number of iterations.

Functions used: vecvec, matmat, tammat, mergesort, vecperm, rowperm, orthog, qrisym, infnrrnmat .

void symeigimp(int n, float **a, float **vec, float val[l, float lbound [I , float ubound [ I , float aux [ I )

f int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int * , int); void free-real-vector(f1oat * , int); void free-real-matrix (float ** , int, int, int) ; void orthog(int, int, int, float * * ) ; void mergesort (float [I, int [I, int, int) ; void vecperm (int 11 , int, int, float [I ) ; void rowperm (int [I , int, int, int, float * * ) ; int qrisym(f1oat ** , int, float [I, float [I ) ; float vecvec (int, int, int, float [I , float [I ) ; float rnatmat(int, int, int, int, float * * , float * * ) ; float tammat(int, int, int, int, float **, float * * ) ; float infnrmmat(int, int, int, int, int *, float * * ) ; int k,i,j,iO,il,i01,iter,maxitpl,stop,nl,iOml,ilpl,*perm; float s,max, tol,mateps, relerra, reltolr,norma,epsZ, dl, dr,ml,

**r, **p, * * y , **pp, *rq, *eps, *z, *val3,*va14,*eta,em[61 ; double dternp;

Copyright 1995 by CRC Press, Inc

Page 225: Numerical Library in C for Scientists and Engineers A

p=allocate real matrix (1, n, 1, n) ; y=allocate~real~matrix (1, n, 1,n) ;

for (iter=l; iter<=maxitpl; iter++) ( if (iter == 1)

stop=o; else

stop=1; max=O. 0 ; for (j=l; jc=n; j++)

for (i=l; ic=n; i++) { dtemp = - (double) (vec[il [jl )*(double) (val [jl ) ; for <k=l; k<=n; k++)

dtemp += (double) (a [il [kl ) * (double) (vec [kl [ jl ) ; r [il [j I =dtemp; if (fabs(r[il [jl) > max) max=fabs(r[il [jl);

if (kax > tol) stop=o; if ( ( !stop) && (iter < maxitpl) ) {

for (i=l; i<=n; i++) { dtemp= (double) (val [il ) ; for (k=l; kc=n; k++)

dtemp += (double) (vec [kl [il ) * (double) (r [kl [il ) ; rq [il =dtemp;

kor (j=1; jc=n; j++) ( for (i=l; ic=n; i++)

eta [il =r [il [jl - (rq[jl -Val [jl *vec [il [jl ; z[j] =sqrt(vecvec(l,n,O,eta,eta)) ;

I I mergesort (rq,perm, 1, n) ; vecperm (perm, 1, n, rq) ; for (i=l; ic=n; i++) {

eps [il =z [perm [ill ; va13 [il =val [perm [ill ; rowperm(perm, 1,n, i,vec) ; rowperm(perm, 1,n, i, r) ;

I

for (i=l; i<=n; i++) for (j=i; j<=n; j++)

p[i] [j]=p[jl [i]=tammat(l,n,i,j,vec,r) ;

j =il=iO ; j++; while ((j > n) ? 0 :

(rq[jl -rq[j-11 c= sqrt ((eps [jl+eps [j il= j ; j ++ ;

if (stop ( [ (iter == maxitpl)) (

z ; j =iOl=i; j++; while ((j>il) ? 0 : rq[jl-rq[j-11 <= eps[jl+eps[j-11) {

iOl=j ; j ++ ;

J if (i == iO1) {

if (i < n) { if (i == I)

dl=dr=rq[i+ll -rq[il -eps [i+ll ; else (

dl=rq[il -rq[i-11 -eps [i-11 ; dr=rq [i+l] -rq [il -eps [i+l] ;

1

Copyright 1995 by CRC Press, Inc

Page 226: Numerical Library in C for Scientists and Engineers A

] else dl=dr=rq[il -rq[i-11 -eps [i-11 ;

eps2=eps [il *eps [if ; lbound [il =eps2/dr+mateps ; ubound [il =eps2/dl+mateps;

) else for (k=i; kc=iOl; k++)

lbound [kl =ubound [kl =eps [kl +mateps; iOl++; i=iOl;

) while (i <= ill; / * bounds * / ) else {

if (i0 == il) { for (k=l; kc=n; k++)

if (k == iO) y [kl [iO] =1.0;

else r [kl [iOl =p [kl [i01 ;

val [iO] =rq [iO] ; ] else {

nl=il-iO+l; em [O] =em [2] =FLT-EPSILON; em [41 =lO*nl; val4=allocate-real-vector (1, nl) ; pp=allocate-real-matrix(l,nl,l,nl); ml=0.0 ; for (k=iO; k<=il; k++) ml += val3 [kl ; ml /= nl; for (i=l; ic=nl; i++)

for (j=l; jc=nl; j++) ( pp [il [jl =p [i+iO-11 [j+iO-11 ; if (i == j ) pp[i] [jl += va13[j+iO-11-ml;

for (i=iO; i<=il; i++) { val3 [il =ml; val [il =rq [il ;

I

for

I for

I for

I qrisym (pp, nl,va14, em) ; mergesort (val4 ,perm, 1,nl) ; for (i=l; ic=nl; i++)

for (j=l; jc=nl; j++) p [i+iO-11 [j+iO-11 =pp [il [perm[jl I ;

iOml=iO-1; ilpl=il+l; for (j=iO; jc=il; j++) {

(i=l; ic=iOml; i++) { s=o.o; for (k=iO; kc=il; k++) s += p [il [kl *p [kl [jl ; r[il [jl=s;

(i=ilpl; ic=n; i++) ( s=o. 0; for (k=iO; kc=il; k++) s += p [il [kl *p [kl [jl ; r[il [jl=s;

I free-real-vector(va14,l); free-real-matrix(pp, l,nl, 1) ;

) / * innerblock */ ) , /* not stop * / 10=11+1;

] while (iO c= n); / * while iO loop * / if ((!stop) && (iter < maxitpl)) {

for (j=l; jc=n; j++) for (i=l; i<=n; i++)

if (val3 [il ! = val3 [jl ) y[il [jl =r [il [jl/ (val3 [jl -val3 [il ) ;

for (i=l; i<=n; i++) { for (j=l; j<=n; j++) z[jl=matmat(l,n,i, j,vec,y) ; for (j=l; j<=n; j++) vec[il [jl=z[jl ;

I orthog(n, l,n,vec) ;

) else {

Copyright 1995 by CRC Press, Inc

Page 227: Numerical Library in C for Scientists and Engineers A

aux [51 =iter-1; break;

1 } I * for iter loop * / aux [ll =norma; aux [31 =max;

free-integer-vector(perm,l); f ree-real-vector (rq, 1) ; f ree-real-vector (eps, 1) ; free-real-vector (z,l) ; free-real-vector(val3,l) ; free-real-vector (eta, 1) ; free-real-matrix (r, 1, n, 1) ; free-real-matrix ( p , 1, n, 1) ; free-real-matrix(y, l,n, 1) ;

1

3.13.6 Asymmetric matrices in Hessenberg form

A. reavalqri

Determines the eigenvalues hj Q=l, ..., n) (all assumed to be real) of an nxn real upper Hessenberg matrix A (Aij=O for i>j+l) by single QR iteration. The method used is the single QR iteration of Francis [Dek&Ho68, Fr61, Wi651. The eigenvalues of a real upper- Hessenberg matrix are calculated provided that the matrix has real eigenvalues only.

Function Parameters: int reavalqri (a, n, em, val)

reavalqri: given the value 0 provided that the process is completed within em[4] iterations; otherwise reavalqri is given the value k, of the number of eigenvalues not calculated;

a: float a[l:n,l:n]; entry: the elements of the real upper Hessenberg matrix must be given in the upper

triangle and the first subdiagonal of array a ; exit: the Hessenberg part of array a is altered;

n: int; entry: the order of the given matrix;

em: float em[0:5]; entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[2]: the relative tolerance used for the QR iteration (em[2] > em[OJ); if the

absolute value of some subdiagonal element is smaller than em[l]*em[2] then this element is neglected and the matrix is partitioned;

em[4]: the maximum allowed number of iterations (for example, em[4]=10*n); exit: em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of val are approximate eigenvalues of the given matrix, where k is delivered in reavalqri;

val: float val[l:n];

Copyright 1995 by CRC Press, Inc

Page 228: Numerical Library in C for Scientists and Engineers A

exit: the eigenvalues of the given matrix are delivered in val.

Functions used: rotcol, rotrow.

#include crnath.h>

int reavalqri(f1oat **a, int n, float em[], float val[l) I

void rotcol (int, int, int, int, float **, float, float) ; void rotrow(int, int, int, int, float ** , float, float) ; int nl, i, il, q,max, count; float det,w,shift,kappa,nu,mu,r,tol,delta,macht~l,~;

machtol=em [O] *em [ll ; tol=em [ll *em [21 ; max=em [ 4 I ; count=O ;

::OiO; nl=n- 1 ;

3 q=1; . i--.

) while ( (i >= 1) ? (fabs(a[i+ll [i] ) > tol) : 0) ; if (q > 1)

if (fabs (a [ql [q-11 ) > r) r=fabs (a [ql [q-11 ) ; if (q == n) {

val [n] =a [nl 11-11 ; n=nl ;

) else { delta=a [n] [n] -a [nll [nll ; det=a [nl [nll *a [nll [nl ; if (fabs (delta) c machtol)

s=sqrt (det) ; else {

w=2.0/delta; s=w*w*det+l.O; s = (S c= 0.0) ? -delta*0.5 : w*det/(sqrt (s)+l.O) ;

1 if (q == nl) {

val [nl =a [nl [nl +s; val [nl] =a [nll [nll -s; n - = 2;

) else { count++; if (count > maxl break; shift=a [nl [nl +s; if (fabs(de1ta) c tol) (

w=a [nll [nll -s; if (fabs (w) c fabs (shift) ) shift=w;

1 a [q] [q] -= shift; for (i=q; ic=n-1; i++) {

il=i+l; a[il] [ill - = shift; kappa=sqrt (a [il [il *a [il [il +a [ill [il *a [ill [il ) ; if (i > q) {

a [il [i-11 =kappa*nu; w=kappa*mu;

) else w=kappa;

mu=a [il [il /kappa; nu=a [ill [il /kappa; a [il [il =w; rotrow(il,n,i,il,a,mu,nu) ; rotcol (q,i, i,il,a,mu,nu) ; a [i] [i] += shift;

1 a [n] [n-11 =a [nl [nl *nu; a [n] [nl =a [n] [nl *mu+shift ;

Copyright 1995 by CRC Press, Inc

Page 229: Numerical Library in C for Scientists and Engineers A

1 } while (n z 0 ) ; em[3l =r; em [51 =count; return n;

1

B. reaveches

Determines the eigenvector corresponding to a single real eigenvalue h of an nxn real Hessenberg matrix A (Aij=O for i>j+l) by inverse iteration [DekHo68, Vr66, Wi651. Starting with ~~~)=(1,1,. . . ,1)~, vectors J,@' and x" are produced by use of the scheme

(~-Xlly')=x xF"'=fl)/ll y m 11 (k=O, I,...). The process is terminated if either (a) 11 (A-M',~~' 11 Es 11 A 11 *tol, where to1 is a tolerance prescribed by the user, or (b) k=kmm+l, where kmax is an integer prescribed by the user.

Function Parameters: void reaveches (a,n, lambda,em,v)

a: float a[l:n,l:n]; entry: the elements of the real upper Hessenberg matrix must be given in the upper

triangle and the first subdiagonal of array a; exit: the Hessenberg part of array a is altered;

n: int; entry: the order of the given matrix;

lambda: float; the given real eigenvalue of the upper Hessenberg matrix (value of h above);

em: float em[0:9]; entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[6]: the tolerance used for eigenvector (value of to1 above, em[6] > em[OJ); the

inverse iteration ends if the Euclidean norm of the residue vector is smaller than em[l]*em[6];

em[8]: the maximum allowed number of iterations (value of kmax above, for example, em[s/=5);

exit: em[7]: the Euclidean norm of the residue vector of the calculated eignenvector; em[9]: the number of inverse iterations performed; if em[7] remains larger than

em[l]*em[6] during em[8] iterations then the value em[8]+1 is delivered; v: float v[l:n];

exit: the calculated eigenvector is delivered in v.

Functions used: vecvec, matvec.

void reaveches(f1oat **a, int n, float lambda, float em[], float v[ll {

int *allocate-integer-vector(int, int);

Copyright 1995 by CRC Press, Inc

Page 230: Numerical Library in C for Scientists and Engineers A

void free integer-vector(int *, int); float vecvec (int, int, int, float [I , float [I ) ; float matvec(int, int, int, float **, float [I 1 ; int i,il,j,count,max,*p; float m,r,norm,machtol,tol;

p=allocate-integer-vector(l,n); norm=em 111 ; machtol=em [Ol *norm; tol=em [61 *norm; max=em [8] ; all] [I] -= lambda; for (i=l; ic=n-1; i++) {

il=i+l; r=a [il [il ; m=a [ill [il ; if (fabs (m) c machtol) m=machtol; p[i] = (fabs(m) <= fabs(r)); if (p [il) {

a[il] [il = m /= r; for (j=il; j<=n; j++)

a[il] [j]=((j > il) ? a[il] [j] : a[ill [jl -lambda) -m*a[il [jl ; 1 else I

- - - - . . for (j=il; jc=n; j++) {

r = (j > il) ? a[ill ljl : a[ill [jl-lambda; a [ill [jl =a [il [jl -m*r; a[il [jl=r;

1 1

1 if (f abs (a [nl In] ) c machtol) a [n] In] aachtol; for (j=l; jc=n; j++) v[jl=l.O;

:ztz0; count++; if (count > max) break; for (i=l; ic=n-1; i++) {

il=i+l; if (p [il )

v [ill -= a [ill [il *v [il ; else {

r=v[ill ; v [ill =v [i] -a [ill [il *r; v [i] =r;

1 1

for (i=n; i>=l; i--) v[i] = (vli.1 -matvec(i+l,n, i,a,v) ) /a[il [il ;

r=l. O/sqrt (vecvec (l,n, O,v,v) ) ; for (j=l; jc=n; j++) v[jl *= r;

} while (r > toll ; em [7l =r; em [91 =count; free-integer-vector(p,l);

1

C. reaqri

Computes all eigenvalues h, (assumed to be real) and corresponding eigenvectors uj (j=l, ..., n) of the nxn real upper Hessenberg matrix A (A,j=O for i>j+l) by single QR iteration. The eigenvectors are calculated by a direct method [see DekHo681, in contrast with reaveches which uses inverse iteration. If the Hessenberg matrix is not too ill- conditioned with respect to its eigenvalue problem then this method yields numerically independent eigenvectors and is competitive with inverse iteration as to accuracy and computation time.

Copyright 1995 by CRC Press, Inc

Page 231: Numerical Library in C for Scientists and Engineers A

Function Parameters: int reaqri (a, n, em, val, vec)

reaqri: given the value 0 provided that the process is completed within em[4] iterations; otherwise reaqri is given the value k, of the number of eigenvalues and eigenvectors not calculated;

a: float a[l:n,l:n]; entry: the elements of the real upper Hessenberg matrix must be given in the upper

triangle and the first subdiagonal of array a; exit: the Hessenberg part of array a is altered;

n: int; entry: the order of the given matrix;

em: float em[0:5]; entry: em[O]: em[l]: em[2]:

em[4]: exit: em[3]: em[5]:

the machine precision; a norm of the given matrix; the relative tolerance used for the QR iteration (em[2] > em[OJ); if the absolute value of some subdiagonal element is smaller than em[l]*em[2] then this element is neglected and the matrix is partitioned; the maximum allowed number of iterations (for example, em[4]=10*n);

the maximum absolute value of the subdiagonal elements neglected; the number of QR iterations performed; if the iteration process is not completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of val and the last n-k columns of vec are approximated eigenvalues and eigenvectors of the given matrix, where k is delivered in reaqri;

val: float val[l:n]; exit: the eigenvalues of the given matrix are delivered in val;

vec: float vec[l:n, l:n]; exit: the calculated eigenvectors corresponding to the eigenvalues in val[l:n] are

delivered in the columns of vec.

Functions used: matvec, rotcol, rotrow.

int reaqri(f1oat **a, int n, float em[], float val[l, float **vet) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float matvec(int, int, int, float ** , float [I ) ; void rotcol(int, int, int, int, float ** , float, float); void rotrow(int, int, int, int, float **, float, float) ; int ml, i, il, m, j , q, max, count; float w, shift, kappa,nu,mu, r, tol, s,machtol, elmax, t, delta, det, *t£;

tf=allocate-real-vector(1,n); machtol=em [Ol *em [ll ; tol=em [ll *em 121 ; max=em 141 ; count=O ; elmax=0.0; m a ; for (i=l; ic=n; i++) {

vec [i] [il=l. 0; for (j=i+l; jc=n; j++) vec[il [jl=vec[jl [il=0.0;

Copyright 1995 by CRC Press, Inc

Page 232: Numerical Library in C for Scientists and Engineers A

ml=m-1; i=m; do { .

q=1; i--;

) while ( (i >= 1) ? (fabs (a [i+ll [il ) > tol) : 0) ; if (q > 1)

if (fabs (a [q] [q-11 ) > elmax) elmax=fabs (a [ql [q-11 ) ; if (q == m) {

val [ml =a [ml Em1 ; m=ml ;

] else { delta=a [ml [ml -a [mil [mll ; det=a [ml [mll *a [mll [ml ; if (fabs (delta) s machtol)

s=sqrt (det) ; else (

w=2.0/delta; s=w*w*det+l.O; s = (S <= 0.0) ? -delta*0.5 : w*det/(sqrt(s)+l.O);

I if (q == ml) {

val [ml = a [ml [ml += s; val [q] = a [ql [ql -= s; t = (fabs (s) < machtol) ? (s+delta) /a [ml [q] : a[q] [m] 1s; r=sqrt (t*t+l.O) ; nu=l. O/r; mu = -t*nu; a[ql [ml -= ah1 [ql ; rotrow (q+Z,n,q,m,a,mu,nu) ; rotcol(l,q-l,q,m,a,mu,nu); rotcol (l,n,q,m,vec,mu,nu) ; m -= 2;

] else ( count++ ; if (count > max) {

em[3] =elmax; em [5] =count; free-real-vector (tf, 1) ; return m;

A[q] [q] -= shift; for (i=q; i<=ml; i++) {

il=i+l; a[il] [ill -= shift; kappazsqrt (a [i] [i] *a [i] [i] +a [ill [il *a [ill [il ) ; if (i > q) {

a [i] [i-11 =kappa*nu; w=kappa*mu;

] else wzkappa;

mu=a [i] [il /kappa; nu=a [ill [il /kappa; a [il [il =w; rotrow(il,n,i,il,a,mu,nu) ; rotcol(l,i,i,il,a,mu,nu) ; a [i] [i] += shift; rotcol(l,n,i,il,vec,mu,nu) ;

1 a [ml [mll =a [ml [ml *nu; a [m] [m] =a [ml [ml *mu+shift ;

. I I

) while (m > 0) ; for (j=n; j>=2; j--) {

tf[jl=l.O; t=a[jl [jl ;

Copyright 1995 by CRC Press, Inc

Page 233: Numerical Library in C for Scientists and Engineers A

for (i=j-1; i>=l; i--) { delta=t-a [i] [il ; tf [il =matvec(i+l, j , i,a, tf) /

( (fabs (delta) c machtol) ? machtol : delta) ; 1 ;or (i=l; i<=n; i++) vec [il [jl =matvec(l, j ,i,vec, t£) ;

1 em [3] =elmax; em [51 =count; free-real-vector (tf, 1) ; return m;

1

D. comvalqri

Determines the real and complex eigenvalues hj Cj=l, ..., n) of an nxn real upper Hessenberg matrix A (Ajj=O for i>j+l) by the double QR iteration of Francis [DekHo68, Fr61, Wi651.

Function Parameters: int comvalqri (a, n, em,re, im)

comvalqri: given the value 0 provided that the process is completed within em[4] iterations; otherwise comvalqri is given the value k, of the number of eigenvalues not calculated;

float a[l :n, 1 :n]; entry: the elements of the real upper Hessenberg matrix must be given in the upper

triangle and the first subdiagonal of array a; exit: the Hessenberg part of array a is altered; int; entry: the order of the given matrix;

float em[0:5]; entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[2]: the relative tolerance used for the QR iteration (em[2] > em[OA; if the

absolute value of some subdiagonal element is smaller than em[l]*em[2] then this element is neglected and the matrix is partitioned;

em[4]: the maximum allowed number of iterations (for example, em[4]=10*n); exit: em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of re and im are approximate eigenvalues of the given matrix, where k is delivered in comvalqri;

re,im: float re[l :n], im[l:n]; exit: the real and imaginary parts of the calculated eigenvalues of the given matrix

are delivered in re, im[l:n], the members of each nonreal complex conjugate pair being consecutive.

#include <math.h>

jnt comvalqri(f1oat **a, int n, float em[], float re [I, float im[l ) t

int i,j,p,q,max,count,nl,pltp2,imin1,il,i2,i3,b; float disc,sigma,rho,gl,g2,g3,psil,psi2,aa,e,k,s,norm,machtol2,

Copyright 1995 by CRC Press, Inc

Page 234: Numerical Library in C for Scientists and Engineers A

tol, w;

norm=em Ell ; w=em [O] *norm; machtol2=w*w; tol=em [21 *norm; max=em l 4 I ; count=O; w=o .o ; do { ,

izni q=1; . 1--.

} while ( (i >= 1) ? (fabs(a[i+ll [il ) > tol) : 0) ; if (p > 1)

~f (fabs (a [ql lq-11 ) > w) w=fabs (a [q-11 ) ; if (q >= n-1) {

nl=n-1; if (q == n) {

re [nl =a [nl In1 ; im[nl=0.0;

) else { sigma=a tnl [nl -a [nll [nll ; rho = -a [nl [nll *a [nll [nl ; disc=sigma*sigma-4.0*rho; if (disc > 0.0) {

disc=sqrt (disc) ; s = -2 .O*rho/ (sigma+( (sigma >= 0.0) ? disc : -disc)) ; re [nl =a [nl [nl +s ; re [nl] =a [nll [nl] -s; im [n] =im [nl] =O. 0;

) else { re [n] =re [nl] = (a [nll [nll +a [nl [nl ) /2.0 ; im[nll =sqrt (-disc) /2 .o; im [nl = -im[nll ;

1

el'se count++; if (count > max) break; nl=n- 1 ; sigma=a [n] [n] +a [nl] [nl] +sqrt (fabs (a [nl] [n-21 *a [nl [nll ) *em [oI ) ; rho=a [n] [nl *a [nll [nll -a [nl [nll *a [nll [nl ; i=n-1; do I

pl=il=i; i--;

} while ( (i-1 >= q) ? (fabs (a Iil [i-11 *a [ill [il * (fabs (a [i] [i] +a [ill [ill -sigma) +fabs (a [i+21 [ill ) ) ) > fabs (a [il [il ( (a [il [il -sigma) +

a [i] [ill *a [ill [i] +rho) ) *toll : 0) ; p=p1-1; p2LP+2 ; for (i=p; i<=n-1; i++) {

iminl=i-1; il=i+l; i2=i+2 ; if (i == p) {

gl=a [pl Ipl * (a lpl [pl -sigma) +a [pl [pll *a [pll tpl +rho; g2=a [pll [pl * (a [pl [PI +a [pll tpll -sigma) ; if (pl <= nl) {

g3=a [pll [pl *a [p21 [pll ; aIp21 [pl=O.O;

) else g3=0.0;

} else { gl=a [il [iminll ; g2=a [ill [iminll ; g3 = (i2 <= n) ? a[i2l [iminll : 0.0;

Copyright 1995 by CRC Press, Inc

Page 235: Numerical Library in C for Scientists and Engineers A

-sqrt(gl*gl+g2*g2+g3*g3) ; b = ( fabs (k) > machtol2) ; aa = (b ? gl/k+l.O : 2 .0 ) ; p s i 1 = ( b ? g2/ (g l+k) : 0.0) ; psi2 = ( b ? g3/ (g l+k) : 0.0) ; i f (i != q)

a [ i l [iminll = (i == p) ? - a f i l [iminll : - k ; f o r ( j = i ; jc=n; j + + ) , {

e=aa* (a [ i l [ j l +ps i l*a [ i l l [ j l + ( ( i 2 c= n) ? psi2*a[i2l [ j l : 0 . 0 ) ) ;

a [ i l [j! -= e ; a [ i l l [ I ] -= ps i l*e ; i f ( i 2 c= n) a [ i 2 ] [ j l - = psi2*e;

1 ;or ( j = q ; jc= ( ( i 2 c= n) ? i 2 : n) ; j++) {

e=aa* ( a [ j l [ i l +ps i l*a [ j l [ i l l + ( ( i 2 c= n) ? psi2*a[ j l [i21 : 0 . 0 ) ) ;

a [ j l [ i l -= e ; a [ j l [ i l l - = ps i l*e ; i f ( i 2 c= n) a [ j l [i21 - = psi2*e;

I i f ( i 2 c= n l ) {

i 3= i+3 ; e=aa*psi2*a [i31 [i21 ; a[ i31 [ i l = -e ; a [ i 3 ] [ i l l = -ps i l*e ; a[ i31 [i21 - = psi2*e;

I

1 1

} while (n > 0) ; em[31 =w; em [51 =count; r e t u r n n;

1

E. comveches

Determines the eigenvector corresponding to a single complex eigenvalue h+pi of an nxn real upper Hessenberg matrix A (Aij=O for i>j+l) by inverse iteration [DekHo68, Vr66, Wi651. Starting with x(O)=(l , I vectors f ) and xm are produced by use of the scheme

(A-Xr)f)=xF), X @ + ' ) = ~ F ' / I ~ ~ ~ [ I E (k=O,I, ...). The process is terminated if either (a) 11 (A-Xr)xF) 11 ,I 11 A 11 *to& where to1 is a tolerance prescribed by the user, or (b) k=kmax+l, where kmax is an integer prescribed by the user.

Function Parameters: void comveches (a,n, lambda, mu,em, u,v)

a: float a[l:n,l:n]; entry: the elements of the real upper Hessenberg matrix must be given in the

upper triangle and the first subdiagonal of array a; exit: the Hessenberg part of array a is altered;

n: int; entry: the order of the given matrix;

lambda, mu: float; real and imaginary part of the given eigenvalue (values of h and 1.1 above);

em : float em[O: 91; entry: em[O]: the machine precision; em[l]: a norm of the given matrix; em[6]: the tolerance used for eigenvector (value of to1 above, em[6] >

Copyright 1995 by CRC Press, Inc

Page 236: Numerical Library in C for Scientists and Engineers A

em[OJ); the inverse iteration ends if the Euclidean norm of the residue vector is smaller than em[l]*em[6];

em[8]: the maximum allowed number of iterations (value of kmax above, for example, em[8]=5);

exit: em[7]: the Euclidean norm of the residue vector of the calculated eigenvector; em[9]: the number of inverse iterations performed; if em[7] remains larger

than em[l]*em[6] during em[8] iterations then the value em[8]+1 is delivered;

float u[l :n], v[l :n]; exit: the real and imaginary parts of the calculated eigenvector are

delivered in the arrays u and v.

Functions used: vecvec, matvec, tarnvec.

void comveches(float **a, int n, float lambda, float mu, float em [I , float u [I , float v [I )

1 float *allocate-realvector(int, int); int *allocate-integer-vector(int, int); void free-integer-vector(int * , int) ; void free-real-vector(f1oat * , int); float vecvec(int, int, int, float [I, float [ I ) ; float matvec(int, int, int, float ** , float [I ) ; float tamvec (int, int, int, float * * , float [I ) ; int i, il, j ,count, max, *p; float aa,bb,d,m,r,s,w,x,y,norm,machtol,tol,*g,*f;

p=allocate-integer-vector(1,n); g=allocate-real-vector (1, n) ; f=allocate-real-vector(1,n); norm=em [ll ; machtol=em [Ol *norm; tol=em [6] *norm; rnax=em [El ; for (i=2; i<=n; i++) {

f [i-11 =a [il [i-11 ; a [il [I] =O. 0;

1 aa=a [I] [I1 -lambda; bb = -mu; for (i=l; i<=n-1; i++) {

il=i+l: m=f [il ; if (fabs (m) < machtol) m=machtol; a [il [il =m; d=aa*aa+bb*bb; p [i] = (fabs (m) < sqrt (d)) ; if (p[il ) {

f [il =r=m*aa/d; g [i] = s = -m*bb/d; w=a [ill [il ; x=a [il [ill ; a [ill [il =y=x*s+w*r; a [i] [ill =x=x*r-w*s; aa=a [ill [ill -lambda-x; bb = - (mu+y) ; for (j=i+2; j<=n; j + + ) {

w=a [jl [il ; x=a[il [jl ; a [j] [i] =y=x*s+w*r; a [il [j] =x=x*r-w*s; a[jl [ill = -y; a[ill [jl - = x;

Copyright 1995 by CRC Press, Inc

Page 237: Numerical Library in C for Scientists and Engineers A

1 } else {

f [il =r=aa/m; g [il =s=bb/m; w=a [ill [ill -lambda; aa=a [il [ill -r*w-s*mu; a [il [ill =w; bb=a [ill [il -s*w+r*mu; a [ill [i] = -mu; for (j=i+2; j<=n; j++) (

w=a [ill [ j l ; a[ill [jl =a[il [jl -r*w; a[il [jl=w; a[jl [ill=a[jl [il -s*w; a[j] [il =O.O;

1 1 p [nI=l; d=aa*aa+bb*bb; if (d < rnachtol*machtol) (

aa=machtol; bb=O.O; d=machtol*machtol;

1 a [nl [nl =d; f [nl =aa; g[nl = -bb( for (i=l; 1<=n; i++) (

u[il=l.O; v[il=O.O;

1 2 Y t = O ;

if (count > max) break; for (i=l; i<=n; i++)

if (p [il) { w=v [il ; v [i] =g [il *u [il +f [il *w; u [i] =f [il *u [i] -g [i] *w; if ( i < n ) (

v[i+ll - = v[il ; u [i+l] -= u [il ;

1 } else (

aa=u [i+ll ; bb=v [i+ll ; u [i+ll =u [i] - (f [il *aa-g [il *bb) ; u [il =aa; v [i+l] =v [il - (g [il *aa+f[il *bb) ; v [il =bb;

1 for (i=n; i>=l; i--) {

il=i+l; u[i] =(u[il -matvec(il,n,i,a,u) +

(p [i] ? tamvec (il,n,i,a,v) : alill [il *v[ill ) )/a [il [il ; v[i] =(v[ll -matvec(il,n,i,a,v) -

(p [i] ? tamvec (il,n,i,a,u) : a [ill [il *u[ill ) )/a [il [il ; 1 &l.O/sqrt (vecvec (l,n, O,u,u) +vecvec(l,n, O,v,v) ) ; for (j=l; jc=n; j++) {

u[jl *= w; v[jl *= w;

1 count++ ;

} while (w > tol); em [71 =w; em [91 =count; free-integer-vector(p,l); free-real-vector (g, 1) ; free-real-vector (f, 1) ;

1

Copyright 1995 by CRC Press, Inc

Page 238: Numerical Library in C for Scientists and Engineers A

3.13.7 Real asymmetric full matrices

A. reaeigval

Determines the eigenvalues A, (j=l, ..., n) (all assumed to be real) of a real nxn matrix A. A is equilibrated to the form A'=PDAD'P" (by means of a call of eqilbr) and transformed to similar real upper Hessenberg form H (by means of a call of tfmreahes). The eigenvalues of H are then computed by QR iteration (by means of a call of reavalqri). The procedure reaeigval should be used only if all eigenvalues are real. For further details see [DekHo68, Fr6 1, Wi651.

Function Parameters: int reaeigval (a,n, em,vaO

reaeigval: given the value 0 provided that the process is completed within em[4] iterations; otherwise reaeigval is given the value k, of the number of eigenvalues not calculated;

a : float a[l:n,l:n]; entry: the matrix whose eigenvalues are to be calculated; exit: the array elements are altered;

n: int; entry: the order of the given matrix;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance used for the QR iteration (em[2] > em[OJ); em[4]: the maximum allowed number of iterations (for example, em[4]=10n); exit: em[l]: the infinity norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of val are approximate eigenvalues of the given matrix, where k is delivered in reaeigval;

val: float val[l:n]; exit: the eigenvalues of the given matrix are delivered in monotonically

nonincreasing order.

Functions used: eqilbr, tfmreahes, reavalqri.

int reaeigval (float **a, int n, float em [ I , float val [I ) I

int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int) ; void free-integer-vector(int * , int); void free-real-vector(f1oat * , int); void tfmreahes(f1oat **, int, float [ I , int [ I ) ; void eqilbr (float ** , int, float [ I , float [ I , int [ I ) ; int reavalqri(f1oat * * , int, float [ I , float [ I ) ; int i,j,k,*ind,*indO; float r,*d;

Copyright 1995 by CRC Press, Inc

Page 239: Numerical Library in C for Scientists and Engineers A

ind=allocate-integer-vector(1,n); indo=allocate-integer-vector(1,n) ; d=allocate-real-vector(1,n) ; eqilbr (a,n, em, d, indo) ; tfmreahes (a, n, em, ind) ; k=reavalqri (a,n,em,val) ; for (i=k+l; ic=n; i++)

for (j=i+l; jc=n; j++) if (val [j I > val [il ) {

r=val [il ; val [il =val I j l ; val tjl=r;

I free-integer-vector(ind,l); free-integer-vector(ind0,l); free-real-vector ( d , 1) ; return k;

1

B. reaeigl

Determines the eigenvalues Aj (all assumed to be real) and corresponding eigenvectors u6) (j=l, ..., n) of a real nxn matrix A. A is equilibrated to the form A'=PDAD-'PI (by means of a call of eqilbr) and transformed to similar real upper Hessenberg form H (by means of a call of tfmreahes). The eigenvalues of H are then computed by single QR iteration (by means of a call of reavalqri). The eigenvectors of H are determined either by direct use of an iterative scheme of the form

or by delayed application of such a scheme. If min I A,-hi ( <c 11 H 11 (j # i) for hi ranging over the previously determined eigenvalues, A, is replaced in (1) by p,, where min I pj-hi I =e 11 H 11 , c being the value of the machine precision supplied by the user. The inverse iteration scheme is terminated if (a) 11 (H-A#xkti) 1) 2 11 H J J z, where T is a relative tolerance prescribed by the user, or (b) k=kmax+l, where the integer value of kmax, the maximum permitted number of inverse iterations, is also prescribed by the user. The above inverse iteration is performed by reaveches. The eigenvectors vw of the equilibrated matrix A ' are then obtained from those, xo), of H by back transformation (by means of a call of bakreahes2) and the eigenvectors wo) of the original matrix A are recovered from the @) by means of a call of baklbr. Finally, the w" are scaled to u@ by imposing the condition that the largest element of u@ is 1 (by means of a call of reascl). The procedure reaeigl should be used only if all eigenvalues are real.

Function Parameters: int reaeig 1 (a, n, em,val, vec)

reaeigl: given the value 0 provided that the process is completed within em[4] iterations; otherwise reaeigl is given the value k, of the number of eigenvalues and eigenvectors not calculated;

a: float a[l:n,l:n]; entry: the matrix whose eigenvalues and eigenvectors are to be calculated; exit: the array elements are altered;

n: int; entry: the order of the given matrix;

Copyright 1995 by CRC Press, Inc

Page 240: Numerical Library in C for Scientists and Engineers A

em: float em[0:9]; entry: em[O]: em[2]: em[4]: em[6]:

em[8]:

exit: em[/: em[3]: em[5]:

em[7]:

em[9]:

the machine precision (the value of E above); the relative tolerance used for the QR iteration (em[2] > em[On; the maximum allowed number of iterations (for example, em[4]=10n); the tolerance used for the eigenvectors (value of .c above; em[6] > em[2n; for each eigenvector the inverse iteration ends if the Euclidean norm of the residue vector is smaller than em[l]*em[6]; the maximum allowed number of inverse iterations for the calculation of each eigenvector (value of kmax above; for example, em[8]=5);

the infinity norm of the equilibrated matrix; the maximum absolute value of the subdiagonal elements neglected; the number of QR iterations performed; if the iteration process is not completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of val and the last n-k columns of vec are approximate eigenvalues and eigenvectors of the given matrix, where k is delivered in reaeigl; the maximum Euclidean norm of the residues of the calculated eigenvectors of the transformed matrix; the largest number of inverse iterations performed for the calculation of some eigenvector; if, for some eigenvector the Euclidean norm of the residue remains larger than em[l]*em[6], then the value em[8]+1 is delivered; nevertheless the eigenvectors may then very well be useful, this should be judged from the value delivered in em[7] or from some other test;

val: float val[l:n]; exit: the eigenvalues of the given matrix are delivered in monotonically decreasing

order; vec: float vec[l :n, I :n];

exit: the calculated eigenvectors corresponding to the eigenvalues in val[l:n] are delivered in the columns of vec.

Functions used: eqilbr, tfmreahes, bakreahes2, baklbr, reavalqri, reaveches, reascl.

int reaeigl(f1oat **a, int n, float em[], float val[l, float **vet) I

int *allocate-integer-vector(int, int); float *allocate~real~vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-integer-vector(int *, int); void free-real-vector(f1oat *, int) ; void free-real-matrix(f1oat **, int, int, int); void tfmreahes (float **, int, float [I , int [I ) ; void bakreahes2 (float ** , int, int, int, int [I , float * * ) ; void eqilbr(f1oat **, int, float [I, float [I, int [I ) ; void baklbr (int, int, int, float [I , int [I , float **) ; int reavalqri (float **, int, float [I , float [I ) ; void reaveches (float **, int, float, float [I, float 11 ) ; void reascl (float **, int, int, int) ; int i,k,max,j,l,*ind,*indO; float residu, r,machtol, *d, *v, **b;

Copyright 1995 by CRC Press, Inc

Page 241: Numerical Library in C for Scientists and Engineers A

residu=O .0 ; max= 0 ; eqilbr (a,n,em,d, indo) ; tfmreahes (a,n,em,ind) ; for (i=l; ic=n; i++)

for (j=((i == 1) ? 1 : i-1); jc=n; j++) b[il [jl=a[il [jl ; k=reavalqri (b,n, em,val) ; for (i=k+l; ic=n; i++)

for (j=i+l; jc=n; j++) if (val[jl > valIil) {

r=val [il ; val [il =val [jl ; val [jl =r;

1 machtol=em [O] *em [l] ; for (l=k+l; lc=n; I++) {

if (1 > 1) if (val [l-l] -val [ll c machtol) val[ll =val [l-11 -machtol;

for (i=l; ic=n; i++) for (j=((i == 1) ? 1 : i-1); jc=n; j++) bIi1 [jl=aIil [jl;

reaveches (b,n,val [ll , em,v) ; if (em[7] > residu) residu=em [71 ; if (em[9] > max) max=em[91 ; for (j=l; jc=n; j++) vec[jl [ll=v[jl;

1 em [7] =residu; em [91 =max; bakreahes2 (a,n, k+l,n, ind,vec) ; baklbr (n,k+l,n,d, ind0,vec) ; reascl (vec,n, k+l, n) ; free-integer-vector (ind, 1) ; free-integer-vector(ind0,l); free-real-vector (d, 1) ; free-real-vector (v, 1) ; free-real-matrix(b, l,n, 1) ; return k;

Determines all eigenvalues hj (assumed to be real) and corresponding eigenvectors ua) (i=l, ..., n) of a real nxn matrix A by equilibration to the form A'=PDAD-'PI (calling eqilbr), transformation to similar real upper Hessenberg form H (calling tfmreahes), computation of the eigenvalues of H by QR iteration and direct determination of the eigenvectors of H (calling reaqri); if all eigenvalues of H have been determined, there follow back transformation from the eigenvectors of H to the eigenvectors of A' (calling bakreahes2) further back transformation from the eigenvectors of A' to those of A (calling baklbr) and finally scaling of the eigenvectors of A in such a way that the element of maximum size in each eigenvector is 1 (calling reascl). The procedure reaeig3 should be used only if all eigenvalues are real.

Function Parameters: int reaeig3 (a, n, em,val, vec)

reaeig3: given the value 0 provided that the process is completed within em[4] iterations; otherwise reueig3 is given the value k, of the number of eigenvalues not calculated;

a: float a[l:n,l:n]; entry: the matrix whose eigenvalues and eigenvectors are to be calculated; exit: the array elements are altered;

Copyright 1995 by CRC Press, Inc

Page 242: Numerical Library in C for Scientists and Engineers A

n: int; entry: the order of the given matrix;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance used for the QR iteration (em[2] > em[On; em[4]: maximum allowed number of QR iterations (for example, em[4]=lOn); exit: em[l]: the infinity norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of val are approximate eigenvalues of the given matrix and no useful eigenvectors are delivered, where k is delivered in reaeig3;

vaE: float val[l:n]; exit: the eigenvalues of the given matrix are delivered;

vec: float vec[l :n, l:n]; exit: the calculated eigenvectors corresponding to the eigenvalues in val[l:n] are

delivered in the columns of vec.

Functions used: eqilbr, tfmreahes, bakreahes2, baklbr, reaqri, r e a d

int reaeig3 (float **a, int n, float em [ I , float val [ I , float **vet) I

int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int) ; void free-integer-vector(int *, int); void free-real-vector(f1oat *, int); void tfmreahes(f1oat **, int, float [ I , int [ I ) ; void bakreahes2(float **, int, int, int, int [ I , float * * ) ; void eqilbr (float **, int, float [ I , float [ I , int [ I ) ; void baklbr(int, int, int, float [ I , int [ I , float **) ; void reascl(f1oat **, int, int, int); int reaqri (float **, int, float [ I , float [ I , float **) ; int i, *ind, *indo ; float *d;

ind=allocate-integer-vector(1,n); indo=allocate-integer-vector(1,n); d=allocate-real-vector(1,n); eqilbr (a,n, em, d, indo) ; tfmreahes (a,n,em, ind) ; i=reaqri(a,n, em,val,vec) ; if (i == 0) {

bakreahes2 (a,n, l,n, ind,vec) ; baklbr(n,l,n,d,indO,vec) ; reascl (vec,n, 1, n) ;

I free-integer-vector(ind,l); f ree-integer-vector (indo, 1) ; free-real-vector (d, 1) ; return i;

1

D. comeigval

Determines the real and complex eigenvalues hi (i=l, ..., n) of a real nxn matrix A by equilibration to the form A'=PDAD-'PI (calling eqilbr) transformation to similar real upper

Copyright 1995 by CRC Press, Inc

Page 243: Numerical Library in C for Scientists and Engineers A

Hessenberg form H (calling tfmreahes) and computation of the eigenvalues of H by double QR iteration (calling comvalqri).

Function Parameters: int comeigval (a,n,em,re,im)

comeigval: given the value 0 provided that the process is completed within em[4] iterations; otherwise comeigval is given the value k, of the number of eigenvalues not calculated;

a: float a[l:n,l:n]; entry: the matrix whose eigenvalues are to be calculated; exit: the array elements are altered;

n: int; entry: the order of the given matrix;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance used for the QR iteration (em[2] > em[On; em[4]: the maximum allowed number of iterations (for example, em[4]=10n); exit: em[l]: the infinity norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of re and im are approximate eigenvalues of the given matrix, where k is delivered in comeigval;

re, im: float re[l:n], im[l:n]; exit: the real and imaginary parts of the calculated eigenvalues of the given matrix

are delivered in re, im[l:n], the members of each nonreal complex conjugate pair being consecutive.

Functions used: eqilbr, tfmreahes, comvalqri.

int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int); void free-integer-vector(int *, int) ; void free-real-vector(f1oat *, int); void eqilbr(f1oat ** , int, float 1 1 , float [ I , int [I); void tfmreahes (float **, int, float [I , int [I ) ; int comvalqri (float **, int, float [I , float [I , float 1 1 ) ; int i,*ind,*indO; float *d;

ind=allocate-integer-vector(1,n) ; indo=allocate-integer-vector(1,n) ; d=allocate-real-vector(1,n); eqilbr (a,n, em, d, indo) ; tfmreahes (a, n, em, ind) ; i=comvalqri (a, n, em, re, im) ; free-integer-vector(ind,l) ; free-integer-vector (indo, 1) ; f ree-real-vector (d, 1) ; return i;

Copyright 1995 by CRC Press, Inc

Page 244: Numerical Library in C for Scientists and Engineers A

E. comeigl

Determines the real and complex eigenvalues hj and corresponding eigenvectors ua) U=l, ..., n) of a real nxn matrix A. A is equilibrated to the form A'=PDAD-'P' (by means of a call of eqilbr) and transformed to similar real upper Hessenberg form H (by means of a call of tfmreahes). The eigenvalues of H are then computed by double QR iteration (by means of a call of comvalqri). The real eigenvectors and complex eigenvectors of H are determined either by direct use of an iterative scheme of the form

or by delayed application of such a scheme. If min I hj-hi I l e I/ H 11 (j # i) for hi ranging over the previously determined eigenvalues, hj is replaced in (I) by pj, where min I pj-hi I =E 11 HI / , e being the value of the machine precision supplied by the user. The inverse iteration scheme is terminated if (a) 11 (H-AJ)xko) 11 I 11 H 11 z, where T is a relative tolerance prescribed by the user, or (b) k=kmax+l, where the integer value of kmax, the maximum permitted number of inverse iterations, is also prescribed by the user. The above inverse iteration is performed, when hj is real, by reaveches, and when hj is complex, by comveches. The eigenvectors @) of the equilibrated matrix A' are then obtained from those, xo), of H by back transformation (by means of a call of bakreahes2) and the eigenvectors wo) of the original matrix A are recovered from the vo) by means of a call of baklbr. Finally, the wm are scaled to uo) by imposing the condition that the largest element of uo) is 1 (by means of a call of comscl).

Function Parameters: int comeig l (a, n, em, re, im, vec)

comeigl: given the value 0 provided that the process is completed within em[#] iterations; otherwise comeigl is given the value k, of the number of eigenvalues and eigenvectors not calculated;

a: float a[l:n,l:n]; entry: the matrix whose eigenvalues and eigenvectors are to be calculated; exit: the array elements are altered;

n: int; entry: the order of the given matrix;

em: float em[0:9]; entry: em[O]: the machine precision (the value of E above); em[2]: the relative tolerance used for the QR iteration (em[2] > em[OB; em[4]: the maximum allowed number of iterations (for example, em[4]=10n); em[6]: the tolerance used for the eigenvectors (value of z above; em[6] > em[28; for

each eigenvector the inverse iteration ends if the Euclidean norm of the residue vector is smaller than em[l]*em[6];

em[8]: the maximum allowed number of inverse iterations for the calculation of each eigenvector (value of kmax above; for example, em[8]=5);

exit: em[l]: the infinity norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of QR iterations performed; if the iteration process is not

Copyright 1995 by CRC Press, Inc

Page 245: Numerical Library in C for Scientists and Engineers A

completed within em[4] iterations then the value em[4]+1 is delivered and in this case only the last n-k elements of re, im and columns of vec are approximate eigenvalues and eigenvectors of the given matrix, where k is delivered in comeigl;

em[7]: the maximum Euclidean norm of the residues of the calculated eigenvectors of the transformed matrix;

em[9]: the largest number of inverse iterations performed for the calculation of some eigenvector; if the Euclidean norm of the residue for one or more eigenvectors remains larger than em[l]*em[6], then the value em[8]+1 is delivered; nevertheless the eigenvectors may then very well be useful, this should be judged from the value delivered in em[7] or from some other test;

re, im: float re[l :n], im[l :n]; exit: the real and imaginary parts of the calculated eigenvalues of the given matrix

are delivered in arrays re[l:n] and im[l:n], the members of each nonreal complex conjugate pair being consecutive;

vec: float vec[l :n, 1 :n]; exit: the calculated eigenvectors are delivered in the columns of vec; an eigenvector

corresponding to a real eigenvalue given in array re is delivered in the corresponding column of array vec; the real and imaginary part of an eigenvector corresponding to the first member of a nonreal complex conjugate pair of eigenvalues given in the arrays re, im are delivered in the two consecutive columns of array vec corresponding to this pair (the eigenvectors corresponding to the second members of nonreal complex conjugate pairs are not delivered, since they are simply the complex conjugate of those corresponding to the first member of such pairs).

Functions used: eqilbr, tfmreahes, bakreahes2, baklbr, reaveches, comvalqri, comveches, comscl.

int comeigl (float **a, int n, float em [I , float re [I , float im[l , float **vet)

( int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int *, int) ; void free-real-vector(f1oat *, int); void free-real-matrix(f1oat ** , int, int, int); void eqilbr (f loat **, int, float [I , float [I , int [I ) ; void tfmreahes(f1oat ** , int, float [I, int [I); void bakreahes2(float ** , int, int, int, int [I, float * * I ; void baklbr (int, int, int, float [I , int [I , float * * ) ; void reaveches (float ** , int, float, float [I , float [I ) ; void comscl(f1oat * * , int, int, int, float [I ) ; int comvalqri (float ** , int, float [I , float [I , float [I ) ; void comveches(f1oat * * , int, float, float,

float [ I , float [I, float [I); int i,j,k,pj,itt,again,*ind,*indO; float ~,y,max,neps,**ab,*d,*u,*v,templ,temp2;

eqilbr (a, n, em, d, indo) ; tfmreahes (a, n, em, ind) ;

Copyright 1995 by CRC Press, Inc

Page 246: Numerical Library in C for Scientists and Engineers A

for (i=l; ic=n; i++) for (j=((i == 1) ? 1 : i-1); jc=n; j++) ab[il [jl=a[il [j];

k=comvalqri (ab, n, em, re, im) ; neps=em [Ol *em [ll ; max=O. 0 ; itt=O; for (i=k+l; ic=n; i++) {

x=re [il ; y=im [il ; pj=O; again=l ; do {

for (j=k+l; jc=i-1; j++) { ternpl=x-re [ j I ; temp2=y-im[jl ; if (templ*templ+temp2*temp2 c= neps*neps) {

if (pj == j) neps=em [21 *em [ll ;

else pj=j;

x += 2.O*neps; again = ( !again) ; break;

I 1

1 again = ( !again) ;

) while (again) ; re [il =x; for (i=l; i<=n; i++)

if (y ! = 0.0) { comveches (ab,n,re [il , im[il ,em,u,v) ; for (j=l; jc=n; j++) vec[jl [il=u[jl; i++; re [il =x;

) else reaveches(ab,n,x,em,v) ;

for (j=l; j<=n; j++) vec[jl [il=v[jl ; if (em[7] > max) max=em [71 ; if (itt c em[91 ) itt=em[91 ;

1 em [7] =max; em [91 =itt; bakreahes2 (a, n, k+l, n, ind, vet) ; baklbr(n,k+l,n,d, ind0,vec) ; comscl (vec, n, k+l,n, i d ; free-integer-vector(ind,l); free-integer-vector(ind0,l); f ree-real-vector (d, 1) ; free-real-vector(u,l); free-real-vector (v, 1) ; free real-matrix(ab,l,n,l); return k;

1

3.13.8 Complex Hermitian matrices

A. eigvalhrm

Determines the n' largest eigenvalues A, of the nxn Hermitian matrix A. A is first reduced by a similarity transformation to real tridiagonal form T by calling hshhrmtrival. The n' largest eigenvalues h, of T are then determined by means of a call of valsymtri.

Function Parameters: void eigvalhrm (a, n, numval, val, em)

a : float a[l:n, l :n];

Copyright 1995 by CRC Press, Inc

Page 247: Numerical Library in C for Scientists and Engineers A

entry: the real part of the upper triangle of the Hermitian matrix must be given in the upper triangular part of a (the elements a[i,j], iilSj); the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], i>j);

exit: the array elements are altered; n: int; entry: the order of the given matrix; numval: int;

entry: eigvalhrm calculates the largest numval eigenvalues of the Hermitian matrix (the value of n ' above);

val: float val[l:numval]; exit: in array val the largest numval eigenvalues are delivered in monotonically

nonincreasing order; em: float em[0:3];

entry: em[O]: the machine precision (value of E above); em[2]: the relative tolerance used for the eigenvalues (value of p above); more

precisely, the tolerance for each eigenvalue h is I h 1 *em[2]+em[l]*em[O]; exit: em[l]: an estimate of a norm of the original matrix; em[3]: the number of iterations performed.

Functions used: hshhrmtrival, valsymtri.

void eigvalhrm(f1oat **a, int n, int numval, float val[l, float em[]) (

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void hshhrmtrival (float ** , int, float [ I , float [I , float [I ) ; void valsymtri (float [I, float [ I , int, int, int,

float [ I , float [I); float *d, *bb;

d=allocate-real-vector(1,n); bb=allocate-real-vector(1,n-1); hshhrmtrival (a,n, d, bb, em) ; valsymtri (d, bb,n, l,numval,val, em) ; free-real-vector (d, 1) ; free-real-vector (bb, 1) ;

1

B. eighrm

Determines the n ' largest eigenvalues A, G = l , ..., n') and corresponding eigenvectors uo) G=l, ..., n ') of the nxn Hermitian matrix A. A is first reduced to similar real tridiagonal form T by a call of hshhrmtri. The required eigenvalues of this tridiagonal matrix are then obtained by a call of valsymtri. The corresponding eigenvectors of T are determined by inverse iteration and (possibly) Gram-Schmidt orthogonalization by a call of vecsymtri; the required eigenvectors of A are then recovered from those of T by means of a call of bakhrmtri.

Function Parameters: void eighrm (a, n, numval, val,vecr,veci, em)

a : float a[I:n, I:n];

Copyright 1995 by CRC Press, Inc

Page 248: Numerical Library in C for Scientists and Engineers A

entry: the real part of the upper triangle of the Hermitian matrix must be given in the upper triangular part of a (the elements a[i,j], i s j ) ; the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], i>j);

exit: the array elements are altered; n: int; entry: the order of the given matrix; numval: int;

entry: eighrm calculates the largest numval eigenvalues of the Hermitian matrix (the value of n ' above);

val: float val[l:numval]; exit: in array val the largest numval eigenvalues are delivered in monotonically

nonincreasing order; vecr,veci: float vecr[l :n, l:numval], veci[l :n, l:nurnval];

exit: the calculated eigenvectors; the complex eigenvector with real part vecr[l:n,i] and the imaginary part veci[l:n,i] corresponds to the eigenvalue val[i], i=l, ..., numval;

em: float em[0:9]; entry: em[O]: em[2]:

em[4]: em[6]: em[8]:

exit: em[l]: em[3 1: em[5]:

em[7]:

em[9]:

the machine precision; the relative tolerance used for the eigenvalues; more precisely, the tolerance for each eigenvalue h is I h 1 *em[2]+ern[I]*em[O]; the orthogonalization parameter (for example, em[4]=0.01); the tolerance for the eigenvectors; the maximum number of inverse iterations allowed for the calculation of each eigenvector;

an estimate of a norm of the original matrix; the number of iterations performed; the number of eigenvectors involved in the last Gram-Schmidt orthogonalization; the maximum Euclidean norm of the residues of the calculated eigenvectors; the largest number of inverse iterations performed for the calculation of some eigenvector; if, however, for some calculated eigenvector, the Euclidean norm of the residues remains greater than em[l ]*em[6], then em[9]=em[8]+1.

Functions used: hshhrmtri, valsymtri, vecsymtri, bakhrrntri.

void eighrm(f1oat **a, int n, int numval, float val[l, float **vecr, float **veci, float em [I )

i float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); void hshhrmtri (float **, int, float [I , float [ I , float [I ,

float [I, float [I, float 11); void valsymtri (float [I, float [I, int, int, int,

float [I, float [I) ; void vecsymtri (float [I, float [I, int, int, int,

float [I, float **, float [I); void bakhrmtri(f1oat **, int, int, int, float **,

float **, float [I, float [I); float *bb,*tr,*ti,*d,*b;

Copyright 1995 by CRC Press, Inc

Page 249: Numerical Library in C for Scientists and Engineers A

bb=allocate-real-vector(1,n-1); tr=allocate-real-vector(1,n-1); ti=allocate-real-vector(1,n-1); d~allocate-real-vector(1,n); b=allocate-real-vector(1,n); hshhrmtri (a,n, d, b, bb, em, tr, ti) ; valsymtri(d,bb,n,l,numval,val,em) b[nl =O.O; vecsymtri (d, b,n, 1, numval,val,vecr bakhrmtri (a,n, l,numval,vecr,veci, free real vector (bb, 1) ; f reeIrealIvector (tr, 1) ; free-real-vector (ti, 1) ; free-real-vector (d, 1) ; free-real-vector (b, 1) ;

1

',em) ; tr, ti) ;

C. qrivalhrm

Determines all eigenvalues Aj of the nxn Hermitian matrix A. A is first reduced by a similarity transformation to real tridiagonal form Tby calling hshhrmtrival. The eigenvalues A, of T are then determined QR iteration using a call of qrivalsymtri.

Function Parameters: int qrivalhrm (a, n, val, em)

qrivalhrm: given the value 0 provided the QR iteration is completed within em[4] iterations; otherwise, qrivalhrm is given the number of eigenvalues, k, not calculated and only the last n-k elements of val are approximate eigenvalues of the original Hermitian matrix;

a: float a[l:n,l:n]; entry: the real part of the upper triangle of the Hermitian matrix must be given

in the upper triangular part of a (the elements a[i,j], i i j ) ; the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], i>j);

exit: the array elements are altered; n: int;

entry: the order of the given matrix; val: float val[l :n];

exit: the calculated eigenvalues; em: float em[O:5];

entry: em[O]: the machine precision; em[2]: the relative tolerance used for the QR iteration; em[4]: the maximum allowed number of iterations; exit: em[l]: an estimate of a norm of the original matrix; em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: number of iterations performed; em[5]=em[4]+1 when qrivalhrmz0.

Functions used: hshhrrntrival, qrivalsymtri.

jnt qrivalhrm(f1oat **a, int n, float val [I , float em [I ) '

float *allocate-real-vector (int, int) ; void free-real-vector(f1oat *, int);

Copyright 1995 by CRC Press, Inc

Page 250: Numerical Library in C for Scientists and Engineers A

void hshhrmtrival (float * * , int, float [I , float [I , float [I ) ; int qrivalsymtri (float [I , float [I , int, float 1 1 ) ; int i; float *bb;

bb=allocate-real-vector(1,n); hshhrmtrival(a,n,val,bb,ern) ; bb[nl=0.0; i=qrivalsymtri(val,bb,n,em); free-real-vector (bb, 1) ; return i;

1

D. qrihrm

Determines all eigenvalues h, and corresponding eigenvectors uo) of the nxn Hermitian matrix A. A is first reduced to similar real tridiagonal form T by a call of hshhrmtri. The eigenvalues hj and corresponding eigenvectors vo of T are then determined QR iteration, using a call of qrisymtri. The eigenvectors uW of A are then obtained from the voj by means of a call of bakhrmtri.

Function Parameters: int qrihrm (a, n, val, vr, vi, em)

qrihrm: qrihrm=O, provided the process is completed within em[4] iterations; otherwise, qrihrm is given the number of eigenvalues, k, not calculated and only the last n-k elements of val are approximate eigenvalues and the columns of the arrays vr, vi[l:n,n-k:n] are approximate eigenvectors of the original Hermitian matrix;

a: float a[l:n, l:n]; entry: the real part of the upper triangle of the Hermitian matrix must be given in the

upper triangular part of a (the elements a[i,j], i s j ) ; the imaginary part of the strict lower triangle of the Hermitian matrix must be given in the strict lower part of a (the elements a[i,j], +j);

exit: the array elements are altered; n: int;

entry: the order of the given matrix; val: float val[l :n];

exit: the calculated eigenvalues; vr,vi: float vr[l:n,l:n], vi[l:n,l:n];

exit: the calculated eigenvectors; the complex eigenvector with real part vr[l:n,i] and the imaginary part vi[l:n,i] corresponds to the eigenvalue val[i], i=l , ..., n;

em: float em[0:5]; entry: em[O]: the machine precision; em[2]: the relative tolerance for the QR iteration; em[4]: maximum allowed number of iterations (for example, em[4]=10n); exit: em[l]: an estimate of a norm of the original matrix; em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: number of iterations performed; em[5]=em[4]+1 when qrihrm#O.

Functions used: hshhrrntri, qrisymtri, bakhrrntri.

Copyright 1995 by CRC Press, Inc

Page 251: Numerical Library in C for Scientists and Engineers A

int qrihrm(f1oat **a, int n, float val [I, float **vr, float **vi, float em [I )

{ float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void hshhrmtri (float ** , int, float [I, float [I , float [I,

float [I, float [I, float [ I ) ; int qrisymtri(f1oat ** , int, float [I, float [I, float [ I , float [I ) ; void bakhrmtri(f1oat **, int, int, int, float ** ,

float ** , float [I, float [I) ; int i, j; float *b,*bb,*tr,*ti;

b=allocate-real-vector(1,n); bb=allocate-real-vector(1,n); tr=allocate-real-vector(1,n-1); ti=allocate-real-vector(1,n-1); hshhrmtri(a,n,val,b,bb,em,tr,ti); for (i=l; ic=n; i++) {

vr [ij [il =l..0; for (j=i+l; jc=n; j++) vr[il

1 b [nl =bb [nl =O. 0 ; ieqrisymtri (vr,n,val,b, bb, em) ; bakhrmtri(a,n,i+l,n,vr,vi,tr,ti) free-real-vector (b, 1) ; free-real-vector (bb, 1) ; f ree-real-vector (tr, 1) ; free-real-vector(ti,l); return i;

I

3.13.9 Complex upper-Hessenberg matrices

A. valqricom

Determines the eigenvalues hj Cj=l, ..., n) of an nxn complex upper Hessenberg matrix A (Aij=O for i>j+l) with real subdiagonal elements Aj,,j, by QR iteration. For further details see the documentation of the procedure qricom.

Function Parameters: int valqricom (al,a2, b, n, em, vall, val2)

valqricom: given the value 0 provided the process is computed within em[4] iterations;

al,a2:

b:

n:

em:

otherwise given the number, k, i f eigenvalues not calculated and only the last n-k elements of the arrays vall and va12 are approximate eigenvalues of the upper Hessenberg matrix; float al[l:n,l:n], a2[1:n,l:n];

entry: the real part and the imaginary part of the upper triangle of the upper Hessenberg matrix must be given in the corresponding parts of the arrays a1 and a2;

exit: the array elements in the upper triangle of a1 and a2 are altered; float b[l:n-I]; entry: the subdiagonal of the upper Hessenberg matrix; exit: the elements of b are altered; int; entry: the order of the given matrix;

float em[0:5]; entry:

Copyright 1995 by CRC Press, Inc

Page 252: Numerical Library in C for Scientists and Engineers A

em[O]: the machine precision; em[l]: an estimate of the norm of the upper Hessenberg matrix (e.g. the sum of

the infinity norms of the real and imaginary parts of the matrix); em[2]: the relative tolerance for the QR iteration; em[4]: the maximum allowed number of iterations (e.g. 10n); exit: em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of iterations performed; em[5]=em[4]+1 in the case

valqricom#O; vall,val2: float vall [I :n], val2[1 :n];

exit: the real part and the imaginary part of the calculated eigenvalues are delivered in vall and va12, respectively.

Functions used: comkwd, rotcomrow, rotcomcol, comcolcst.

int valqricom(f1oat **al, float **a2, float b[l, int n, float em[], float vall [I , float va12 [I )

void comcolcst (int, int, int, float ** , float **, float, float) ; void rotcomcol(int, int, int, int, float * * , float ** ,

float, float, float) ; void rotcomrow(int, int, int, int, float ** , float **,

float, float, float) ; void comkwd(float, float, float, float,

float * , float * , float *, float * ) ; int nml, i, il, q, ql,max, count; float r, zl, z2, ddl, dd2, cc, gl, g2, kl, k2, hc, alnn, a2nn, ai j 1, ai j 2,

aili,kappa,nui,muil,mui2,muimll,muiml2,nuiml,tol;

tol=em [ll *em 121 ; max=em [ 4 1 ; count=O; r=O.O; if (n > 1) hc=b [n-11 ; do {

nml=n- 1 ;

&an! q=1; i--;

) while ((i >= 1) ? (fabs(b[i]) > tol) : 0); if (q > 1)

~f (fabs (b [q-11 ) > r) r=fabs (b [q-11 ) ; if (q == n) {

vall [n] =a1 [nl [nl ; va12 [n] =a2 [nl [nl ; n=nml; if (n > 1) hc=b[n-11 ;

) else ( ddl=al [nl 11-11 ; dd2=a2 [nl [nl ; cc=b [nmll ; comkwd( (a1 [nmll [nml] -ddl) /2.0, (a2 [nml] [nmll -dd2) /2.0,

cc*al [nmll [n] , cc*a2 [nmll [n] , &gl, &g2, &kl, &k2) ; if (q == nml) {

vall [nml] =gl+ddl; val2 [nml] =g2+dd2 ; vall [n] =kl+ddl; va12 [nl =k2+dd2 ; n -= 2; if (n > 1) hc=b[n-11 ;

) else { count++; if (count > max) break;

Copyright 1995 by CRC Press, Inc

Page 253: Numerical Library in C for Scientists and Engineers A

2l=kl+ddl; z2=k2+dd2; if (fabs(cc) > fabs(hc)) 21 += fabs(cc) ; hc=cc/2.0; i=ql=q+l; aijl=al [ql [ql -21; aij2=a2 [ql [ql -22; aili=b [ql ; kappa=sqrt (aijl*aijl+aij2*aij2+aili*aili ; muil=aijl/kappa; mui2=aij2/kappa; nui=aili/kappa; a1 [ql [ql =kappa; a2 [ql [ql = O . 0 ; a1 [qll [qll - = 21; a2 [qll [qll - = 22; rotcomrow (ql, n, q, ql, al, a2, muil , mui2, nui) ; rotcomcol (q, q, q, ql, al, a2,muil, -mui2, -nui) ; a1 [ql [ql += 21; a2 [ql [ql += 22; for (il=ql+l; il<=n; il++) {

aijl=al [il [il ; aij2=a2 [il [il ; aili=b [il ; kappa=sqrt(aijl*aijl+aij2*aij2+aili*ali; muimll=muil; muiml2=mui2; nuiml=nui; muil=aijl/kappa; mui2=aij2/kappa; nui=aili/kappa; a1 [ill [ill - = zl; a2 [ill [ill - = 22; rotcomrow (il,n, i, il, al, a2,muil, mui2,nui) ; a1 [il [il =muimll*kappa; a2 [i] [i] = -muiml2*kappa; b [i-11 =nuiml*kappa; rotcomcol (q, i, i, il, al, a2 ,muil, -mui2, -nui ; a1 [il [il += 21; a2 [il [il += z2;

ai j L a 1 [nl 11-11 ; ai j2=a2 [nl [nl ; kappa=sqrt (ai j l*ai jl+ai j2*ai j2) ; if ((kappa c tol) ? 1 : (aij2*aij2 <= em101 *aij

b [nmll =nui*ai j 1; a1 [nl [nl =aijl*muil+zl; a2 11-11 [nl = -aijl*mui2+22;

} else ( b [nmll =nui*kappa; alnn=muil*kappa; a2nn = -mui2*kappa; muil=aijl/kappa; mui2=aij2/kappa; comcolcst(q,nml,n,al,a2,muil,mui2); a1 [n] [nl =muil*alnn-mui2*a2nn+zl; a2 [n] [n] =muil*a2nn+mui2*alnn+z2 ;

1

I

1 } while (n > 0) ; em 131 =r; em [5] =count ; return n;

1

B. qricom

aijl)) {

Computes the eigenvalues A, and corresponding eigenvectors vu) o=l, ..., n) of an nxn

Copyright 1995 by CRC Press, Inc

Page 254: Numerical Library in C for Scientists and Engineers A

complex upper Hessenberg matrix A (Aij=O for i>j+l) with real subdiagonal elements Aj+lj. A is transformed into a complex upper triangular matrix U by means of the Francis QR iteration [Fr61, Wi651. The diagonal elements of U are its eigenvalues; the eigenvectors of U are obtained by solving the associated upper triangular system, and the eigenvectors of A are recovered by back transformation.

Function Parameters: int qricom (al, a2, b, n, em,vall,va12, vecl, vec2)

qricom: given the value 0 provided the process is computed within em[#] iterations; otherwise given the number, k, of eigenvalues not calculated and only the last n-k elements of the arrays vall and va12 are approximate eigenvalues of the upper Hessenberg matrix and no useful eigenvectors are delivered;

a l ,a2: float al[l:n,I:n], a2[1:n,l:n]; entry: the real part and the imaginary part of the upper triangle of the upper

Hessenberg matrix must be given in the corresponding parts of the arrays a 1 and a2;

exit: the array elements in the upper triangle of a1 and a2 are altered; b : float b[l :n-11;

entry: the real subdiagonal of the upper Hessenberg matrix; exit: the elements of b are altered;

n: int; entry: the order of the given matrix;

em : float em[0:5]; entry: em[O]: the machine precision; em[l]: an estimate of the norm of the upper Hessenberg matrix (e.g, the sum of

the infinity norms of the real and imaginary parts of the matrix); em[2]: the relative tolerance for the QR iteration; em[4]: the maximum allowed number of iterations (e.g. 10n); exit: em[3]: the maximum absolute value of the subdiagonal elements neglected; em[5]: the number of iterations performed; em[5]=em[4]+1 in the case qricom#O;

vall,val2: float vall[l :n], val2[1:n]; exit: the real part and the imaginary part of the calculated eigenvalues are

delivered in vall and va12, respectively. vecl,vec2: float vecl[l:n, l:n], vec2[1:n, l:n];

exit: the eigenvectors of the upper Hessenberg matrix; the eigenvector with real part vecl[l:n,j] and imaginary part vec2[1:n,j] corresponds to the eigenvalue vall/j]+val2fi]*i, j=l, ..., n.

Functions used: comkwd, rotcomrow, rotcomcol, comcolcst, comrowcst, matvec, commatvec, comdiv.

int qricom(f1oat **al, float **a2, float b[l , int n, float em[], float vall[l, float va12[1, float **vecl, float **vec2)

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int);

Copyright 1995 by CRC Press, Inc

Page 255: Numerical Library in C for Scientists and Engineers A

void comkwd(float, float, float, float, float *, float *, float * , float * ) ;

void rotcornrow(int, int, int, int, float **, float ** , float, float, float) ;

void rotcorncol (int, int, int, int, float **, float ** , float, float, float) ;

void comcolcst(int, int, int, float ** , float **, float, float); void comrowcst (int, int, int, float **, float ** , float, float) ; float matvec(int, int, int, float ** , float [I ) ; void comrnatvec(int, int, int, float **, float **,

float [I, float [I, float * , float * ) ; void comdiv(float, float, float, float, float * , float * ) ; int m, nrnl, i, il, j , q, ql, max, count; float r, zl, 22, ddl, dd2, cc,pl,p2, tl, t2, deltal, delta2,mvl, rnv2, h, hl,

h2,gl,g2,kl,k2,hc,aij12,aij22,alnn,a2nn,ai~l,ai]2,aili, kappa,nui,muil,mui2,rnuimll,rnuirnl2,nuiml,tol,rnachtol, *tfl,*tf2;

tfl=allocate-real-vector(1,n); tf2=allocate-real-vector(1,n); tol=ern [ll *em [21 ; machtol=em [OI *em [ll ; max=em [41 ; count=O; r=O . 0 ; m=n; if (n > 1) hc=b [n-11 ; for (i=l; i<=n; i++) (

vecl [il [il =1.0; vec2 [il [il =0.0: - - . - for (j=i+l; j<=n; j++)

vecl [i] [j] =vecl [jl [i] =vec2 [il [jl =vec2 [jl [il =O. 0; 1 A0 (

nrnl=n- 1 ;

:in i q=1; 1--;

} while ((i >= 1) ? (fabs(b[il) > tol) : 0); if (q > 1)

if (fabs (b[q-11 ) > r) r=fabs (b [q-11 ; if (q == n) {

vall [n] =a1 [nl [nl ; val2 11-11 =a2 [nl [nl ; n=nml ; if (n > 1) hc=b[n-11;

) else ( ddkal [nl [nl ; dd2=a2 11-11 [nl ; cc=b [nmll ; pl= (a1 [nmll [nrnll -ddl) *O. 5; p2=(a2 [nmll [nmll -dd2)*O.S; comkwd (pl,p2, cc*al [nmll [nl , cc*a2 [nmll [nl , &gl, &g2, &kl, &k2) ; if (q == nml) {

a1 [nl [nl =vall [n] =gl+ddl; a2 [nl [nl =val2 [n] =g2+dd2; a1 [ql [q] =vall [ql =kl+ddl; a2 [q] [q] =va12 [ql =k2+dd2 ; kappa=sqrt(kl*kl+k2*k2+cc*cc); nui=cc/kappa; muil=kl/kappa; mui2=k2/kappa; ai j l=al [ql [nl ; aij2=a2 [ql [nl ; hl=muil*muil-mui2*mui2; h2=2.0*muil*mui2; h = -nui*2.0; a1 [ql [n] =h* (pl*rnuil+p2*rnui2) -nui*nui*cc+aij l*hl+aij2*h2; a2 [ql [n] =h* (p2*rnuil-pl*mui2) +aij2*hl-aijl*h2; rotcomrow (q+2,m, q, n, al, a2,muil,mui2,nui) ; rotcomcol (1, q-1, q, n, al, a2, muil, -mui2, -nui) ; rotcomcol(l,m,q,n,vecl,vec2,muil,-rnui2,-nui); n - = 2;

Copyright 1995 by CRC Press, Inc

Page 256: Numerical Library in C for Scientists and Engineers A

if (n > 1) hc=b In-11 ; b[q]=O.O;

) else ( count++; if (count > rnax) (

em131 =r; em 151 =count; free-real-vector (tf 1, 1) ; free-real-vector (tf2,l) ; return n;

1 Ll=kl+ddl; z2=k2+dd2; if (fabs(cc) > fabs(hc)) zl += fabs(cc) ; hc=cc/2.0; ql=q+l; aijl=al [ql [ql -21; ai j 2=a2 [ql [ql - z2 ;

nui=aili/kappa; a1 [ql [ql =kappa; a2 [ql [ql =O .O ; a1 [qll [qll - = zl; a2 [qll [qll - = 22 ; rotcomrow(ql,m,q,ql,al,a2,muil,mui2,nui) ; rotcomcol(1, q, q,ql, al, a2,muil, -rnui2, -nui ; a1 [ql [ql += zl; a2 [ql [ql += 22; rotcomcol(l,m,q,ql,vecl,vec2,muil,-mui2,-nui) ; for (i=ql; i<=nml; i++) {

il=i+l; aij l=al [il [il ; aij2=a2 [il [il ;

muiml2=rnui2; nuiml=nui; muil=aijl/kappa; mui2=aij2/kappa; nui=aili/kappa; a1 [ill [ill -= zl; a2 [ill [ill -= 22; rotcomrow (il,m, i, il, al, a2 ,rnuil,mui2,nui) ; a1 [il [il =muimll*kappa; a2 [il [il = -muirnl2*kappa; b [i-11 =nuirnl*kappa; rotcorncol(l, i, i, il, al,a2,rnuil, -rnui2, -nui ; a1 [il [il += zl; a2 [il [il += 22; rotcorncol(l,m,i,il,vecl,vec2,muil,-rnui2,-nui) ;

1 ai j l=al [nl [nl ; ai j2=a2 [nl [nl ; aijl2=aijl*aijl; aij22=aij2*aij2; kappa=sqrt (aij l2+aij22) ; if ((kappa c tol) ? 1 : (aij22 <= ern[Ol *aijl2) ) {

b [nrnll =nui*aij 1; a1 [nl [nl =ai j l*rnuil+zl; a2 [n] [nl = -aijl*mui2+z2;

) else ( b [nrnll =nui*kappa; alnn=muil*kappa; a2nn = -rnui2*kappa; muil=aijl/kappa; mui2=aij2/kappa; corncolcst(l,nrnl,n,al,a2,muil,mui2); corncolcst(l,nrnl,n,vecl,vec2,muil,mui2) ; cornrowcst (n+l,m,n, al, a2 ,muil, -mui2) ; corncolcst(n,m,n,vecl,vec2,rnuil,mui2) ;

Copyright 1995 by CRC Press, Inc

Page 257: Numerical Library in C for Scientists and Engineers A

} while (n > 0) ; for (j=m; j>=2; j--) {

tfl[jl=l.O; tf2 [jl=O.O; tl=al[jl [jl; t2=a2 [jl [jl ; for (i=j-1; i>=l; i--) {

deltal=tl-a1 [il [il ; delta2=t2-a2 [il [il ; commatvec(i+l, j, i, al, a2, tfl, tf2, &mvl, &mv2) ; if (fabs(delta1) c machtol && fabs(delta2) c machtol) {

tf 1 [il =mvl/machtol; tf2 [il =mv2/rnachtol;

) else corndiv(rnvl,rnv2,deltal,delta2,&tfl~il ,&tf2 [ i l ) ;

for (i=l; ic=m; i++) commatvec(1, j ,i,vecl,vec2, tfl, tf2,&vecl [il [jl ,&vec2 [il [jl ) ;

em[3] =r; em 151 =count; free-real-vector (tf l,1) ; f ree-real-vector (tf2,l) ; return n;

1

3.13.10 Complex full matrices

A. eigvalcom

Computes the eigenvalues h, (j=l, ..., n) of an nxn complex matrix A. A is first transformed to equilibrated form A ' (by means of a call of eqilbrcom); A ' is then transformed to complex upper Hessenberg form H with real subdiagonal elements (by means of a call of hshcomhes). The eigenvalues hj (j=l, ..., n) of H are then determined by QR iteration (by means of a call of valqricom).

Function Parameters: int eigvalcom (ar, ai, n, em, valr, vali)

eigvalcom: given the value 0 provided the process is computed within em[4] iterations; otherwise given the number, k, of eigenvalues not calculated and only the last n-k elements of the arrays valr and vali are approximate eigenvalues of the original matrix;

ar, ai: float ar[l:n, 1:nJ ai[l:n, l:n]; entry: the real part and the imaginary part of the matrix must be given in the

arrays a r and ai, respectively; exit: the array elements of a r and ai are altered;

n: int; entry: the order of the given matrix;

em : float em[0: 71; entry: em[O]: the machine precision; em[2]: the relative tolerance for the QR iteration; em[4]: the maximum allowed number of QR iterations (e.g. 10n);

Copyright 1995 by CRC Press, Inc

Page 258: Numerical Library in C for Scientists and Engineers A

em[6]: the maximum allowed number of iterations for equilibrating the original matrix (e.g. em[6]=n* nl2);

exit: em[l]: the Euclidean norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected in the

QR iteration; em[j]: the number of QR iterations performed; em[j]=em[4]+1 in the case

eigvalcom#O; em[7]: the number of iterations performed for equilibrating the original matrix;

valr,vali: float valr[l :n], vali[l :n]; exit: the real part and the imaginary part of the calculated eigenvalues are

delivered in valr and vali, respectively.

Functions used: eqilbrcom, comeucnrm, hshcomhes, valqricom.

int eigvalcom(float **ar, float **ai, int n, float em[], float valr [I , float vali [I )

1 ' int *allocate-integer-vector(int, int) ;

float * a l l o c a t e - r e a l v e c t o r ( i n t , int); void free-integer-vector(int *, int) ; void free-real-vector(f1oat * , int); void hshcomhes (float **, float ** , int, float [I, float 11 ,

float [I, float [I, float [I) ; float comeucnrm(f1oat ** , float ** , int, int); void eqilbrcom(f1oat ** , float ** , int, float [I, float [I, int [I ) ; int valqricom(f1oat ** , float ** , float [I, int, float [I,

float [ I , float [I) ; int i, *ind; float *d, *b, *del, *tr, *ti;

ind=allocate-integer-vector(1,n); d=allocate-real-vector(1,n); b=allocate-real-vector(1,n) ; del=allocate-realvector(1,n); tr=allocate-real-vector (1,n) ; ti=allocate-real-vector (1,n) ; eqilbrcom(ar,ai,n,em,d, ind) ; em [l] =comeucnrm (ar, ai, n-1, n) ; hshcomhes (ar, ai,n, em, b, tr, ti, del) ; i=valqricom(ar, ai, b, n, em,valr,vali) ; free-integer-vector(ind,l); free-real-vector (d, 1) ; free-realvector (b, 1) ; f ree-realvector (del , 1) ; f ree-real-vector (tr, 1) ; free-real-vector (ti, 1) ; return i;

1

B. eigcom

Computes the eigenvalues A, and eigenvectors ufi) Q=l, ..., n) of an nxn complex matrix A . A is first transformed to equilibrated form A' (by means of a call of eqilbrcom); A' is then transformed to complex upper Hessenberg form H with real subdiagonal elements (by means of a call of hshcomhes). The eigenvalues h, and eigenvectors va) Q=l, ..., n) of H are then determined by QR iteration (by means of a call of qricom), and the ua) are then recovered from the va) by two successive back transformation (by means of calls of bakcomhes and baklbrcom).

Copyright 1995 by CRC Press, Inc

Page 259: Numerical Library in C for Scientists and Engineers A

Function Parameters: int eigcom (ar, ai, n, em, valr, vali, vr, vi)

eigcom: given the value 0 provided the process is computed within em[4] iterations; otherwise given the number, k, of eigenvalues not calculated and only the last n-k elements of the arrays valr and vali are approximate eigenvalues of the original matrix and no useful eigenvectors are delivered;

ar, ai: float ar[l:n,l:n], ai[l:n,l:n]; entry: the real part and the imaginary part of the matrix must be given in the

arrays a r and ai, respectively; exit: the array elements of a r and ai are altered;

n: int; entry: the order of the given matrix;

em : float em[0: 71; entry: em[O]: the machine precision; em[2]: the relative tolerance for the QR iteration; em[4]: the maximum allowed number of QR iterations (e.g. Ion); em[6]: the maximum allowed number of iterations for equilibrating the original

matrix (e.g. em[6]=n*n/2); exit: em[l]: the Euclidean norm of the equilibrated matrix; em[3]: the maximum absolute value of the subdiagonal elements neglected in the

QR iteration; em[5]: the number of QR iterations performed; em[5]=em[4]+1 in the case

eigcom#O; em[7]: the number of iterations performed for equilibrating the original matrix;

valr,vali: float valr[l:n], vali[l :n]; exit: the real part and the imaginary part of the calculated eigenvalues are

delivered in valr and vali, respectively; vr, vi: float vr[l:n,l:n], vi[l:n,l:n];

exit: the eigenvectors of the matrix; the normalized eigenvector with real part vr[l:n,j] and imaginary part vi[l:n,j] corresponds to the eigenvalue valrfi]+valifi]*i, j=l, ..., n.

Functions used: eqilbrcom, comeucnrm, hshcomhes, qricom, bakcomhes, baklbrcom, sclcom.

int eigcom(f1oat **ar, float **ai, int n, float ern[], float valr [I, float vali [I, float **vr, float **vi)

{ int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int) ; void free-integer-vector(int *, int) ; void free-real-vector(f1oat * , int); void eqilbrcom(f1oat ** , float ** , int, float [I, float [I , int [ I ) ; float comeucnrm(float ** , float ** , int, int) ; void hshcomhes (float **, float **, int, float [I , float [I ,

float [I, float [I, float [I); int qricom(f1oat ** , float **, float [I, int, float [I,

float [ I , float [I, float **, float * * I ; void bakcomhes (float ** , float **, float [I , float [I , float [I ,

float ** , float ** , int, int, int); void baklbrcom(int, int, int, float [I , int [I , float ** , float * * ) ;

Copyright 1995 by CRC Press, Inc

Page 260: Numerical Library in C for Scientists and Engineers A

void sclcom(f1oat ** , float ** , int, int, int); int i, *ind; float *d,*b,*del,*tr,*ti;

ind=allocate-integer-vector (1, n) ; d=allocate-real-vector (1, n) ; b=allocate-real-vector (1, n) ; del=allocate-real-vector(1,n); tr=allocate-real-vector(1,n); ti=allocate-real-vector(1,n); eqilbrcom(ar, ai, n, em, d, ind) ; em [ll =comeucnrm (ar, ai, n- 1, n) ; hshcomhes(ar,ai,n,em,b,tr,ti,del) ; i=qricom (ar, ai, b, n, em, valr, vali,vr,vi) ; if (i == 0) (

bakcomhes (ar, ai, tr, ti, del,vr,vi, n, 1,n) ; baklbrcom(n, l,n, d, ind,vr,vi) ; sclcom(vr,vi,n, l,n) ;

1 kree-integer-vector (ind, 1) ; f ree-real-vector (d, 1) ; free-real-vector (b, 1) ; f ree-real-vector (del, 1) ; free-real-vector (tr, 1) ; free-real-vector (ti, 1) ; return i;

1

3.14 The generalized eigenvalue problem

3.14.1 Real asymmetric matrices

A. qzival

Solves the generalized matrix eigenvalue problem Ax=XBx by means of QZ iteration [MS71]. Given two nxn matrices A and B, qzival determines complex aa) and real Ra) such that RO'A-aa)B is singular (i=l, ..., n).

QZ iteration may fail to converge in the determination of a sequence a('), R(') (i=l, ..., m). Such failure is signalled at return from qzival by the allocation of the value -1 to the array iter[i], (i=l, ..., m) and allocation of a nonnegative value, that of the number of iterations required in each case, to the array iterb] (i=m+l, ..., n) to signal success in the determination of the remaining pairs of numbers a@, Ra). In particular, if iter[l] contains the value 0 at exit, then the computations have been completely successful.

If QZ iteration is completely successful (i.e. m=O above), A and B are both reduced by unitary transformations to quasi-upper triangular form U and upper triangular form V respectively: U has 1x1 or 2x2 blocks on the principal diagonal, but Qj=O for i>j+l and Ui+,,i=O for those elements not belonging to the blocks; vj=O for i>j.

The sets aa), Ba) (i=m+l ,..., n) may contain complex conjugate pairs in the sense that for some k>m+l, a(k)lR(k) = conjugate of {a(k")lR(k")); the components of such pairs are stored consecutively in the output arrays alfr, aalfi and beta.

Function Parameters: void qzival (n, a, b,alfr, a@, beta, iter, em)

n: int; entry: the number of rows and columns of the matrices a and b;

a: float a[l:n,l:n]; entry: the given matrix;

Copyright 1995 by CRC Press, Inc

Page 261: Numerical Library in C for Scientists and Engineers A

exit: a quasi upper triangular matrix (value of U above); b: float b[l:n, I:n];

entry: the given matrix; exit: an upper triangular matrix (value of V above);

alfr: float alf[l:n]; exit: the real part of crU) given in a&b], j=m+l, ..., n, in the above;

a&: float alJi[l:n]; exit: the imaginary part of ah) given in aljlu], j=m+l, ..., n, in the above;

beta: float beta[] :n]; exit: the value of Ra) given in betab], j=m+l, ..., n, in the above;

iter: int iter[I :n]; exit: trouble indicator and iteration counter, see above; if iter[l]=O then no trouble

is signalized; em: float em[O: I];

entry: em[O]: the smallest positive machine number; em[l]: the relative precision of elements of a and b.

Functions used: elmcol, hshdecmul, hestgl2, hsh2co1, hsh3co1, hsh2row2, hsh3row2, chsh2, hshvecmat, hshvectam.

void qzival (int n, float **a, float **b, float alfr [I , float alfi [I , float beta [I , int iter [I , float em[] )

I

void elmcol (int, int, int, int, float ** , float **, float) ; void hshdecmul (int, float **, float ** , float) ; void hestgl2 (int, float ** , float * * ) ; void hsh2row2 (int, int, int, int, float, float,

float ** , float * * ) ; void hsh3row2 (int , int , int , float, float, float,

float ** , float * * ) ; void hsh2col (int, int, int, int, float, float, float **, float * * ) ; void hsh3col (int, int, int, int, float, float, float,

float **, float * * ) ; void chshZ(float, float, float, float, float * , float * , float * ) ; void hshvecmat (int, int, int, int, float, float [I, float * * ) ; void hshvectam(int, int, int, int, float, float [I, float * * ) ; int i,q,m,ml,ql,j,k,kl,k2,k3,kml,stationary,goon,l,out; float dwarf, eps, epsa, epsb,

anorm,bnorm,ani,bni,constt,a10,a20,a30,bll,b22,b33,b44,all, a12,a2l,a22,a33,a34,a43,a44,bl2,b34,oldl,old2, an, bn, e, c,d, er,ei, allr, al1i,al2r,a12ira2lr, a21i, a22r, a22i, cz, szr, szi, cq, sqr, sqi, ssr, ssi, tr, ti, bdr,bdi, r;

dwarf =em [OI ; eps=em Ill ; hshdecmul (n, a, b, dwarf) ; hestgl2 (n, a, b) ; anorm=bnorm=O.O; for (i=l; i<=n; i++) (

bni=O. 0 ; iter [il =O; ani = (i > 1) ? fabs(a[il [i-11) : 0.0; for (j=i; j<=n; j++) {

ani += fabs (a [il [jl ) ; bni += fabs (b [il [jl ) ;

1 if (ani > anorm) anorm=ani; if (bni > bnorm) bnorm=bni;

1 if (anorm == 0.0) anorm=eps;

Copyright 1995 by CRC Press, Inc

Page 262: Numerical Library in C for Scientists and Engineers A

if (bnorm == 0.0) bnorm=eps ; epsa=eps*anorm; epsb=eps*bnorm; m=n; out=O; do I ,

I=q=m; while ((i > 1) ? fabs(a[il [i-11) > epsa : 0) (

q=i-1; I--.

1 if (q > 1) a [q] [q-ll=0.0; goon=l ; while (goon) (

if (q s= m-1) { m=q- 1 ; goon= 0 ;

) else ( if (fabs (b [ql [ql ) c= epsb) {

q=q1; ) else (

goon=O ; ml=m-1; ql=q+l; constt=0.75; (iter [ml ) ++; stationary = (iter[ml == 1) ? 1 :

(fabs (a [ml [m- 11 ) >= constt*oldl && fabs(a[m-11 [m-21) >= constt*old2);

if (iter[ml > 30 && stationary) ( for (i=l; ic=m; i++) iter[il = out=1; break;

1 if (iter[m] == 10 && stationary) (

a10=0.0 ; a20=1.0; a30=1.1605;

2 - - - - blllb [ql [ql ; b22 = (fabs (b [qll [qll ) < epsb) b33 = (f abs (b [mll [mll ) c epsb) b44 = ( f abs (b [ml [ml ) c epsb) ? all=a [ql [ql /bll; a12=a Iql [qll /b22 ; a21=a [qll [ql /bll; a22=a [qll [qll /b22 ; a33=a [mll [mll /b33 ;

? epsb : b [qll [qll ; ? epsb : b [mll [mll ; epsb : b [ml [ml ;

a34=a [mll [ml /b44; a43=a [ml [mll /b33 ; a44=a [ml [ml /b44 ; bl2=b [ql [qll /b22; b34=b [mll [ml /b44 ; alO=((a33-all)*(a44-all)-a34*a43+a43*b34*all)/a21+

a12-all*b12; a20= (a22-all-a21*b12) - (a33-all) - (a44-all) +a43*b34; a30=a [q+21 [qll /b22 ;

I oldkf abs (a [ml Em-11 ) ; old2=fabs (a [m-11 [m-21) ; for (k=q; kc=ml; k++) {

kl=k+l ; k2=k+2 ; k3 = (k+3 > m) ? m : k+3;

if (k == q) hsh3col (kml, km1.n. k, a10, a20, a30, a, b) ;

else ( hsh3col (kml,kml,n,k, a [kl [kmll ,

Copyright 1995 by CRC Press, Inc

Page 263: Numerical Library in C for Scientists and Engineers A

a [kl] [kmll =a [k21 [kmll =O .O; \

) else { hsh2col (kml, kml,n, k, a [kl [kmll ,a [kll a [kll [kml] =O .O;

1

a [kll [kmll ,a [k21 [kmll .

,a, b) ;

kmll ,a, b) ;

1 ) /* goon loop * / if (out) break;

) while (m >= 3) ;

do ( if ( (m > 1) ? (a[ml [m-11 == 0) : 1) {

alf r [ml =a [ml [ml ; beta [ml =b [ml [ml ; alfi [ml =O. 0; m-- .

) else { l=m-1; if (fabs (b [ll [ll ) <= epsb) {

b [ll [ll =O, 0; hsh2col (l,l,n,l,a [ll 111 ,a[ml [11 ,a,b) ; a [m] [ll =b [ml [ll =O. 0; alfr [ll =a ill [ll ; alfr [ml =a [ml [ml ; beta [ll =b [ll [ll ; beta [ml =b [ml [ml ; alfi[mI=alfi[ll=O.O;

\ else , - - - - if (fabs (b [ml [ml ) <= epsb) (

b[ml [ml=O.O; hsh2row2(1,m,m,1,a[ml [ml ,a[ml [11 ,arb); a [m] [ll =b [ml ill =O. 0; alfr [1] =a [ll [l] ; alf r [m] =a [ml [ml ; beta [ll =b [ll [11 ; beta [ml =b [ml [ml ; alf i [m] =alfi [ll =O. 0 ;

} else ( an=fabs (a [l] [l] ) +fabs (a [ll [ml ) +fabs (a [ml [I]

f abs (a [ml [ml ) ; bn=fabs (b [l] [ll ) +fabs (b [l] [ml ) +fabs (b [ml [ml all=a [ll 111 /an; a12=a [ll [ml /an; a2l=a [ml [ll /an; a22=a [ml [ml /an; blkb [ll [ll /bn; b12=b [l] [ml /bn; b22=b [ml [ml /bn; e=all/bll; c= ( (a22-e*b22) /b22- (a21*b12) / (bll*b22) ) /2.0; d=c*c+ (a21* (al2-e*bl2) ) / (bll*b22) ; if (d >= 0.0) {

e += ((c c 0.0) ? c-sqrt (d) : c+sqrt(d)) ; all -= e*bll; a12 -= e*b12; a22 - = e*b22; if (fabs (all) +fabs (al2) >= fabs (a2l) +fabs (a22)

hsh2row2 (l,m,m, l,al2,all, a,b) ; else

hsh2row2 (l,m,m, 1, a22,a2l, a, b) ; if (an >= fabs(e)*bn)

hsh2col(l, l,n, l,b 111 Ell ,b [ml [I1 ,a,b) ;

Copyright 1995 by CRC Press, Inc

Page 264: Numerical Library in C for Scientists and Engineers A

a [m] [I] =b [ml [ll =O. 0; alfr [ll =a [ll [ll ; alf r [ml =a [ml [ml ; beta [l] =b [ll [ll ; beta [m] =b [ml [ml ; alfi [m] =alfi [lI=O. 0;

) else { er=e+c; ei=sqrt (-d) ; allr=all-erfbll; alli=ei*bll; a12r=a12-er*b12; a12i=ei*b12; a21r=a21; a2li=0.0; a22r=a22 -er*b22 ; a22i=ei*b22; if (fabs (allr) +fabs (alli) +fabs (al2r) +fabs ( a >=

fabs (a2lr) +fabs (a22r) +fibs (a22i) ) chsh2 (al2r, al2i, -allr, -alli, &cz, &szr, &szi) ;

else chsh2 (a22r,a22i, -a21r, -a2li, &cz, &szr, &szi) ;

if (an >= (fabs (er) +fabs (ei) ) *bn) chsh2(cz*bll+szr*bl2,szi*b12,szr*b22,szi*b22,

&cq, &sqr, &sqi) ; else

chsh2(cz*all+szr*al2,szi*al2,cz*a2l+szr*a22, szi*a22, &cq, &sqr, &sqi) ;

ssr=sqr*szr+sqi*szi; ssi=sqr*szi-sqi*szr; tr=cq*cz*all+cq*szr*al2+sqr*cz*a2l+ssr*a22; ti=cq*szi*al2-sqi*cz*a21+ssi*a22; bdr=cq*cz*bll+cq*szr*b12+ssr*b22; bdi=cq*szi*bl2+ssi*b22; r=sqrt (bdr*bdr+bdi*bdi) ; beta [ll =bn*r; alfr [ll =an* (tr*bdr+ti*bdi) /r; alfi [ll =an* (tr*bdi-ti*bdr) /r; tr=ssr*all-sqr*cz*al2-cq*szr*a2l+cq*cz*a22; ti = -ssi*all-sqi*c~*al2+cq*szi*a21; bdr=ssr*bll-sqr*cz*b12+cq*cz*b22; bdi = -ssi*bll-sqi*cz*bl2; r=sqrt (bdr*bdr+bdi*bdi) ; beta [ml =bn*r; alfr [ml =an* (tr*bdr+ti*bdi) /r; alfi [ml =an* (tr*bdi-ti*bdr) /r;

B. qzi

Solves the generalized matrix eigenvalue problem Ax=XBx by means of QZ iteration [MS71]. The procedure qzi applies the same method as qzival. Given two nxn matrices A and B, qzi determines complex aQ) and real BQ) such that BQ)A-aa)~ is singular and vectors xQ) such that Ba)Axa)=aa)~xa) U=l, ..., n), the latter being normalized by the condition that max( I real@,")) I , 1 imag(x ,"') I )=1 (1 SiSn) for each x" and either real(x,"))=l or imag(x,"') for some x,(i).

With regard to the determination of the aQ), Ba), the remarks made in the documentation to qzival apply with equal force here. In particular, (a) QZ iteration may fail to converge in the determination of a sequence a('), B(') (i=l, ..., m); this failure is signalled by the insertion of -1 in the array iter[i], (i=l, ..., m) and for those am, f l u ) that are determined, the required number of QZ iterations required in each case is allocated to the array iterb]

Copyright 1995 by CRC Press, Inc

Page 265: Numerical Library in C for Scientists and Engineers A

Cj=m+l ,..., n); (b) a quasi-upper triangular matrix U and an upper triangular matrix V are produced and (c) the sets am, Bcj) (j=m+l, ..., n) may contain complex conjugate pairs in the sense that for some k2m+l, a(k)l13@) = conjugate of {a@")lB(k'l)}, and the components of such pairs are stored consecutively in the output arrays a f i alp and beta.

Function Parameters: void qzi (n,a, b,x,alfr,alfi, beta, iter,em)

int; entry: the number of rows and columns of the matrices a, b and x; float a[l:n, l:n]; entry: the given matrix; exit: a quasi upper triangular matrix (value of U above); float b[l:n, 1 :n]; entry: the given matrix; exit: an upper triangular matrix (value of V above); float x[l:n, 1 :n]; entry: the nxn unit matrix; exit: the matrix of eigenvectors (components of xcj) above); the eigenvectors are

stored in x as follows: if alfi[m]=O then x[.,m] is the m-th real eigenvector; otherwise, for each pair of consecutive columns x[.,m] and x[.,m+l] are the real and imaginary parts of the m-th complex eigenvector, x[.,m] and -x[.,m+l] are the real and imaginary parts of the (m+l)-st complex eigenvector; the eigenvectors are normalized such that the largest component is 1 or l+O*i;

alfr: floatalfr[l:n]; exit: the real part of aa) given in alfl;], j=m+l, ..., n, in the above;

alp: float alJijl:n]; exit: the imaginary part of aa) given in arfil;], j=m+l, ..., n, in the above;

beta: float beta[l:n]; exit: the value of Ba) given in betal;], j=m+l, ..., n, in the above;

iter: int iter[l :n]; exit: trouble indicator and iteration counter, see qzival; if iter[I]=O then no trouble

is signalized; em: float em[O:l];

entry: em[O]: the smallest positive machine number; em[]]: the relative precision of elements of a and b.

Functions used: matmat, hshdecmul, hestgl3, hsh2co1, hsh2row3, hsh3row3, hsh3co1, chsh2, comdiv.

void qzi(int n, float **a, float **b, float **x, float alfr[l, float alfi [ I , float beta [ I , int iter [ I , float em [ I )

I float matmat(int, int, int, int, float **, float ** ) ; void hshdecmul (int, float **, float **, float) ; void hestgl3 (int, float **, float **, float * * ) ; void hsh2row3(int, int, int, int, int, float, float,

float **, float **, float * * ) ; void hsh3row3 (int, int, int, int, float, float, float,

float **, float **, float * * ) ; void hsh2col(int, int, int, int, float, float, float **, float * * ) ;

Copyright 1995 by CRC Press, Inc

Page 266: Numerical Library in C for Scientists and Engineers A

void hsh3col(int, int, int, int, float, float, float, float ** , float * * ) ;

void chsh2 (float, float, float, float, float *, float *, float * ) ; void comdiv(float, float, float, float, float * , float * ) ; int i,q,m,ml,ql,j,k,kl,k2,k3,kml,stationary,goon,l,mr,mi,ll,out; float dwarf,eps,epsa,epsb,

anorm,bnorm,ani,bni,constt,a10,a20,a30,bll,b22,b33,b44,all, a12, a21, a22, a33, a34, a43, a44,b12,b34,oldl,old2, an,bn,e, c,d, er,ei,allr, alli, a12r, a12i,a21rt a21i, a22r, a22i, cz, szr, szi, cq, sqr, sqi, ssr, ssi, tr, ti,bdr,bdi,r, betm,alfm,sl,sk,tkk,tkl,tlk,tll,almi,almr,slr,sli,skr,ski, dr,di,tkkr,tkki,tklr,tkli,tlkr,tlki,tllr,tlli,s;

dwarf =em [O] ; eps=em [ll ; hshdecmul (n, a, b, dwarf) ; hestgl3 (n, a,b,x) ; anorm=bnorm=O.O; for (i=l; i<=n; i++) {

bni=0.0; iter [il =O; ani = (i > 1) ? fabs(a[il [i-11) : 0.0; for (j=i; j<=n; j++) {

ani += fabs (a [il [ jl ) ; bni += fabs (b [il [jl ) ;

1 if (ani > anorm) anorm=ani; if (bni > bnorm) bnorm=bni;

1 if (anorm == 0.0) anorm=eps; if (bnorm == 0.0) bnorm=eps ; epsa=eps*anorm; epsb=eps*bnorm; m=n ; out=O; do { ,

1=q=m; while ((i > 1) ? fabs(aLi.1 [i-11) > epsa : 0) {

q=i-1; i--;

1 if (q > 1) a [ql [q-11 =O.O; goon=l; while (goon) {

if (q >= m-1) { m=q- 1 ; goon=O ;

} else { if (fabs (b [ql [ql ) c = epsb) {

b [ql [ql =O . 0 ;

- - q=qz;

) else { goon=O ; ml=m- 1 ; ql=q+l; constt=0.75; (iter [ml ) ++; stationary = (iter[m] == 1) ? 1 :

(fabs (a [m] [m-11 ) >= constt*oldl && fabs (a [m-11 [m-21) >= constt*old2) ;

if (iter [ml > 30 && stationary) { for (i=l; i<=m; i++) iter[il = -1; out=l; break:

1 if (iter [ml == 10 && stationary) {

a10=0.0 ; a20~1.0; a3O=l. 1605;

} else { bll=b [ql [ql ;

Copyright 1995 by CRC Press, Inc

Page 267: Numerical Library in C for Scientists and Engineers A

b22 = (fabs (b [qll [qll ) < epsb) ? epsb : b lqll lqll ; b33 = (fabs (b [ml] [mll ) < epsb) ? epsb : b [mll [mll ; b44 = (fabs (b [ml [ml ) < epsb) ? epsb : b [ml [ml ; all=a [ql [ql /bll; al2=a [ql [qll /b22 ; a21=a [qll [ql /bll; a22=a [qll [qll /b22; a33=a [mll [mll /b33 ; a34=a [mll [ml /b44; a43=a [ml [mll /b33 ; a44=a [ml [ml /b44 ; bl2=b [ql [qll /b22 ; b34=b [mll [ml /b44 ; ale= ( (a33-all) * (a44-all) -a34*a43+a43*b34*all) /a21+

a12-all*b12 ; a20= (a22-all-a2l*b12) - (a33-all) - (a44-all) +a43*b34; a30=a [q+21 [qll /b22;

1 &ldl=f abs (a [ml [m- 11 ) ; old2=fabs(a[m-11 [m-21) ; for (k=q; k<=ml; k++) {

kl=k+l; k2=k+2; k3 = (k+3 > m) ? m : k+3; kml = (k-1 < ? q : k-1; if (k ! = ml) 9)

if (k == q) hsh3col(kml,kml,n,k,a10,a20,a30,a,b) ;

else { hsh3col (kml, kml,n, k, a [kl [kmll ,

a [kll [kmll ,a [k21 [kmll ,a, b) ; a [kll [kmll =a [k21 [kmll =O. 0;

1 hsh3row3 (l,k3,n,k, b Lk21 [kZl ,b [k21 [kll ,

b[k21 [kl ,a,b,x) ; b [k21 [kl =b [k21 [kll =O. 0;

) else { hsh2col (kml, kml,n, k, a [kl [kmll ,a [kll [kmll ,a, b) ; a [kll [kmll =O .O ;

I

I } / * goon loop * / if (out) break;

} while (m >= 3);

do I if ((m > 1) ? (a[ml [m-11 == 0) : 1) {

alf r Em1 =a lml [ml ; beta [ml =b [ml [ml ; alfi [ml=0.0; m--;

} else { l=m-1; if (fabs (b [ll [ll <= epsb) (

b [l] 111 =O. 0; hsh2c0l(l,l,n,1,a[ll [I1 ,ah1 111 ,a,b); a [m] [ll =b [ml [ll =O. 0; alfr [ll =a [ll [I1 ; alf r [ml =a [ml [ml ; beta [ll =b [ll [I1 ; beta [ml =b lml [ml ; alfi [ml =alfi [ll=0.0;

} else if (fabs (b [ml [ml ) c= epsb) {

b[ml [ml=O.O; hsh2row3 (l,m,m,n,l,a[m] [ml ,ah] [I] ,atbrx) ; a [ml [ll =b [ml Dl =O. 0; alfr [l] =a [ll [l] ; alf r [ml =a [ml [ml ;

Copyright 1995 by CRC Press, Inc

Page 268: Numerical Library in C for Scientists and Engineers A

beta [ll =b [ll 111 ; beta [ml =b [ml [ml ; alfi [ml =alfi [ll=0 .O;

} else { an=fabs (a 111 [11 ) +fabs (a [ll [ml ) +fabs (a [ml [ll ) +

f abs (a [ml [ml ; bn=fabs (b [ll ill ) +fabs (b [ll [ml ) +fabs (b [ml [ml ) ; all=a [ll [ll /an; al2=a [ll [ml /an; a21=a [ml [l] /an; a22=a [ml [ml /an; bll=b [ll [l] /bn; b12=b [ll [ml /bn; b22=b [ml [ml /bn; e=all/bll; c= ( (a22-e*b22) /b22- (a21*b12) / (bll*b22) ) /2 .O; d=c*c+ (a21* (al2-e*bl2) ) / (bll*b22) ; if (d >= 0.0) {

e += ( (c < 0.0) ? c-sqrt (dl : c+sqrt (dl ) ; all - = e*bll; a12 -= e*b12; a22 -= e*b22; if (fabs (all) +fabs (al2) >= fabs (a2l) +fabs (a22) )

hsh2row3 (l,m,m,n, 1, a12, all, a, b,x) ; else

hsh2row3 (l,m,m,n, 1, a22, a21, a, b,x) ; if (an >= fabs(e) *bn)

hsh2col (l,l,n,l,b[l] [11 ,b[ml Ill ,a,b) ; else

hsh2col(l,l,n,l,a [ll [l] ,a[ml [l] ,a,b) ; a [ml Ill =b [ml 111 =O. 0; alfr [ll =a [ll [I] ; alfr [ml =a [ml [ml ; beta [ll =b [ll [ll ; beta [ml =b [ml [ml ; alfi [ml =alfi [ll=0.0;

} else { er=e+c; ei=sqrt (-dl ; allr=all-er*bll; alli=ei*bll; a12r=a12-er*b12 ; al2i=ei*bl2; a2 1r=a2 1 ; a21i=0.0; a22r=a22-er*b22; a22i=ei*b22; if (fabs (allr) +fabs (alli) +fabs (al2r) +£abs ( a >=

fabs (a2lr) +fabs (a22r) +fabs (a22i) ) chsh2 (alzr, al2i, -allr, -alli, &cz, &szr, &szi) ;

else chsh2 (a22r,a22i, -a21r, -a2li,&cz, &szr,&szi) ;

if (an >= (fabs (er) +fabs (ei) ) *bn) chsh2(cz*bll+szr*bl2,szi*b12,szr*b22,szi*b22,

&cq, &sqr, &sqi) ; else

chsh2(cz*all+szr*a~2,szi*al2,cz*a2l+szr*a22, szi*a22, &cq, &sqr, &sqi) ;

ssr=sqr*szr+sqi*szi; ssi=sqr*szi-sqi*szr; tr=cq*cz*all+cq*~zr*al2+sqr*cz*a2l+ssr*a22; ti=cq*szi*al2-sqi*cz*a21+ssi*a22; bdr=cq*cz*bll+cq*szr*b12+ssr*b22; bdi=cq*szi*bl2+ssi*b22; r=sqrt (bdr*bdr+bdi*bdi) ; beta [ll =bn*r; alfr [ll =an* (tr*bdr+ti*bdi) /r; alfi [ll =an* (trfbdi-ti*bdr) /r; tr=ssr*all-sqr*cz*al2-~q*szr*a2l+cq*cz*a22; ti = -ssi*all-sqi*cz*al2+cq*szi*a21; bdr=ssr*bll-sqr*cz*bl2+cq*cz*b22; bdi = -ssi*bll-sqi*cz*bl2; r=sqrt (bdr*bdr+bdi*bdi) ; beta [ml =bn*r;

Copyright 1995 by CRC Press, Inc

Page 269: Numerical Library in C for Scientists and Engineers A

alfr [m] =an* (tr*bdr+ti*bdi) /r; alfi [m] =an* (tr*bdi-ti*bdr) /r;

, I

i } while (m > 0) ;

for (m=n: m>=l: m--) (alfi[ml == 0.0) ( alfm=alf r [ml ; betm=beta [ml ; b [ml [ml =l . 0 ; ll=m; for (l=m-1; 1>=1; I--) {

sl=0.0 ; for (j=ll; j<=m; j++)

sl += (betrn*a [ll [jl -alfmtb [ll [jl ) *b[jl [ml ; if ((1 ! = 1) ? (betm*a [ll [l-11 == 0.0) : 1) {

d=betm*a [ll [l] -alfm*b [ll [ll ; if (d == 0.0) d= (epsa+epsb) /2.0; b [ll [ml = -sl/d;

} else { k=l-1; sk=O .O ; for (j=ll; j<=m; j++)

sk += (betm*a[kl [jl -alfm*b [kl [jl ) *b [jl [ml ; tkk=betm*a [k] [kl -alfm*b [kl [kl ; tkl=betm*a [kl [l] -alfm*b [kl Ell ; tlk=betm*a [ll [kl ; tll=betm*a [l] [ll -alfm*b [ll [l] ; d=tkk*tll-tkl*tlk; if (d == 0.0) d= (epsa+epsb) /2.0; b [ll [m] = (tlk*sk-tkk*sl) /d; b [kl [ml = (fabs (tkk) >= fabs (tlk) ) ?

- (sk+tkl*b [ll [ml ) /tkk : - (sl+tll*b [ll [ml ) Itlk;

I--.

i 11=1;

1 } else {

almr=alfr [m-11 ; almi=alfi [rn-11 ; betm=beta [m-11 ; mr=m- 1 ; mi=m; b [m-I] [mrl =almi*b [ml [ml / (betm*a [ml [m-11 ) ; b [m-l] [mil = (betm*a [ml [ml -almr*b [ml [ml ) / (betm*a [ml [m-11 ) ; b[ml [mrl =O.O; b[m] [mil = -1.0; ll=m-1; for (1=m-2; 1>=1; 1--) {

slr=sli=O.O; for (j=ll; jc=m; j++) {

tr=betm*a [ll [jl -almr*b [ll [jl ; ti = -almi*b[ll [jl; slr += tr*b [ jl [mrl -ti*b [ j I [mil ; sli += tr*b [j I [mil +ti*b [ j I [mrl ;

if ( (1 ! = 1) ? (betm*a [ll [l-11 == 0.0) : 1) { dr=betm*a [ll [l] -almr*b [ll [ll ; di = -almi*b [ll [ll ; comdiv(-slr, -sli,dr,di,&b[ll [mrl ,&b[ll [mil ) ;

} else { k=l-1; skr=ski=O.O; for (j=ll; j<=m; j++) {

tr=betm*a [kl [jl -almr*b [kl [jl ; ti = -almi*b[kl [jl ; skr += tr*b [jl [mrl -ti*b [jl [mil ; ski += tr*b [jl [mil +ti*b [jl [mrl ;

1

tkkr=betm*a [kl [kl -almr*b [kl [kl ;

Copyright 1995 by CRC Press, Inc

Page 270: Numerical Library in C for Scientists and Engineers A

tkki = -almi*b [kl [kl ; tklr=betm*a [k] [l] -almr*b [kl [l] ; tkli = -almi*b [kl [l] ; tlkr=betm*a [ll [kl ; tlki=O. 0; tllr=betm*a [l] [ll -almr*b [ll [ll ; tlli = -almi*b [ll [I] ; dr=tkkr*tllr-tkki*tlli-tklr*tlkr; di=tkkr*tlli+tkki*tllr-tkli*tlkr; if (dr == 0.0 && di == 0 .O) dr= (epsa+epsb) /2.0; comdiv(tlkr*skr-tkkr*slr+tkki*sli,

tlkr*ski-tkkr*sli-tkki*slr, dr, di, &b [ll [mrl , &b [ll [mil ) ;

if (fabs (tkkr) +fabs (tkki) >= fabs (tlkr) ) comdiv(-skr-tklr*b [ll [mrl +tkli*b [ll [mil ,

-ski-tklr*b [ll [mil -tkli*b 111 [mrl , tkkr, tkki, &b [kl [mrl , &b [kl [mil ) ;

else comdiv(-slr-tllr*b [ll [mrl +tlli*b [ll [mil ,

-sli-tllr*b [ll [mil -tlli*b 111 [mrl , tlkr, tlki, &b [kl [mrl , &b [kl [mil ) ;

I for (m=n; m>=l; m--)

for (k=l; k<=n; k++) x[kl [ml=matmat(l,m,k,m,x,b); for (m=n; m>=l; m--) {

s=o.o; if (alfi[ml == 0.0) {

for (k=l; k<=n; k++) ( r=f abs (x [kl [ml ) ; if (r >= s) {

1 for

) else for '(k=l; k<=n; k++) {

r=fabs (x [kl [m-11 ) +fabs (x [kl [ml ; an=x [kl [m-11 /r; bn=x [kl [ml /r; r *= sqrt (an*an+bn*bn) ; if (r >= S) {

l J for (k=l; k<=n; k++)

comdiv (x [kl [m-I] , x [kl [ml , dr, di, &x [kl [m- 11 , &x [kl [ml ; m--;

1 1

1

C. hshdecmul

Given an nxn matrix A, determines vectors di) (i=l, ..., n'-1; n ' s n ) such that with

AJ=EA is of upper triangular form and, also given the nxn matrix B, forms B1=EB.

Copyright 1995 by CRC Press, Inc

Page 271: Numerical Library in C for Scientists and Engineers A

hshdecmul is used in qzi and qzival.

Function Parameters: void hshdecmul (n, a, b, dwarf)

n: int; entry: the order of the given matrices;

a: float a[l:n,l:n]; entry: the given matrix; exit: the transformed matrix (value of A' above);

b: float b[l:n, l:n]; entry: the given matrix; exit: the upper triangular matrix (value of 3' above);

dwarf: float; entry: the smallest positive machine number.

Functions used: tammat, hshvecmat.

void hshdecmul(int n, float **a, float **b, float dwarf) I

float *al loca te - rea lgec tor ( in t , int); void free-real-vector(f1oat *, int); float tammat (int, int, int, int, float **, float * * ) ; void hshvecmat (int, int, int, int, float, float [I , float * * ) ; int j,k,kl,nl; float r,t,c,*v;

v=allocate-real-vector(1,n); k=l ; nl=n+l; for (k1=2: klc=nl: kl++)

, . . , if (r > dwakfj {

r = (b [kl [k] c 0.0) ? -sqrt (r+b [kl [kl *b [kl [kl ) : sart (r+b [kl [kl *b [kl [kl ) ;

v[kl =l.O; for (j=kl; jc=n; j++) v[jl=b[jl [kl/t; hshvecmat (k.n,kl,n.c,v,b) ; . . . .

hshvecmat (k)n,l,n,c,v,a) ;

free-real-vector (v, 1) ; 1

Given an nxn matrix A and an nxn upper triangular matrix U, obtains vectors u,('), u?) such that with

and Q, similarly defined, Q,AQ2=H is an upper Hessenberg matrix and Q,UQ2=U1 is an

Copyright 1995 by CRC Press, Inc

Page 272: Numerical Library in C for Scientists and Engineers A

upper triangular matrix and, also given an nxn matrix X, forms X'=Q,XQ2. hestgZ3 is used in qzi.

Function Parameters: void hestgl3 (n,a, b,x)

n: int; entry: the order of the given matrices; a: float a[Z:n, l:n];

entry: the given matrix; exit: the upper Hessenberg matrix (value of H above);

b: float b[l:n,l:n]; entry: the given upper triangular matrix (value of U above); exit: the upper triangular matrix (value of U' above);

x: float x[Z:n, l:n]; entry: the given matrix (value of X above); exit: the transformed matrix (value of X' above).

Functions used: hsh2co1, hsh2row3.

void hestgl3 (int n, float **a, float **b, float **x) I

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void hsh2col (int, int, int, int, float, float, float **, float **) ; void hsh2row3(int, int, int, int, int, float, float,

float **, float **, float **) ; int nml,k,l,kl,ll;

if (n > 2) { for (k=2; kc=n; k++)

for (1=1; lc=k-1; I++) b[kl [11=0.0; nml=n-1; k=l ; for (kl=2; kls=nml; kl++) (

ll=n; for (1s-1; l>=kl; I--) (

hsh2col (k,l,n.l,a[ll [kl ,a[lll [kl ,a,b) ; a [lll [kl =O. 0; hsh2row3 (l,n, ll,n, 1,b 1111 [Ill ,b [Ill [ll ,a,b,x) ; b [ll] [ll=O .O; 11=1;

Given an nxn matrix A and an nxn upper triangular matrix U, obtains vectors u,('), u,(') such that with

n'-1 (13 (0 T (OT (1 Q~ = n (1 - U 1 lul ~ ~ ' 3 , (nl n)

i=l

and Q, similarly defined, Q,AQ,=H is an upper Hessenberg matrix and Q,UQ2=U9 is an upper triangular matrix. hestgl2 is used in qzival.

Copyright 1995 by CRC Press, Inc

Page 273: Numerical Library in C for Scientists and Engineers A

Function Parameters: void hestgl2 (n,a, b)

n: int; entry: the order of the given matrices;

a: float a[l:n, 1 :n]; entry: the given matrix; exit: the upper Hessenberg matrix (value of H above);

b: float b[l:n,l:n]; entry: the given upper triangular matrix (value of U above); exit: the upper triangular matrix (value of U' above).

Functions used: hsh2col. hsh2row2.

void hestgl2 (int n, float **a, float **b) 1

float *allocate-real-vector (int, int) ; void free-real-vector(f1oat *, int); void hsh2col (int, int, int, int, float, float, float **, float **) ; void hsh2row2 (int, int, int, int, float, float,

float ** , float * * ) ; int nml,k,l,kl,ll;

if (n > 2) { for (k=2; k<=n; k++)

for (1~1; lc=k-1; I++) b[kl [11=0.0; nml=n-1; k=l ; for (kl=2; klc=nrnl; kl++) (

ll=n; for (l=n-1; l>=kl; I--) {

hshZcol(k,l,n,l,a[11 fkl ,at111 Ekl ,a,b) ; a Ill] [kl =O .O; hsh2row2 (l,n, ll,l,b tlll Ill1 ,btlll tll ,a,b) ; b [ll] [ll =O. 0; 11=1;

1 k=kl ;

1 1

I

(a) Given the values of two elements Mkj (k=i,i+l) belonging to a certain column of a rectangular matrix M, determines a vector v such that all rows except the i-th and (i+l)-th of M and M'=EM agree, where E=I-2wTIvTv and Adij=O and, @) given the elements Akj (k=i,i+l; j=la, ..., u) of the rectangular matrix A, determines the corresponding elements of A'=EA and, (c) given the elements Bkj (k=i,i+l; j=lb, ..., u) of the rectangular matrix B, determines the corresponding elements of B'=EB. hsh2col is used in qzival and qzi.

Function Parameters: void hsh2col (la,lb, u, i,al,a2,a, b)

la: int; entry: the lower bound of the running column subscript of a (value of la above);

Ib: int; entry: the lower bound of the running column subscript of b (value of Ib above);

u: int;

Copyright 1995 by CRC Press, Inc

Page 274: Numerical Library in C for Scientists and Engineers A

entry: the upper bound of the running column subscript of a and b (value of u above);

i: int; entry: the lower bound of the running row subscript of a and b (value of i above);

i+l is the upper bound; al ,a2: float;

entry: a1 and a2 are the i-th and (i+l)-th component of the vector to be transformed, respectively (values of Mkj (k=i,i+l) above);

a: float a[i: i+ l,la:u]; entry: the given matrix (value of A above); exit: the transformed matrix (value of A' above);

b: float b[i:i+l,lb:u]; entry: the given matrix (value of B above); exit: the transformed matrix (value of B' above).

Function used: hshvecmat.

void hsh2col(int la, int lb, int u, int i, float al, float a2, float **a, float **b)

i ' float *allocate-real-vector(int, int) ;

void free-real-vector(f1oat *, int) ; void hshvecmat (int, int, int, int, float, float [I , float * * ) ; float *v, dl, d2, sl, s2, r, d, c;

if (a2 ! = 0.0) { v=allocate-realvector(i,i+l); dl=fabs (al) ; d2=fabs (a2) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; if (d2 <= dl) {

r=d2/dl; d=sqrt (l.O+r*r) ; c = -1.0-l.O/d; v [i+l] =sl*s2*r/ (l.O+d) ;

) else { r=dl/d2 ; d=sqrt (l.O+r*r) ; c = -1.0-r/d; v [i+ll =sl*s2/ (r+d) ;

1 v[il=l.O; hshvecmat(i,i+l,la,u,c,v,a) ; hshvecmat(i,i+l,lb,u,c,v,b) ; f ree-real-vector (v, i) ;

1 1

(a) Given the values of three elements Mkj (k=i,i+l,i+2) belonging to a certain column of a rectangular matrix M, determines a vector v such that all rows except the i-th, (i+l)-th and (i+2)-th of M and M'=EM agree, where

E = I - 2wT/vTv and Adij = Adij+, = 0 and, (b) given the elements A,, (k=i,i+l,i+2; j=la, ..., u) of the rectangular matrix A, determines the corresponding elements of A'=EA and, (c) given the elements Bkj

Copyright 1995 by CRC Press, Inc

Page 275: Numerical Library in C for Scientists and Engineers A

(k=i,i+l,i+2; j=lb, ..., u) of the rectangular matrix B, determines the corresponding elements of B1=EB, hsh3col is used in qzival and qzi.

Function Parameters: void hsh3col (Ia,lb,u,i,al,a2,a3,a, b)

la: int; entry: the lower bound of the running column subscript of a (value of la

above); Ib: int;

entry: the lower bound of the running column subscript of b (value of Ib above);

U: int; entry: the upper bound of the running column subscript of a and b (value of

u above); i: int;

entry: the lower bound of the running row subscript of a and b (value of i above);

i+2 is the upper bound; al,a2,a3: float;

entry: a l , a2 and a3 are the i-th, (i+l)-th and (i+2)-th component of the vector to be transformed, respectively (values of Mkj (k=i,i+l,i+2) above);

a: float a[i: i+2, la: u]; entry: the given matrix (value of A above); exit: the transformed matrix (value of A' above);

b : float b[i:i+2,lb:u]; entry: the given matrix (value of B above); exit: the transformed matrix (value of B' above).

Function used: hshvecmat.

void hsh3col(int la, int lb, int u, int i, float al, float a2, float a3, float **a, float **b)

( float *allocate real vector (int, int) ; void free-real-?ector(float *, int); void hshvecmat (int, int, int, int, float, float I 1 , float * * ) ; float c,*v,dl,d2,d3,sl,s2,s3,rl,r2,r3,d;

if (a2 ! = 0.0 I I a3 ! = 0.0) { v=allocate~real~vector(i,i+2); dl=fabs (all ; d2=fabs (a2) ; d3=fabs (a3) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; s3 = (a3 >= 0.0) ? 1.0 : -1.0; if (dl >= d2 && dl >= d3) (

r2=d2/dl; r3 =d3 /dl ; d=sqrt(l.O+rZ*rZ+r3*r3); c = -1.0-(l.O/d); d=l.O/(l.O+d); v [i+l] =sl*sZ*rZ*d; v [i+21 =sl*s3*r3*d;

} else if (d2 >= dl && d2 >= d3) { rl=dl/d2;

Copyright 1995 by CRC Press, Inc

Page 276: Numerical Library in C for Scientists and Engineers A

r3=d3/d2; d=sqrt(l.O+rl*rl+r3*r3); c = -1.0- (sl*rl/d) ; d=l. 0/ (rl+d) ; v [i+ll =sl*s2*d; v [i+21 =sl*s3*r3*d;

} else { rl=dl/d3 ; r2=d2/d3 ; d=sqrt(l.O+rl*rl+r2*r2); c = -1.0- (sl*rl/d) ; d=l. 0/ (rl+d) ; v [i+ll =sl*s2*r2*d; v[i+2] =sl*s3*d;

1 v[il =l.O; hshvecmat (i,i+2,la,u,c,v,a) ; hshvecmat (i,i+2,lb,u, c,v,b) ; free-real-vector (v, i) ;

1 1

(a) Given the values of two elements Mi,, (k=jj+l) belonging to a certain row of a rectangular matrix M, determines a vector v such that all columns except the j-th, (j+l)-th of M and M'=ME agree, where E=I-2wTIvTv and Mij=O and, (b) given the elements Ai,, (i=l, ..+a; k=jj+l) of the rectangular matrix A, determines the corresponding elements of A1=AE and, (c) given the elements Bi,k (i=I, ..., ub; k=jj+l) of the rectangular matrix B, determines the corresponding elements of B1=BE and, (d) given the elements A,, (i=l, ...,wc; k=jj+l) of the rectangular matrix X, determines the corresponding elements of X1=XE. hsh2row3 is used in qzi.

Function Parameters: void hsh2row3 (I,ua,ub,wc,j,al,a2,a,b,x)

I: int; entry: the lower bound of the running row subscript of a, b and x (value of I above);

ua: int; entry: the upper bound of the running row subscript of a (value of ua above);

ub: int; entry: the upper bound of the running row subscript of b (value of ub above);

wc: int; entry: the upper bound of the running row subscript of x (value of wc above);

j : int; entry: the lower bound of the running column subscript of a, b and x (value of j

above); j+ l is the upper bound;

al,a2: float; entry: a1 and a2 are the j-th and (j+l)-th component of the vector to be transformed,

respectively (values of M,,, (k=jj+l) above); a: float a[l:ua,jj+l];

entry: the given matrix (value of A above); exit: the transformed matrix (value of A' above);

b: float b[l:ub,jj+l]; entry: the given matrix (value of B above);

Copyright 1995 by CRC Press, Inc

Page 277: Numerical Library in C for Scientists and Engineers A

exit: the transformed matrix (value of B' above); x: float x[l:ux,j:j+l];

entry: the given matrix (value of X above); exit: the transformed matrix (value of X' above).

Function used: hshvectam.

void hsh2row3(int 1, int ua, int ub, int ux, int j, float al, float a2, float **a, float **b, float **x)

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void hshvectarn(int, int, int, int, float, float [ I , float * * ) ; float *v,dl,d2,sl,s2,r,d,c;

if (a2 ! = 0.0) { v=allocate-real-vector(j,j+l); dl=fabs (al) ; d2=fabs (a2) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; if (d2 c= dl) {

r=d2/dl; d=sqrt (l.O+r*r) ; c = -1.0-l.O/d; v[j] =sl*sz*r/ (l.O+d) ;

) else { r=dl/d2 ; d=sqrt (l.O+r*r) ; c = -1.0-r/d; v [ j I =sl*s2/ (r+d) ;

1

(a) Given the values of two elements Mi,, (k=jj+l) belonging to a certain row of a rectangular matrix M, determines a vector v such that all columns except the j-th, (j+l)-th of M and M'=ME agree, where E=I-2wTlvTv and Mij=O and, (b) given the elements Ai,, (i=l, ..., ua; k=jj+l) of the rectangular matrix A, determines the corresponding elements of AJ=AE and, (c) given the elements Bi,, (i=I, ..., ub; k=jj+l) of the rectangular matrix B, determines the corresponding elements of BJ=BE. hsh2row2 is used in qzival.

Function Parameters: void hsh2row2 (I,ua,ub,j,al,a2,a, b)

I: int; entry: the lower bound of the running row subscript of a and b (value of I above);

ua: int; entry: the upper bound of the running row subscript of a (value of ua above);

ub: int; entry: the upper bound of the running row subscript of b (value of ub above);

j : int;

Copyright 1995 by CRC Press, Inc

Page 278: Numerical Library in C for Scientists and Engineers A

entry: the lower bound of the running column subscript of a and b (value o f j above); j+l is the upper bound;

al,a2: float; entry: a1 and a2 are the j-th and G+l)-th component of the vector to be transformed,

respectively (values of M,, (k=jj+l) above); a: float a[a: ua,jj:j+ I];

entry: the given matrix (value of A above); exit: the transformed matrix (value of A ' above);

b: float b[lb:ub,jj+l]; entry: the given matrix (value of B above); exit: the transformed matrix (value of B' above).

Function used: hshvectarn.

#include cmath.h>

void hsh2row2(int 1, int ua, int ub, int j, float al, float a2, float **a, float **b)

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void hshvectam(int, int, int, int, float, float [ I , float * * ) ; float *v, dl, d2, sl, s2, r, d, c;

if (a2 != 0.0) { v=allocate-real-vector(j,j+l); dl=fabs (al) ; d2=fabs (a2) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; if (d2 c= dl) (

r=d2/dl; d=sqrt (l.O+r*r) ; c = -1.0-l.O/d; v[j] =sl*s2*r/ (l.O+d) ;

) else ( r=dl/d2 ; d=sqrt (l.O+r*r) ; c = -1.0-r/d; v [ j I =sl*s2/ (r+d) ;

I v[j+ll =l.O; hshvectam(l,ua, j, j+l,c,v,a) ; hshvectam(l,ub, j , j+l,c,v,b) ; f ree-real-vector (v, j ) ;

I 1

(a) Given the values of three elements M,, (k=jj+l j+2) belonging to a certain row of a rectangular matrix M, determines a vector v such that all columns except the j-th, G+l)-th and (j+2)-th of M and M'=ME agree, where E = I - ~ w ~ I v ~ v and M',j=M'i+,j=O and, (b) given the elements Ai,k (i=I, ..., U; k=jj+l j+2) of the rectangular matrix A, determines the corresponding elements of A '=AE and, (c) given the elements Bi,, (i=I, ..., U; k=jj+l j+2) of the rectangular matrix B, determines the corresponding elements of B'=BE and, (c) given the elements X,,, (i=l, ..., w; k=jj+l j+2) of the rectangular matrix X, determines the corresponding elements of X'=XE. hsh3row3 is used in qzi.

Copyright 1995 by CRC Press, Inc

Page 279: Numerical Library in C for Scientists and Engineers A

Function Parameters: void hsh3row3 (I,u,~~,j,al,a2,a3,a, b,x)

I : int; entry: the lower bound of the running row subscript of a, b and x (value of

l above); U : int;

entry: the upper bound of the running row subscript of a and b (value of u above);

UX: int; entry: the upper bound of the running row subscript of x (value of ux

above); j : int;

entry: the lower bound of the running column subscript of a , b and x (value of j above); j+2 is the upper bound;

al,aZ,a3: float; entry: a l , a2 and a3 are the j-th, (j+l)-th and (j+2)-th component of the vector

to be transformed, respectively (values of M , , (k=j j+ l j+2) above); a: float a[]: uj:j+2];

entry: the given matrix (value of A above); exit: the transformed matrix (value of A' above);

b: float b[l:uj.j+2]; entry: the given matrix (value of B above); exit: the transformed matrix (value of B' above);

x: float x[l:wcj.j+2]; entry: the given matrix (value of X above); exit: the transformed matrix (value of X' above).

Function used: hshvectam.

void hsh3row3(int 1, int u, int ux, int j, float al, float a2, float a3, float **a, float **b, float **x)

I float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void hshvectam(int, int, int, int, float, float [I , float * * ) ; float *v, c, dl, d2, d3, sl, s2, s3, rl, r2, r3, d;

if (a2 ! = 0.0 I I a3 ! = 0.0) ( v=allocate-real_vector(j,j+2); dl=fabs (al) ; d2=fabs (a2) ; d3=fabs (a3) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; s3 = (a3 >= 0.0) ? 1.0 : -1.0; if (dl >= d2 && dl >= d3) (

r2=d2/dl; r3=d3 /dl ; d=sqrt(l.O+rZ*r2+r3*r3); c = -1.0-(l.O/d); d=l.O/ (l.O+d) ; v [j+l] =sl*s2*r2*d; v [ jl =sl*s3*r3*d;

) else if (d2 >= dl && d2 >= d3) ( rl=dl/d2 ; r3=d3 /d2 ; d=sqrt (l.O+rl*rl+r3 *r3) ;

Copyright 1995 by CRC Press, Inc

Page 280: Numerical Library in C for Scientists and Engineers A

c = -1.0- (sl*rl/d) ; d=l. 0/ (rl+d) ; v[j+ll =sl*sZ*d; v[j] =sl*s3*r3*d;

) else { rl=dl/d3 ; r2=d2/d3 ; d=sqrt(l.O+rl*rl+r2*rZ); c = -1.0- (sl*rl/d) ; d=l. O/ (rl+d) ; v [ j+l] =sl*sZ*rZ*d; v [j ] =sl*s3 *d;

1

(a) Given the values of three elements (k==jj+lj+2) belonging to a certain row of a rectangular matrix M, determines a vector v such that all columns except the j-th, (j+l)-th and (jt-2)-th of M and M'=ME agree, where E=I-2wT/vTv and M'ij=M'i+,j=O and, (b) given the elements Ai,k (i=I, ..., U; k=jj+ 1 j+2) of the rectangular matrix A, determines the corresponding elements of AJ=AE and, (c) given the elements Bi,k (i=I, ..., U; k=jj+l j+2) of the rectangular matrix B, determines the corresponding elements of B'=BE. hsh3row2 is used in qzival.

Function Parameters: void hsh3row2 (I, u,j, a l , a2, a3, a, b)

I: int; entry: the lower bound of the running row subscript of a and b (value of 1

above); U: int;

entry: the upper bound of the running row subscript of a and b (value of u above);

j: int; entry: the lower bound of the running column subscript of a and b (value of

j above); j+2 is the upper bound;

al,a2,a3: float; entry: al, a2 and a3 are the j-th, (j+l)-th and (j+2)-th component of the vector

to be transformed, respectively (values of M i , (k=j j+ l j+2) above); a: float a[l:u j3+2];

entry: the given matrix (value of A above); exit: the transformed matrix (value of A' above);

b: float b[l:~jY+2]; entry: the given matrix (value of B above); exit: the transformed matrix (value of B' above).

Function used: hshvectarn.

Copyright 1995 by CRC Press, Inc

Page 281: Numerical Library in C for Scientists and Engineers A

void hsh3row2(int 1, int u, int j, float al, float a2, float a3, float **a, float **b)

I 1

float *allocate-real-vector(int, int); void free real vector(f1oat *, int); void hshv&tamTint, int, int, int, float, float [ I , float * * ) ; float *v, c, dl, d2, d3, sl, s2, s3, rl, r2, r3, d;

if (a2 != 0.0 a3 ! = 0.0) { v=allocate~real~vector(j,j+2); dl=£ abs (al) ; d2=fabs (a2) ; d3=fabs (a3) ; sl = (a1 >= 0.0) ? 1.0 : -1.0; s2 = (a2 >= 0.0) ? 1.0 : -1.0; s3 = (a3 >= 0.0) ? 1.0 : -1.0; if (dl >= d2 && dl >= d3) (

r2=d2/dl; r3 =d3 /dl ; d=sqrt(l.O+r2*r2+r3*r3) ; c = -1.0-(l.O/d); d=l. O/ (l.O+d) ; v [ j+l] =sl*s2*r2*d; v[j] =sl*s3*r3*d;

) else if (d2 >= dl && d2 >= d3) { rl=dl/d2 ; r3 =d3 /d2 ; d=sqrt(l.O+rl*rl+r3*r3) ; c = -1.0- (sl*rl/d) ; d=l. 0/ (rl+d) ; v [j+ll =sl*s2*d; v [ j] =sl*s3*r3*d;

} else { rl=dl/d3 ; r2=d2/d3 ; d=sqrt(l.O+rl*rl+r2*r2); c = -1.0- (sl*rl/d) ; d=l. 0/ (rl+d) ; v [ j+l] =sl*s2*r2*d; v[jl =sl*s3*d;

1 v[j+2] =1.0; hshvectam(l,u, j, j+2, c,v, a) ; hshvectam(l,u, j, j+2, c,v, b) ; f ree-real-vector (v, j ) ;

1 1

3.15 Singular values

3.1 5.1 Real bidiagonal matrices

A. qrisngvalbid

Computes, by use of a variant of the QR algorithm the singular values of a bidiagonal nxn matrix A, i.e. the elements d,, ..., d,, of the diagonal matrix D for which A=UDVT, where UTU=VTV=I (nxn unit matrix).

Function Parameters: int qrisngvalbid (4 b, n,em)

qrisngvalbid given the number of singular values not found, i.e. a number not equal to zero if the number of iterations exceeds em[4J;

Copyright 1995 by CRC Press, Inc

Page 282: Numerical Library in C for Scientists and Engineers A

d

b:

n:

em:

float d[l :n]; entry: the diagonal of the bidiagonal matrix; exit: the singular values; float b[l:n]; entry: the super diagonal of the bidiagonal matrix in b[l:n-I]; int; entry: the length of b and 4

float em[l: 71; entry: em[l]: the infinity norm of the matrix; em[2]: the relative precision in the singular values; em[4]: the maximal number of iterations to be performed; em[6]: the minimal non-neglectable singular value; exit: em[3]: the maximal neglected superdiagonal element; em[5]: the number of iterations performed; em[7]: the numerical rank of the matrix; i.e. the number of singular values greater

than or equal to em[6].

Method: The method is described in detail in [WiR71]. qrisngvalbid is a rewriting of part of the procedure SVD published there.

int qrisngvalbid(f loat d[l , float b [I , int n, float em [I ) I 1

int nl,k,kl,i,il,count,max,rnk; float tol, bmax, z, x, y, g, h, f, c, s, min;

tol=em [2l *em [ll ; count=O; bmax=O .0 ; max=em [dl ; min=em [61 ; rnk=n; do {

k=n; nl=n-1; while (1) {

k- - ; if (k <= 0) break; if (fabs (b [kl ) >= tol) {

if (fabs(dIk1) < tol) { C=O . 0 ; s=1.0 ; for (i=k; i<=nl; i++) {

f =s*b [il ; b[il *= c; il=i+l; if (fabs(f) < tol) break; g=d [ill ; d [ill =h=sqrt (f*f+g*g) ;

break; 1

el'se { if (fabs (b [k] ) > bmax) bmax=fabs (b [kl ) ; break;

1

Copyright 1995 by CRC Press, Inc

Page 283: Numerical Library in C for Scientists and Engineers A

i f ( k == n l ) ( i f (d [n] < 0 . 0 ) d [n l = - d [ n l ; i f (d [n] <= min) r n k - - ; n = n l ;

) e l s e { count++; i f (count > max) break ; k l = k + l ; z=d [nl ; x=d [ k l l ; y=d [ n l l ; g = ( n l == 1) ? 0 .0 : b[n l -11 ; h=b [ n l l ; f = ( ( y - z ) * ( y + z ) + (g-h) * ( g + h ) ) / ( 2 . 0 * h * ~ ) ; g = s q r t ( f * f + l . O ) ; f = ( ( x - z ) * (x+z)+h* (y / ( ( f c 0 . 0 ) ? f - g : f + g ) - h ) ) /x ; c = s = 1 . 0 ; f o r ( i = k l + l ; i c = n ; i + + ) (

il=i-1; g=b [ i l l ; y=d [ i l ; h=s*g; g *= c ; z = s q r t ( f *f+h*h) ; c = f / z ; s = h / z ; i f (il ! = k l ) b [ i l - l l = z ; f=x*c+g*s; g=g*c-x*s; h=y*s ;

} w h i l e ( n > 0) ; em [ 3 I =bmax; em [51 =count ; em [71 =rnk; r e t u r n n ;

1

B. qrisngvaldecbid

Computes by use of a variant of the QR algorithm the singular value decomposition of an mxn matrix A (m 2 n), i.e. the mxn matrix U, the nxn diagonal matrix D, and the nxn matrix V for which A=UDV*, where UTU=VTv=I (nxn unit matrix). It is assumed that A has been reduced to bidiagonal form by preliminary pre- and post-multiplication by matrices of the form

by use of hshreabid.

Function Parameters: int qrisngvaldecbid (d, b,m,n, u,v,em)

qrisngvaldecbid: given the number of singular values not found, i.e. a number not equal to zero if the number of iterations exceeds em[4];

d: float d[I:n]; entry: the diagonal of the bidiagonal matrix; exit: the singular values;

Copyright 1995 by CRC Press, Inc

Page 284: Numerical Library in C for Scientists and Engineers A

float b[l:n]; entry: the super diagonal of the bidiagonal matrix in b[l:n-I]; int; entry: the number of rows of the matrix u; int; entry: the length of b and d, the number of columns of u and the number of columns

and rows of v; float u[l:m, l:n]; entry: the premultiplying matrix as produced by pretfmmat; exit: the premultiplying matrix U of the singular value decomposition UDVT; float v[l:n, l:n]; entry: the transpose of the postmultiplying matrix as produced by psttfmmat; exit: the transpose of the postmultiplying matrix V of the singular value

decomposition; em: float em[l: 71;

entry: em[l]: the infinity norm of the matrix; em[2]: the relative precision in the singular values; em[4]: the maximal number of iterations to be performed; em[6]: the minimal non-neglectable singular value; exit: em[3]: the maximal neglected superdiagonal element; em[5]: the number of iterations performed; em[7]: the numerical rank of the matrix; i.e. the number of singular values greater

than or equal to em[6].

Function used: rotcol.

Method: The method is described in detail in [WiR71]. qrisngvaldecbid is a rewriting of part of the procedure SVD published there.

void rotcol (int, int, int, int, float **, float, float) ; int n0,nl,k,kl,i,il,count,max,rnk; float tol,bmax,z,x,y,g,h,f,c,s,min;

tol=em [21 *em [ll ; count=O ; bmax=O . 0 ; max=em [ 4 I ; rnin=em [6] ; zk;nO=n;

k=n; n k n - 1 ; while (1) {

k- - ; if (k <= 0) break; if (fabs (b [kl ) >= tol) {

if (fabs(d[kl) c tol) { c=o.o; s=1.0; for (i=k; ic=nl; i++) {

f =s*b [il ;

Copyright 1995 by CRC Press, Inc

Page 285: Numerical Library in C for Scientists and Engineers A

b [il *= c; il=i+l; if (fabs(f) c tol) break; g=d [ill ; d [ill =h=sqrt (f*f+g*g) ; c=g/h; s = -f/h; rotcol (l,m,k, il,u,c,s) ;

1 break;

if (k == nl) { if (d[nl c 0.0) {

d [nl = -d [nl ; for (i=l; i<=nO; i++) v[i] 11-11 = -v[il [nl ;

1 if (d[n] <= min) rnk--; n=nl ;

} else { count++; if (count > max) break; kl=k+l; z=d [nl ; x=d [kll ; y=d [nl] ; g = (nl == 1) ? 0.0 : b[nl-11; h=b [nl] ; f= ( (y-z) * (y+z) + (g-h) (g+h) ) / (2.0*h*y) ; g=sqrt (f*f+l. 0) ; f=((x-z)*(x+z)+h*(y/((f c 0.0) ? f-g : f+g)-h))/x; c=s=1.0; for (i=kl+l; ic=n; i++) {

il=i-1; g=b [ill ; y=d[il ; h=s*g; g *= c; z=sqrt (f *f+h*h) ; c=f/z; s=h/z; if (il != kl) b[il-11 =z; f=x*c+g*s; g=g*c-x*s; h=y*s; y *= c; rotcol (l,nO,il,i,v,c,s) ; d [ill =z=sqrt (f*f+h*h) ; c=f/z; s=h/z; f=c*g+s*y; x=c*y-s*g; rotcol (l,m,il, i,u,c,s) ;

1 b [nll =f; d [nl =x;

1 1

} while (n > 0) ; em [31 =bmax; em [51 =count; em [71 =rnk; return n;

1

3.15.2 Real full matrices

Copyright 1995 by CRC Press, Inc

Page 286: Numerical Library in C for Scientists and Engineers A

A. qrisngval

Computes the singular values of a given matrix. The matrix is first transformed to bidiagonal form by calling hshreabid, and then the singular values are calculated by qrisngvalbid.

Function Parameters: int qrisngval (a, m, n,val, em)

qrisngval: given the number of singular values not found, i.e. a number not equal to zero if the number of iterations exceeds em[4];

a: float a[l:m,l:n]; entry: the input matrix; exit: data concerning the transformation to bidiagonal form;

m: int; entry: the number of rows of the matrix a;

n: int; entry: the number of columns of a, n should satisfy d m ;

val: float val[l:n]; exit: the singular values;

em: float em[O: 71; entry: em[O]: the machine precision; em[2]: the relative precision in the singular values; em[4]: the maximal number of iterations to be performed; em[6]: the minimal non-neglectable singular value; exit: em[l]: the infinity norm of the matrix; em[3]: the maximal neglected superdiagonal element; em[5]: the number of iterations performed; em[7]: the numerical rank of the matrix; i.e. the number of singular values greater

than or equal to em[6].

Functions used: hshreabid, qrisngvalbid.

int qrisngval(f1oat **a, int m, int n, float val[l, float ern[]) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void hshreabid (f loat **, int, int, float [I , float [I , float [I ) ; int qrisngvalbid(f1oat [I , float [ I , int, float I 1 ) ; int i; float *b;

b=allocate-real-vector (1, n) ; hshreabid(a,m,n,val,b,em); i=qrisngvalbid(val,b,n,em); free-real-vector (b, 1) ; return i;

1

B. qrisngvaldec

Calculates the singular value decomposition A=UDVT of a given matrix A. The matrix is

Copyright 1995 by CRC Press, Inc

Page 287: Numerical Library in C for Scientists and Engineers A

first transformed to bidiagonal form by calling hshreabid, the two transforming matrices are calculated by calling psttfmmat and pretfmmat, and finally the singular value decomposition is calculated by qrisngvaldecbid.

Function Parameters: int qrisngvaldec (a, m, n, val, v, em)

qrisngvaldec: given the number of singular values not found, i.e. a number not equal to zero if the number of iterations exceeds em[4];

a : float a[l:m,l:n]; entry: the given matrix; exit: the matrix U in the singular value decomposition UDVT;

m: int; entry: the number of rows of the matrix a ;

n: int; entry: the number of columns of a, n should satisfy nlm;

val: float val[l:n]; exit: the singular values;

v: float v[l:n,l:n]; exit: the transpose of matrix V in the singular value decomposition;

em: float em[0: 71; entry: em[O]: the machine precision; em[2]: the relative precision in the singular values; em[4]: the maximal number of iterations to be performed; em[6]: the minimal non-neglectable singular value; exit: em[l]: the infinity norm of the matrix; em[3]: the maximal neglected superdiagonal element; em[S]: the number of iterations performed; em[7]: the numerical rank of the matrix; i.e. the number of singular values greater

than or equal to em[6].

Functions used: hshreabid, psttfmmat, pretfmmat, qrisngvaldecbid.

int qrisngvaldec(f1oat **a, int m, int n, float val[l, float **v, float em [ I )

{ float *allocate real vector(int, int); void free-real-vectoi;(float * , int); void hshreabid(f1oat ** , int, int, float [ I , float [ I , float [ I ) ; void psttfmmat (float ** , int, float ** , float [I ) ; void pretfmmat (float ** , int, int, float [ I ; int qrisngvaldecbid (float [ I , float [I , int, int, float ** ,

float **, float [I); int i; float *b;

b=allocate-real-vector(1,n); hshreabid(a,m,n,val, b, em) ; psttfmmat (a,n,v, b) ; pretfmmat (a,m,n,val) ; i=qrisngvaldecbid(val,b,m,n,a,v,em); free-real-vector (b, 1) ; return i;

1

Copyright 1995 by CRC Press, Inc

Page 288: Numerical Library in C for Scientists and Engineers A

3.16 Zeros of polynomials

3.16.1 Zeros of general real polynomials

A. zerpol

Attempts to determine, by use of Laguerre's method [Dek66] and composite deflation [Ad67, PeW71, Rey771, the zeros of the polynomial

where the a, are real and an+O. For real zeros, Laguerre's method makes use of the recursion

Again for real zeros, the deflation used may by described as follows: with a a derived approximation to a zero of P(z), and r determined from the condition that I u p i / takes its maximum value for 0 5 i 5 n when i=r, pi and q, are obtained by use of the recursions

Pn-, = anr Pi-, = ai + ffPi (i=n-1, ..., r+l) q,, = -a/ct, qi = (a, - q,Ja (i=l, ..., r-I)

(with obvious modifications if r-0 or r=n), the polynomial

is formed; its roots are those of P(z) with a omitted. If all zeros of P(z) are real, the above deflation may be continued.

Function Parameters: int zerpol (n, a, em,re, im, d)

zerpol: given the number, k, of zeros not found; n: int;

entry: the degree of the polynomial; a: float a[O:n];

entry: the coefficients of the polynomial (values of a, above); em: float em[0:4];

entry: em[O]: the machine precision; em[l]: the maximal number of iterations allowed for each zero (e.g. 40); exit: em[2]: fail indication;

0 successful call;

Copyright 1995 by CRC Press, Inc

Page 289: Numerical Library in C for Scientists and Engineers A

upon entry degree n 5 0; upon entry leading coefficient a[n]=O; number of iterations exceeded em[l]; number of new starts in the last iteration; if upon exit, em[2]=3 and em[3]<5 then it may be useful to start again with a higher value of em[l]; total number of iterations performed;

re,im: float re[l:n], im[l:n]; exit: the real and imaginary parts of the zeros of the polynomial; the members of

each nonreal complex conjugate pair are consecutive; d: float d[O:n];

exit: if the call is unsuccessful and only n-k zeros have been found, then d[O:k] contains the coefficients of the (deflated) polynomial; furthermore the zeros found are delivered in re[k+l:n], im[k+l:n], whereas the remaining parts of re and im contain no information.

Functions used: comabs, comsqrt.

int zerpol (int n, float a [I , float em[] , float re [I , float im [I , float d [I )

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float comabs(float, float); void comsqrt (float, float, float * , float * ) ; int zerpolfunction (int, float [I , float [I , float,

float, float, int * , float * ) ; int i,totit,it,fail,start,up,max,giex,itmax,control,ih,m,split; float x, y,newf ,oldf ,maxrad, ae, tol,hl, h2,ln2, f [ I tries I ,

h,side,slre,slirn,s2re,s2im,dx,dy,h3,h4,h5,h6,*b;

totit=it=fail=up=start=O; ln2=log(2.0) ; newf=FLT-W; ae=FLT MIN; giex=log (newf) 111-12-40.0; tol=em [O] ; itmax=em [ll ; for (i=O; ic=n; i++) d[il=a[n-il ; if (n c= 0)

fail-1; else

if (d[O] == 0.0) fail=2; if (fail > 0) {

em[2] =fail; em 131 =start; em [ 4 1 =totit; for (i=(n-1)/2; i>=O; i--1 (

tol=d [il ; d [il =d [n-il ; d [n-i] =tol;

1 return n;

\ khile (d[n] == 0.0 && n > 0) {

re [nl =im [nl =O . 0; n--;

1 x=y=O .o; while (n s 2) {

/ * control * / if (it > itmax) {

totit += it:

Copyright 1995 by CRC Press, Inc

Page 290: Numerical Library in C for Scientists and Engineers A

f ail=3 ; em[2] =fail; em [31 =start; em 141 =totit; for (i=(n-1)/2; i>=O; i--) (

tol=d [il ; d [il =d [n-il ; d In-il =tol;

\ keturn n;

) else if (it == 0) {

maxrad=O.O; max= (giex-log(fabs (d [Ol ) ) /ln2) /n; for (i=l; ic=n; i++) {

hl = (d[il == 0.0) ? 0.0 : exp(log(fabs(d[il/d[~l ))/i); if (hl > maxrad) maxrad=hl;

1 for (i=l; ic=n-1; i++)

if (d[il ! = 0.0) { ih= (giex-log(fabs (dlil ) ) /ln2) / (n-i) ; if (ih c max) max=ih;

\ max=max*ln2/10g (n) ; side = -d[ll /d [Ol ; side = (fabs(side) c tol) ? 0.0 :

((side > 0.0) ? 1.0 : -1.0); if (side == 0.0) {

tries 171 =tries [2] =maxrad; tries191 = -maxrad; tries [6] =tries [41 =tries 131 =maxrad/sqrt (2.0) ; tries [51 = -tries [31 ; tries [lo] =tries 181 =tries [l] =O. 0;

) else { tries [8] =tries [4] =maxrad/sqrt (2.0) ; tries [I] =side*maxrad; tries [3] =tries 141 *side; tries [61 =maxrad; tries [71 = -tries [31 ; tries [91 = -tries [ll ; tries [2] =tries 151 =tries [lo] =O. 0;

1 if (comabs (x, y) > 2.0*maxrad) x=y=O . 0 ; control=O;

) else { if (it > 1 && new£ >= oldf) {

up++ ; if (up == 5 && start c 5) {

start++; up=o; x=tries [2*start-11 ; y=tries [2*startl ; control=O;

) else control=l;

) else control=l;

1 / * end of control * / if (control) (

/* laguerre * / if (fabs(f 101 ) > fabs(f [ll)) {

hl=f [Ol ; h6=f [ll /hl; h2=f [21 +h6*f [31 ; h3=f 131 -h6*f [21 ; h4=f [41 +h6*f [51 ; h5=f 151 -h6*f [41 ; h6=h6*f [ll +hl;

) else { hl=f [ll ; h6=f [O] /hl; h2=h6*f [21 +f [31 ; h3=h6*f [31 -f 121 ; h4=h6*f 141 +f 151 ;

Copyright 1995 by CRC Press, Inc

Page 291: Numerical Library in C for Scientists and Engineers A

ilre=h2/h6; slim=h3/h6; h2=slre*slre-slim*slim; h3=2.0*slre*slim; s2re=h2-h4/h6; s2im=h3-h5/h6; hl=s2re*s2re+s2im*s2im; hl = (hl != 0.0) ? (s2re*h2+~2im*h3)/hl : 1.0; m = (hl > n-1) ? ((n > 1) ? n-1 : 1) : ((hl > 1.0) ? hl : 1) ; hl=(float) (n-m)/(float) m; comsqrt (hl* (n*s2re-h2) , hl* (n*s2im-h3) , &h2, &h3) ; if (slre*h2+slim*h3 < 0.0) {

h2 = -h2; h3 = -h3;

h2 += slre; h3 += slim; hl=h2*h2+h3*h3; if (hl == 0.0) {

dx = -n; dy=n;

) else { dx 5 -n*h2/hl; dy=n*h3/hl;

hl=f abs (x) *tol+ae; h2=fabs (y) *tol+ae; if (fabs(dx) < hl && fabs(dy) < h2) {

dx = (dx == 0.0) ? hl : ((dx > 0.0) ? hl : -hl); dy = (dy == 0.0) ? h2 : ((dy > 0.0) ? h2 : -h2);

) x += dx; y += dy; if (comabs(x, y) > 2 .O*maxrad) {

hl = (fabs (x) > fabs (y)) ? fabs (x) : fabs (y) ; h2=log (hl) /ln2+1.0-max; if (h2 > 0.0) {

h2=pow(2.0,h2) ; x /= h2; y /= h2;

I

) )* end of laguerre * / 1 old£ =newf ; if (zerpolfunction(n,d,f,x,y,tol,&it,&newf)~ (

if (y ! = 0.0 && fabs(y) < 0.1) { h=y ; y=o . 0 ; if (!zerpolfunction(n, d, f,x, y, tol, &it, &newf ) y=h;

I

J

/* deflation * / if (X == 0.0 && y == 0.0)

n- - ; else {

b=allocate-real-vector(0,n-1); if (y == 0.0) {

n--; b[nl = -d[n+ll/x; for (i=l; 1<=n; i++) b [n-il = (b [n-i+ll -d [n-i+ll ) /x; for (i=l; i<=n; i++) d[il += d[i-ll*x;

) else { hl = -2.0*~; h2=x*x+y*y; n -= 2; b [nl =d [n+21 /h2 ;

Copyright 1995 by CRC Press, Inc

Page 292: Numerical Library in C for Scientists and Engineers A

b [n-I]= (d[n+ll -hl*b [nl ) /h2; for (i=2: i<=n: i++)

split=n; h2=fabs (d 11-11 -b 11-11 ) / (fabs (d [nl ) +fibs (b [nl ) ) ; for (i=n-1; i>=O; i--) (

hl=fabs (d [il ) +fabs (b [il ) ; if (hl > tol) (

hl=fabs (d [il -b [il ) /h1; if (hl < h2) (

h2 =hl ; split=i;

J for (i=split+l; ic=n; i++) d [il =b [il ; d [split] = (d [splitl +b [splitl ) /2.0; f ree-real-vector (b, 0) ;

) / * end of deflation * / totit += it; up=start=it=O;

1

im[ll =O.O; } else {

hl = -0.5*d[ll /d[OI ; h2=hl*hl-d[21 /d[01 ; if (h2 >= 0.0) {

re [2] = (hl < 0.0) ? hl-sqrt (h2) : hl+sqrt (h2) ; re [I] =d [21 / (at01 *re [21 ; im[2]=im[ll =0.0;

} else ( re [21 =re [ll =hl; im[2] =sqrt (-h2) ; im[ll = -im[21 ;

1 1

em[2] =fail; em[31 =start; em [4] =totit; return 0;

1 int zerpolfunction(int n, float d[l, float £[I, float x,

float y, float tol, int *it, float *newf) I

/ * this function is used internally by ZERPOL * /

int k,ml,m2; float p,q,qsqrt,f01,f02,f03,fll,f12,f13,f21,f22,f23,stop;

(*it)++; p=2. o*x; q = - (x*x+y*y) ; qsqrt=sqrt (-q) ; fOl=fll=f21=d [OI ; f02=f12=£22=0.0; ml=n-4 ; m2=n-2; stop=fabs(fOl)*O.E; for (k=l; k<=ml; k++) (

f 03=f02; f02=fOl; f01=d [kl +p*f O2+q*f 03; f13=f12; f 12=f 11; fll=fOl+p*fl2+q*fl3; f23=f22; f22=f21;

Copyright 1995 by CRC Press, Inc

Page 293: Numerical Library in C for Scientists and Engineers A

J

if (ml < 0) ml=O; for (k=ml+l; k<=m2; k++) {

f03=f02; f 02=f 01 ; f 01=d [kl +p*f02+q*f03; f13=f12; f12=fll; fll=fOl+p*fl2+q*fl3; stop=qsqrt*stop+fabs(f01);

1

f [S] =y* (6.0*£12-8.0*y*y*f22) ~ t o ~ = ~ s q r t * (qsqrt*stop+£abs (£01) ) +fabs (f [Ol ) ; *newf =f 02=comabs (f [OI , f [ll ) ; return (£02 < (2.0*fabs(x*fol) -8.0* (fabs(f[01 )+fabs(f~l) *qsqrt)+

lo.0*stop)*tol*pow(l.O+to1,4*n+3.0)); 1

B. bounds

Calculates upper bounds for the absolute error in given approximated zeros of a polynomial with real coefficients.

Given approximations ai (i=l, ..., n) to the zeros of a polynomial

with real coefficients, determines centers y, and radii r, of disjoint discs Dl together with positive integers m, such that ml zeros of P(z) are contained in Dl (I=l, ..., n'; m,+ ...+ m,,. =n).

The results upon which the method used is based may be described as follows. Let

~ ( z ) = a, rl[ (z - ai> and Q(z) = R(z) - P(z) = &,z . k=l

Let m of the a;, namely a,(,, (i=l, ..., m) lie near to each

n

rl[ .fk) denote a product

other; let

ir i= l

from which the terms with suffix k(i) (i=l, ..., m) have been removed; set

Copyright 1995 by CRC Press, Inc

Page 294: Numerical Library in C for Scientists and Engineers A

and B, = ai - y (i=l, ..., n). For z on the circle C with center y and suitable radius r,

If 1 Q(z) I <I R(z) 1 for all z on C, then R(z) and R(z)-Q(z) =P(z) have the same number of zeros in C, i.e. if

C contains m zeros of P(z). A suitable value of r may be estimated by iteration: r, is determined from the condition

where d = max 18,(,, I (llilrn), and r from the condition that (r-d)" = I. l(r,-4". For a more detailed description see [Pew7 1, Rey771.

Copyright 1995 by CRC Press, Inc

Page 295: Numerical Library in C for Scientists and Engineers A

Function Parameters: void bounds (n,a, re, im, reEe,abse,recentre, imcentre, bound)

n: int; entry: the degree of the polynomial;

a: float a[O:n]; entry: the coefficients of the polynomial of which re/j]+im/j]*i are the approximated

zeros (values of ai above); re,im: float re[l:n], im[l :n];

entry: real and imaginary parts of approximated zeros of a polynomial such that the members of each nonreal complex conjugate pair are consecutive (values of ai above);

exit: a permutation of the input data; rele: float;

entry: relative error in the non-vanishing coefficients a/j] of the given polynomial; abse: float;

entry: absolute error in the vanishing coefficients a/j] of the given polynomial; if there are no vanishing coefficients, abse should be zero;

recentre, imcentre: float recentrerl :n], imcentrerl :n]; exit: real and imaginary parts of the centers of disks in which some number

of zeros of the polynomial given by a are situated; the number of identical centers denotes the number of zeros in that disk;

bound float bound[l:n]; exit: radius of the disks whose centers are given correspondingly

in recentre and imcentre.

void bounds(int n, float a[], float re[], float im[l, float rele. float abse, float recentre [I , float imcentre [I , float bound [I )

I float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void kcluster (int, int, int, float [ I , float [1 , float [] ,

float [I, float [I, float [I, float [I); int i,j,k,indexl,index2,goon,place,clustin; float h,min,recent,imcent,xk,yk,zk,corr,*rc,*c,*r~e,*~~~~t~

boundin,*wal,*wa2,templ,temp2;

rc=allocate~real~vector(0,n); c=allocate~real~vector(0,n); rce=allocate~real~vector(0,n); clust=allocate~real~vector(l,n); rc [Ol =c [OI =a En] ; rce lo] =fabs (c [Ol ) ;

Copyright 1995 by CRC Press, Inc

Page 296: Numerical Library in C for Scientists and Engineers A

k=O ; for (ill; i<=n; i++) {

rc [il =rce [il =O. 0; c lil =a [n-il ;

I while (k < n) {

k++ ; xk=re [kl ; yk=im [kl ; zk=xk*xk+yk*yk; for (j=k; j>=l; j - - ) rce[jl += rce[j-ll*sqrt(zk); if (yk == 0.0)

for (j=k; j>=l; j--) rclj] - = xk*rc[j-11; else {

k++ ; if (k <= n && xk == re[kl && yk == -im[kl) {

xk = -2.O*xk; for (j=k; j>=l; j--) rcelj] += rce[j-ll*sqrt(zk); for (j=k; j>=2; j--) rclj] += xk*rc[j-ll+zk*rc[j-21; rc [I] += xk*rc [OI ;

, I 1

j rc [Ol =rce [Ol ; corr=l.O6*FLT_MIN; for (i=l; i<=n-1; i++)

rc [i] dabs (rc [il -c [il ) +rce [il *corr* (n+i-2) + rele*fabs (c [il ) +abse;

rc [n] =fabs (rc [n] -c [n] ) +rce [nl *corr* (n-1) +rele*fabs (c [nl ) +abse; for (i=l; i<=n; i++)

kcluster(l,i,n,rc,re,im,recentre,imcentre,b~~nd,~l~st~; goon=l ; while (goon) {

indexl=index2=0; min=FLT-MAX; i=n-clust [nl +l; while !i >= 2) {

3=1; recent=recentre [il ; imcent=imcentre [il ; while (j >= 2) {

j - = clust[j-11; templ=recent-recentre[jl ; temp2=imcent-imcentrelj]; h=sqrt (templ*templ+temp2*temp2) ; if (h < bound[il+bound[jl && h <= min) {

indexl= j ; index2 =i ; min=h;

, 1 j i - = clust [i-11 ;

I 1

if (indexl == 0) goon=o ;

else { if (imcentre [indexll == 0.0) {

if (imcentre [index21 ! = 0.0) clust [index21 I I else

if (imcentre [index21 == 0.0) clust lindexll k=indexl+clust [index11 ; if (k ! = index2) (

/ * shift * / wa~=allocate~real~vector(l,clust[index21); wa2=allocate~real~vector(~,clust[index21~ ; clustin=clust [index21 : - . boundin=bound [index2 1 ; imcent-imcentre [index21 ; recent~recentre [index21 ; for (j=l; j<=clustin; j++) {

place=index2+j-1; wal [ j I =re [place] ; wa2 I j I =im [place] ;

Copyright 1995 by CRC Press, Inc

Page 297: Numerical Library in C for Scientists and Engineers A

I for (jzindex2-1; j>=k; j--) {

place= j+clustin; re [placel =re j I ; im [placel =im [ j I ; clust [placel =clust l jl ; bound [place] =bound [ j I ; recentre [placel =recentre [ jl ; imcentre [placel =imcentre [ j I ;

1 for (j=k+clustin-1; j>=k; j--) {

place=j+l-k; re [j ] =wal [place] ; im [j] =wa2 [place] ; bound [ j I =boundin; clust [ j I =dustin; recentre [ j I =recent; imcentre [ j I =imcent ;

1 iree-real-vector (wal, 1) ; free real vector(wa2.1);

) / * end of-shift * / k=clust [indexll +clust [kl ; kcluster(k,indexl,n,rc,re,im,recentre,imcentre,

bound, clust) ;

1 I

£re=-real-vector (rc, 0) ; free real vector(c,O); f reeIreal-ector (rce, 0) ; free-real-vector(clust,l);

I void kcluster(int k, inf m, int n, float rc [I, float re [ I ,

float im [I , float recentre [I , float imcentre [ I , float bound [I , float clust [I )

1 1

/* this function is used internally by BOUNDS */

int i,stop,l,nonzero; float recent, imcent,d,prod, rad,gr, r, *dist,s,hl,h2, tempi, temp2;

dist=allocate-real-vector(m,m+k-1); recent=re [ml ; imcent=im [ml ; stop=m+k-1; 1 = (imcent == 0 .O) ? 0 : ( (imcent > 0.0) ? 1 : -1) ; nonzero = (1 ! = 0); for (i=m+l; ic=stop; i++) {

recent += re [il ; if (nonzero) {

nonzero=(l =s ((im[il == 0.0) ? 0 : ((im[i]>O.O) ? 1 : -1)));

imcent += im lil ;

kecent /= k; imcent = (nonzero ? imcent/k : 0.0); dzO.0; rad=O .0 ; for (i=m; ic=stop; i++) {

recentre [il =recent; imcentre [il =imcent ; templ=re [il -recent; temp2=im [il -imcent; dist [i] =sqrt (templ*templ+ternp2*temp2) ; if (d c dist [il) d=dist [il ;

I I s=sqrt(recent*recent+imcent*imcent); hl=rc [ll ; h2=rc [OI ; for (i=2; i<=n; i++) hl=hl*s+rc[il; for (i=l; i<=m-1; i++) {

templ=re [il -recent;

Copyright 1995 by CRC Press, Inc

Page 298: Numerical Library in C for Scientists and Engineers A

temp2=im [il -imcent; h2 *= fabs(sqrt(templ*templ+ternp2*temp2) 1 ;

I for (i=m+k; ic=n; i++) {

templ=re [il -recent; temp2=im [il -imcent; h2 *= fabs(sqrt(templ*templ+temp2*temp2));

I

I r=rad; rad=d+exp (log (l.l*gr) /k) ; if (rad == r) rad *= exp(log(l.l)/k) ; s=sqrt(recent*recent+imcent*imcent)+rad; hl=rc 111 ; h2=rc [Ol ; for (i=2; ic=n; i++) hl=hl*s+rc [il ; for (i=l; ic=m-1; i++) (

templ=re [il -recent; temp2=im [il -imcent ; h2 *= fabs (sqrt (templ*templ+temp2*temp2)

1

&(hl == 0.0) ? 0.0 : ((h2 == 0.0) ? -10.0 : hl/h2) ; prod=l .0 ; for (i=m; ic=stop; i++) prod *= (rad-dist [il ) ;

} while (prod c= gr) ; for (i=m; ic=stop; i++) (

bound [il s a d ; clust [il =k;

1

3.16.2 Zeros of orthogonal polynomials

A. allzerortpol

Calculates all zeros of an orthogonal polynomial given by the coefficients of their recurrence relation. allzerortpol determines the roots of the polynomial p,,(x), where

po@) = 1, p 1 b ) = x - b, P ~ + I @ ) = f~-blSP&) - c ~ P ~ - I ( x ) (k=I, ..., n-I)

the bk and c , are being given (ck>O, k= l , ..., n-I). The roots of p,(x) are the eigenvalues of the nxn tridiagonal matrix T for which

T i i i ( i = n ) T , i+ l=~+l , i=c i1 '2 ( i = l , ..., n-I). These eigenvalues are obtained by QR iteration, using a call of qrivalsymtri.

Function Parameters: void allzerortpol (n, b, c,zer, em)

n: int; entry: the degree of the orthogonal polynomial of which the zeros are to be

calculated; b,c: float b[O:n-I], c[O:n-I];

entry: the elements b[i] and c[i], i=O, I , ..., n-I, contain the coefficients of the recurrence relation p,+,(x) =(x-b[i/) *p i(x)-c[i]*pi-I (x), i=O, I , ..., n-I, assuming c[O]=O;

Copyright 1995 by CRC Press, Inc

Page 299: Numerical Library in C for Scientists and Engineers A

exit: the contents of the arrays b and c are not altered; zer: float zer[l:n];

exit: the zeros of the n-th degree orthogonal polynomial; em: float em[0:5];

entry: em[O]: the machine precision; em[2]: the relative tolerance of the zeros; em[#]: the maximal allowed number of iterations (e.g. 5*n); exit: em[l]: the value of max(( b[0] (+l , c[fi ( b[i] 1 +l (i=l ,..., n-2), c[n-1]+ 1 b[n-I] 1); em[3]: the maximum absolute value of the codiagonal elements neglected; em[5]: the number of iterations performed.

Functions used: qrivalsymtri, dupvec.

References: see the procedure selzerortpol.

#include <math.h>

void allzerortpol (int n, float b [I, float c [I, float zer [I , float em[] ) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); int qrivalsymtri (float [I , float [I, int, float [I ) ; void dupvec (int, int, int, float [I, float [I ) ; int i; float nrm, *bb;

for (i=l; i<=n-2; i++) if (c [i] +fabs (b [il ) > nrm) nrm=c [il +fabs (b [il ) ;

if (n s 1) nrm = (nrm+l >= c [n-11 +fabs (b [n-11 ) ? nrmcl. 0 :

(c [n-11 +fabs (b [n-11 ) ) ; em [ll =nrm; for (i=n; i>=l; i--) zer [il =b [i-11 ; dupvec(1,n-l,O,bb,c) ; qrivalsymtri (zer, bb,n, em) ; free-real-vector (bb, 1) ;

1

B. lupzerortpol

Calculates a number of adjacent upper or lower zeros of an orthogonal polynomial given by the coefficients of their recurrence relation. lupzerortpol determines either the m smaller roots or the m larger roots of the polynomial p,(x), where

po(x) = 1, pI($ = x - b, P,+I(X) = (x-bJ~,(x) - C ~ I C - I (x) (k=I, ..., n-I)

the b, and c, are being given (c,>O, k=l ,..., n-I). The roots of pn(x) are the eigenvalues of the nxn tridiagonal matrix T for which

T,i=bi., (i=l, ..., n), T,i+,=~.+I,i=ci"2 (i=l,.,., n-I). The m smaller eigenvalues of this matrix are determined by use of a rational variant of the QR algorithm. The m larger roots ofp,,(x) may be obtained by supplying -b, in place of b, in the above (k=O, ..., n-I) so that the roots of pn(-x) are found, and reversing the signs attached to the values of the roots determined in this way.

Copyright 1995 by CRC Press, Inc

Page 300: Numerical Library in C for Scientists and Engineers A

Function Parameters: void lupzerortpol (n, m, b, c,zer, em)

n: int; entry: the degree of the orthogonal polynomial of which the zeros are to be

calculated; m: int;

entry: the number of zeros to be calculated; b,c: float b[O:n-I], c[O:n-I];

entry: the elements b[i] and c[i], i=O,l, ..., n-I, contain the coefficients of the recurrence relation pi+, (x) =(x-b[i]) *p ,(x)-c[i]*p,, (x), i=O, I, ..., n-I, assuming c[O]=O;

exit: the contents of the arrays b and c are altered; zer: float zer[l :m];

exit: the m lowest zeros are delivered; if the array b[O:n-I] contained the opposite values of the corresponding recurrence coefficients then the opposite values of the m upper zeros are delivered; in either case zer[i] < zer[i+l], i=l, ..., m-I;

em: float em[0:6]; entry: em[O]: em[2]: em[4]: em[6]: exit: em[l/: em[3]: em[5]:

the machine precision; the relative tolerance of the zeros; the maximal allowed number of iterations (e.g. 15*m); if all zeros are known to be positive then 1 else 0;

the value of max( I b[O] 1 +1, c[i]+ I b[i] 1 +1 (i=l, ..., n-2), c[n-I]+ I b[n-I] I); the maximum absolute value of the theoretical errors of the zeros; the number of iterations performed.

Functions used: dupvec, infnrmvec.

Reference: see the procedure selzerortpol.

void lupzerortpol(int n, int m, float b[l, float c[l, float zer[l, float em11 )

float infnrmvec(int, int, int *, float [I ) ; void dupvec (int, int, int, float [I , float [I ) ; int i,posdef,j,k,t,converge; float nrm,dlam, eps, delta, e,ep, err,p, q, qp, r, s,tot;

nrm=fabs (b [Ol ) ; for (i=l: ic-n-2: i++)

nrm = (nrm+l >= c[n-l]+fabs(b[n-11)) ? nrm+l.O : (c [n-11 +fabs (b [n-11 ) ) ;

em [ll =nrm; for (i=n; i>=l; i--) b[il=b[i-11; for (i=n; i>=2; i--) c[il=c[i-11; posdef = (em[6] == 1.0) ; dlam=em [21 ; eps=em [O] ; c [ll =err=q=s=O. 0; tot=b [ll ; for (i=n; i>=l; i--) (

p=q; q=sqrt (c [il ) ;

Copyright 1995 by CRC Press, Inc

Page 301: Numerical Library in C for Scientists and Engineers A

e=b [il -p-q; if (e c tot) tot=e;

1 if (posdef && (tot c 0.0) )

tot=o. 0; else

for(i=l; ic=n; i++) b[il - = tot; t=O; for (k=l; kc=m; k++) {

converge=O; / * next qr transformation */ do {

t++; tot += s; delta=b [nl -s; i=n; e=fabs (eps*tot) ; if (dlam c e) dlam=e; if (delta c= dlam) {

convergezl; break;

1

Pd.0 ; for (i=n-1; i>=k; i--) (

q=b [il -s-e; ;=q/qp; p=p*r+l.O; ep=e*r; b [i+ll =qp+ep; delta=q-ep; if (delta c= dlam) {

converge=l; break;

1 &=c [i] /q; qp=delta+e; c [i+ll =qp*ep;

1 if (converge) break; b [kl =qp; s=qp/p;

} while (tot+s > tot); / * end of qr transformation * / if (!converqe) {

/ * irregular end of iteration, deflate minimum diagonal element */

s=o.o; i=k; delta=qp; for (j=k+l; jc=n; j++)

if (b [jl < delta) {

J

/ * convergence */ if (i c n) c[i+ll=c[il *e/qp; for (j=i-1; j>=k; j--) (

b[j+ll=b[jl -s; c[j+ll =c[jl ;

1 1

b [kl =tot; c [k] = err += fabs (delta) ;

I

C. selzerortpol

Copyright 1995 by CRC Press, Inc

Page 302: Numerical Library in C for Scientists and Engineers A

Calculates a number of adjacent zeros of an orthogonal polynomial given by the coefficients of their recurrence relation [GolW69, L57, St721. selzerortpol determines the subset h, (k=nl,nl +l,...,n2) of the total set of roots h, (k=l, ..., n) (arranged in descending order) of the polynomial p,(x), where

po(x) = 1, p,(x) = x - bo ~ k + l (x) = (x-UP k(x) - ~ k ~ k - I (x) (k=l, ..., n-1)

the b, and c, are being given (c,>O, k=l, ..., n-I). The roots of p,(x) are the eigenvalues of the nxn tridiagonal matrix T for which

b i ( i = n), T,,i+l=T,+,,i=ci"2 (i=l, ..., n-I). These eigenvalues are obtained by means of a call of valsymtri.

It is efficient to use allzerortpol if more than 50 percent of extreme zeros or more than 25 percent of selected zeros are wanted.

Function Parameters: void selzerortpol (n,nl,n2, b,c,zer,em)

n,nl,n2: int; entry: the degree of the orthogonal polynomial of which the nl-th up to and

including n2-th zeros are to be calculated (zer[nl] 2 zer[n2A; b,c: float b[O:n-I], c[O:n-I];

entry: the elements b[i] and c[i], i=O,l, ..., n-I, contain the coefficients of the recurrence relation pi+, (x) =(x-b[v) *p i(x)-c[i]*p,, (x), i=O, I, ..., n-I, assuming c[O]=O;

exit: the contents of the arrays b and c are not altered; zer: float zer[nl :n2];

exit: the n2-nl+ I calculated zeros in decreasing order; em: float em[0:5];

entry: em[O]: the machine precision; em[2]: the relative tolerance of the zeros; exit: em[l]: the value of max( 1 b[0] 1 +1, c[i]+ 1 b[i] 1 +l (i=l, ..., n-2), c[n-I]+ 1 b[n-I] 1 ); em[5]: the number of iterations performed.

Function used: valsymtri.

void selzerortpol(int n, int nl, int n2, float b[l, float c[l, float zer [I , float em [I )

1 ' float *allocate-real-vector(int, int);

void free-real-vector(f1oat *, int); void valsymtri (float [ I , float 1 1 , int, int, into

float [I, float [I); int i; float nrm,*d;

d=allocate-real-vector (1, n) ; nrm=fabs (b [Ol ) ; for (i=n-2; i>=l; i--)

if (c [il +fabs (b [il ) > nrm) nrm=c [il +fabs (b [il ) ; if (n > 1)

nrm = (nrm+l >= c[n-ll+fabs(b[n-11)) ? nrm+l.O : (c [n-11 +fabs (b In-11 ) ) ;

em [ll =nrm;

Copyright 1995 by CRC Press, Inc

Page 303: Numerical Library in C for Scientists and Engineers A

for (i=n; i>=l; i--) d[il=b[i-11; valsymtri (d, c,n,nl,n2, zer, em) ; em[5] =em[31 ; free-real-vector (d, 1) ;

1

D. alljaczer

Calculates all zeros of the n-th Jacobi polynomial P , ' ~ ( X ) , see [AbS65]. The Jacobi polynomials satisfy the recursion

P~'*)(x) = 1, P,(*)(x) = 1/2 (a+J+2)x+ 1/2 (a$), 2(k+l)(k+a+J+l)(2k+a+J) P , + , ( ~ ( x ) =

(~~+(Y+J+I)((~~+cY+J)(~~+(Y+J+~)x+~~$Z) P~*)(x) - 2k(k+a) (k+J) (2k+a+J+2) Pk-,(4(~) (k=2,3,. . .)

and the coefficient of Xk in Pi4&) is

The polynomials p,(x) = P,(*)(x)/c, satisfy the recursion

The roots of p,(x) (i.e. those of P,'*)(x)) may be obtained by a call of allzerortpol. However, for the special case in which a=R,

P2m(04tJ(~) = C,,,P,(%-~/~) (22-1) P2m-1(ad(~) = d,~P,(g'/~)(2?-1)

where c , and dm are independent of x. Thus, in this special case, the determination of the roots of P,'*)(x) may slightly be simplified.

Function Parameters: void alljaczer (n,alfa, beta,zer)

n: int; entry: the upper bound of the array zer, n 2 1;

alfa, beta: float; entry: the parameters of the Jacobi polynomial (values of a and R above);

alfa, beta > - 1 ; zer: float zer[l :n];

exit: the zeros of the n-th Jacobi polynomial with parameters alfa and beta.

Function used: allzerortpol.

Copyright 1995 by CRC Press, Inc

Page 304: Numerical Library in C for Scientists and Engineers A

void alljaczer(int n, float alfa, float beta, float zer[l) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void allzerortpol(int, float [I, float [I, float [ I , float [I ) ; int i,m; float sum,min, *a, *b, em[6] ,gamma, zeri;

if (alfa == beta) { a=allocate-real_vector(O,n/2); b=allocate-real-vector(O,n/2); m=n/2 ; if (n ! = 2*m) {

gamma=0.5; zer [m+ll =O. 0 ;

) else gamma = -0.5;

minz0.25-alfa*alfa; sum=alfa+gamma+2.0; a [0l= (gamma-alfa) /sum; a [ll =min/sum/ (sum+2.0) ; b[l] =4.0*(1.0+alfa) (l.o+gamma) /sum/sum/(sum+l.~) ; for (i=2; ic=m-1; i++) {

sum=i+i+alfa+gamma; a [il =min/sum/ (sum+2.0) ; sum *= sum; b [i] =4.0*i* (i+alfa+gamma) (i+alfa) * (i+gamma) /sum/ (sum-1.0) ;

1 em [O] =FLT-MIN; em [2 I =FLT-EPSILON; em [41=6*m; allzerortpol (m, a, b, zer, em) ; for (i=l; ic=m; i++) {

zer [i] = zeri = -sqrt ( (1. o+zer [il ) /2.0) ; zer[n+l-i] = -zeri;

kree-real-vector (a, 0) ; f ree-real-vector (b, 0) ;

) else ( a=allocate-real-vector(0,n); b=allocate-real-vector(0,n); min= (beta-alfa) * (beta+alfa) ; sum=alfa+beta+2.0; b[Ol=O.O; a [OI = (beta-alfa) /sum; a [ll =min/sum/ (sum+2.0) ; b [I] =4. o* (l.O+alfa) * (1. o+beta) /sum/sum/ (sum+l. 0) ; for (i=2; i<=n-1; i++) {

sum=i+i+alfa+beta; a [il =min/sum/ (sum+2.0) ; sum *= sum; b [i] =4.0*i* (i+alfa+beta) * (i+alfa) * (i+beta) / (sum-1.0) /sum;

I J em [Ol =FLT-MIN; em [21 =FLT-EPSILON; em [41=6*n; allzerortpol (n, a, b, zer, em) ; f ree-real-vector (a, 0) ; free-real-vector (b, 0) ;

1 1

E. alllagzer

Calculates all zeros of the n-th Laguerre polynomial L,'~(X), see [AbS65]. The Laguerre polynomials satisfy the recursion

L,'*'(x) = I, L,'"'(x) = a+l -x , (k+l) Lk+,'"'(x) = (2k+a+l-x) L,(*'(x) - (k+a) L,,(*'(x)

and the coefficient of 2 in LL9'(x) is ~ ~ = ( - l ) ~ / k ! . The polynomials pk(x) = ~ , ( ~ ( x ) / c , satisfy

Copyright 1995 by CRC Press, Inc

Page 305: Numerical Library in C for Scientists and Engineers A

the recursion po(x) = I, p,(x) = x-a-I,

PL+I(X) = P~(x) - k(k+a) P~-I(x) (k=2,3, ...). The roots of p,(x) (i.e. those of L,'"'(x)) are obtained by means of a call of allzerortpol.

Function Parameters: void alllagzer (n,alfa,zer)

n: int; entry: the upper bound of the array zer, n 2 1;

alfa: float; entry: the parameter of the Laguerre polynomial (value of a above); alfa > -1;

zer: float zer[l :n]; exit: the zeros of the n-th Laguerre polynomial with parameters alfa.

Function used: allzerortpol.

void alllagzer(int n, float alfa, float zer[l) 1 ' float *allocate-real-vector(int, int);

void free-real-vector(f1oat * , int) ; void allzerortpol(int, float [ I , float 1 1 , float 11, float 11); int i; float *a, *b,em[61 ;

a=allocate-real-vector(0,n); b=allocate-real-vector (0, n) ; b[Ol=O.O; a [n- 11 =n+n+alf a- 1.0 ; for (i=l; ic=n-1; i++) (

a [i-11 =i+i+alfa-1 .O; b [il =i* (i+alfa) ;

1 &m LO] =FLT-MIN; em [2] =FLT EPSILON; - em [41=6*n; allzerortpol (n , a, b, zer, em) ; free-real-vector (a, 0) ; free-real-vector (b, 0) ;

1

3.16.3 Zeros of complex polynomials

comkwd

Determines the roots g and k of the quadratic equation 9-2~z-q=0 with complex p and q.

Function Parameters: void cornkwd (pr,pi,qr,qi,gr,gi, kr, ki)

pr,pi,qr,qi: float; entry: pr, qr are the real parts and pi, qi are the imaginary parts of the

coefficients of the quadratic equation: 2 - 2(pr+pi*i)z - (qr+qi*i) = 0;

gr,gi,kr,ki: float *; exit: the real parts and the imaginary parts of the dinomial are delivered in gr,

Copyright 1995 by CRC Press, Inc

Page 306: Numerical Library in C for Scientists and Engineers A

kr and gi, ki, respectively; moreover, the modulus of gr+gi*i is greater than or equal to the modulus of b+ki*i.

Functions used: commul, comdiv, comsqrt.

void comkwd(f1oat pr, float pi, float qr, float qi, float *gr, float *gi, float *kr, float *ki)

I void commul(float, float, float, float, float * , float * ) ; void comdiv(float, float, float, float, float * , float * ) ; void comsqrt (float, float, float *, float * ) ; float hr, hi ;

if (qr == 0.0 && qi == 0.0) { *kr = *ki = 0.0; *gr = pr*2.0; *gi = pi*2.0; return;

if (pr == 0.0 && pi == 0.0) ( comsqrt (qr,qi,gr,gi) ; *kr = -(*gr); *ki = -(*gi); return;

if (fabs(pr) > 1.0 I I fabs(pi) > 1.0) { corndiv(qr, qi,pr,pi, &hr, &hi) ; comdiv(hr,hi,pr,pi, &hr,&hi) ; comsqrt (l.O+hr, hi, &hr, &hi) ; commul (pr, pi, hr+l. 0, hi, gr, gi) ;

} else { comsqrt (qr+ (pr+pi) * (pr-pi) , qi+pr*pi*2.0, &hr, &hi) ; if (pr*hr+pi*hi > 0.0) {

*gr = pr+hr; *gi = pi+hi;

) else { *gr = pr-hr; *gi = pi-hi;

Copyright 1995 by CRC Press, Inc

Page 307: Numerical Library in C for Scientists and Engineers A

4. Analytic Evaluations

4.1 Evaluation of an infinite series

A. euler

Applies the Euler transformation to the series

The course of the computations is determined by two parameters, both prescribed by the user: eps, a real tolerance; tim, a positive integer specifying the number of consecutive transformed sums whose agreement to within the tolerance eps is taken to imply that the last of them is an acceptable approximation to the Euler sum of the original series.

A set of numbers Mij, a sequence of integers J(i), and sequences of partial sums Si and terms ti for which Si+,=Si+ti+, are computed as follows. Initially M,,,=a,, J(I)=O, Sl=?4a,. For i 2 I , and with Mi+,,,=ai+,, the numbers Mi+lj+l = I/z(Mij+Mi+,j O=l, ..., J(9) are computed. If I Mi+l,Jo)+, 1 < I MLJW 1 then J(i+l) =J(i)+l and ti+, =I/zMi+,,Jo+l; otherwise J(i+l) =J(i) and ti+l=Mi+l,Jo+,. If I ti+, ( <eps for i= I,..., I+tim-1 for some PO, the process terminated.

Function Parameters: float euler (ai,eps, tim)

euler: delivers the computed sum of the infinite series; ai: float (*ai)(i); int i;

this function is the i-th term of the series, i 2 0; eps: float;

entry: summation criterion, see tim below; tim: int;

entry: the summation is continued until tim successive terms of the transformed series are in absolute value less than eps.

£loat euler (float (*ai) (int) , float eps, int tim) I

int i,k,n,t; float mn,mp,ds, sum,m[l61 ;

n=t=i=O; m[Ol =(*ail (i) ; sum=m[OI /2 .O; do {

i++; mn= (*ai) (i) ; for (k=O; kc=n; k++) {

mp= (mn+m [kl ) /2.0; m [kl =mn; mn=mp ;

Copyright 1995 by CRC Press, Inc

Page 308: Numerical Library in C for Scientists and Engineers A

ds=mn/2.0; n++ ; m [nl =mn;

} else ds =mn ;

sum += ds; t = (fabs(ds) c eps) ? t+l : 0;

) while (t c tim) ; return sum;

B. sumposseries

Performs the summation of a convergent series with positive monotonically decreasing terms using the Van Wijngaarden transformation [Dan69, Vnw651 of the series to an alternating series.

sumposseries estimates the sum of a series of real terms

by use of the transformation

The above transformation may be derived from the identity

Differentiating throughout, and dividing the resulting relationship by the original version

Replacing x by the displacement operator D (Dv(i) = v(i+l)) and applying both sides of the derived relationship to v(O), the transformation (2) is obtained.

Euler's transformation may be applied to the series on the right hand side of relationship (2): denoting the Euler sum of a series by E{. ..I, relationship (2) yields

Copyright 1995 by CRC Press, Inc

Page 309: Numerical Library in C for Scientists and Engineers A

where

Each series (3) involves a subsequent of the terms of the series (I), and may converge far more rapidly than the latter. For example, when v(i) = 1- (a>l),

but

(e.g. when a=2,2" decreases to zero more rapidly than n".) Again when v(i)=x' (1x1 4 ) the two remainder terms are O(Y) and ~ ( x ' ) (where 1=2") respectively. The auxiliary sums (3) with even values of j may be obtained from values of sums previously determined:

Thus the sum of the component series (3) may often be evaluated directly or indirectly by direct summation; the sum of the alternating series of sums on the right hand side of relationship (2) may then be obtained by use of Euler's transformation. In this way the numerical sum of a large number of terms of the series (1) is effectively approximated by a weighted sum which involves relatively few of them.

It may occur that the auxiliary series (3) do not converge with sufficient rapidity. In such a case, application of the transformation (2) may be repeated:

where

Again, for fixed j,

Copyright 1995 by CRC Press, Inc

Page 310: Numerical Library in C for Scientists and Engineers A

and relationship (3) still holds. For odd j, the terms vl'o,l) are obtained, directly or indirectly, by summation; they are inserted into an Euler process to yield terms v'l;) given by formula (5); the v'l;) with even j are derived by use of relationship (4); the v'Q) are inserted into a further Euler process to yield the sum (1).

Clearly the above process of recursion may be extended: letting i be an integer vector with components i(l), i(2), ... and vo)(i) be a function of the first j components of i,

where

and vF)(i) is obtained by direct summation:

where P1'(i), sF+')(i) are integer functions of the first k+l components if i, and may be derived by use of the following recursion:

f(1) = 1, $1) = 2ifi+1)-1

fl;+l) = fl;)W = 2sO)W+l)-I o=l , ..., k-1)

P1)( i ) = f(k)s(k) sF+I)(' I) - - z(l)s(k). '

For fixed i(l), i(2), ..., il;-I), vo)(i) with even values of il;) may be determined without summation or transformation: writing vo)(i) as vm(i(l),i(2), ..., io)), etc.

vo)(i(l),i(2), ..., i&l),2iQ)) =

%(vo)(i(l),i(2) ,..., io-l),i(j)) - F1)(i( l ) , i(2), . . ., iQ), l ) v (~~+~) ( i ( l ) , i(2), . . ., iQ), I)))

for j=l, ..., k. For many series

of real terms with consistent sign

Copyright 1995 by CRC Press, Inc

Page 311: Numerical Library in C for Scientists and Engineers A

If R(n) 5 8 for n=m,m+l, ..., m+tim-1, E being a real tolerance, m and tirn being positive integers, it may reasonably be inferred that the partial sum

represents the sum of the series in question to the stated tolerance. This test is used to establish the level k at which the recursion functions during the computation. With integer values of m and tim supplied by the user, the above test is first applied to the series (1) itself, and if the test is passed, no transformation is carried out. If the test fails, then with i(l)=l, the test is applied to the series (6 ) with k=l; if this test fails, it is applied to the series (6) with k=2 and i(I)=i(2)=1, and so on; acceptance of the test determines the value of k for which vw(i) is to be determined, directly or indirectly, by summation.

With i(1) =i(2) =... =i(k) =I, vF)(i) is determined by summation, and inserted into the Euler process to determine vF-"(4. With i(1) =i(2) =... =i(k-I) =I, i(k) =2, vM(i) is determined by use of relationship (7) with j=k, and -vm(i) is inserted into the above Euler process. With i(l)=i(2)= ... =i(k-l)=1, i(k)=3, vN(i) is determined by summation, and so on. When the Euler process produces a transformed sum (namely vfi-"(1,l ,...,I)) it is inserted into the penultimate Euler process. vfi-"(i) with i(1) =i(2) =.. . =i(k-I), i(k-I) =2 is determined by use of relationship (7) with j=k-I. The rate of convergence of the series (6) with k replaced by k-1 is now tested as described above; if the test is passed, the @-')(i) are determined by direct summation; otherwise k is increased to a level at which convergence is sufficiently rapid, and the process described above is continued; testing rate of convergence takes place after the termination of each Euler process. Finally the Euler process involving the terms v(')(i) terminates, and the transformed sum of the series (1) is obtained.

Function Parameters: float sumposseries (ai, maxaddup, maxzero, maxrecurs, machexp, tirn)

sumposseries: delivers the computed sum of the infinite series; ai: float (*ai)(i); float i;

this function is the i-th term of the series, i 2 1; maxaddup: int;

entry: upper limit for the number of straightforward additions (value of m above); maxzero: float;

entry: tolerance in the Euler summation, see tim below; maxzero is also used as a tolerance for maxaddup straightforward additions;

marecurs: int; entry: upper limit for the recursion depth of the Van Wijngaarden transformation;

machexp: int; entry: in order to avoid overflow and evaluation of those terms which can be

neglected, machexp has to be the largest admissible value for which terms with index k*(2m"chexp ) can be computed (k is small); otherwise overflow might occur in computing a value for the parameter i (in function ai), which can be an usually high power of 2;

tim: int; entry: tolerance in the Euler summation; the summation is continued until tirn

successive terms of the transformed series are in absolute value less than maxzero.

Copyright 1995 by CRC Press, Inc

Page 312: Numerical Library in C for Scientists and Engineers A

float sumposseries(f1oat (*ai) (float), int maxaddup, float maxzero, int maxrecurs, int machexp, int tim)

1

float sumposseriessumup (int, float ( * ) (float) , int, float, int, int, int, int, int, int, int, int) ;

int recurs,vl,vl2,vl4;

recurs=O ; vl=1000; v12=2*vl; v14=2*v12; return sumposseriessumup(0,ai,maxaddup,maxzero,maxrecurs,

machexp,tirn,recurs,vl,v12,~14,0); 1 float sumposseriessumup (int bjk, float (*ai) (float) ,

int maxaddup, float maxzero, int maxrecurs, int machexp, int tim, int recurs, int vl, int v12, int v14, int jj)

/ * this function is internally used by SUMPOSSERIES * /

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); float sumposseriesbjk (int, float, float, float ( * ) (float) ) ; int j,transform,j2,jodd,k,n,t; float i,sum,nextterm,*v,mn,mp,ds,esum,m[161 ,temp,vj;

i=maxaddup+l; j=1; transform=O; while (1) (

temp = (bjk) ? sumposseriesbjk(jj,i,machexp,ai) : (*ail (i); if (temp c= maxzero) (

if (j >= tim) break; I + + ; 1++;

) else ( if (recurs ! = maxrecurs) transform=l; break;

1 1

if (!transform) ( sum=i=0.0; j=O; do {

i++; nextterm = (bjk) ?

sumposseriesbjk (j j, i,machexp, ail : (*ai) (i) ; j = (nextterm c= maxzero) ? j+l : 0; sum += nextterm;

) while (j c tim); return sum;

I )* transform series * / v=allocate~real~vector(l,vl) ; j2=0; jodd=l; / * euler * / n=t= j =0 ;

jodd=0 ;' recurs++; temp=vj=sumposseriessumup(1,ai,maxaddup,maxzero,

maxrecurs,machexp,tim,recurs,vl,vl2,v14,jj); recurs- - ; if (j j c= vl)

v[jjl=temp; else

if (jj c= v12) v[j j-vll=temp; ) else (

Copyright 1995 by CRC Press, Inc

Page 313: Numerical Library in C for Scientists and Engineers A

j odd=l ; if (jj > v14) {

recurs++; vj = -sumposseriessumup(l,ai,maxaddup,maxzero,

maxrecurs, machexp, tim, recurs, vl, vl2, vl4, j j ) ; recurs- - ;

] else { j2++; i=j2; if (jj > v12) {

temp = (bjk) ? sumposseriesbjk (j j , i,machexp, ai) : (*ai) (i) ;

vj = -(v[j2-vll-temp)/2.0; 1 else {

temp = (bjk) ? sumposseriesbjk (j j, i,machexp, ai) : (*ai) (i) ;

temp=v[(jj <= vl) ? jj : jj-vl]=(v[j2]-temp)/2.0; vj = -temp;

, I I

]odd=0;' recurs++; temp=vj =sumposseriessumup (1, ai, maxaddup, maxzero,

maxrecurs,machexp,tim,recurs,vl,vl2,vl4,jj~; recurs- - ; if (jj <= vl)

v[jjl=temp; else

if (jj <= v12) v[jj-vll=temp; \ else !

recurs++ ; vj = -sumposseriessumup(l,ai,maxaddup,maxzero,

maxrecurs,machexp,tim,recurs,vl,vl2,vl4,j~); recurs- - ;

] else { j2++; i=j2; if (jj > v12) {

temp = (bjk) ? sumposseriesbjk (j j, i,machexp, ai) : (*ai) (i) ;

vj = - (v[j2-vll -temp)/2.0; ) else {

temp = (bjk) ? sumposseriesbjk (j j, i,machexp, ail : (*ai) (i) ;

temp=v[(jj <= vl) ? jj : jj-vl]=(v[j21-temp)/2.0; vj = -temp;

I 1

mn=vj ; for (k=O; k<=n; k++) {

mp= (mn+m [kl ) /2.0 ; m [kl =mn; mn=mp ;

j if (fabs (mn) < fabs (m[n] ) && n < 15) {

ds=mn/2.0; n++ ; m [nl =mn;

] else ds =mn ;

esum += ds; t = (fabs(ds) < maxzero) ? t+l : 0;

] while (t < tim) ;

Copyright 1995 by CRC Press, Inc

Page 314: Numerical Library in C for Scientists and Engineers A

free-real-vector (v, 1) ; return esum;

1 float surnposseriesbjk(int j , float i, float machexp,

float (*ai) (float) )

/ * this function is internally used by SUMPOSSERIESSUMUP * /

float coeff;

if (i > machexp) return 0.0; coeff=pow(2.0,i-1.0); return coeff* (*ai) (j*coeff) ;

Quadrature

4.2.1 One-dimensional quadrature

A. qadrat

Evaluates the integral

where f i s real valued, a and b are finite (b<a is permitted). qadrat functions recursively [RoF72]. With$=f(a+ih), where h=(b-a)/32, two sums of

the form

are computed ( U and V are such that Uh and Vh are equal to I6a,b) iff is a polynomial of degree I 16). If either 1 h 1 <hmin= 1 b-a ) q a, where qa is an absolute tolerance prescribed by the user, or I U-VI <I Vl qr+qa, where q r is a relative tolerance also prescribed by the user, then Vh is accepted as an approximation to I&a,b). If neither of these conditions is satisfied, a further sum of the form

is computed (again Wh is equal to I&a,b) iff is a polynomial of degree I 16). If now I W-VI <I Wl qr+qa, then Wh is accepted as an approximation to ICfja,b). If this further condition is not satisfied, ICfja,b) is then expressed as and the two integrals are each treated in the above manner (with hmin left unchanged). The first is approximated by linear sums involving the function values

A' = f(a+ih') where h' = (b-a)/64.

Copyright 1995 by CRC Press, Inc

Page 315: Numerical Library in C for Scientists and Engineers A

Since hi ' = Ji' (i=0,1,2,4,6,8,12,16), this set of values may immediately be used in an attempt to evaluate the first of the integrals (1). The second integral is approximated by linear sums involving the function values J' = f(b+ih 7 , where h ' = (a-b)/64. Since hi' =

f32-i (i=0,1,2,4,6,8,12,16).

Function Parameters: float qadrat (x, a, b,fx, e)

qadrat: delivers the computed value of the definite integral from a to b of the function f(x); x: float *;

integration variable; a,b: float;

entry: (a,b) denotes the interval of integration; b<a is allowed; fx: float (*fx)(x); Jloat x;

fx denotes the integrand f(x); e: float e[l:3];

entry: e[l]: the relative accuracy required (value of q, above); e[2]: the absolute accuracy required (value of q, above); exit: e[3]: the number of elementary integrations with h < 1 b-a I *e[l].

float qadrat (float *x, float a, float b, float (*fx) (float) , float e 11 )

I float lint(f1oat * , float (*)(float), float [I, float, float,

float, float, float, float, float, float, float, float, float, float, float, float) ;

float fO,f2,f3,f5,f6,f7,f9,fl4,hmin,hmax,re,ae,result;

hmax= (b-a) /l6.O; if (hmax == 0.0) return 0.0; re=e Ill ; ae=2. 0*e [21 /fabs (b-a) ; e[31=0.0; hmin=fabs (b-a) *re; *x=a; f0= (*fx) (*x) ; *x=a+hmax; f2= (*fx) (*x) ; *x=a+2.0*hmax; f3= (*fx) (*x) ; *x=a+4.0*hmax; f5= (*fx) (*x) ; *x=a+6.0*hmax; f6=(*fx) (*x) ; *x=a+S.O*hmax; f7=(*fx) (*x) ; *x=b-4.0*hmax; f9= (*fx) (*x) ; *x=b; f14=(*fx) (*x) ; result = lint(x,fx,e,a,b,fO,f2,f3,f5,f6,f7,f9,f14,

hmin,hmax, re,ae) *l6.O; return result;

I

Copyright 1995 by CRC Press, Inc

Page 316: Numerical Library in C for Scientists and Engineers A

float lint (float *x, float (*fx) (float), float e [ I , float xO, float xn, float £0, float f2, float f3, float £5, float £6, float f7, float f9, float f14, float hmin, float hmax, float re, float ae)

I 1

/ * this function is internally used by QADRAT * /

xm= (xO+xn) /2.0; h= (xn-x0) /32.O; *x=xm+4.0*h; f8= (*fx) (*x) ; *x=xn-4.0*h; fll= (*fx) ( *x) ; *x=xn-2.0*h; fl2= (*fx) (*XI ; ~=0.330580178199226*f7+0.173485115707338*(f6+f8)+

0.321105426559972*(f5+f9)+0.135007708341042*~f3+fll)+ 0.165714514228223*(f2+f12)+0.393971460638127e-l*(fO+fl4);

*x=xO+h; fl=(*fx) (*x) ; *x=xn- h; fl3= (*fx) (*x) ; ~=0.260652434656970*f7+0.239063286684765*(f6+f8)+

0.263062635477467*(f5+f9)+0.218681931383057*(f3+fll)+ 0.275789764664284e-1*(f2+f12)+0.105575010053846*~fl+fl3~+ 0.157119426059518e-l*(fO+f14);

if (fabs(h) < hmin) e[31 += 1.0; if (fabs (v-w) c fabs (w) *re+ae I fabs (h) < hrnin)

return h*w; else (

*x=x0+6.0*h; f4= (*£XI (*x) ; *x=xn-6.0*h; flO= (*fx) (*XI ; v=0.245673430093324*f7+OO255786258286921*(f6+f8)+

0.228526063690406*(f5+f9)+0.50055713152546Oe-l*(f4+flO~+ 0.177946487736780*(f3+f11)+0.584014599347449e-l*(f2+fl2)+ 0.874830942871331e-l*(fl+f13)+ 0.189642078648079e-l*(fO+f14);

return ((fabs(v-w) c fabs(v) *re+ae) ? h*v : (lint (x, fx,e,xO,xm, £0, fl,f2,f3, -5, f6, £7,

hrnin, hmax, re, ae) - lint(x,fx,e,xn,xm,fl4,f13,fl~,fll,flO,f9,f8~f7,

hmin,hmax,re,ae)));

B. integral

Evaluates the integral

where f is real valued, -m < a < m, and -m I B I m (when I3 < m, I3 < a is permitted). This is done by means of Simpson's rule with Richardson correction [DekR71, RoF721. If the fourth derivative is too large (and thus the correction term), the total interval is split into two equal parts and the integration process is invoked recursively. This is done in such a way that the total amount of Richardson corrections is slightly smaller than or equal to e[l]* 1 integral of the function from a to b 1 +e[2]. For the integration of a definite integral over a finite interval, the use of qadrat is recommended, especially when high accuracy is required.

Copyright 1995 by CRC Press, Inc

Page 317: Numerical Library in C for Scientists and Engineers A

integral may be called a number of times to evaluate the integral off over a sequence of intervals of the form [a,,a,], [a,,a,] ,..., [ a ,-,, a,] and, when used in this way, may be directed to accumulate the total integral over the range [a,,a,].

The values of a and I3 in expression (1) are determined partly by the values of a and b occurring in the parameter list of integral. If ua is nonzero then a=a; otherwise a=a' . If ub is nonzero then B=b; if ub is zero, then R=m if b>a, and B=-m if b<a. Immediately before return from a successful call, integral sets a'=b if ub is nonzero, and in this way the integrals over the above sequence of intervals may be evaluated without adjustment of a.

If ub is zero (so that B=m or l3=-m above) the integral (1) is expressed as

if B=m, and as

if B=-m. integral evaluates the two relevant integrals over finite ranges, and forms their difference.

For integration over a finite subrange, use is made of the formula

where h = (6-y)/4, and with A = =f(y+ih) I, = W3)Cfo + 4f, + 2 ! + 4h +fJ I* = W3)(2fO + 8x7 + 2fJ. Acceptance of the value of the expression I,A - (I2-13/15 as an approximation to the

value of the intermediate integral (2) is decided by the values of two tolerances q, and q, provided by the user, from which a further tolerance T, is derived. If in expression (1) I3 is finite (i.e. ub is nonzero) then T, = 180/(B-a). If If3 I is infinite, so that the pair (2) or (3) of integrals is to be evaluated, T, = 90qa/ I b-a I for the first integral of the pair, and T, =

907, for the second. A minimum stepsize hmin is also determined. If in expression (1) B is finite, then hmin = IB-a I qr . If I B I is infinite so that the pair (2) or (3) of integrals is to be evaluated, hmin = I b-a 1 q , for the first integral, and hmin = q, for the second.

integral functions recursively. Formula (4) is first examined with y and 6 set equal to the endpoints of the relevant integral over a finite range being evaluated. The sums

v = 15Cfo+h+2!+4fi +fa t = h + d h + h - 4 f i + f J

(so that v = 180I,/h, t = 180(12-IJ/h) are formed. If I t 1 < 1 v 1 q, + T,, or 16-y 1 < hmin, where q , r, and hmin are as defined above, then I, - (I2-13/15 is accepted as an approximation to the value of the integral (4); otherwise, the formula

is used, each constituent of the right hand side being treated as above. The computed approximation to the first constituent integral involves function values A' = f(y+ih ') where

Copyright 1995 by CRC Press, Inc

Page 318: Numerical Library in C for Scientists and Engineers A

h ' = (6-y)/8, so that hi' = J; (i=0,1,2); those even order f;' have already been evaluated, and may be used directly. The computed approximation to the second constituent integral involves function values J;' = f(%(y+6)+ih ') so that hi ' = A+, (i=O, 1,2).

Function Parameters: float integral (a, b,fx, e, ua, ub)

integral: delivers the computed value of the definite integral of the function from a to b; after successive calls of the procedure, the integral over the total interval is delivered, i.e, the value of a in the last call with ua equals nonzero is the starting point of the integral;

a,b: float; entry: (a,b) denotes the interval of integration; b<a is allowed;

fx: float (*j$ (x); float x; fx denotes the integrand f(x);

e: float e[I:6]; entry: e[I]: the relative accuracy required (value of q, above); e[2]: the absolute accuracy required (value of q, above); exit: e[3]: the number of skipped integration steps; e[4]: the value of the integral from a to b; e[5]: if ub is zero then e[5]=0 else e[5]=b; e[6]: if ub is zero then e[5]=0 else e[5]=f(b);

ua: int; entry: determines the starting point of the integration; if ua is zero then the starting

point is e[5] otherwise the starting point is a; ub: int;

entry: determines the final point of the integration; if ub is nonzero then the final point is b; otherwise if b > a then the final point is a, else it is -a,.

float integral(f1oat a, float b, float (*fx) (float), float e[l, int ua, int ub)

float integralqad (int, float ( * I (float) , float [I , float , float *, float * , float *, float * , float *, float, float, float) ;

float xO,xl,x2,fO,fl,f2,re,ae,bl,x;

re=e Ell ; if (ub)

ae=e [21*180.0/fabs (b-a) ; else

ae=e [21 *go. O/fabs (b-a) ; if (ua) {

e[3I=e[41=0.0; x=xO=a; f0= (*fx) (x) ;

) else ( x=xO=a=e [SI ; f 0=e [61 ;

1 e [Sl =x=x2=b; e [61 =f2= (*fx) (x) ; e [41 += integralqad(0, fx, e, &x0, &XI, &x2, &f0, &fl, &f2, re, ae,bl) ; if (!ub) {

Copyright 1995 by CRC Press, Inc

Page 319: Numerical Library in C for Scientists and Engineers A

if (a c b) ( bl=b-1.0; xo=1.0 ;

) else ( bl=b+l. 0 ; xo = -1.0;

1 fO=e [61 ; e 151 =x2=0.0:

float integralqad(int transf, float (*£XI (float), float e [ I , float *xO, float *xl, float *x2, float *fO, float *fl, float *f2, float re, float ae, float bl)

' / * this function is internally used by INTEGRAL * /

void integralint (int, float ( * ) (float) , float [ I , float * , float * , float * , float *, float * , float * , float * , float, float, float, float) ;

float sum,hmin,x,z;

hmin=fabs ( (*x0) - (*x2) ) *re; x= (*xl) = ( (*x0) + (*x2) ) *0.5; if (transf) (

z=l. o/x; x=z+bl; (*fl) = (*.Ex) (x) *z*z;

) else (*fl) = (*fx) (x) ;

sum=O. 0 ; integralint (transf, fx, e, x0, x1, x2, fO,fl, £2, &sum, re, ae, bl, hmin) ; return sum/l80.0;

1 void integralint (int transf, float (*fx) (float) , float e [ I ,

float *xO, float *xl, float *x2, float *fO, float *fl, float *f2, float *sum, float re, float ae, float bl, float hmin)

1 I

/ * this function is internally used by INTEGRALQAD of INTEGRAL * /

int anew; float x3,x4,f3,f4,h,x,z,v,t;

x4= (*x2) ; (*x2) = (*x1) ; f4= (*f2) ; (*f2) = (*fl) ; anew=l; while (anew) (

anew=O ; x=(*x1)=((*x0)+(*x2))*0.5; if (transf) (

z=1. o/x; x=z+bl; (*fl) = (*fx) (x) *z*z;

} else (*fl) =(*fx) (x) ;

x=x3=( (*x2)+~4)*0.5; if (transf) (

z=l. o/x; x=z+bl; f3= (*fx) (x) *z*z;

1 else

Copyright 1995 by CRC Press, Inc

Page 320: Numerical Library in C for Scientists and Engineers A

if (fabs (t) c fabs (v) *re+ae) (*sum) += (v-t) *h;

else if (fabs(h) c hmin) e[31 += 1.0;

else ( integralint(transf,fx,e,xO,xl,x2,fO,fl,f2,sum,

re, ae, bl, hmin) ; *x2 =x3 ; *f2=f3; anew=l ;

4.2.2 Multidimensional quadrature

tricub

Evaluates the double integral

where R is a triangle with vertices (xi,yi), (x,,y,) and (x,,y,), and g is real valued. A nested sequence of cubature rules of order 2, 3, 4 and 5 is applied [He73]. If the difference between the result with the 4-th degree rule and the result with the 5 t h degree rule is too large, then the triangle is divided into four congruent triangles. This process is applied recursively in order to obtain an adaptive cubature algorithm.

The theory of the method adopted may be presented as follows. The area of R is A= ' / ~ I x & - x f i + xkyi-xyk + xiyk-XkyjI.

Denote the argument pair (x,y,) by z,, and the other pairs similarly. Set Zjfk = % (z, + ZJ

and define z,,, z j j similarly (z,,, is the midpoint of the line joining zj and z,). Set z, = (z, + z, + zJ/3

(z, is the barycenter is R) . Set z,' = %(z, + Z J and define z,', z,' similarly. Set zU,, = %(z, + z,,J

and define zkiij, zj;,,, similarly. Denote values of g at the above points by corresponding suffices, so that g, = g(zJ = g(x,yJ, gjk = g(z,,J = g(%(x,+xA, %(y,+yk)) and so on. Set

A = g, + g, + gk, B = g . j,k + g , , + g . . , 'J

c = g,' + g.' + g,', J = gi,j,k + gk;ij + gj;k,i

and S 2 = 5 A + 4 5 g , , S 3 = 3 A + 2 7 g , + 8 B S, = A + 9g, + 4B + 12C S, = (51A + 2187g, + 276B + 972C - 768D)/63

and '/ = q d 6 0 .

If g is a polynomial in x and y of degree I j, then 4 = I(g;Q) exactly. The user is asked to provide values of tolerances qr,qa. tricub determines from these

further tolerances: 7, = 30qr, T,' = AT, and 7, = 30qala. tricub functions recursively. S, and S, are evaluated, and if

Copyright 1995 by CRC Press, Inc

Page 321: Numerical Library in C for Scientists and Engineers A

either A<T,' or I S,-S, 1 <T, then I, is accepted as an approximation to I(g;Q). If neither of these conditions is satisfied, S, is evaluated and if IS4-S, 1 <T,, I, is accepted as an approximation to I(g;Q). If this condition is not satisfied, S, is evaluated and if IS,-S, 1 <T,, I, is accepted as an approximation to I(g;Q). If this condition is not satisfied R is subdivided into four congruent triangles whose vertices are zij, z,,, zk,,; z,, zij, z,,,; zj, z,,, z,,,; z,, zkj, z,,, and the integrals over these four triangles are individually treated as above. The barycenter of the first triangle is z, (i.e. that of R). The barycenters of the remaining three triangles are z,', z,' and z,' respectively. z,,~,, z,;~,, and z,,,~ are the midpoints of the sides of the first triangle. The values of g at the points just mentioned (and at z , zj, z,) are required in the treatment of the integrals over the four triangles. Further function values at the midpoints of the lines joining z, and zij, z, and z,,, z, and Z, ,~ Z, and z,,, zk and zkj, and zk and z , , are required.

Function Parameters: float tricub (xi,yi,xj,yj,xk,yk,g,re,ae)

tricub: delivers the computed value of the definite integral of the function g(x,y) over the triangular domain with vertices (xi,yi), (xj,yj) and (xk,yk);

xi,yi: float; entry: the coordinates of the first vertex of the triangular domain of integration;

xj,yj: float; entry: the coordinates of the second vertex of the triangular domain of integration;

xk,yk: float; entry: the coordinates of the third vertex of the triangular domain of integration;

the algorithm is symmetric in the vertices; this implies that the result of the procedure (on all counts) is invariant for any permutation of the vertices;

g: float (*g;)(x,y); float x, float y; g denotes the integrand g(x,y);

re: float; entry: the required relative error (value of 7, above);

ae: float; entry: the required absolute error (value of q, above);

one should take for ae and re values which are greater than the absolute and relative error in the computation of the integrand g.

float tricub(f1oat xi, float yi, float xj, float yj, float xk, float yk, float (*g) (float, float), float re, float ae)

I 1

float tricubint(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float ( * ) (float, float) , float, float, float *, float) ;

float surf,surfmin,xz,yz,gi,gj,gk;

surf=0.5*fabs'(xj*yk-xk*yj+xi*yj-xj*yi+xk*yi-xi*yk); surfmin=surf*re; re *= 30.0; ae=30.0*ae/surf; xz= (xi+xj+xk) /3.0; yz= (yi+yj+yk) /3.0; gl= (*g) (xi, yi) ; gj=(*g) (xj,yj); gk= (*g) (xk, yk) ;

Copyright 1995 by CRC Press, Inc

Page 322: Numerical Library in C for Scientists and Engineers A

xi * = 0.5; yf *= 0.5;

*= 0.5; ;j * = 0.5; xk * = 0.5; yk *= 0.5; return tricubint (xi, yi, gi,xj, yj

xj+xk, yj+yk, xk+xi , yk+yi ,

,gj,xk!yk,gk, (*g) (xj+xk, yj+yk) , (*g) (xk+xi, yk+yi) ,

xi+xj, yi+yj, (*g) (xi+xj , yi+yj) , 0 . 5 * ~ ~ , 0 . 5 * ~ ~ , (*g) (xz,~Z), g, re, ae, &surf, surfmin) /6O. 0;

float tricubint(f1oat axl, float ayl, float afl, float ax2, float ay2, float af2, float ax3, float ay3, float af3, float bxl, float byl, float bfl, float bx2, float by2, float bf2, float bx3, float by3, float bf3, float px, float py, float pf, float (*g) (float, float) , float re, float ae, float *surf, float surfmin)

I I

/ * this function is internally used by TRICUB * /

float e,i3,i4,i5,a,b,c,sxl,syl,sx2,sy2,sx3,sy3,cxl,cyl,cfl, cx2, cy2, cf 2, cx3, cy3, cf3, dxl, dyl, df 1, dx2, dy2, df2, dx3, dy3, df3,result;

a=afl+af2+af3; b=bf l+bf2+bf 3 ; i3=3.0*a+27.0*pf+8.0*b; e=fabs (i3) *re+ae; if (*surf c surfmin I I fabs(5.0*a+45.0*pf-i3) c e)

return i3* (*surf) ; else {

cxl=axl+px; cyl=ayl+py; cfl= (*g) (cx1, cy1) ; cx2=ax2+px; cy2=ay2+py; cf2= (*g) (cx2,cy2) ; cx3 =ax3 +px; cy3 =ay3+py; cf3=(*g) (cx3,cy3) ; c=cf1+cf2+cf3; i4=a+9.0*pf+4.O*b+12.0*~; if (fabs(i3-i4) c e)

return i4* (*surf) ; else {

sx1=0.5*bxl; syl=0.5*byl; dxl=axl+sxl; dyl=ayl+syl; dfl=(*g) (dx1,dyl) ; sx2=0.5*bx2; sy2=0.5*by2; dx2=ax2+sx2; dy2=ay2+sy2; df2=(*g) (dx2,dy2) ; sx3=O. 5*bx3; sy3=O. 5*by3; dx3 =ax3 +sx3 ; dy3=ay3+sy3 ; df3=(*g) (dx3,dy3) ; i5=(51.0*a+2187.0*pf+276.0*b+972.0*c-

768.0*(dfl+df2+df3))/63.0; if (fabs(i4-i5) c e)

return i5* (*surf) ; else {

(*surf) *= 0.25; result=tricubint(sxl,syl,bf1,sx2,sy2,bf2,~~3,sy3,bf3,

dxl, dyl, dfl, dx2, dy2, df2, dx3, dy3, df 3, px, py, pf , g, re, ae, surf, surfmin) +

tricubint(axl,ayl,af1,sx3,sy3,bf3,~~2,sy2,bf2, dxl, dyl, dfl, axl+sx2, ayl+sy2,

Copyright 1995 by CRC Press, Inc

Page 323: Numerical Library in C for Scientists and Engineers A

(*g) (axl+sx2,ayl+sy2),axl+sx3,ayl+sy3, (*g) (axl+sx3,ayl+sy3),0.5*cxl,O.5*cyl,cfl, g,re,ae,surf, surfmin)+

tricubint(ax2,ay2,af2,sx3,sy3,bf3,sxl,syl,b£l, dx2, dy2,df2,ax2+sxl, ay2+syl, (*g) (ax2+sxl, ay2+syl) , ax2+sx3, ay2+sy3, (*g) (ax2+sx3,ay2+sy3),0.5*cx2,0.5*cy2,cf2, g, re, ae, surf, surfmin) +

tricubint(ax3,ay3,af3,sxl,syl,b£l,sx2,sy2,b£2, dx3, dy3, df3, ax3+sx2, ay3+sy2, (*g) (ax3+sx2,ay3+sy2) ,ax3+sxl, ay3+syl, (*g) (ax3+sxl,ay3+syl),0.5*cx3,0.5*cy3,cf3, g,re,ae,surf,sur£min) ;

(*surf) *= 4.0; return result;

1

4.2.3 Gaussian quadrature - General weights

A. reccof

Calculates from a given weight function on [-1,1] the recurrence coefficients of the corresponding orthogonal polynomials [G68a, G68bI.

Given w(x), defined for -1 lx l1 , and n, derives the coefficients b, and c, occurring in the recursion p,(x) = I, p,(x) = x - b,

pk+dx) = (x-~!&~(x) - ~ ! g k - l ( ~ ) (k=lJ-. ,n) (I) satisfied by the polynomials

defined by the conditions

The formulae

are used with k=O to determine b, (and hence p,(x)) and then with c , = LJL,, and (1) with k = l , ..., n-I to determine the b, and c,. The integrals (2) and (3) are evaluated by use of the formula The user must supply the value of m.

Copyright 1995 by CRC Press, Inc

Page 324: Numerical Library in C for Scientists and Engineers A

When w is symmetric (w(-x) =w(x)), the above formulae may be simplified (for example, by b, are zero). For this reason the user is asked to allocate a value to the variable sym upon call of recto$ nonzero if w is symmetric, zero otherwise.

Function Parameters: void reccof (n,m,x, wx, b,c,l,sym)

n: int; entry: upper bound for the indices of the arrays b, c, I (n 2 0);

m: int; entry: the number of points used in the Gauss-Chebyshev quadrature rule for

calculating the approximation of the integral representations of b[k], c[k]; x: float *;

entry: the weight function variable; wx: float (*wx)(x); float x;

the weight function (w(x) above); b,c, I: float b[O:n], c[O:n], l[O:n];

exit: the approximate recurrence coefficients for pp+,(x) =(x-b[k]) *pk(x)-c[k]*p,,(x), k=0,1,2,.. .,n, and the approximate square lengths I[k] = integral from -1 to 1 (w(x) *p,(x) *pk(x)) a!x;

sym: int; entry: if sym is nonzero then the weight function of [-1,1] is even, otherwise the

weight function on [-1,1] is not even.

Function used: ortpol.

void reccof (int n, int m, float *x, float (*wx) (float) , float b [I , float c [I , float 1 [I , int sym)

1 ' float ortpol (int, float, float [ I , float [ I ) ; int i,j,up; float r,s,pim,h,hh,arg,sa,temp;

pim=4.0*atan(l.0) /m; if (sym) {

for (j=O; jc=n; j++) ( r=b[jl=O.O; up=m]2 ; for (i=l; ic=up; i++) {

arg= (i-0.5) *pim; *x=cos (arg) ; temp=ortpol (j , *x, b, c) ; r += sin (arg) (*wx) (*x) *temp*temp;

I if (up*2 == m)

1 [jl=2.0*r*pim; else {

*x=o . 0 ; temp=ortpol(j,O.O,b,c) ; 1 [j] = (2.0*r+ (*wx) (*x) *temp*temp) *pim;

I

Copyright 1995 by CRC Press, Inc

Page 325: Numerical Library in C for Scientists and Engineers A

1 } e l s e

fo r

1 1

( j = o ; j<=n; j++) { r=s=O. 0; up=m/2 ; f o r (i=l; ic=up; i + + ) {

a r g = ( i - 0 . 5 ) *pim; sa=s in (arg) ; *x=cos (arg) ; ternp=ortpol ( j , *x, b, c ) ; h= (*wx) (*x) *ternp*ternp; *x = - (*x) ; ternp=ortpol (j , *x, b, c) ; hh= (*wx) (*x) *ternp*temp; r += (h+hh)*sa; s += (hh-h) * (*XI *sa;

b [ j I =s*pirn; i f (up*2 == rn)

1 [ j I =r*pim; e l s e {

*x=o . 0 ; ternp=ortpol ( j ,O. 0, b, c) ; 1 [ j ] = (r+ (*wx) (*x) *temp*ternp) *pirn;

1

B. gsswts

Calculates from the recurrence coefficients of orthogonal polynomials the Gaussian weights of the corresponding weight function [G70]. Given the coefficients b, and c, occurring in the recursion

= 1, PI($ = x - bo pk+, (x) = (x-bdp&) - C#LI (x) (k= 1,. . ., n-1)

satisfied by the polynomials

defined by the conditions

and the n real roots z ,,..., z, of p,, derives the weights w ,,..., w,, which render the quadrature formula

exact for all polynomials of degree < 2n. The wi are given by

Copyright 1995 by CRC Press, Inc

Page 326: Numerical Library in C for Scientists and Engineers A

Function Parameters: void gsswts (n,zer, b,c, w)

n: int; entry: the number of weights to be computed; upper bound for arrays z and w (n2l);

zer: float zer[l:n]; entry: the zeros of the n-th degree orthogonal polynomial;

b, c: float b[O:n-I], c[l:n-I]; entry: the recurrence coefficients;

w: float w[l:n]; exit: the Gaussian weights divided by the integral over the weight function.

Function used: allortpol.

' float *allocate-real-vector (int, inti ; void free real vector(f1oat * , int); void allortpol'Tint, float, float [l , float [I , float [ I ) ; int j,k; float s,*p;

peallocate real-vector (0, n-1) ; for (j=l; j<=n; j++) {

allortpol (n-1, zer [jl ,b, c,p) ; s=o . 0; for (k=n-1; k>=l; k--) s= (s+p [kl *p [kl ) /C [kl ; w[jl=l.~/(l.O+s);

f ree-real-vector (p ,0) ; 1

C. gsswtssym

Calculates from the recurrence coefficients of orthogonal polynomials the Gaussian weights of the corresponding weight function. Given the coefficients ck occurring in the recursion

PO($ = 1, P& = x pk+,(x) = xpk(x) - c ~ ~ - ~ ( x ) (k=l,...,n-1)

satisfied by the polynomials

defined by the conditions

Copyright 1995 by CRC Press, Inc

Page 327: Numerical Library in C for Scientists and Engineers A

where w is symmetric (w(-x) =w(x)), and n '=d2 nonpositive roots z,, ..., z,. (zi<zi+,) of p,, derives the weights w ,,..., w,.. (nU=(n+1)/2) which with w,., ,,..., w, further defined by wj=wt,+,,. G=l ,..., nt'-1) render the quadrature formula

exact for all polynomials of degree < 2n. (For the roots of p,, z,=-z,,,,. G=l, ..., n'-I) also; in providing n ' negative roots, one provides them all). The wi above are given by

Function Parameters: void gsswtssym (n,zer,c, w)

n: int; entry: the weights of an n-points Gauss rule are to be computed (because of

symmetry only (n+1)/2 of the values are delivered); zer: float zer[l:n/2l;

entry: the negative zeros of the n-th degree orthogonal polynomial (zer[iJ<zer[i+l], i=1,2, ..., d2-1; if n is odd then 0 is also a zero);

c: float c[l:n-I]; entry: the recurrence coefficients;

w: float w[l: (n+ l)/2J; exit: part of the Gaussian weights divided by the integral of the weight function

(note that w[n+ I-k]=w[k], k=1,2,. .., (n+ 1)/2).

Function used: allortpolsym.

Method: see the procedure gsswts, this procedure is supplied for storage economical reasons.

void gsswtssym (int n, float zer [I , float c [ I , float w [ I ) I

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void allortpolsym (int, float, float [ I , float [I ) ; int i, twoi, low,up; float s,*p;

up=n; while (low < up) {

allortpolsym (n-1, zer [low1 , c,p) ; s=p [n-11 *p 111-11 ; for (i=n-1; i>=l; i--) s=s/c [il +p [i-11 *p [i-11 ; w [lowl =I.. o/s; low++; up--;

1 if (low == up) {

s=1.0;

Copyright 1995 by CRC Press, Inc

Page 328: Numerical Library in C for Scientists and Engineers A

for (twoi=n-1; twoi>=2 ; twoi - = 2) s=s*c [twoi-11 /c [twoil +l. 0; w [low] =l. o/s;

1 f ree-real-vector ( p , 0) ;

1

4.2.4 Gaussian quadrature - Special weights

A. gssjacwghts

Computes the n roots, xi, of the n-th Jacobi polynomial P , ' ~ and corresponding Gauss- Christoffel numbers wi needed for the n-point Gauss-Jacobi quadrature over [- 1,1] with weight function (I-$"(I +xy. The quadrature formula

is exact iff is a polynomial of degree I 2n-1. The xi are first determined by means of a call of alljaczer, and the wi then derived by

use of the formula

Function Parameters: void gssjacwghts (n,alfa, beta,x, w)

n: int; entry: the upper bound of the arrays x and w (n2l);

alfa, beta: float; entry: the parameters of the weight function for the Jacobi polynomials,

alfa, beta > - 1 ; X: float x[l:n];

exit: x[iJ is the i-th zero of the n-th Jacobi polynomial; w: float w[l:n];

exit: w[iJ is the Gauss-Christoffel number associated with the i-th zero of the n-th Jacobi polynomial.

Functions used: gamma, alljaczer.

Method: See [AbS65, St721.

void gssjacwghts(int n, float alfa, float beta, float x[l , float w[l) {

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int) ; float gamma (f loat) ; void all jaczer (int, float, float, float [I ) ; int i, j,m;

Copyright 1995 by CRC Press, Inc

Page 329: Numerical Library in C for Scientists and Engineers A

float rO,rl,r2,s,hO,alfa2,xi,*a,*b,min,sum,alfabeta,temp;

if (alfa == beta) { b=allocate-real-vector(1.n-1); all jaczer (n, alfa, alfa,x) ; alfa2=2.0*alfa; temp=gamma(l.O+alfa); ho=pow(2.0, alfa2+l. 0) *temp*temp/gamma(alfa2+2.0) ; b [ll =l. O/sqrt (3.0+alfa2) ; m=n-n/2 ; for (i=2; i<=n-1; i++)

b [i] =sqrt (i* (i+alfa2) / (4. O* (i+alf a) * (i+alfa) -1.0) ) ; for (i=l; i<=m; i++) {

xi=fabs (x[il) ; r0=1.0 ; rl=xi/b [ll ; s=l.O+rl*rl; for (j=2; jc=n-1; j++) {

r2= (xi*rl-b [j-11 *rO) /b[jl ; rO=rl; rl=r2; s += r2*r2;

J free real-vector (b, 1) ;

} else r a=allocate-real-vector(0,n); b=allocate-real-vector(0,n); alfabeta=alfa+beta; min= (beta-alfa) *alfabeta; b[Ol=O.O; sum=alfabeta+2.0; a LO]= (beta-alfa) /sum; a [ll =min/sum/ (sum+2.0) ; b [l] =2.0*sqrt ( (l.O+alfa) * (l.O+beta) / (sum+l. 0) ) /sum; for (i=2; ic=n-1; i++) (

sum=i+i+alfabeta; a [il =min/sum/ (sum+2.0) ; b [i] = (2.0/sum) *sqrt (i* (sum-i) * (i+alfa) * (i+betal / (sum*sum-1.0) ) ;

1 I h0=pow(2.O,alfabeta+l.O)*gamma(1.0+alfa)*gamma(1.0+beta)/

gamma (Z.O+alfabeta) ; alljaczer (n, alfa, beta,x) ; for (i=l; ic=n; i++) {

xi=x [il ; r0=1.0 ; rl= (xi-a [Ol ) /b [ll ; sum=l.O+rl*rl; for (j=2; j<=n-1; j++) {

r2=((xi-a[j-11)*r1-b[j-1l*rO)/b[jl; sum += r2*r2; rO=rl; rl=r2 ;

kree-real-vector (a, 0) ; free-real-vector(b,O);

I 1

B, gsslagwghts

Computes the n roots, xi, of the n-th Laguene polynomial Lid and corresponding Gauss-Christoffel numbers wi needed for the n-point Gauss-Laguerre quadrature of f(x) over (O,w] with respect to the weight function Ye". The quadrature formula is exact iff is a polynomial of degree S 2n-1.

The xi are first determined by means of a call of alllagzer, and the wi then derived by

Copyright 1995 by CRC Press, Inc

Page 330: Numerical Library in C for Scientists and Engineers A

use of the formula

Function Parameters: void gsslagwghts (n,alfa,x, w)

n: int; entry: the upper bound of the arrays x and w (n2l);

alfa: float; entry: the parameter of the weight function for the Laguerre polynomials, a& > -1;

x: float x[l:n]; exit: x[i] is the i-th zero of the n-th Laguerre polynomial;

w: float w[l:n]; exit: w[ij is the Gaussian weight associated with the i-th zero of the n-th Laguerre

polynomial.

Functions used: gamma, alllagzer.

Method: The zeros and weights are computed in the same way as in the procedure gssjacwghts.

void gsslagwghts (int n, float alfa, float x[] , float w [I ) {

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void alllagzer (int, float, float [I ) ; float gamma (float) ; int i, j; float hO, s, rO, rl, r2,xi, *a, *b;

a=allocate-real-vector (0, n) ; b=allocate-real-vector(0,n); a [O] =l.O+alfa; a [l] =3.0+alfa; b [l] =sqrt (a [OI ) ; for (i=2; ic=n-1; i++) {

a [i] =i+i+alfa+l .O ; b [i] =sqrt (i* (i+alfa) ) ;

\ alllagzer (n, alfa,x) ; hO=gamma (l.O+alfa) ; for (i=l; i<=n; i++) {

xi=x[il ; r0=1.0 ; rl= (xi-a [Ol ) /b [ll ; s=l.o+rl*rl; for (j=2; j<=n-1; j++) {

r2=( (xi-a[j-11) *rl-b[j-11 *rO) /b[jl ; rO=r1;

Copyright 1995 by CRC Press, Inc

Page 331: Numerical Library in C for Scientists and Engineers A

iree-real-vector (a, 0) ; free-real-vector(b,O);

1

4.3 Numerical differentiation

4.3.1 Calculation with difference formulas

A. jacobnnf

Calculates the Jacobian matrix of an n-dimensional function of n variables using forward differences. jacobnnf computes first order difference quotient approximations

Jij = Cr;(x ,,..., X,,,X,+~,X,+~ ,..., x,S-f i(xl ,..., X,~~,X,,X,+~ ,..., xJ)/)/S, (i,j=l ,..., n) to the partial derivatives qj = af;(x)/ax, of the components of the function f(x) ExeRn).

Function Parameters: void j acobnnf (n,x,xjac, difunct)

n: int; entry: the number of independent variables and the dimension of the function;

x: float x[l:n]; entry: the point at which the Jacobian has to be calculated;

f: float f[l:n]; entry: the values of the function components at the point given in array x;

jac: float jac[l:n, l:n]; exit: the Jacobian matrix in such a way that the partial derivative offri] with respect

to xlj] is given in jac[i,j], i,j=l, ..., n; di: float (*di)(i), int i;

entry: the partial derivatives to x[i] are approximated by forward differences, using an increment in the i-th variable equal to the value of di, i=l, ..., n;

funct: void (*fun@ (n,x,fi; entry: the meaning of the parameters of the function funct is as follows:

n: the number of independent variables of the function x: the independent variables are given in x[l:n]; f: after a call of funct the function components should be given in f[l:n].

void jacobnnf (int n, float x[] , float f [I , float **lac, float (*di) (int), void (*funct) (int, float[], float[] ) )

I float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); int i, j; float step,aid,*fl;

f l=allocate-real-vector (1,n) ; for (i=l; i<=n; i++) {

step= (*di) (i) ; aid=x [il ; x [i] =aid+step; step=l.O/step; (*funct) (n,x, £1) ; for (j=l; j<=n; j++) jacfj] [il=(flljl -f [jl )*step;

Copyright 1995 by CRC Press, Inc

Page 332: Numerical Library in C for Scientists and Engineers A

B. jacobnmf

Calculates the Jacobian matrix of an n-dimensional function of m variables using forward differences. jacobnmf computes first order difference quotient approximations

J,i = g(x,,. . .,x,-, ,~,+li~,x,+~, . . .,x,,, )d(x,, . . . , X ~ ~ ~ , X ~ X , + ~ , . . .,xJ)/lij (ij= I, .. ., nd= I,. . . m) to the partial derivatives J j = aA(x)/ax, of the components of the function f(x) ('jX',xeR").

Function Parameters: void jacobnmf (n, m,x,f;jac, di, funct)

n: int; entry: the number of function components;

m: int; entry: the number of independent variables;

x: float x[l:m]; entry: the point at which the Jacobian has to be calculated;

f: floatf[l:n]; entry: the values of the function components at the point given in array x;

jac: float jac[l :n, l:m]; exit: the Jacobian matrix in such a way that the partial derivative of f[i] with respect

to xo] is given in jac[i,j], i=l , ..., n, j=l , . . .,m; di: float (*di)(i), int i;

entry: the partial derivatives to x[i] are approximated by forward differences, using an increment in the i-th variable equal to the value of di, i=l, ..., m;

funct: void (*funct) (n,m,x,); entry: the meaning of the parameters of the function funct is as follows:

n: the number of function components; m: the number of independent variables of the function A x: the independent variables are given in x[l:m]; f: after a call of funct the function components should be given in f[l:n].

void jacobnmf (int n, int m, float xi], float f [I, float **jac, float (*di) (int) , void (*funct) (int, int, float [ I , float [I )

float *allocate-real-vector(int, int); void f ree-real-vector (float *, int) ; int i, j; float step,aid,*fl;

fl=allocate-real-vector(1,n); for (i=l; ic=m; i++) {

step=(*di) (i) ; aid=x [il ; x [il =aid+step; step=l.O/step; (*funct) (n,m,x, £1) ; for (j=l; jc=n; j++) jac[jl [il=(fl[jl-f[jl)*step; x [il =aid;

Copyright 1995 by CRC Press, Inc

Page 333: Numerical Library in C for Scientists and Engineers A

C. jacobnbndf

Calculates the Jacobian matrix of an n-dimensional function of n variables, if this Jacobian is known to be a band matrix and have to be stored rowwise in a one-dimensional array, jacobnbndf computes first order difference quotient approximations

J l j = &(xl ,... ,X , -~ ,X,+~~,X~+~ ,..., x,J-~@~ ,..., xji ,X,,X,+~ ,..., xn))/6i for i = l ,... n; max(1,i-lw)ljlmin(n,i+rw) to the partial derivatives Ji, = aA(x)/axj of the components of the function f(x) (fxeRn).

Function Parameters:

n:

lw:

rw:

x:

f:

jac:

di:

void j acobnbndf (n, lw, rw,x,Jjac, di, funct) int; entry: the number of independent variables and the dimension of the function; int; entry: the number of codiagonals to the left of the main diagonal of the Jacobian

matrix, which is known to be a band matrix; int; entry: the number of codiagonals to the right of the main diagonal of the Jacobian

matrix; float x[l :n]; entry: the point at which the Jacobian has to be calculated; float f[l:n]; entry: the values of the function components at the point given in array x;

float jac[l: (lw+rw) *(n-1) +n]; exit: the Jacobian matrix in such a way that the (ij)-th element of the Jacobian, i.e.

the partial derivative of f[i] to xfi] is given in jac[(lw+rw)*(i-l)+j], i=l, ..., n, j=max(l ,i-lw),...,min(n,i+rw);

float (*di)(i), int i; entry: the partial derivatives to x[i] are approximated with forward differences, using

an increment to the i-th variable that equals the value of di, i=l, ..., n; funct: void (*funct)(n,l, u,x,fi;

entry: the meaning of the parameters of the function funct is as follows: n: the number of function components; 1,u: int; the lower and upper bound of the function component subscript; x: the independent variables are given in x[l:n]; f: after a call of funct the function components f[i], i=l, ..., u, should be given in

f[l:u].

void jacobnbndf(int n, int lw, int rw, float x [ ] , float f[l, float jac[l, float (*di) (int), int (*funct) (int, int, int, float [I , float [I )

{ float *allocate-real-vector(int, int); void f ree-real-vector (float *, int) ; int i,j,k,l,u,t,b,ll; float aid, stepi, *fl;

1=1; u=lw+1; t=rw+l; b=lw+rw; for (i=l; ic=n; i++) {

11=1;

Copyright 1995 by CRC Press, Inc

Page 334: Numerical Library in C for Scientists and Engineers A

fl=allocate-real-vector(l1,u); stepi= (*di) (i) ; aid=x [il ; x [i] =aid+stepi ; (*funct) (n, l,u,x, £1) ; x [il =aid; k = i+((i <= t) ? 0 : i-t)*b; for (j=l; j<=u; j++) {

jac[kl=(fl[jl -f [jl )/stepi; k += b;

\ J

if (i >= t) 1++; if (U c n) u++; free-real-vector (f 1,ll) ;

Copyright 1995 by CRC Press, Inc

Page 335: Numerical Library in C for Scientists and Engineers A

5. Analytic Problems

5.1 Non-linear equations

5.1.1 Single equation - No derivative available

A. zeroin

Given the values, xo and yo say, of the end points of an interval assumed to contain a zero of the function f(x), zeroin attempts to find, by use of a combination of linear interpolation, extrapolation, and bisection, values, x, and y,, say, of the end points of a smaller interval containing the zero. The method used is described in detail in [BusD75]. At successful exitf(xlJf(rlJlO, I f(xJ I I I f(y,J I and Ix,,-y,, II2*tol(x J, where to1 is a tolerance function prescribed by the user. The value of tol(x) may be changed during the course of the computation or left constant, as the user requires. For example tol(x) may be the function 1x1 *re+ae (where re, the permissible relative error, should be greater than the machine precision, and ae, the permissible absolute error should not be set equal to zero if the prescribed interval contains the origin).

The algorithm used results in the construction of five sequences of real numbers xi, a , b , ci and dj, and two integer sequences j(i), k(i) (i=l, ..., n) as follows. Initially, with x,=yo, if 1 f(xJ I I I f(xJ I then b,=x,, a,=cl=xo, otherwise b,=xo, a,=c,=x,. Then, for i=2 ,..., n: (a) j(i) is taken to be the largest integer in the range l<j(i)<i for which I b,(,,-~,(~ lI1h 1 b,(i)-l-~,(il-l I with j(i)=l if this condition is never satisfied; (b) with

h(b,c) = b + sign(c-b)tol(b) m(b,c) = (b+c)/2 0 , a) = b - f(b) (b-a)/Cf(b)-S(a)) Cff4 #f(b)) I(b,a) = 00 Cf(a) =f(V # 0) I(b,a) = b Cf(4 =f(@ =O)

and w(l,b,c) = I if I is between h(b,c) and m(b,c); w(l,b,c) = h(b,c) if I I-b 1 vol(b) and 1 does not lie

outside the interval bounded by b and m(b,c);

w(l,b,c) =m(b,c) otherwise and r(b,a,d) determined by the condition that

(x-r(b, a, d))/(px+q) = f(x) when x=a,b,d, xi is determined by use of the formula

~~=w(l(b,-~,a,J,b,, ,c,J i f j ( i ) k i - 2 xi = w(r(b,-,,a,,,diJ, b,-,,cJ if j(i) = i-3 xi = m(bi-,,ci-J otherwise

(c) k(i) is taken to be the largest integer in the range Olk(i)<i for which f ( ~ ~ ( ~ , ) f ( x J I 0 , and if I f(xJ I I lf(xkfU 1 , then bi=x, ~~=x, (~ , , a,=b,,, otherwise bi=xk(,,, ai=ci=xj; also, if bi=xi or bi=b,, then di=a,,, otherwise di=b,,; (d) n is the smallest integer for which I b,,- C, I 12*tol(b,J, and then x,=b,, yn=cn.

The number of evaluations of fx and tolx is at most 4* log,( I x-y 1 )/tau, where x and y are the argument values given upon entry, tau is the minimum of the tolerance function tolx

Copyright 1995 by CRC Press, Inc

Page 336: Numerical Library in C for Scientists and Engineers A

on the initial interval. If upon entry x and y satisfy f(x)*f(yl<O, then convergence is guaranteed and the asymptotic order of convergence is 1.618 for simple zeros.

Function Parameters: int zeroin (x,y,fx tolx)

zeroin: on exit zeroin is given a nonzero value when a sufficiently small subinterval of J containing a zero of the function f(x) has been found; otherwise zeroin is given the value zero;

x: float *; entry: one endpoint of interval J in which a zero is searched for; exit: a value approximating the zero within the tolerance 2*tol(x) when zeroin has

the value nonzero, and a presumably worthless argument value otherwise; y: float *;

entry: the other endpoint of interval J in which a zero is searched for; upon entry x < y as well as y < x is allowed;

exit: the other straddling approximation of the zero, i.e. upon exit the values of y and x satisfy (a) f(x)*f(y)lO, (b) I x-y 1 <2*tol(x) and (c) I f(x) 1 I1 f(yll when zeroin has a nonzero value;

fx: float (*fi)(x); entry: defines function f as a fimction depending on the actual parameter for x;

tolx: float (*tolx)(x); entry: defines the tolerance function to1 which may depend on the actual parameter

for x; one should choose tolx positive and never smaller than the precision of the machine's arithmetic at x, i.e. in this arithmetic x+tolx and x-tolx should always yield values distinct from x; otherwise the procedure may get into a loop.

jnt zeroin (f loat *x, float *y, float (*fx) (float) , float (*tolx) (float) ) {

int ext,extrapolate; float c, fc,b,fb,a, fa,d, fd,fdb,fda,w,mb,tol,m,p,q;

b = *x; fb= (*fx) (*x) ; a = * x = *Y; fa= (*fx) (*x) ; c=a; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) c fabs(fb)) ( if (C ! = a) {

d=a ; fd=fa;

1

Copyright 1995 by CRC Press, Inc

Page 337: Numerical Library in C for Scientists and Engineers A

if (ext > 2 ) w=mb ;

else { if (mb == 0.0)

tol=O.O ; else

if (mb < 0.0) to1 = -tol; p= (b-a) *fb; if (ext <= 1)

q=fa-fb; else {

fdb= (fd-fb) / (d-b) ; fda= (fd-fa) / (d-a) ; p *= fda; q=fdb*fa-fda*fb;

d=a; fd=fa; a=b; fa=fb; *x = b += w; fb= (*fx) (*x) ; if ((fc >= 0.0) ? (fb >= 0.0) : (fb <= 0.0)) {

c=a; fc=fa; ext=O;

) else ext = (w == mb) ? 0 : ext+l;

) else break;

1 * y = c; return ((fc >= 0.0) ? (fb <= 0.0) : (fb >= 0.0));

1

B. zeroinrat

Given the values, xo and yo say, of the end points of an interval assumed to contain a zero of the function f(x), zeroinrat attempts to find, by use of a combination of linear interpolation, extrapolation, and bisection, values, xn and yn say, of the end points of a smaller interval containing the zero. The method used is described in detail in [BusD75]. At successful exit f(xJf(vJ50, I f(xJ I < I f(yJ 1 and I xn-yn 112*tol(x,,), where to1 is a tolerance function prescribed by the user (see the documentation of zeroin).

The algorithm used by zeroinrat closely resembles that used by zeroin, except that x, is now determined by use of the formula

X, = w(l(b,,,a,,), b,,,c,3 if j(i) 1 i-2 X, = w(r(b,,,a,,,d,J, b,,,c,J i f~ ( I ) = i-3 x, = w(2r(b ,.,, a,.,,d,,)-b,,,b ,-,, c,J if i13 and j(i)=i-4 x, = m(b,,,c,J otherwise. The number of evaluations of f i and tolx is at most 5*log,( I x-y 1 )/tau, where x and y

are the argument values given upon entry, tau is the minimum of the tolerance function tolx on the initial interval. If upon entry x and y satisfy f(x)*ff(yl<O, then convergence is guaranteed and the asymptotic order of convergence is 1.839 for simple zeros.

zeroln is preferable for simple (i.e. cheaply to calculate) functions andlor when no high precision is required. zerornrat is preferable for complicated (i.e. expensive) hnctions when a zero is required in rather high precision and also for functions having a pole near the zero.

Copyright 1995 by CRC Press, Inc

Page 338: Numerical Library in C for Scientists and Engineers A

When the analytic derivative of the function is easily obtained, then zeroinder should be taken into consideration.

Function Parameters: int zeroinrat (x,y,jk, tolx)

zeroinrat: on exit zeroinrat is given a nonzero value when a sufficiently small subinterval of J containing a zero of the function f(x) has been found; otherwise zeroinrat is given the value zero;

x: float *; entry: one endpoint of interval J in which a zero is searched for; exit: a value approximating the zero within the tolerance 2*tol(x) when zeroinrat

has a nonzero value; y: float *;

entry: the other endpoint of interval J in which a zero is searched for; upon entry x < y as well as y < x is allowed;

exit: the other straddling approximation of the zero, i.e. upon exit the values of y and x satisfy (a) f(x)*f(y)lO, (b) Ix-yll2*tol(x) and (c) I f(x) 12 1 f & ) l when zeroinrat has a nonzero value;

fx: float (*jk)(x); entry: defines function f as a function depending on the actual parameter for x;

tolx: float (*tolx)(x); entry: defines the tolerance function to1 which may depend on the actual parameter

for x; one should choose tolx positive and never smaller than the precision of the machine's arithmetic at x, i.e. in this arithmetic x+tolx and x-tolx should always yield values distinct from x; otherwise the procedure may get into a loop.

int zeroinrat (float *x, float *y, float (*£XI (float) , float (*tolx) (float))

r I

int ext,first,extrapolate; float b,fb,a,fa,d,fd,c,fc,fdb,fda,w,mb,tol,m,p,q;

b = *x; fb= (*£XI (*x) ; a = * x = *Y; fa= (*fx) (*x) ; f irst=l; c=a; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) c fabs(fb)) { if (C ! = a) {

d=a; fd=fa;

1

Copyright 1995 by CRC Press, Inc

Page 339: Numerical Library in C for Scientists and Engineers A

mb=m-b; if (fabs(mb) > tol) {

if (ext > 3 ) w=mb ;

else { if (mb == 0.0)

tol=O.O ; else

if (mb c 0.0) to1 = -tol; p= (b-a) *fb; if (first) {

q=fa-fb; first=O;

} else { fdb= (fd-fb) / (d-b) ; fda=(fd-fa)/(d-a) ; p *= fda; q=fdb*fa-fda*fb;

I

I if (ext == 3) p *= 2.0; w= (pcFLT-MIN I I p<=q*tol) ? to1 : ( (p<mb*q) ? p/q : mb) ;

1 d=a; fd=fa; a=b; fa=fb; *X = b += w; fb= (*fx) (*x) ; if ((fc >= 0.0) ? (fb >= 0.0) : (fb <= 0.0)) {

c=a; f c=fa; ext=O;

) else ext = (W == mb) ? 0 : ext+l;

) else break;

1 *y = c; return ((fc >= 0.0) ? (fb c = 0.0) : (fb >= 0.0));

1

5.1.2 Single equation - Derivative available

zeroinder

Given the values, xo and yo say, of the end points of an interval assumed to contain a zero of the functionf(x), zeroinder attempts to find, by use of a combination of interpolation and extrapolation based upon the use of a fractional linear function, and of bisection, values, xn and yn say, of the end points of a smaller interval containing the zero. At successful exit f(xJf(yJI0, I f(xJ I I1 f(yJ I and I xn-y, I I2*tol(x,J, where to1 is a tolerance function prescribed by the user (see the documentation of zeroin).

The algorithm used by zeroinder is similar to that used by zeroin, with the difference that the estimate I(b,a) of the zero off($ obtained by linear interpolation between the two function values at x=a and x=b is replaced by an estimate obtained by interpolation based upon use of a fractional linear function (x-u)/(vx+w) whose value agrees with that of f(x) at x=a and x=b, and whose derivative is also equal in value to that of f(x) at one of these points.

zeroinder is to prefer to zeroin or zeroinrat if the derivative is (much) cheaper to evaluate than the function.

Copyright 1995 by CRC Press, Inc

Page 340: Numerical Library in C for Scientists and Engineers A

The number of evaluations of@, dfx and tolx is at most 4*log,( I x-y I )/tau, where x and y are the argument values given upon entry, tau is the minimum of the tolerance function tolx on the initial interval (i.e. zeroinder requires at most 4 times the number of steps required for bisection). If upon entry x and y satisfy f(x)*ff(y))lO then convergence is guaranteed and the asymptotic order of convergence is 2.414 for a simple zero off:

Function Parameters: int zeroinder (x,y&, dfi, tolx)

zeroinder: on exit zeroinder is given a nonzero value when a sufficiently small subinterval of J containing a zero of the function f(x) has been found; otherwise zeroin is given the value zero;

x: float *; entry: one endpoint of interval J in which a zero is searched for; exit: a value approximating the zero within the tolerance 2*tol(x) when zeroinder

has a nonzero value; y: float *;

entry: the other endpoint of interval J in which a zero is searched for; upon entry x < y as well as y < x is allowed;

exit: the other straddling approximation of the zero, i.e. upon exit the values of y and x satisfy (a) f(x)*f(y))lO, (b) Ix-y l l2*tol(x) and (c) I f(x) 12 1 f(y) )l when zeroinder has a nonzero value;

fx: float (*fx)(x); entry: defines function f as a function depending on the actual parameter for x;

dfx: float (*dfx)(x); entry: defines derivative df of f as a function depending on the actual parameter for

x; tolx: float (*tolx)(x);

entry: defines the tolerance function to1 which may depend on the actual parameter for x; one should choose tolx positive and never smaller than the precision of the machine's arithmetic at x, i.e. in this arithmetic x+tolx and x-tolx should always yield values distinct from x; otherwise the procedure may get into a loop.

int zeroinder (float *x, float * y , float (*fx) (float) , float (*dfx) (float) , float (*tolx) (float) )

{ int ext,extrapolate; float b, fb, dfb, a, fa, dfa, c, fc, dfc, d, w , m , tol,m,p, q;

b = *x; fb= (*fx) (*x) ; dfb= (*dfx) (*x) ; a = * x = *Y; fa= (*fx) (*x) ; dfa= (*dfx) (*XI ; c=a; fc=fa; df c=dfa; ext=O ; extrapolate=l; while (extrapolate) {

if (fabs(fc) c fabs(fb)) { a=b; fa=fb;

Copyright 1995 by CRC Press, Inc

Page 341: Numerical Library in C for Scientists and Engineers A

to1= (*tolx) (*x) ; m= (c+b) *0.5; mb=m-b; if (fabs(mb) > tol) {

if (ext > 2 ) w =mb ;

else { if (mb == 0.0)

tol=O .O ; else

if (mb < 0.0) to1 = -tol; d = (ext == 2) ? dfa : (fb-fa)/(b-a) ; p=fb*d* (b-a) ; q=fa*dfb-fb*d; if (p < 0.0) {

P = -p; q = -q;

1 w= (p<FLT-MIN I / p<=q*tol) ? to1 : ((p<mb*q) ? p/q : mb) ;

1 a=b; fa=fb; df a=dfb ; *X = b += w; fb= (*fx) (*x) ; dfb= (*dfx) (*x) ; if ((fc >= 0.0) ? (fb >= 0.0) : (fb c = 0.0)) {

c=a; fc=fa; df c=df a ; ext=O;

} else ext = (w == mb) ? 0 : ext+l;

) else break ;

I * y = c; return ((fc >= 0.0) ? (fb <= 0.0) : (fb >= 0.0));

I

5.1.3 System of equations - No Jacobian matrix

A. quanewbnd

Solves systems of non-linear equations of which the Jacobian is known to be a band matrix and an approximation of the Jacobian is assumed to be available at the initial guess. The method used is the same as given in [Br071].

quanewbnd computes an approximation to the solution x of the system of equations f(x) =O V;xtR") for which the components ~J)=a~j(x)/axo) of the associated Jacobian matrix are zero when j>i+rw or i>j+lw, an approximation xo to x and an approximation Jo to df(xJldxo being assumed to be available.

At the i-th stage of the iterative method used, 6i is obtained by solving (decsolbnd is called for this purpose) the band matrix system of equations

ASi = -j(xJ (1) with xi+, = xi + and with p!) = (0 ,..., 0,6 ,..., 6hoj,0 ,..., 0) where hfj)=max(l j-lw), k(j)=rnin(n,j+rw), and with Ij being the matrix whose (jJ)-th element is

Copyright 1995 by CRC Press, Inc

Page 342: Numerical Library in C for Scientists and Engineers A

unity, all other elements being zero, and (the bars denoting Euclidean norms) with A!) = ~ f ( x ~ + , ) ( P ~ ) ~ / ( p ~ ) , ~ ~ ) ) if IIPF) 11 2e2 11 4 11 \ I P i 11 , and 0 otherwise

(E being the machine precision) J,+, is obtained from the relationship

formula (1) is reapplied and the process continued.

Function Parameters: void quanewbnd (n, Iw,rw,x,J;jac, funct, in, out)

n: int; entry: the number of independent variables; the number of equations should also be

equal to n; lw: int;

entry: the number of codiagonals to the left of the main diagonal of the Jacobian; rw: int;

entry: the number of codiagonals to the right of the main diagonal of the Jacobian; x: float x[l:n];

entry: an initial estimate of the solution of the system that has to be solved; exit: the calculated solution of the system;

f: float f[l:n]; entry: the values of the function components at the initial guess; exit: the values of the function components at the calculated solution;

jac: float jac[l:(lw+rw) *(n-l)+n]; entry: an approximation of the Jacobian at the initial estimate of the solution;

an approximation of the (i,j)-th element of the Jacobian is given in jac[(lw+rw) *(i- I)+j], for i=l, ..., n and j=max(l,i-lw) ,..., min(n,i+rw);

exit: an approximation to the Jacobian at the calculated solution; funct: int (*funct) (n, I, u,x,f);

entry: the meaning of the parameters of the function funct is as follows: n: the number of independent variables of the function 1,u: int; the lower and upper bound of the function component subscript; x: the independent variables are given in x[l:n]; f: after a call of funct the function components f[i], i=l, ..., u, should be given in

f[l: 4 ; exit: if the value of funct is zero then the execution of quanewbnd will be

terminated, while the value of out[5] is set equal to 2; in: float in[0:4];

entry: in[O]: the machine precision; in[l]: the relative precision asked for; in[2]: the absolute precision asked for; if the value, delivered in out[5] equals zero

then the last correction vector d, say, which is a measure for the error in the solution, satisfies the inequality 11 d 11 I 11 x 11 *in[l]+in[2], whereby x denotes the calculated solution, given in array x and 11 . / I denotes the Euclidean norm; however, we cannot guarantee that the true error in the solution satisfies this inequality, especially if the Jacobian is (nearly) singular at the solution;

Copyright 1995 by CRC Press, Inc

Page 343: Numerical Library in C for Scientists and Engineers A

in[3]: the maximum value of the norm of the residual vector allowed; if out[5]=0 then this residual vector r, say, satisfies: 11 r 11 lin[3];

in[4]: the maximum number of function component evaluations allowed; I-u+l function component evaluations are counted for each call of funct(n,l,u,xf); if out[5]=l then the process is terminated because the number of evaluations exceeded the value given in in[4];

out: float out[l:5]; exit: out[l]: the Euclidean norm of the last step accepted; out[2]: the Euclidean norm of the residual vector at the calculated solution; out[3]: the number of function component evaluations performed; out[4]: the number of iterations carried out; out[5]: the integer value delivered in out[5] gives some information about the

termination of the process; out[5]=0: the process is terminated in a normal way; the last step and the norm

of the residual vector satisfy the conditions (see in[2], in[3J; if out[5]+0 then the process is terminated prematurely;

out[5]=l: the number of function component evaluations exceeds the value given in in[4];

out[5]=2: a call of funct delivered the value zero; out[5]=3: the approximation to the Jacobian matrix turns out to be singular.

Functions used: mulvec, dupvec, vecvec, elmvec, decsolbnd.

void quanewbndfint n, int lw, int rw, float x[l, float f[l, float jac[l, int (*funct) (int, int, int, float [I, float [I ) , float in [I , float out [I )

1 float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float vecvec(int, int, int, float [I, float [I ) ; void elmvec (int, int, int, float [ I , float [I , float) ; void mulvec (int, int, int, float [ I , float [I , float) ; void dupvec (int, int, int, float [ I , float [I ) ; void decsolbnd(f loat [I , int, int, int, float [I , float [ I ) ; int l,it,fcnt,fmax,err,b,i,j,k,r,m; float macheps,reltol,abstol,tolres,nd,mz,res,*delta,mul,~rit,

*pp, *s,aux[61 , *lu;

delta=allocate-real-vector(1,n) ; nd=O .O; macheps=in [OI ; reltol=in [ll ; abstol=in [21 ; tolres=in [31 ; fmax=in [41 ; mz=macheps*macheps; it=fcnt=O; b=lw+rw; l= (n-1) *b+n; b++; res=sqrt (vecvec (l,n, 0, £ , £ ) ) ; err=O ; while (1) {

if (err ! = 0 I I (res c tolres && sqrt (nd) c sqrt (vecvec (l,n, O,x,x) ) *reltol+abstol) ) break;

it++; if (it ! = 1) {

Copyright 1995 by CRC Press, Inc

Page 344: Numerical Library in C for Scientists and Engineers A

/* update jac * / pp=allocate-real-vector(1,n); s=allocate-realvector(1,n); crit=nd*mz; for (i=l; ic=n; i++) pp [il =delta[il *delta [il ; r=k=l; m=rw+l; for (i=l; i<=n; i++) {

mul=O. 0 ; for (j=r; jc=m; j++) mu1 += pp[jl; j=r-k; if (fabs (mul) > crit) elmvec (k,m- j, j, jac,delta, f[il /mul) ; k += b; if (i > lw)

r++; else

k--; if (m c n) m++;

I I

free-real-vector (pp, 1) ; free-real-vector (s, 1) ;

1 I * direction */ lu=allocate~real~vector(l,l); aux [2 I =macheps ; mulvec(l,n,0,delta,fI-1.0) ; dupvec(l,l, O,lu, jac) ; decsolbnd(lu,n, lw,rw,aux,delta) ; free-real-vector(lu,l); if (aux[3l != n) {

err=3 ; break;

] else { elmvec (l,n,O,x, delta, 1.0) ; nd=vecvec (l,n, O,delta,delta) ; / * evaluate * / fcnt += n; if ( ! ( (*funct) (n, l,n,x, f) ) ) {

err=2 ; break;

J if (fcnt s fmax) err=l; res=sqrt(vecvec(l,n,O,f,f)) ;

, I I out [1l =sqrt (nd) ; out [21 =res; out [31 =fcnt; out [41 =it; out [51 =err; free-real-vector (delta, 1) ;

I

B. quanewbndl

Solves systems of non-linear equations of which the Jacobian is known to be a band matrix and an approximation to the Jacobian at the initial guess is calculated using forward differences.

Computes an approximation to the solution x of the system of equations f(x)=O V;x&") for which the components ~ j ) = a ~ ) ( x ) / a x 0 ) to the associated Jacobian matrix are zero when j>i+rw or i>j+lw, an approximation xo to x being assumed to be available.

An approximation Jo to af(x,J/axo, based upon the use of first order finite difference approximations using equal increments d for all components, is first obtained by means of a call of jacobnbndJ; and quanewbnd is then called to obtain the desired approximation.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 345: Numerical Library in C for Scientists and Engineers A

void quanewbndl (n,lw,rw,x,lfunct, in, out) n: int;

entry: the number of independent variables; the number of equations should also be equal to n;

fw: int; entry: the number of codiagonals to the left of the main diagonal of the Jacobian;

rw: int; entry: the number of codiagonals to the right of the main diagonal of the Jacobian;

x: float x[l:n]; entry: an initial estimate of the solution of the system that has to be solved; exit: the calculated solution of the system;

j float f[l:n]; exit: the values of the function components at the calculated solution;

funct: int (*funct) (n,l, u,x,) ; entry: the meaning of the parameters of the function funct is as follows:

n: the number of independent variables of the function f,u: int; the lower and upper bound of the function component subscript; x: the independent variables are given in x[l:n]; j after a call of funct the hnction components f[i], i=l, ..., u, should be given in

f[l: 4 ; exit: if the value of funct is zero then the execution of quanewbndl will be

terminated, while the value of out[5] is set equal to 2; in: float in[0:5];

entry: in[O]: the machine precision; in[l]: the relative precision asked for; in[2]: the absolute precision asked for; if the value delivered in out[5] equals zero

then the last correction vector d, say, which is a measure for the error in the solution, satisfies the inequality 11 d 11 I 11 x 11 *in[l]+in[2], whereby x denotes the calculated solution, given in array x and 1 1 . 1 1 denotes the Euclidean norm; however, we cannot guarantee that the true error in the solution satisfies this inequality, especially if the Jacobian is (nearly) singular at the solution;

in[3]: the maximum value of the norm of the residual vector allowed; if out[5]=0 then this residual vector r, say, satisfies: 11 r 11 lin[3];

in[4]: the maximum number of function component evaluations allowed; 1-u+l function component evaluations are counted each call of funct(n, I, u,x,); if out[5]=l then the process is terminated because the number of evaluations exceeded the value given in in[4];

in[5]: the Jacobian matrix at the initial guess is approximated using forward differences, with a fixed increment to each variable that equals the value given in in[5];

out: float out[l:5]; exit: out[l]: the Euclidean norm of the last step accepted; out[2]: the Euclidean norm of the residual vector at the calculated solution; out[3]: the number of function component evaluations performed; out[4]: the number of iterations carried out; out[5]: the integer value delivered in out[5] gives some information about the

Copyright 1995 by CRC Press, Inc

Page 346: Numerical Library in C for Scientists and Engineers A

termination of the process; out[5]=0: the process is terminated in a normal way; the last step and the norm

of the residual vector satisfy the conditions (see in[2], in[3n; if out[5]#0 then the process is terminated prematurely;

out[5]=1: the number of function component evaluations exceeds the value given in in[4];

out[5]=2: a call of funct delivered the value zero; out[5]=3: the approximation of the Jacobian matrix turns out to be singular.

Functions used: jacobnbndf, quanewbnd.

void quanewbndl (int n, int lw, int rw, float x[l , float f [I, int (*funct) (int, int, int, float [I , float [I ) , float in [I , float out [I )

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int) ; float quanewbndlt (float, int) ; void quanewbnd(int, int, int, float [I, float [I, float [I,

int ( * ) (int, int, int, float [I , float [I ) , float [I, float [I);

void jacobnbndf (int, int, int, float [I , float [I , float [I, float ( * ) (int), int ( * ) (int, int, int, float [I , float [I ) ) ;

int k; float *jac;

in[4] - = k; quanewbndlt (in [51 , 1) ; jacobnbndf (n, lw, rw, x, W a c , quanewbndls, funct) ; quanewbnd (n, lw, rw, x, f,jac, funct, in, out) ; in141 += k; out[31 += k; f ree-real-vector (jac, 1) ;

I float quanewbndls(int i) 1 1

/ * this function is used internally by QUANEWBNDl * /

float quanewbndlt (float, int) ;

return (quanewbndlt (0 .O, 0 ) ) ; I ;loat quanewbndlt(f1oat x, int i) 1

/ * this function is used internally by QUANEWBNDl * /

static float y;

y = ( i ? x : y); return (y) ;

1

5.2 Unconstrained optimization

5.2.1 One variable - No derivative

minin

Copyright 1995 by CRC Press, Inc

Page 347: Numerical Library in C for Scientists and Engineers A

Determines a point xe[a,b] at which the real valued function f(x) assumes a minimum value. It is assumed that, for some point p&(a,b) either (a) f is strictly monotonically decreasing on [a+) and strictly monotonically increasing on [p,b] or (b) these two intervals may be replaced by [a+] and (p,b] respectively. Use is made of function values alone.

The method used involves the determination of five sequences of points a,, b,,, v,, w,, x,, and further auxiliary numbers, u , p, and q, (n=0,1, ...). Initially

a, = a, b, = b, v, = w, = x, = a, + %(3-1/5)(b,-ad. At the n-th stage of the computations a local minimum is known to lie in [a,b,] and x,&[a,,b,]. If max(x,-a,, b,-x,) I2*tol(xJ, where tol(x) is a tolerance function prescribed by the user, the computations terminate, x, is such that f(xJ < f(xJ either (a) for r=O,l, ..., n-1 or (b) for r=O,l, ..., n-2 with f(xJ = f(x,.J; f(wJ < f(xJ for r=O,l, ..., n-2 in case (a) and for r=O,l, ..., n-3 in case (b). If the computations are not terminated, p,, q, are determined such that x, + p,,/qn is a turning point of the parabola through (v,,f(vJ), (w,,f(wJ) and (x,,, f(x,J):

PI1 = * (6,-vJ 2Cf(xJf(w J)-(xn-wJ2B(~J-SivJ)) qn = f 2((xn-vJ2Cf(xJ-f(wJ)-(xn-wJ Cf(wn) XvJ)).

If either Ip,/q, 1 ltol(xJ or q,=O or x,+p,/q, E (a,,b,) then u,,+, = %v5-1)xn+%(3-V5)an if xn2%(an+bJ u,,+, = %(/5-l)x,+%(3-1/5)bn if x,<%(a,+bJ;

otherwise u,+, = x, + pJq,. The points a,, ..., w, are updated as follows: if f(u,+ J I f(x J then (a) a,,+,=a,, and b,,+,=x, if u,+, < x,, while if u,+, 1 x,, an+,=xn and b,+,=b,, and also (b) v,,+,=w,,, w,+,=x, and x,+,=u,+,; if however, f(u,,, J > f(xJ then (a) an+,=un+, and b,+,=b, if u,,+,<x,,, while if url+, 1 x,, a,+,=a, and b,+,=u,+, and also (b) x,,+,=x,, v,+,=x,, and w,,+,=u,,+, if f(u,,+J < f(wJ or w,=x, while, if neither of these conditions is satisfied and either f(u,,+S SfPJ Or v,=x, Or v,=w,, then x,+,=x,, v,+,=u,+,, wn+,=wn.

The user should be aware of the fact that the choice of tolx may highly affect the behavior of the algorithm, although convergence to a point for which the given function is minimal on the interval is assured. The asymptotic behavior will usually be fine as long as the numerical function is strictly 6-unimodal on the given interval (see [Bre73]) and the tolerance hnction satisfies tol(x)26, for all x in the given interval.

Function Parameters: float minin (x,a,b,fx,tolx)

minin: delivers the calculated minimum value of the function, defined by fx, on the interval with endpoints a and b;

x: float *; entry: the actual parameter forfx and tolx depends on x; exit: the calculated approximation of the position of the minimum;

a,b: float*; entry: the endpoints of the interval on which a minimum is searched for; exit: the endpoints of the interval with length less than 4*tol(x) such that a<x<b;

fx: float (*&)(XI; entry: the function is given by the actual parameter fx which depends on x;

tolx: float (*tolx)(x); entry: defines the tolerance function which may depend on x; a suitable tolerance

function is: 1x1 *re+ae, where re is the relative precision desired and ae is an absolute precision which should not be chosen equal to zero.

Copyright 1995 by CRC Press, Inc

Page 348: Numerical Library in C for Scientists and Engineers A

float minin(f1oat *x, float *a, float *b, float (*fx) (float), float (*tolx) (float) )

1 L

float z,c,d,e,m,p,q,r,tol,t,u,v,w,fu,fv,fw,fz;

w = *x = *a; fw=(*fx) (*XI ; Z = *X = *b; fz=(*fx) (*x) ; if (£2 > fw) {

z=w; W = *x; v=f 2; f z=fw; fw=v;

1 v=w ; fv=fw; e=O . 0 ; while (1) {

m=(*a + *b)*0.5; tol= (*tolx) (*x) ; t=tol*2.0; if (fabs (2-m) c= t- (*b - *a) *0.5) break; p=q=r=O.O; if (fabs(e) z tol) {

r=(z-w) * (fz-fv) ; q=(z-v) * (£2-fw) ; p= (z-v) *q- (z-w) *r; q= (q-r) *2.0; if (q > 0.0)

p = -p; else

q = -q; r=e ; e=d;

I

if (fabs(p) < fabs(q*r*0.5) && p > (*a-z)*q && p < (*b-z)*q) { d=p/q; u=z+d; if (u- (*a) c t I I (*b)-u < t) d = ( ( 2 c rn) ? to1 : -toll ;

) else ( e = ((z < m) ? *b : *a) - z; d=c*e;

I 1

u = *x = z + ((fabs(d) >= tol) ? d : ((d>O.O) ? to1 : -tol)); fu= (*fx) (*x) ; if (fu <= fz) (

if (U c Z) *b=z;

else *a=z;

v=w ; fv=fw; w=z ; fw=fz; z=u; fz=fu;

) else { if (U c Z)

*a=u; else

*b=u; if (fu <= fw) (

v=w ; fv=fw; w=u; fw=fu;

Copyright 1995 by CRC Press, Inc

Page 349: Numerical Library in C for Scientists and Engineers A

) else if (fu <= fv I I v == W ) (

v=u; fv=fu;

1

*x=z ; return £2;

}

5.2.3 One variable - Derivative available

mininder

Determines a point xs[a,b] at which the real valued function f(x) of one variable assumes a minimum value, when the analytical derivative Df(x) of the function is available.

mininder has almost the same structure as the procedure given in [Bre73]. However, cubic interpolation (see [Dav59]) is used instead of quadratic interpolation to approximate the minimum. The method used involves the determination of a sequence of intervals [a,, b,,] (n=0,1, ...) known to contain the required minimum point, and a further sequence of points u, (n=1,2, ...). Initially a,=a, b,=b. u,+, is the point at which g has a minimum value, where g is the osculating cubic for which g(x)=f(x) and Dg(x)=Df(x) when x=an and x=b,. With Df(a,,S 10, Df(b J>O, a,+,=u,+, and b,+,=b, if Df(uJ I 0, while a,+,=a,, b,+,=u,+, if Df(u J > 0. Termination occurs when b,+,-a,+, 5 3*tol(u,+ J, where tol(x) is a tolerance function prescribed by the user.

The user should be aware of the fact that the choice of tolx may highly affect the behavior of the algorithm, although convergence to a point for which the given function is minimal on the interval is assured. The asymptotic behavior will usually be fine as long as the numerical function is strictly 8-unimodal on the given interval (see [Bre73]) and the tolerance function satisfies tol(x) 26, for all x in the given interval. Let the value of dfx at the begin and end point of the initial interval be denoted by dfa and dfb, respectively, then, finding a global minimum is only guaranteed if the function is convex and dfa I 0 and dfb 2 0. If these conditions are not satisfied then a local minimum or a minimum at one of the end points might be found.

Function Parameters:

mininder:

x: float *; entry:

exit: y: float *;

entry: exit:

float mininder (x,y,fx,dfx,tolx) delivers the calculated minimum value of the function, defined by fx, on the interval with endpoints a and b;

one of the end points of the interval on which the function has to be minimized; the calculated approximation of the position of the minimum;

the other end point of the interval on which the function has to be minimized; a value such that Ix-y l 2 3*tol(x);

fx: float (*fx)(x); entry: the function is given by the actual parameter fx which depends on x;

dfx: float (*dfx)(x); entry: the derivative of the function is given by the actual parameter dfx which

Copyright 1995 by CRC Press, Inc

Page 350: Numerical Library in C for Scientists and Engineers A

depends on x; fx and dfx are evaluated successively for a certain value of x; tolx: float (*tolx)(x);

entry: defines the tolerance function which may depend on x; a suitable tolerance function is: I x 1 *retae, where re is the relative precision desired and ae is an absolute precision which should not be chosen equal to zero.

float mininder(f1oat *x, float *y, float (*fx) (float), float (*dfx) (float) , float (*tolx) (float) )

{ int sgn; float a,b,c,fa,fb,fu,dfa,dfb,dfu,e,d,to1,baaz,p,q,s;

if (*x c= *Y) ( a = *x; fa=(*fx) (*x) ; dfa=(*dfx) (*XI ; b = *x = * y ; fb=(*fx) (*x) ; dfb= (*dfx) (*x) ;

} else { b = *x; fb= (*fx) (*x) ; dfb= (*dfx) (*XI ; a = *x = *y; fa= (*fx) (*x) ; dfa=(*dfx) (*x) ;

1 c=(3 .O-sqrt (5.0) ) /2.0; d=b-a; e=d*2.0; z=e*2.0; while (1) {

ba=b-a; tol= (*tolx) (*XI ; if (ba < tol*3.0) break; if (fabs(dfa) c= fabs(dfb1) (

*x=a; sgn=l;

} else { *x=b; sgn = -1;

1 if (dfa <= 0.0 && dfb >= 0.0) {

z=(fa-fb)*3.0/ba+dfa+dfb; s=sqrt (z*z-dfa*dfb) ; p = (sgn == 1) ? dfa-s-z : dfb+s-z; p *= ba; q=dfb-dfa+s*2.0; z=e; e=d; d = (fabs (p) <= fabs(q) *tol) ? tol*sgn : -p/q;

) else d=ba ;

if (fabs(d) >= fabs(z*0.5) I I fabs(d) > ba*0.5) ( e=ba; d=c*ba*sgn;

1 1

*X += d; fu= (*fx) (*x) ; dfu= (*dfx) (*x) ; if (dfu >= 0.0 I I (fu >= fa && dfa <= 0.0)) {

b = *x; fb=fu; dfb=dfu;

) else ( a = *x; fa=fu; dfa=dfu;

1

Copyright 1995 by CRC Press, Inc

Page 351: Numerical Library in C for Scientists and Engineers A

1 if (fa c = fb) {

*x=a; *y=b; r e t u r n fa;

} else { *x=b; *y=a; r e t u r n fb;

1

5.2.4 More variables - Auxiliary procedures

A. linemin

Determines the real value a,,, (>O) of a for which f(a) = F(x,+ad) attains a minimum, where F(x) is a real valued function of xsP; X ~ E P is fixed, and ~ E P is a fixed direction. It is assumed that the partial derivatives gi(x) = aF(x)/axi (i=l, ..., n) may easily be computed; we then have f'(a) = af(a)/act = dTg(x,+cwd).

The method employed utilises an iterative process, based upon cubic interpolation (see [Dav59]), for locating a minimum of the real-valued function J: The process involves an initial approximation a,, three real sequences u, vk and yk, a fixed real parameter ys(O,lh), and relative and absolute tolerances, E, and E, respectively, used to terminate the process. Initially yo=uo=O, vo=cyo. At step k: (a) if f'(aJ 2 0, compute y = vk - ( v ~ - u & C ~ ' ( V & + W - Z ) / C ~ ' ( V & ~ ( U J + ~ W )

where z = 3Cf(uJ-j(vJ)/(vk-uJ + f'(@ + f'(vJ and w = (2 - f ' ( ~ J f ' ( v J ) ~ ' ~ ; set ek = IIx0 + y&ll E, + E,; yk+, is determined as follows: (i) if b-uk) < ck then yk+, = u ~ + E ~ , else (ii) if (vk-y)Qk then yk+,=vk-~,, else (iii) yk+,=y; uk+, and vk+, are determined as follows: (iv) if f'(y,+ J 2 0 then vk+,=yk+, and uk+,=uk; else (v) vk+,=vk and uk+,=yk+,.

(b) if f'(vJ < 0 then (i) if Cf(vJ-j(O))/vJ'(O) > y (now 0 < vk < emin) set uk+,=vk and Y ~ + ~ = v ~ + ~ = ~ v ~ ; else (ii) (now uk < E,, < vk) set yk+, = %(uk+vJ and if f'(vk+ J 2 0 or Cf?k+J-f(O))/~k+lf(O) > then vk+l=yk+~ and uk+l=uk, vk+l=vk and uk+l=yk+~.

The above process is terminated if either 1. lh I vk - ~k I < 11x0 + ~k+ldll Er + &a,

11. P 2 C ~ ~ J - ~ ( W / Y J ' ( O ! 5 1 - P, or 111. the maximal permitted number of simultaneous evaluations of f(e) and f'(e) is exceeded. In cases I and 11, yk+, is an acceptable approximation to emin.

The direction vector d and the initial values, x , f(O)=F(x,J, and f'(O)=drg(O) must be supplied by the user. The user must also prescribe the value of the variable strongsearch: if this is nonzero then the stopping criteria I and I11 alone are used; if it is zero then all criteria are used. The stopping criterion used when the value of strongsearch is zero is described in [Fle63] and [GolP67]. A detailed description of this procedure is given in [Bus72b].

Function Parameters: void linemin (n,x, d, nd, alfa,g, funct,p f l , dp , dfl, evlmax,strongsearch, in)

n: int; entry: the number of variables of the given function

x: float x[l:n];

Copyright 1995 by CRC Press, Inc

Page 352: Numerical Library in C for Scientists and Engineers A

entry: a vector x,, such that f is decreasing in x,, in the direction given by d; exit: the calculated approximation of the vector for which f is minimal on the line

defined by: x, + alfa*d, (alfa>O); d float d[I:n];

entry: the direction of the line on which f has to be minimized; n d float;

entry: the Euclidean norm of the vector given in d[l:n]; alfa: float *;

the independent variable that defines the position on the line on which f has to be minimized; this line is defined by x, + alfa*d, (alfa>O); entry: an estimate alfaO of the value for which h(alfa)=F(x,+alfa*d) is minimal; exit: the calculated approximation alfam of the value for which h(alfa) is minimal;

g: float g[l:n]; exit: the gradient off at the calculated approximation of the minimum;

funct: float (* funct)(n,x, g); entry: a call of funct should effectuate:

1. funct=f(x); 2. the value of g[i], (i=l, ..., n), becomes the value of the i-th component of the

gradient off at x; jU: float;

entry: the value of h(O), (see alfa); f l : float *;

entry: the value of h(alfaO), (see alfa); exit: the value of h(alfam), (see alfa);

djU: float; entry: the value of the derivative of h at a W 0 ;

dfl: float *; entry: the value of the derivative of h at alfa=alfaO; exit: the value of the derivative of h at alfa=alfam;

evlmax: int *; entry: the maximum allowed number of calls of funct; exit: the number of times funct has been called;

strongsearch: int: entry: if the value of strongsearch is nonzero then the process makes use of two

stopping criteria: A: the number of times funct has been called exceeds the given value of

evlmax; B: an interval is found with length less than two times the prescribed

precision, on which a minimum is expected; if the value of strongsearch is zero then the process makes also use of a third stopping criterion: C : p I (h(alfak)-h(alfaO))l(alfak*djU) < 1 - y, whereby alfak is the current

iterate and p a prescribed constant; in: float in[l:3];

entry: in[l]: relative precision, E,, necessary for the stopping criterion B (see strongsearch); in[2]: absolute precision, E,, necessary for the stopping criterion B (see strongsearch);

the prescribed precision, E, at alfa=alfak is given by:

Copyright 1995 by CRC Press, Inc

Page 353: Numerical Library in C for Scientists and Engineers A

E = 11 x0+alfa*d 11 E f E ,, where 11 . I 1 denotes the Euclidean norm; in[3]: the parameter p necessary for stopping criterion C; this parameter must satisfy:

0<p<0.5; in practice, a choice of p=0.0001 is advised.

Functions used: vecvec, elmvec, dupvec.

void linemin(int n, float x[l , float d[l , float nd, float *alfa, float g[] , float (*funct) (int, float [I, float [I ) , float £0, float *fl, float df0, float *dfl, int *evlmax, int strongsearch, float in[])

I ' float *allocate-real-vector(int, int) ;

void free-real-vector(f1oat *, int); float vecvec (int, int, int, float [I , float [I ) ; void elmvec(int, int, int, float [I, float [I, float); void dupvec (int, int, int, float [I , float [ I ) ; int ev1,notinint; float f, oldf, df, olddf,mu, alfa0, q, w, y, z, reltol, abstol, eps, aid, *xO;

xO=allocate-real-vector (1,n) ; reltol=in [ll ; abstol=in [21 ; mu=in [ 3 1 ; evl=O ; alfa0=0.0; oldf =f 0 ; olddf=dfO; y = *alfa; notinint=l; dupvec(l,n,0,x0,x) ; eps= (sqrt (vecvec (I, n, 0, x,x) ) *reltol+abstol) /nd; q=( (*fl)-fO)/( (*alfa)*dfO) ; while (1) {

if (notinint) notinint = ( (*df 1) c 0.0 && q > mu) ; aid = *alfa; if (*dfl >= 0.0) {

/ * cubic interpolation */ z=3.0* (oldf- (*£I) ) / (*alfa) +olddf+ (*dfl) ; w=sqrt (z*z-olddf * (*dfl) ) ; *alfa = (*alfa)*(l.O-((*dfl)+w-z)/((*dfl)-olddf+w*2.0)); if (*alfa < eps)

*alfa=eps; else

if (aid- (*alfa) < eps) *alfa=aid-eps; } else

if (notinint) { alfaO = *alfa = y; olddf = *dfl; old£ = *fl;

} else *alfa *= 0.5;

y = (*alfa)+alfaO; dupvec(l,n, O,x,xO) ; elmvec (l,n, O,x,d, y) ; eps= (sqrt (vecvec (l,n, O,x,x) ) *reltol+abstol) /rid; f=(*funct) (n,x,g) ; evl++; df=vecvec (l,n, O,d,g) ; q= (f-£0) / (y*dfO) ; if ( ! ( ( (notinint ( ( strongsearch) ? 1 : (q < mu ( q s 1.0

&& (evl < *evlmax))) break; if (notinint I I df > 0.0 I I q < mu) {

*df l=df ; *fl=f;

) else { alf aO=y; *alfa=aid- (*alfa) ; olddf=df ; oldf =f ;

Copyright 1995 by CRC Press, Inc

Page 354: Numerical Library in C for Scientists and Engineers A

if (*alfa <= eps*2.0) break;

*alfa=y; *evlmax=evl; *df l=df; *f l=f; f ree-real-vector (x0,l) ;

1

B. rnklupd

Determines the upper triangular part of the symmetric nxn matrix g by use of the formula g = h + cwT. h being a given symmetric matrix whose upper triangular part is available, c being a real constant, and vsRn a vector.

Function Parameters: void rnklupd (h,n,v,c)

h: float h[l:n*(n+l)/2]; entry: the upper triangle (stored columnwise, i.e. a,=h[&l) *j/2+i], 1 I i I j I n) of the

symmetric matrix that has to be updated; exit: the upper triangle (stored columnwise) of the updated matrix;

n: int; entry: the order of the symmetric matrix whose upper triangle is stored columnwise

in the one-dimensional array h; v: float v[l:n];

entry: the given matrix is updated (another matrix is added to it) with a symmetric matrix u, of rank one, defined by: uij=c*v[i]*vfi];

c: float; see v.

Function used: elmvec.

void elmvec (int, int, int, float [I , float [I , float) ; int j ,k;

k++ ; elmvec(j, j+k-1,l-j,h,v,v[kl *c) ; j += k;

} while (k c n); 1

C. davupd

Determines the upper triangular part of the symmetric nxn matrix g by use of the formula

g = h + c,wT - c2wwT. h being a given symmetric matrix whose upper triangular part is available, c, and c, being real constants, and v,wsRn vectors.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 355: Numerical Library in C for Scientists and Engineers A

void davupd (h, n,v, w,cl,c2) h: float h[l:n*(n+l)/2];

entry: the upper triangle (stored columnwise, i.e, ag=h[&1) *j/2+i], I I i I j I n ) of the symmetric matrix that has to be updated;

exit: the upper triangle (stored columnwise) of the updated matrix; n: int;

entry: the order of the symmetric matrix whose upper triangle is stored columnwise in the one-dimensional array h;

v,w: float v[l:n], w[l:n]; entry: the given matrix is updated with a symmetric matrix u, of rank two, defined

by: uij=cl *v[i]*vlj]-c2 *w[i]*wlj]; cl,c2: float; see v and w above.

k=O ; j=1; do (

k++ ; vk=v[k] *cl; wk=w [k] *c2 ; for (i=O; i<=k-1; i++) h[i+j] += v[i+ll *vk-w [i+l] *wk; j += k;

) while (k < n) ; 1

D. fleupd

Determines the upper triangular part of the symmetric nxn matrix g by use of the formula

g = h - c,vwT - c 2 w T + (I + (c,/cJc,wT). h being a given symmetric matrix whose upper triangular part is available, c, and c2(+O) being real constants, and v,w&Rn vectors.

Function Parameters: void fleupd (h,n,v, w,cl,c2)

h: float h[l:n(n+l)/2]; entry: the upper triangle (stored columnwise, i.e. ag=h[&l)j/2+i], I S i Sj S n ) of the

symmetric matrix that has to be updated; exit: the upper triangle (stored columnwise) of the updated matrix;

n: int; entry: the order of the symmetric matrix whose upper triangle is stored columnwise

in the one-dimensional array h; v, w: float v[l:n], w[l:n];

entry: the given matrix is updated with a symmetric matrix u, of rank two, defined by: uij=c2 *v[i]*vlj]-cl *(v[i]*wfi]+w[iJ*vjj']);

cl,c2: float; see v and w above.

void fleupd(f1oat h[] , int n, float v[l , float w [ I , float cl, float c2)

int i,j,k;

Copyright 1995 by CRC Press, Inc

Page 356: Numerical Library in C for Scientists and Engineers A

float vk,wk;

vk = -w [k] *cl+v [kl *c2; wk=v [kl *cl; for (i = O ; i<=k-1; i++) h[i+j] += v [i+ll *vk-w [i+ll *wk; j += k;

} while (k < n) ; 1

5.2.5 More variables - No derivatives

praxis

Determines a point x at which the function f(x) is a minimum, where x=(x, ,..., x,,), by use of an iterative algorithm due to Brent [Bre73]. An initial approximation to x is to be provided.

Function Parameters: void praxis (n,xfunct, in, out)

n: int; entry: the number of variables of the function to be minimized;

x: float x[l:n]; entry: an approximation of the position of the minimum; exit: the calculated position of the minimum;

funct: float (*funct)(n,x); funct should deliver the value of the function to be minimized, at the point given by x[l:n]; the meaning of the parameters of the function funct is as follows: n: the number of variables; x: the values of the variables for which the function has to be evaluated;

in: float in[0:9]; entry: in[O]: the machine precision; in[l]: the relative tolerance for the stepvector (relative to the current estimates of the

variables), see in[2]; in[2]: the absolute tolerance for the stepvector (relative to the current estimates of the

variables); the process is terminated when in in[8]+1 successive iteration steps the Euclidean norm of the step vector is less than (in[l]* 11 x (1 +in[2A*0.5; in[l] should be chosen in agreement with the precision in which the function is calculated; usually in[l] should be chosen such that in[l] 2 d ( i n [ 0 ~ ; in[O] should be chosen different from zero;

in[3],in[4]: in[3] and in[4] are neither used nor changed; in[5]: the maximum number of function evaluations allowed (i.e. calls of funct); in[6]: the maximum step size; in[6] should be equal to the maximum expected

distance between the guess and the minimum; if in[6] is too small or too large then the initial rate of convergence will be slow;

in[7]: the maximum scaling factor; the value of in[7] may be used to obtain automatic scaling of the variables; however, this scaling is worthwhile but may be unreliable; therefore, the user should try to scale his problem as well as

Copyright 1995 by CRC Press, Inc

Page 357: Numerical Library in C for Scientists and Engineers A

possible and set in[7]=1; in either case, in[7] should not be chosen greater than 10;

in[8]: the process terminates if no substantial improvement of the values of the variables is obtained in in[8]+1 successive iteration steps (see in[l], in[2J; in[8]=4 is very cautious; usually, in[8]=1 is satisfactory;

in[9]: if the problem is known to be ill-conditioned (see [Bre73]) then the value of in[9] should be negative, otherwise in[9]20;

out: float out[l:6]; exit: out[l]: this value gives information about the termination of the process;

out[l]=O: normal termination; out[l]=l: the process is broken off because at the end of an iteration step the

number of calls offunct exceeded the value given in in[5]; out[l]=2: the process is broken off because the condition of the problem is too

bad; out[2]: the calculated minimum of the function; out[3]: the value of the function at the initial guess; out[4]: the number of function evaluations needed to obtain this result; out[5]: the number of line searches (see [Bre73]); out[6]: the step size in the last iteration step.

Functions used: inivec, inimat, dupvec, dupmat, dupcolvec, mulrow, mulcol, vecvec, tammat, mattarn, ichrowcol, elmveccol, qrisngvaldec.

void praxis (int n, float x [I , float (*funct) (int, float [I ) , float in [I , float out [I

I float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); void inivec (int, int, float [ I , float) ; void inimat (int, int, int, int, float **, float) ; void dupvec(int, int, int, float [I, float 11 ) ; void dupmat (int, int, int, int, float **, float **) ; void dupcolvec (int, int, int, float **, float [I ) ; void mulrow(int, int, int, int, float **, float **, float) ; void mulcol(int, int, int, int, float **, float **, float) ; float vecvec (int, int, int, float [I , float [I ) ; float tammat (int, int, int, int, float **, float **) ; float mattam(int, int, int, int, float **, float * * ) ; void ichrowcol(int, int, int, int, float * * ) ; void elmveccol(int, int, int, float [I, float **, float); int qrisngvaldec (float **, int, int, float [I , float **, float [I ) ; void praxismin(int, int, float *, float *, float *, int, int,

float [I , float **, float *, float *, float *, float, float, float [I , float [I , int *, int *, float , float, float, float, float, float, float, float, float, float ( * ) (int, float[l));

int illc,i,j,k,k2,nl,maxf,nf,kl,kt,ktm,emergency; float s,sl,dn,dmin,fx,fl,lds,ldt,sf,df,qfl,qdO,qdl,qa,qb,qc,m2,m4,

small,vsmall,large,vlarge,scbd,ldfac,t2,ma~heps,reltol, abstol,h,**v,*d, *y,*z, *qO,*ql, **a,em[81 ,l;

Copyright 1995 by CRC Press, Inc

Page 358: Numerical Library in C for Scientists and Engineers A

macheps=in [Ol ; reltol=in [ll ; abstol=in [21 ; maxf=in [51 ; h=in 161 ; scbd=in [71 ; ktm=in [81 ; illc = in[91 c 0.0; small=macheps*macheps; vsmall=srnall*small; large=l.O/srnall; vlarge=l.O/vsrnall; m2=reltol; m4=sqrt (m2) ; srand ( 1) ; ldfac = (illc ? 0.1 : 0.01) ; kt=nl=O; nf=l; out [3] =qfl=fx= (*funct) (n,x) ; abstol=t2=small+fabs(abstol) ; drnin=small; if (h c abstol*100.0) h=abstol*100; ldt=h; inimat(l,n,l,n,v,O.O) ; for (i=l; ic=n; i++) v[il [iI=l.O; d[ll =qdO=qdl=O .O; dupvec(l,n, O,ql,x) ; inivec(l,n,qO, 0.0) ; ernergency=O;

while (1) { sf =d [ll ; d [ll =s=O. 0; praxisrnin(l,2,&(d[ll) ,&s,&fx,O,

n, x, v, &qa, &qb, &qc, qdo, qdl, q0, ql, &nf, &nl, &fx,rn2,rn4,dmin, ldt,reltol,abstol,small,h, funct) ;

if (S c= 0.0) mulcol (l,n, l,l,v,v, -1.0) ; if (sf c= 0.9*d[l] I I 0.9*sf >= d[ll ) inivec(2,n,d, 0.0) ; for (k=2; kc=n; k++) {

dupvec(l,n, O,y,x) ; sf=fx; illc = (illc I kt > 0) ; while (1)

if (ilic) { / * random stop to get off resulting valley * / for (i=l; ic=n; i++) {

s=z [iI=(O. 1*ldt+t2*~0~(10.0, kt) ) * (rand0 j(f1oat)RAND-MAX-0.5) ;

elrnveccol (l,n,i,x,v,s) ; 1

1 for (k2=k; k2c=n; k2++) {

sl=fx; s=O . 0; praxismin (k2,2, & (d [k2l) , &s, &fx, 0,

n,x,v,&qa, &qb, &qc,qdO,qdl,qO,ql, &nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct~;

s = illc ? d[k21* (s+z [k21 ) * (s+z [k21) : sl-fx; if (df c s) {

df=s; kl=k2 ;

1 if ( ! illc && df c fabs (100 .O*macheps*fx) )

illc=l:

Copyright 1995 by CRC Press, Inc

Page 359: Numerical Library in C for Scientists and Engineers A

else break;

1 ?or (k2=1; k2<=k-1; k2++) {

s=o.o; praxismin (k2,2, &(d [k21) , &s, &fx, 0,

n,x,v, &qa, &qb,&qc,qdO,qdl,qO,ql,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,£unct~ ;

1 f kfx; fx=sf; lds=O.O; for (i=l; i<=n; i++) {

sl=x [il ; x [il =y [il ; y[il = sl -= y[il; Ids += sl*sl;

1 lds=sqrt (lds) ; if (Ids > small) {

for (i=kl-1; i>=k; i--) ( for (j=l; j<=n; j++) v d [i+ll =d [il ;

1 - -

dupcolvec (l,n, k,v, y) ; mulcol(l,n,k,k,v,v,l.O/lds) praxismin(k,4,&(dlkl) ,&lds,&fl,l,

n,x, v, &qa, &qb, &qc, qdO, qdl, qO,ql, &nf, &nl, &£x,mZ,m4,dmin, ldt, reltol, abstol,small, h, funct) ;

if (Ids <= 0.0) { Ids = -1ds; mulcol(l,n,k,k,v,v,-1.0);

\ I

idt *= ldfac; if (ldt < Ids) ldt=lds; t2=m2*sqrt (vecvec (l,n, O,x,x) ) +abstol; kt = (ldt > 0.5*t2) ? 0 : kt+l; if (kt > ktm) {

out [l]=O. 0; emergency=l;

1 1

if (emergency) break; /* quad * / sax; f x=qf 1 ; qf 1=s ; qdl=O .O; for (i=l; i<=n; i++) {

s=x [il ; x [il =l=ql [il ; ql lil =s; qdl += (s-1) * (s-1) ;

I I l=qdl=sqrt (qdl) ; s=o.o; if ((qdO*qdl > FLT-MIN) && (nl >=3*n*n)) (

praxismin (0,2, &s, &l, &q£l, 1, n,x,v,&qa,&qb,&qc,qdO,qdl,qO,ql,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct);

qa=l* (1-qdl) / (qdO* (qdO+qdl) ) ; qb= (l+qd~) * (qdl-1) / (qd~*qdl) ; qc=l* (l+qdO) / (qdl* (qdO+qdl) ) ;

} else { f x=qf 1 ; qa=qb=0.0; qc=1.0 ;

1 qdO=qdl; for (i=l; i<=n; i++) {

s=qO [i] ; q0 [i] =x [i] ;

Copyright 1995 by CRC Press, Inc

Page 360: Numerical Library in C for Scientists and Engineers A

)* end of quad */ dn=O. 0; for (i=l; ic=n; i++) {

d [il =I. O/sqrt (d [ill ; if (dn c d [il ) dn=d [il ;

f if (scbd > 1.0) {

s=vlarge; for (i=l; i<=n; i++) {

sl=z [il =sqrt (mattam(l,n, i, i,v,v) ) ; if (sl < m4) z[il=m4; if (S > s1) s=sl;

1 for (i=l; ic=n; i++) (

sl=s/z [il ; z [il =l. O/sl; if (z[il > scbd) {

sl=l.O/scbd; z [il =scbd;

1 I mulrow(l,n,i,i,v,v,sl);

1 1

for (i=l; ic=n; i++) ichrowcol (i+l,n, i, i,v) ; em [o] =em [21 =macheps; em [ 4 ] =lO*n; em [6] =vsmall; dupmat (l,n, l,n,a,v) ; if (qrisngvaldec(a,n,n,d,v.em) != 0) {

out [ll=2.0; emergency=l;

1 if (emergency) break; if (scbd > 1.0! {

for (i=l; i<=n; i++) mulrow(l,n,i,i,v,v,z[il); for (i=l; ic=n; i++) {

s=sqrt (tammat(l,n,i,i,v,v)) ; d[il *= s; s=1. o/s; mulcol (l,n,i,i,v,v,s) ;

1 I

;or (i=1; i<=n; i++) { s=dn*d [il ; d[il = (s > large) ? vsmall :

( (s c small) ? vlarge : l.O/ (s*s) ) ; 1 ;* sort */ for (i=l; i<=n-1; i++) {

k=i ; s=d [il ; for (j=i+l; jc=n; j++)

if (d[jl > S) ( k=j ; s=d[jl ;

I

d [il =s; for (j=l; jc=n; j++) {

s=v[jl [il ; v[jl [il =v[jl [kl ; v[jl [kl=s;

1

1 /* end of sort */ dmin=d [nl ;

Copyright 1995 by CRC Press, Inc

Page 361: Numerical Library in C for Scientists and Engineers A

if (dmin c small) drnin=small; illc = (m2*d[ll ) > dmin; if (nf >= rnaxf) (

out [ll =l.0; break;

1 I

out [21 =fx; out [41 =nf; out [S] =nl; out [61 =ldt; free-real-vector (d, 1) ; f ree-real-vector (y, 1) ; f ree-real-vector (z,l) ; free-real-vector (q0,l) ; free-real-vector (ql, 1) ; free-real-matrix(v, 1,n, 1) ; f ree-real-matrix (a, 1, n, 1) ;

I void praxismin(int j, int nits, float *d2, float *xl, float *fl,

int fk, int n, float x[l , float **v, float *qa, float *qb, float *qc, float qd0, float qdl, float q0 [ I , float ql [I , int *nf, int *nl, float *fx, float m2, float m4, float dmin, float ldt, float reltol, float abstol, float small, float h, float (*funct) (int, float [I ) )

/ * this function is internally used by PRAXIS */

float praxisflin(float, int, int, float [I, float **, float *, float * , float *, float, float, float [I , float [I, int *, float (*)(int, float[]));

int k, dz, loop; float x2,xm,fO,f2,fm,dl,t2,s,sfl,sxl;

sf1 = *fl; SX1 = *XI; k=O ; xm=O .o; fO = fm = *fx; dz = *d2 c reltol; s=sqrt (vecvec (l,n, O,x,x) ) ; t2=m4*sqrt (fabs (*fx) / (dz ? dmin : *d2) +s*ldt) +m2*ldt; s=s*m4+abstol; if (dz && (t2 > s)) t2=s; if (t2 c small) t2=small; if (t2 > 0.01*h) t2=0.01*h; if (fk && (*fl c= fm)) {

xm = *xl; fm = *fl;

I if (!fk 1 1 (fabs(*xl) c t2)) (

*Xl = (*x1 > 0.0) ? t2 : -t2; *f l=praxisf lin (*xl, j ,n,x,v, qa, qb, qc, qdO, qdl, q0, ql,nf, funct) ;

loop=1; while (loop) (

if (dz) { / * evaluate praxisflin at another point and

estimate the second derivative * / x2 = (fO c *fl) ? -(*xl) : (*x1)*2.0; f 2=praxisf lin (x2, j , n, x, v, qa, qb, qc, qdO , qdl, q0, ql, nf , funct ) ; if (f2 c= fm) (

xm=x2 ; fm=f2;

I / * estimate first derivative at 0 * / dl= ( (*fl) -fO) / (*XI) - (*XI) * (*d2) ;

Copyright 1995 by CRC Press, Inc

Page 362: Numerical Library in C for Scientists and Engineers A

dz=l; x2 = (*d2 c= small) ? ((dl c 0.0) ? h : -h) : -0.5*dl/(*d21 ; if (fabs(x2) > h) x2 = (x2 > 0.0) ? h : -h; while (1) {

f2=praxisflin(x2, j ,n,x,v, b qc,qdO,qdl, qO,ql,nf, funct) ; if (k < nits && f2 > £0) qatq '

k++ ; if (£0 c *£I && (*xl)*x2 > 0.0) break; x2=0.5*~2;

) else { loop=0 ; break;

else fm=f2;

*d2 = (fabs(x2*(x2-(*XI))) > small) ? ( (x2* ( (*fl) -fO) - (*xl) * (fm-£0) ) / ( (*xl) *x2* ( (*XI) -x2) ) ) :

((k > 0) ? 0.0 : *d2); if (*d2 c= small) *d2=small; *x1=x2 ; *fx=fm; if (sf1 c *fx) {

*fx=sf 1; *x1=sx1:

float praxisflin(f1oat 1, int j, int n, float x[l , float **v, float *qa, float *qb, float *qc, float qd0, float qdl, float q0 [I, float ql [I, int *nf, float (*funct) (int, float [I )

I L

/* this function is internally used by PRAXISMIN */

int i; float *t,result;

t=allocate real vector(1,n); - if (j > 0)-

for (i=l; ic=n; i++) t [i] =x[i] +l*v[il Ijl ; else {

/ * search along parabolic space curve */ *qa=l* (1-qdl) / (qdO* (qdO+qdl) ) ; *qb= (l+qdO) * (qdl-1) / (qd0*qd1) ; *qc=l* (l+qdO) / (qdl* (qdO+qdl) ) ; for (i=l; =c=n; i++) t [il = (*qa) *q0 [il + (*qb) *x [il + (*qc) *ql [il ;

(*nf) ++; result= (*funct) (n, t) ; free-real-vector (t, 1) ; return result ;

1

5.2.6 More variables - Gradient available

4. rnklmin

Determines a vector x R n for which the real valued function F(x) attains a minimum. t is assumed that the partial derivatives gi(x)=aF(x)/axi ( i = l ,..., n) may easily be computed. nklmin is suitable, in particular, for use in connection with problems for which the nxn lessian matrix G(x), whose components are G,(x) =a2F(x)/ax ,ax, (i,j=l, ..., n), is almost

Copyright 1995 by CRC Press, Inc

Page 363: Numerical Library in C for Scientists and Engineers A

singular at the minimum. With H(x)=G(x)-', and the initial vector x(O) prescribed, the sequence of vectors x@)

produced by use of the Newton scheme xF") = xF) - H(xFqg(x ") (kO, 1 ,...) under certain conditions converges quadratically. Use of this scheme requires the evaluation and inversion of a Hessian matrix at each stage, and in order to avoid this rnklmin determines a sequence of vectors xF) by use of a scheme of the form xF") = x" - aF)~#g(xF)) in which the metric p) is an approximation to H(xF9, and is corrected by use of a simple updating formula of the form HF") = @) + CF) where cF) is of rank one (or possibly rank two), and the aF) are suitably determined real numbers.

The user is asked to provide at outset the initial approximation vector x(O) and values of the machine precision e, the required relative and absolute precisions, e, and e, respectively, in the determination of the minimum, a descent parameter y in the range O<y<1/2 (often y=0.0001 is suitable), an upper bound e, for 11 g(x) 11 (here and in the sequel all norms are Euclidean) and a lower bound F,, for F(x), both holding for all x in a domain containing the minimum and all x" produced, either a rough estimate c>O of 11 G(x(O9 1) (1.0 is often suitable) or approximate values of the elements of the upper triangular part of the inverse Hessian matrix H(x(O9, the maximum permitted number of simultaneous evaluations of F(x) and g(x) for the required values of x, and an orthogonality parameter R for which (eIc,)'"ln~R<l.O (often 0.0 1 is suitable).

The algorithm used consists first of an initialization, and then in determinations of sequences of directions dF', virtual steplengths aW, steps SF), approximations xw to the minimum, increments in derivatives t", and metrics HW. Initially, either H(O)=cI (I being the nxn unit matrix) or Po) is the approximation to the inverse Hessian matrix, whose elements have been supplied by the user. Then, for k0 ,1 , ... steps I to VI as follows are carried out. I. If

~(x@~~H@)~(x'"!, > 0 (1) then set 8) = -H")g(xW). If condition (1) is violated, and the new direction 8) were to be taken as just given then (89Tg(~F9 > 0, i.e. the derivative of F(x) in the direction 8) at the point xm would be decreasing. To avoid this, @) is decomposed in the form H") = UhUT, where U is a matrix of eigenvectors, and A an nxn diagonal matrix of eigenvalues hi (i=l, ..., n); defining 1 A ( to be the diagonal matrix with diagonal elements I hi I (i=l, ..., n), and K@ by fl = UI A I UT (SO that fl) is positive definite) we take 8) = -KWg(xF9 when condition (1) is violated.

11. If k=O, set @) = min(1, 2(F,,-F(~(~'))/(-d(")~g(x(~')), and determine the smallest integer rLO for which either

(d09 Tg(x(0)+2'e(0)d'09 2 0 or

(~(x'~)-2'e'~)d(~~ - F ( X ( ~ ~ ) / ~ ' B ( ~ ) ( ~ ~ ~ Tg(x'09 < y and set = 2'tf0) for this r. F(x) now decreases and then increases upon the line ~=x(~)+acf0l (a>O). An approximation to the value of a specifying the point at which F is minimum upon this line is determined by cubic interpolation (see the theory of linemin and [Dav59]) or (if (do))Tg(x(0)+B(O)do~ < 0 by bisection. For the value of a so determined

y s (F(x~)+cY~') - F ( x ~ ) ) ) / c x ( ~ ~ ( x I 1-p. (2) If h 0 , set P) = 11 SF-') 11 111 dF) 11 if k<n, and BF)=l otherwise. If

(F(X~ +eF)d @)) - F(X@)))/P)('".',~(XF)) > y (3) set aF) = BF). If condition (3) is violated, the distance from x=xm to the minimum of F(x) upon the line xm+a8) (OPO) is overestimated by setting a=BF), and a value of a

Copyright 1995 by CRC Press, Inc

Page 364: Numerical Library in C for Scientists and Engineers A

in the range 0<a<BF) is determined by cubic interpolation or bisection as above, such that condition (2) is satisfied for this a , for which we set @)=a.

111. Set a@) = a@)&) and xF") = xW + a@). IV. If condition (1) is satisfied, set 2" = -aF)g(xm). Otherwise set = -~"uAu~&) where,

with U and A being determined as in stage I, A is the nxn diagonal matrix with diagonal elements sign (h,) (i=l ,..., n).

V. If, with yF) = g(x@+lI) - g(xF)), I (y@)-~;@))~li~ I > B I/ yF)-~@) 11 11 A@) 11 (4)

then pi) is determined by use of the rank-one updating formula p i ) = tl(k) + +@) @) F) T

U (. ) ( 5 ) where up) = - H@)ylk), C@ = l/((y(kJ)'ufiIFi). If condition (4) is violated, but

c@) (.@I) T ~ @ ) > 0 (6) then the rank-two updating formula

pi) = HF) - cimv@) (wF)) - C , ~ W @ ) ( V ~ ) ) ~ + (1 + (C,@)/C,~))C~"V~ (v(k?) (7) with

cl& = l/(&@))TyW, C2@) = - ~ / ( ~ ( k ) ) * ~ f i ) ~ ( k ! =a@), W@)=~F)yF) (8) is used. If both condition (4) and (6 ) are violated, the rank-two updating formula

= p) + c,OvF)(vF))T + c,F) w@)w@I (9) with ciF), ..., W" as defined by formulae (8) is used.

VI. If 11 pl)g(~F+')) 11 < E, 11 xF+') 11 + E, and 11 g(xfi+") 11 < cg and g(xfi+'. ')T~')g(x@+ 2 0 and k 2 n then xF") is accepted as an approximation to the minimum. If k is equal to the number specified by the maximum number of function evaluations then the process is terminated (and xF") is then not an acceptable approximation).

The eigen-value/vector determination possibly required at stage I (in most practical cases this requirement is of infrequent occurrence) is carried out by a call of eigsyml. The line minimization required at stage I1 is carried out by linemin. The updating formulae (5,7,9) possibly required at stage V are implemented by rnklupd, fleupd and davupd respectively. A detailed description of the algorithm and some results about its convergence is given in [Bus72 b].

Function Parameters: float rnklmin (n,x,g, h, funct, in,out)

rnklmin: delivers the calculated least value of the given function; n: int;

entry: the number of variables of the function to be minimized; x: float x[l:n];

entry: an approximation of a minimum of the function; exit: the calculated minimum of the function;

g: float g[l:n]; exit: the gradient of the function at the calculated minimum;

h: float h[l :n(n+l)/2]; the upper triangle of an approximation of the inverse Hessian is stored columnwise in h (i.e. the (i,j)-th element = h[@I)j/2+i], I<i<j<n); if in[6pO initializing of h will be done automatically and the initial approximation of the inverse Hessian will equal the unit matrix multiplied with the value of in[6]; if in[6]<0 then no initializing of h will be done and the user should give in h an approximation of the inverse Hessian, at the starting point; the upper triangle of an approximation of the inverse Hessian at the

Copyright 1995 by CRC Press, Inc

Page 365: Numerical Library in C for Scientists and Engineers A

calculated minimum is delivered in h; funct: float (*funct)(n,x,g;);

a call of funct must have the following results: 1. funct becomes the value of the function to be minimized at the point x; 2. the value of g[i], (i=l, ..., n), becomes the value of the i-th component of the

gradient of the function at x; in: float in[0:9];

entry: in[O]: the machine precision; in[l]: the relative tolerance for the solution; this tolerance should not be chosen

smaller than in[O]; in[2]: the absolute tolerance for the solution; in[3]: a parameter used for controlling line minimization (see [Fle63, GolP671);

usually a suitable value is 0.0001; in[4]: the absolute tolerance for the Euclidean norm of the gradient at the solution; in[5]: a lower bound for the function value; in[6]: this parameter controls the initialization of the approximation of the inverse

Hessian (metric), see h; usually the choice in[6]=1 will give good results; in[7]: the maximum allowed number of calls of funct; in[8]: a parameter used for controlling the updating of the metric; it is used to avoid

unboundedness of the metric (see [Po70]); the value of in[8] should satisfy: q(in[~]/in[ll)ln < in[8] < 1; usually a suitable value will be 0.01;

out: float out[0:4]; exit: out[O]: the Euclidean norm of the product of the metric and the gradient at the

calculated minimum; out[l]: the Euclidean norm of the gradient at the calculated minimum; out[2]: the number of calls of funct necessary to attain this result; out[3]: the number of iterations in which a line search was necessary; out[4]: the number of iterations in which a direction had to be calculated with the

method given in [Gr67]; in such an iteration a calculation of the eigenvalues and eigenvectors of the metric is necessary.

Functions used: vecvec, matvec, tamvec, elmvec, symmatvec, inivec, inisymd, mulvec, dupvec, eigsyml, linemin, rnklupd, davupd, fleupd.

float rnklmin(int n, float x [ l , float g[l , float h t l , float (*funct) (int, float [ I , float [ I ) , float in11 , float out [ I )

I float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat * , int); void free-real-matrix(f1oat ** , int, int, int) ; float vecvec (int, int, int, float [ I , float [ I ) ; float matvec(int, int, int, float ** , float [I ) ; float tamvec(int, int, int, float **, float [ I 1 ; void elmvec (int, int, int, float [ I , float [ I , float) ; float symmatvec (int, int, int, float [ I , float [ I ) ; void inivec (int, int, float [ I , float) ; void inisymd (int, int, int, float [ I , float) ;

Copyright 1995 by CRC Press, Inc

Page 366: Numerical Library in C for Scientists and Engineers A

void mulvec (int, int, int, float [I , float [I , float) ; void dupvec (int, int, int, float [I , float [I ) ; void eigsyml(f1oat [I, int, int, float [I, float **, float [I); void linemin (int, float [I , float [I , float, float * , float [ I ,

float ( * ) (int, float[], float[]), float, float * , float, float * , int , int, float [I ) ;

void rnklupd (f loat [I , int, float [I , float) ; void davupd(f1oat [I, int, float [I, float [I, float, float) ; void fleupd(f1oat [I, int, float [I, float [I, float, float) ; int i,it,n2,cntl,cnte,evl,e~lma~,0k; float f,f0,fmin,mu,dg,dg0,ghg,gs,nrmdelta,alfa,macheps,reltol,

abstol,eps,tolg,orth,aid,*v,*delta,*gamma,*S,*p,**~e~,*th, em [lo] , templ, temp2;

rnacheps=in [OI ; reltol=in 111 ; abstol=in 121 ; mu=in [31 ; tolg=in [41 ; fmin=in [51 ; it=O; alfa=in [61 ; evlmax=in [71 ; orth=in [El ; n2= (n* (n+1) ) /2; cntl=cnte=O; if (alfa > 0.0) {

inivec(l,n2,h, 0.0) ; inisymd(l,n, O,h,alfa) ;

1 k= (*funct) (n,x,g) ; evl=l; dg=sqrt (vecvec (l,n, O,g,g) ) ; for (i=l; i<=n; i++) delta[il = -symmatvec(l,n,i,h,g) ; nrmdelta=sqrt (vecvec (l,n, 0, delta, delta) ) ; dgO=vecvec(l,n, 0, delta,g) ; ok = dg0 < 0.0; eps=sqrt (vecvec (1, n, O,x,x) ) *reltol+abstol; it++; while ((nrmdelta > eps / I dg > tolg I / !ok) && (evl < evlmax)) (

if (!ok) ( / * calculating greenstadts direction * / th=allocate-real_vector(l,n2) ; em [OI =macheps; em [21 =aid=sqrt (macheps*reltol) ; em [41 =orth; em [61 =aid*n; em[8] =5.0; cnte++; dupvec(l,n2,0, th,h) ; eigsyml (th,n,n,v,vec,em) ; for (i=l; i<=n; i++) (

aid = -tamvec(l,n,i,vec,g) ; s [il =aid*fabs (v [il ) ; v[i]=((v[i] == 0.0) ? 0.0 : ((v[il > 0.0) ? aid : -aid));

1 for (i=l; ic=n; i++) (

delta [il =matvec (l,n, i,vec,s) ; p[i]=matvec(l,n,i,ve~,v);

hgo=vecvec(l,n, O,delta,g) ; nrmdelta=sqrt (vecvec (l,n, O,delta, delta) ) ; free-real-vector(th,l) ;

1 dupvec(l,n,O,s,x) ; dupvec(l,n, O,v,g) ; if (it > n)

Copyright 1995 by CRC Press, Inc

Page 367: Numerical Library in C for Scientists and Engineers A

alfa=l. 0; else {

if (it ! = 1) alfa /= nrmdelta;

else ( alfa=2.0*(fmin-f)/dgO; if (alfa 2 1.0) alfa=l.O;

I 1

1

elmvec (l,n, 0,x, delta, alfa) ; fO=f; f= (*funct) (n,x,g) ; evl++; dg=vecvec (l,n, O,delta,g) ; if (it == 1 I I fO-f c -mu*dgO*alfa) (

/* line minimization * / i=evlmax-evl; cntl++; linemin(n, s, delta,nrmdelta, &al£a,g, funct, £0, &f,

dgO,&dg,&i,O,in) ; evl += i; dupvec(l,n,O,x,s) ;

I 1

dupvec (l,n, O,gamma,g) ; elmvec(l,n, O,gamma,V, -1.0) ; if (!ok) mulvec(l,n,O,v,p, -1.0) ; dg -= dg0; if (alfa ! = 1.0) {

mulvec (l,n, 0, delta, delta, alfa) ; mulvec (l,n, O,v,v, alfa) ; nrmdelta *= alfa; dg *= alfa;

dupvec (1,n, 0 ,p,gamma) ; elmvec(1,n,O,p,v,1.0) ; for (i=l; i<=n; i++) v[i] =symmatvec (l,n, i, h,gamma) ; dupvec(l,n,O,s,delta) ; elmvec(l,n,O,s,v,-1.0) ; gs=vecvec (1, n, 0, gamma, s) ; ghgxvecvec (l,n, 0,v, gamma) ; aid=dg/gs; ternpl=vecvec (l,n, 0, delta,p) ; temp2=orth*nrrndelta; if (templ*templ > vecvec(l,n,O,p,p)*temp2*temp2)

rnklupd(h,n,s, l.O/gs) ; else

if (aid >= 0.0) fleupd(h,n, delta,^, l.O/dg, (l.O+ghg/dg) /dg) ;

else davupd(h,n,delta,v, l.O/dg, l.O/ghg) ;

for (i=l; i<=n; i++) delta[i] = -symmatvec(l,n, i,h,g) ; alfa=nrmdelta; nrmdelta=sqrt (vecvec (l,n, 0, delta, delta) ) ; eps=sqrt(vecvec(l,n,O,x,x) )*reltol+abstol; dg=sqrt (vecvec(l,n, O,g,g)) ; dgO=vecvec (l,n, O,delta,g) ; ok = dg0 <= 0.0; it++;

1 out [o] =nrrndelta; out [ll =dg; out 121 =evl; out [31 =cntl; out [41 =cnte; free-real-vector (v, 1) ; f ree-real-vector (delta, 1) ; free-real-vector(gamma,l); f ree-real-vector (s, 1) ; free real vector(p,l); f reeIrealImatrix (vec, 1, n, 1) ; return f;

1

Copyright 1995 by CRC Press, Inc

Page 368: Numerical Library in C for Scientists and Engineers A

B. flemin

Determines a vector xsRn for which the real valued function F(x) attains a minimum by means of the variable metric algorithm given in [Fle63], except for some details (see [Bus72b]). It is assumed that the partial derivatives g,(x)=aF(x)/ax, (i=l, ..., n) may easily be computed. flemin is suitable, in particular, for use in connection with problems for which n is relatively large and the computation of F(x) and g(x) is relatively cheap.

The theory underlying the operation offlemin is similar to that underlying the operation of rnklmin, and the algorithms employed are similar in many respects.

The user is asked to provide at outset the initial approximation vector x'") and the same parameters E,, E,, p, E,, Fmin, (possibly) C, and a number specifying the maximum permitted number of simultaneous evaluations of F(x) and g(x), together with (possibly) approximations to the elements in the upper triangular part of ~(x")), as for rnklmin.

The initialization for the algorithm employed is the same as that for rnklmin. The stages are as follows. I. Simply set dF' = -fl)g(xN). I1 and 111. As for rnklmin. IV. If

(6fi)) 'p < 0 (1) then set P I ) = f l ) . If condition (1) is violated and

(SF)) Tr 0 2 @I) ' ~ f i ) ~ @ ) (2) then the rank-two updating formulae (7,8) of rnklmin are used. If both condition (1,2) are violated, the rank-two updating formulae (8.9) of rnklmin are used.

V. If 11 P')g(xF+')) 11 I E, 11 xF+') 11 + E, and 11 g(xF+')) 11 s c, and k 2 n then xF+') is accepted as an approximation to the minimum. If k is equal to the number specified by the maximum number of function evaluations then the process is terminated (and xF") is then not an acceptable approximation).

The above algorithm differs from one given by Fletcher (see [Fle63]), (which may fail when F(x) is not approximately a quadratic function in the components of x) only in the determination of 0" at stage I1 (the method adopted byflemin to a large extent overcomes the difficulty mentioned).

Function Parameters: float flemin (n,x,g, h, funct, in, out)

flemin: delivers the calculated least value of the given function; int; entry: the number of variables of the function to be minimized; float x[l :n]; entry: an approximation of a minimum of the function; exit: the calculated minimum of the function; float g[l:n]; exit: the gradient of the function at the calculated minimum; float h[l:n(n+ l)/2]; the upper triangle of an approximation of the inverse Hessian is stored columnwise in h (i.e. the (i,j)-th element = h[&l)j/2+i], IIiIj ln); if in[6p0 initializing of h will be done automatically and the initial approximation of the inverse Hessian will equal the unit matrix multiplied with the value of in[6]; if in[6]<0 then no initializing of h will be done and the user should give in h an approximation of the inverse Hessian, at the

Copyright 1995 by CRC Press, Inc

Page 369: Numerical Library in C for Scientists and Engineers A

starting point; the upper triangle of an approximation of the inverse Hessian at the calculated minimum is delivered in h;

funct: float (*funct)(n,x,g); a call of funct must have the following results: 1. fund becomes the value of the function to be minimized at the point x; 2. the value of g[i], (i=l, ..., n), becomes the value of the i-th component of the

gradient of the function at x; in: float in[l: 71;

entry: in[l]: the relative tolerance for the solution; in[2]: the absolute tolerance for the solution; in[3]: a parameter used for controlling line minimization (see mklmin); usually a

suitable value is 0.0001; in[4]: the absolute tolerance for the Euclidean norm of the gradient at the solution; in[5]: a lower bound for the function value; in[6]: this parameter controls the initialization of the approximation of the inverse

Hessian (metric), see h; usually the choice in[6]=1 will give good results; in[7]: the maximum allowed number of calls of funct;

out: float out[0:4]; exit: out[O]: the Euclidean norm of the product of the metric and the gradient at the

calculated minimum; out[l]: the Euclidean norm of the gradient at the calculated minimum; out[2]: the number of calls of funct, necessary to attain this result; out[3]: the number of iterations in which a line search was necessary; out[4]: if out[4]=-1 then the process is broken off because no down hill direction

could be calculated; the precision asked for may not be attained and is possibly chosen too high; normally out[4]=0.

Functions used: vecvec, elmvec, symmatvec, inivec, inisymd, mulvec, dupvec, linemin, davupd, fleupd.

float flemin(int n, float x[l , float g[l , float h[l , float (*funct) (int, float [I , float [I ) , float in [I , float out [I )

I float *allocate-real-vectorfint, int); void free-real-vector (f loat *, int) ; float vecvec (int, int, int, float [I , float [I void elmvec (int, int, int, float [I , float El , float symmatvec(int, int, int, float [I, float void inivec (int, int, float [I , float) ; void inisymd (int, int, int, float [ I , float) ; void mulvec (int, int, int, float [ I , float [I , void dupvec (int, int, int, float [I , float [I ) void linemin(int, float [I , float [I , float, f

float ( * ) (int, float[], float[]

float) ; [I ) ;

float) ;

oat *, float [I , , float, float *,

i )

float, float *, int *, int, float [I ) ; void davupd (float [I , int, float [I , float [I , float, float) ; void fleupd(f1oat [I, int, float [I, float [I, float, float) ; int i,it,cntl,evl,evlmax; float f,fO,fmin,mu,dg,dgO,nrmdelta,alfa,reltol,ab~t~l,ep~,t~lg,

aid, *v, *delta, * s ;

Copyright 1995 by CRC Press, Inc

Page 370: Numerical Library in C for Scientists and Engineers A

reltol=in Ill ; abstol=in 121 ; mu=inl31 ; tolg=in 141 ; fmin=in 151 ; alfa=in 161 ; evlmax=in 171 ; out [41=0.0; it=O; f= (ffunct) (n,x,g) ; evl=l;

;or (i=l; i<=n; i++) delta lil = -symmatvec (l,n,i,h,g) dg=sqrt (vecvec(l,n, O,g,g)) ; nrmdelta=sqrt (vecvec (l,n, o,delta, delta) ) ; eps~sqrt(vecvec(l,n,O,x,x))*relt~l+abstol; dgO=vecvec(l,n, O,delta,g) ; it++ ; while ((nrmdelta > eps I I dg > tolg) && (evl < evlmax

dupvec(l,n,O,s,x) ; dupvec(l,n,O,v,g); if (it >= n)

alfa=l.O; else {

if (it ! = 1) alfa /= nrmdelta;

else { alfa=2.0* (fmin-f) /dg0; if (alfa > 1.0) alfa=l.O;

I 1

elmvec(1,n,O,x,delta,alfa); fO=f; f= (*funct) (n,x,g) ; evl++; dg=vecvec (l,n, 0, delta, g) ; if (it == 1 I I fO-f < -mu*dgO*alfa) {

/ * line nhmization * / i=evlmax-evl: cntl++; linemin(n, s,delta,nrmdelta, &alfa,g, funct, fO,&f,

dgO,&dg,&i,O,in) ; evl += i; dupvec(l,n,O,x,s) ;

I if (alfa ! = 1.0) mulvec(l,n,O,delta,delta,alfa) ; mulvec(l,n,O,v,v,-1.0) ; elmvec (1,n: O,v,g, 1.0) ; for (i=l; 1<=n; I++) s [il =symmatvec(l,n, i,h,v) ; aid=vecvec(l,n, O,v,s) ; dg=(dg-dgO)*alfa; if (dg . 0.0)

if (dg >= aid) fleupd (h,n, delta, s, l.O/dg, (l.~+aid/dg) /dg) ;

else davupd(h,n,delta, s, l.~/dg, l.O/aid) ;

for (i=l; i<=n; i++) delta[il = -symmatvec(l,n, i,h,g) ; alfa *= nrmdelta; nrmdelta=sqrt (vecvec (l,n, O,delta,delta) ) ; eps=sqrt (vecvec (l,n, O,x,x) ) *reltol+abstol; dg=sqrt(vecvec(l,n,O,g,g)) ; dgO=vecvec (l,n, O,delta,g) ; if (dgO > 0.0) {

out[4] = -1.0; break;

1

Copyright 1995 by CRC Press, Inc

Page 371: Numerical Library in C for Scientists and Engineers A

1 out [O] =nrrndelta; out 111 =dg; out [21 =evl; out 131 =cntl; free-real-vector (v, 1) ; free-real-vector(delta,l) ; f ree-real-vector ( s , 1) ; return f;

I

5.3 Overdetermined nonlinear systems

5.3.1 Least squares - With Jacobian matrix

A. marquardt

Calculates the least squares solution of an overdetermined system of nonlinear equations with Marquardt's method [BusDK75, M631.

marquardt computes the values of the components p,, ...,p, of psRn such that

is a minimum at p , where f(t,p) is a real-valued function, and d, (i=l, ..., m) are given data readings (m 1 n) by use of an improved version of the Levenberg-Marquardt algorithm (the p, offers a parameter set of best fit of the function f(t,p) to the data at the points ti).

An initial approximation pfO) to p , two tolerances e, and e,, and a real number 6 expressing the ratio between the gradient and Gauss-Newton directions must be specified (6 may be taken to be 0.01 for well-conditioned problem; in any case 6 must satisfy the inequality: machine precision < 6 I llmachine precision).

At the k-th stage of the algorithm, the mxn Jacobian matrix ~(pr"'), whose components are given by J,,(p) = af(t,,p)/ap, (i=l, ..., m; j= l , ..., n) with p=p", is decomposed in the form J(pg)=@)D"V@) where fl) is an orthogonal mxm matrix, D@) is an mxn matrix whose principal nxn submatrix is the diagonal matrix p) of singular values of J(pF)) (D@) having zeros elsewhere), and V@) is an nxn orthogonal matrix.

The scalar pw = [ 11 DM 11 is determined. The further number X I w is determined by setting

), '(0) = ),(-I) = p(O) if k=O and,

if k21, X '@) = wXF-') if A@-') < - and X 5 A@-') if A@-') > A@-') (W is a real number in the range 0 < w < 1; marquardt uses the value 0.5). If h(XJ@)) 2 p (p being a real number in the range 0 < p 5 0.5; marquardt uses the value 0.5) where, with sF'(X) defined by

(JcpF9 'JcpF)) + w" (X) = -Jcp@9'f@pJ 9

hF)(X) = (+(pF)) - +(pFi +sN(X))) / -s&) 'J@@)) 'fcpw), the components of f(pW) being f(ti,p'k?)-dF (i=l ..., m) then XM is set equal to A'". If, however, h(X1@9 < p, A@) is taken to be v ,max(~ '@,~@)) (v being a real number in the range l<v<oo; marquardt uses the value 10) where r is the smallest nonnegative integer for which the relationship h ( d m a ~ ( X ' @ ) , ~ ~ ) ) 1 p, is satisfied, pF") is then determined by p@+J)=p@)+sW~@9.

Copyright 1995 by CRC Press, Inc

Page 372: Numerical Library in C for Scientists and Engineers A

The algorithm is terminated (with p" accepted as an approximation t o p ) when +(p@'') - +(pF)) I e,+(pW) + E ~ , or +(pF9 I E,.

Function Parameters: void marquardt (m,n,par,g,v, funct,jacobian, in,out)

m: int; entry: the number of equations;

n: int; entry: the number of unknown variables; n should satisfy n I m;

par: float par[l :n]; entry: an approximation to a least squares solution of the system; exit: the calculated least squares solution;

g: float g[l:m]; exit: the residual vector at the calculated solution;

v: float v[l:n, l:n]; exit: the inverse of the matrix JTJ where J denotes the transpose of the matrix of

partial derivatives ag[i]/apar.lj] (i=l, ..., m; j= l , ..., n); i.e. v[i,j] contains the (i,j)- th element of (J(~)~J@))-' (i,j=l, ..., n) where p is the value of pfi) in the above at termination;

note that the standard deviation of o, associated with the computed estimate of p, (j=l, ..., n) and the correlation pij between the estimates of pi and p, (i=l, ..., n; j=i+l, ..., n) may easily be extracted from the contents of the array v by use of the formula o = l/(v.lj,j]/m) (j=l , ..., n), pij = v[i,j]h/(v[i, i]*vb,jJ) (i=l, ..., n; j=i+l, ..., n);

funct: int (*funct) (m,n,par,g;); entry: m, n,par;

m, n have the same meaning as in the procedure marquardt; array par[l:n] contains the current values of the unknowns and should not be altered;

exit: upon completion of a call of funct, the array g[l:m] should contain the residual vector obtained with the current values of the unknowns; e.g. in curve fitting problems, g[i] = theoretical value f(x[i], par) - observed value y[i];

after a successful call of funct, the function should deliver the value nonzero; however, if funct delivers the value zero then it is assumed that the current estimates of the unknowns lie outside a feasible region and the process is terminated (see out[IJ); hence, proper programming of funct makes it possible to avoid calculation of a residual vector with values of the unknown variables which make no sense or which even may cause overflow in the computation;

jacobian: void (*jacobian) (m,n,par,g,jac) ; entry: m,n,par,g;

m, n, par: see funct; g contains the residual vector obtained with the current values of the unknowns and should not be altered;

exit: float jac[l:m, l:n]; upon completion of a call of jacobian, the array jac should contain the partial derivatives ag[i]/apar.lj], obtained with the current values of the unknown variables given in par[l:n];

it is a prerequisite for the proper operation of the procedure marquardt that the precision of the elements of the matrix jac is at least the precision defined by in[3] and

Copyright 1995 by CRC Press, Inc

Page 373: Numerical Library in C for Scientists and Engineers A

in[4]; in: float in[0:6];

entry: in[O]: the machine precision; in[l], in[2]: these are not used by marquardt; in[3]: the relative tolerance for the difference between the Euclidean norm of the

ultimate and penultimate residual vector (value of c,, above); see in[4]; in[4]: the absolute tolerance for the difference between the Euclidean norm of the

ultimate and penultimate residual vector (value of e, above); the process is terminated if the improvement of the sum of squares is less than in[3]*(sum of squares)+in[4]*in[4]; these tolerances should be chosen greater than the corresponding errors of the calculated residual vector;

in[5]: the maximum number of calls of funct allowed; in[6]: a starting value used for the relation between the gradient and the Gauss-

Newton direction (value of 5 above); if the problem is well conditioned then a suitable value for in[6] will be 0.01; if the problem is ill conditioned then in[6] should be greater, but the value of in[6] should satisfy:

in[O] < in[6] 2 llin[O]; out: float out[l: 71;

exit: out[l]: this value gives information about the termination of the process;

out[l]=O: normal termination; out[l]=l: the process has been broken off because the number of calls of funct

exceeded the number given in in[5]; out[l]=2: the process has been broken off because a call of funct delivered the

value zero; out[l]=3: funct became zero when called with the initial estimates of par[l:n];

the iteration process was not started and so v[l:n,l:n] cannot be used; out[l]=4: the process has been broken off because the precision asked for

cannot be attained; this precision is possibly chosen too high, relative to the precision in which the residual vector is calculated (see in[3J;

out[2]: the Euclidean norm of the residual vector calculated with values of the unknowns delivered;

out[3]: the Euclidean norm of the residual vector calculated with the initial values of the unknown variables;

out[4]: the number of calls of funct necessary to attain the calculated result; out[5]: the total number of iterations performed; note that in each iteration one

evaluation of the Jacobian matrix had to be made; out[6]: the improvement vector in the last iteration step; out['/]: the condition number of JTJ, i.e, the ratio of its largest to smallest eigenvalues.

Functions used: mulcol, dupvec, vecvec, matvec, tamvec, mattarn, qrisngvaldec.

void marquardt(int m, int n, float par[], float g[l, float **v, int (*funct) (int, int, float [I, float [ I ) , void ( * jacobian) (int, int, float [ I , float [I , float * * ) , float in [I , float out [I )

( float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int);

Copyright 1995 by CRC Press, Inc

Page 374: Numerical Library in C for Scientists and Engineers A

void free-real-vector(f1oat * , int); void free-real-matrix(f1oat **, int, int, int); void mulcol(int, int, int, int, float **, float ** , float); void dupvec (int, int, int, float [I , float [I ) ; float vecvec (int, int, int, float [I , float [I ) ; float matvec (int, int, int, float ** , float 11 ) ; float tamvec(int, int, int, float ** , float [I ) ; float mattam(int, int, int, int, float ** , float * * ) ; int qrisngvaldec (float ** , int, int, float [I , float ** , float [I ) ; int maxfe,fe,it,i,j,err,emergency; float w,ww,w,mu,res,fpar,fparpres,lambda,lambdamin,p,pw,reltolres,

abstolres,em[8l,*val,*b,*bb,*parpres,**ja~,temp;

w=10.0 ; w=o.5; mu=O. 01; ww = (in[6] c 1.0e-7) ? 1.0e-8 : l.0e-l*in[6] ; em [ol =em [2l =em 161 =in [Ol ; em [41 =lO*n; reltolres=in 131 ; abstolres=in [41 *in [41 ; maxfe=in [51 ; err=O ; fe=it=l; p=fpar=res=O.O; pw = -log(ww*in[01 ) /2.30; if ( ! (*funct) (m,n,par,g) ) (

err=3 ; out [41 =fe; out [51 =it-1; out [ll =err; f ree-real-vector (val, 1) ; f ree-real-vector (b, 1) ; f ree-real-vector (bb, 1) ; free-real-vector(parpres,l); free-real-matrix( jac, l,m, 1) ; return;

1 kpar=vecvec (l,m, 0, g, g) ; out [31 =sqrt (fpar) ; emergency=O;

; (*jacobian) (m,n,par,g, jac) ; i=qrisngvaldec (jac,m,n,val,v, em) ; if (it == 1)

lambdazin [61 *vecvec (1, n, 0, val, Val) ; else

if (p == 0.0) lambda *= w; for (i=l; ic=n; i++) b [i] =val [il *tamvec (l,m, i, jac,g) ; while (1) {

for (i=l; ic=n; i++) bb [il =b [i] / (val [il *val [il +lambda) ; for (i=l; i<=n; i++) parpres [il =par[il -matvec(l,n, i,v,bb) ; f e++ ; if (fe >= maxfe)

err=l; else

if ( ! (*funct) (m,n,parpres, g) ) err=2; if (err ! = 0) {

emergency=l; break;

1 fparpres=vecvec (l,m, O,g, g) ; res=fpar-fparpres; if (res c mu*vecvec(l,n, O,b,bb) ) (

p += 1.0; lambda *= w ; if (p == 1.0) {

Copyright 1995 by CRC Press, Inc

Page 375: Numerical Library in C for Scientists and Engineers A

lambdamin=ww*vecvec(l,n,0,val,val); if (lambda c lambdamin) lambda=lambdamin;

1 if (p >= pw) (

err=4 ; emergency=l; break;

I ) else {

dupvec (l,n, O,par,parpres) ; fpar=fparpres ; break;

I if (emergency) break; it++;

) while (fpar > abstolres && res > reltolres*fpar+abstolres); for (i=l; ic=n; i++) mulcol(l,n,i,i, jac,v,l.O/ (val [il +in[Ol ) ) ; for (i=l; ic=n; i++)

for (j=l; jc=i; j++) v[il [jl=v[jl [il=mattam(l,n,i, j, jac, jac); lambda=lambdamin=val [I1 ; - -

for (i=2; ic=n; i++) if (val[il > lambda)

lambda=val [il ; else

if (val [il c lambdamin) lambdamin=val [il ; temp=lambda/(lambdamin+in[Ol); out [71 =temp*temp; out [21 =sqrt (fpar) ; out [6] =sqrt (res+fpar) -out 121 ; out [41 =fe; out 151 =it-1; out [ll =err; f ree-real-vector (val ,1) ; free-real-vector(b,l); f ree-real-vector (bb, 1) ; f ree-real-vector (parpres, 1) ; free-real-matrix( jac, l,m, 1) ;

1

B. gssnewton

Calculates the least squares solution of an overdetermined system of nonlinear equations with the Gauss-Newton method [BusDK75, Har6 1, Sp671.

gssnewton computes the values of the components p,, ...,pn of psRn such that

is a minimum at p, where f(t,p) is a real-valued function, and 4 (i=l, ..., m) are given data readings (m 2 n) by use of an improved version of the Gauss-Newton algorithm (the p, offer a parameter set of best fit of the function f(t,p) to the data at the points ti).

An initial approximation p(o) top , three tolerances E,,, E, and e, must be given. At the k-th stage of the algorithm, the mxn Jacobian matrix J(p@$, whose components are given by Jij@ = af(ti,p)/ap, (i=l, ..., m; j=l, ..., n) with p=pM, is decomposed in the form ~(pfig=@)dk' where @) is an mxn orthogonal matrix, and dk' is an mxn upper triangular matrix. The direction vector &)ER" is determined by solving the nxn upper triangular system derived from the first n equations of the system dk'dF1 = -(@gTf(pfig where the components of f(pF9~Rrn are f(ti,p@$-4 (i=l ,..., m).

The scalar a@ is determined (a) by setting @=l if @(pfi)+&g 5 @(pF9 or, if this

Copyright 1995 by CRC Press, Inc

Page 376: Numerical Library in C for Scientists and Engineers A

condition is violated, (b) by setting aW=2", where r is the smallest nonnegative integer for which

*(p" + 2"@9 < *OR)), a(pfi1 + 2+&9 < + 2++~@9

(these inequalities are inspected for r replaced by r ' (r '=O,l, ..., r)) p(k''l is then P@) + a@)@). The algorithm is terminated (with p" accepted as an approximation to p) when (c)

+(p@91~,2 or (d) IlpF+')-pF) I/ 5 /IP@+') 11 E, + E,, and the standard deviations of the elements of p are then calculated.

Function Parameters: void gssnewton (m,n,par,g,vfunct,jucobian, in, out)

m: int; entry: the number of equations;

n: int; entry: the number of unknowns in the m equations; (n 5 m);

par: floatpar[l:n]; entry: an approximation to a least squares solution of the system; exit: the calculated least squares solution;

rv: float w[l:m]; exit: the residual vector of the system at the calculated solution;

j~inv: float jjinv[l:n, 1 :n]; exit: the inverse of the matrix J ~ J where J denotes the transpose of the Jacobian

matrix at the solution; funct: int (*funct) (m, n,par, w) ;

entry: m,n,par; m, n have the same meaning as in the procedure gssnewton; array par[l:n] contains the current values of the unknowns and should not be altered;

exit: upon completion of a call of funct, the array rv[l:m] should contain the residual vector obtained with the current values of the unknowns;

the programmer of funct may decide that some current estimates of the unknowns lie outside a feasible region; in this case funct should deliver the value zero and the process is terminated (see out[lJ, otherwise funct should deliver the value nonzero;

jacobian: void (*jacobian)(m,n,par,rvjac); the parameters of jacobian are: m, n: see gssnewton; par: entry: current estimate of the unknowns, these values should not be changed; rv: entry: the residual vector of the system of equations corresponding to the vector

of unknowns as given in par; on exit the values are not changed; juc: exit: float jac[I:m, I:n];

a call of the procedure jacobian should deliver the Jacobian matrix evaluated at the current estimates of the unknown variables given in par in such a way, that the partial derivative arv[i]ldparb] is delivered in jac[i,j], i=l, ..., m, j=l , ..., n;

in: float in[0:7]; entry: in[O]: the machine precision; in[l]: the relative tolerance for the step vector (relative to the vector of current

Copyright 1995 by CRC Press, Inc

Page 377: Numerical Library in C for Scientists and Engineers A

estimates in par) (value of E, above); see in[2]; in[l] should not be chosen smaller than in[O];

in[2]: the absolute tolerance for the step vector (relative to the vector of current estimates in par) (value of E, above);

the process is terminated if in some iteration (but not the first) the Euclidean norm of the calculated Newton step is less than in[]]* llpar 11 +in[2];

in[3]: not used by gssnewton; in[#]: the absolute tolerance for the Euclidean norm of the residual vector (value of

eo above); the process is terminated when this norm is less than in[4]; in[5]: the maximum allowed number of function evaluations (i.e. calls of funct); in[6]: the maximum allowed number of halvings of a calculated Newton step vector,

a suitable value is 15; in[7]: the maximum allowed number of successive in[6] times halved step vector,

suitable values are 1 and 2; out: float out[l:9];

exit: the process was terminated because out[l] =

1: the norm of the residual vector is small with respect to in[4]; 2: the calculated Newton step is sufficiently small (see in[l], in[2j); 3: the calculated step was completely damped (halved) in in[7] successive iterations; 4: out['/] exceeds in[5], the maximum allowed number of calls offunct; 5: the Jacobian was not full-rank (see out[8J; 6: funct delivered zero at a new vector of estimates of the unknowns; 7: funct delivered zero in a call from jacobian; out[2]: the Euclidean norm of the last residual vector; out[3]: the Euclidean norm of the initial residual vector; out[#]: the total number of calls offunct; out[4] will be less than in[5]+in[6]; out[5]: the total number of iterations; out[6]: the Euclidean norm of the last step vector; out[7]: iteration number of the last iteration in which the Newton step was halved; out[8],out[9]: rank and maximum column norm of the Jacobian matrix in the last

iteration, as delivered by lsqortdec in awc[3] and awc[5].

Functions used: dupvec, vecvec, elmvec, lsqortdec, lsqsol, Isqinv.

void gssnewton (int m, int n, float par [ I , float r v [ l , float **Jjinv, int (*funct) (int, int, float [ I , float [ I ) , void ( * jacobian) (int, int, float [ I , float [ I , float **) , float in [ I , float out [ I

I int *allocate-integer-vector(int, int); float *al loca te - rea lvec tor ( in t , int); float **allocate-real-matrix(int, int, int, int); void free-integer-vector(int *, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); float vecvec (int, int, int, float [ I , float [I ) ; void dupvec(int, int, int, float [ I , float [ I ) ; void elmvec (int, int, int, float [ I , float [ I , float) ; void lsqortdec(f1oat **, int, int, float [ I , float [ I , int [ I ) ; void lsqsol (float **, int, int, float [ I , int [ I , float [ I ) ; void lsqinv (f loat **, int, float [ I , int [ I ) ; int i,j,inr,mit,text,it,itmax,in~ax,tim,fe~al,fe~alma~,con~,

testthf,dampingon,*ci,fail;

Copyright 1995 by CRC Press, Inc

Page 378: Numerical Library in C for Scientists and Engineers A

float rho,resl,res2,rn,reltolpar,abstolpar,abstolres,stap,normx, **jac, *pr, *aid, *sol, *fu2,aux[61 ;

itmax=f evalmax=in 151 ; aux [2] =n*in [O] ; tim=in 171 ; reltolpar=in 111 *in [ll ; abstolpar=in 121 *in [21 ; abstolres=in 141 *in [41 ; inrmax=in [61 ; dupvec (l,n, 0,pr.par) ; if (m < n)

for (i=l; i<=n; i++) jac [m+ll [il =O. 0; text=4; mit=O; testthf=l; res2=stap=out [5] =out 161 =out [71 =O. 0; (*funct) (m,n,par, fu2) ; rn=vecvec(l,m,O,fu2,fu2); out [3] =sqrt (rn) ; feval=l; dampingon=O; fail=O; it=l; do I

out [51 =it; (*jacobian) (m,n,par,fu2, jac) ; if (!testthf) (

text=7; fail=l; break;

1 isqortdec (jac,m,n,aux,aid,ci) ; if (aux[31 ! = n) {

text=5; fail=l; break;

I I lsqsol (jac,m,n, aid, ci, fu2) ; dupvec(l,n,O,sol, fu2) ; stap=vecvec (l,n, 0, sol, sol) ; rho=2.0 ; normx=vecvec (1,n, 0, par, par) ; if (stap > reltolpar*normx+abstolpar 1 1 it == 1 && stap > 0.0) {

:zO; rho / = 2.0; if (inr > 0) {

resl=res2; dupvec(l,m,O,rv,fu2); dampingon = inr > 1;

1

for (i=l; i<=n; i++) pr [il =par [il -sol [il *rho; f eval++; if ( ! (*funct) (m,n,pr, fu2) : {

text=6; fail=l; break;

1 res2=vecvec(l,m,0,fu2,£~2) ; conv = inr >= inrmax; inr++ ;

} while ( (inr == 1) ? (dampingon I res2 >= rn) : ( !conv && (rn <= resl / I res2 < resl) ) ) ;

if (fail) break; if (conv) {

mit++:

Copyright 1995 by CRC Press, Inc

Page 379: Numerical Library in C for Scientists and Engineers A

if (mit < tim) conv=O; } else

mit=O; if (inr > 1) {

rho *= 2.0; elmvec (l,n, O,par, sol, -rho) ; rn=resl; if (inr > 2) out [71=it;

) else ( dupvec (l,n, 0,par.pr) ; rn=res2 ; dupvec(l,m, O,rv, fu2) ;

1 if (rn <= abstolres) {

text=l; itmax=it ;

} else if (conv && inrmax > 0) {

text=3 ; itmax=it ;

} else dupvec(l,m,O, fu2,rv) ;

} else { text=2 ; rho=l. 0 ; itmax=it;

1 it++;

} while (it s= itmax && feval s fevalmax) ; if (!fail) {

lsqinv( jac,n, aid,ci) ; for (i=l; is=n; i++) {

j jinv[il [il =jac[il [il ; for (j=i+l; js=n; j++) jjinvri] [jl=jjinv[jl [il=jacIil [jl ;

1 1

out [6] =sqrt (stap) *rho; out [2] =sqrt (rn) ; out [4] =feval; out [ll =text; out [El =aux[31 ; out [91 =aux [51 ; free-integer-vector(ci,l); f ree-real-vector (pr, 1) ; free-real-vector (aid, 1) ; free-real-vector(so1,l); free-real-vector(fu2,l); f ree-real-matrix (jac, 1, m+l, 1) ;

1

5.4 Differential equations - Initial value problems

5.4.1 First order - No derivatives right hand side

A. rkl

Solves an initial value problem for a single first order ordinary differential equation dy/& = f(x,y) by means of a 5-th order Runge-Kutta method [see 2641. The equation is assumed to be non-stiff.

rkl is based on an explicit 5-th order Runge-Kutta method and is provided with step length and error control. The error control is based on the last term of the Taylor series which is taken into account. A step is rejected if the absolute value of this last term is greater than ( Ifxv 1 *e[l]+e[2J)* I h 1 lk, where k = I b-(if fi is nonzero then a else d[3J 1 denotes the length of the integration interval, otherwise a step is accepted. rkl uses as its

Copyright 1995 by CRC Press, Inc

Page 380: Numerical Library in C for Scientists and Engineers A

minimal absolute step length hmin = e[l]*k+e[2]. If a step of length I h I = hmin is rejected then the step is skipped.

Function Parameters: void rk 1 (x,a, b, y, ya,Jjcy, e, d$)

x: float *; entry: the independent variable; exit: upon completion of a call, x is equal to b;

a : float; entry: the initial value of x;

b: float; entry: a value parameter, giving the end value of x;

y: float *; entry: the dependent variable;

ya: float; entry: the value of y at x=a;

fxv: float (*fxy)(x,y); entry: the function giving the value of @/dx;

e: float e[I:2]; entry: e[l]: a relative tolerance; e[2]: an absolute tolerance;

d float d[I:4]; exit: d[l]: number of steps skipped; d[2]: equals the step length; d[3]: equals b; d[4]: equals y@);

fi: int; entry: if$ is nonzero then rkl integrates from x=a to x=b with initial value y(a)=ya

and trial step b-a; if$ is zero then rkl integrates from x=d[3] to x=b with initial value y(d[3])=d[4] and step length h=d[2]*sign(b-d[3]), while a and ya are ignored.

void rkl(f1oat *x, float a, float b, float *y, float ya, float (*fxy) (float, float), float e [I , float d[l , int fi)

I int last, first, reject, test, ta, tb; float el,e2,xl,yl,h,ind,hmin,absh,kO,kl,k2,k3,k4,k5,discr,tol,mu,

mul, fh,hl;

1

d[l]=O.O; xl=d [31 ; yl=d[41 ; if (fi) d[21 =b-d[31 ; absh=h=fabs (d [Zl) ; if (b-xl c 0.0) h = -h; ind=fabs (b-xl) ; hmin=ind*e [ll +e [21 ; el=e [ll /ind;

Copyright 1995 by CRC Press, Inc

Page 381: Numerical Library in C for Scientists and Engineers A

1 while (1) {

if (test) { absh=fabs (h) ; if (absh c hmin) {

h = (h > 0.0) ? hmin :

absh=hmin; 1 ta=(h >= b-xl) ; tb= (h >= 0.0) ; if ((ta && tb) / I (!(ta tb))) {

d [21 =h; last=l; h=b-xl; absh=fabs (h) ;

} else last=O;

1 test=l; *x=xl; *y=yl; kO= (*fxy) (*x, *y) *h; *x=xl+h/4.5; *y=yl+k0/4.5; kl= (*fxy) (*x, *y) *h; *x=xl+h/3.0; *y=yl+ (kO+kl*3.O) /12.0; k2= (*fxy) (*x, *y) *h; *x=xl+h*0.5; *y=yl+ (kO+k2*3.O) /8.0; k3= (*fxy) (*x, *y) *h; *x=xl+h*0.8; *y=yl+(k0*53.0-kl*135.0+k2*126.0+k3*56.0)/125.0; k4= (*fxy) (*x, *y) *h; *x = (last ? b : xl+h) ; *y=yl+(k0*133.0-kl*378.0+k2*276.0+k3*112.O+k4*25.0~/168.0; k5= (*fxy) (*x, *y) *h; discr=fabs(k0*21.0-k2*162.0+k3*224.0-k4*125.O+k5*42.0~/14.0; tokfabs (k0) *el+absh*eZ ; reject = discr > tol; mu=tol/ (tol+discr) +0.45; if (reject) {

if (absh c= hmin) { d[ll += 1.0; *y=yl; f irst=l; if (b == *x) break; xl = *x; yl = *y;

} else h *= mu;

} else { if (first) {

f irst=O; hl=h; h *= mu:

} else { fh=mu*h/hl+mu-mul;

h *= fh; 1 mul=mu; *y=yl+(-k0*63.0+kl*189.0-k2*36.0-k3*112.O+k4*50.0~/28.0; k5= (*fxy) (*x, *y) *hl; *y=yl+(k0*35.0+k2*162.O+k4*125.0+k5*14.0)/336.0; if (b == *x) break; x1 = *x; yl = *y;

Copyright 1995 by CRC Press, Inc

Page 382: Numerical Library in C for Scientists and Engineers A

B. rke

Solves an initial value problem for a system of first order ordinary differential equations dy/& = f(x,y), from x = xO to x = xe where y(x0) = yo, by means of a 5-th order Runge- Kutta method. The system is assumed to be non-stiff.

The method upon which rke is based, is a member of a class of 5-th order Runge-Kutta formulas presented in [Eng69]. Automatic stepsize control is implemented in a way proposed in [Z64]. For further information see [Be74].

Function Parameters: void rke (x,xe, n,y,der,data,fi, out)

x: float *; entry: the independent variable; the initial value xO;

xe: float *; entry: the final value of x;

n: int; entry: the number of equations of the system;

y: float y[l:n]; entry: the dependent variable; the initial values at x = xO; exit: the values of the solution at x = xe;

der: void (*der)(n,t,v); this procedure performs an evaluation of the right hand side of the system with dependent variables v[l:n] and independent variable t; upon completion of der the right hand side should be overwritten on v[l:n];

data: float data[l:6]; in array data one should give:

data[l]: the relative tolerance; data[2]: the absolute tolerance;

after each step data[3:6] contains: data[3]: the steplength used for the last step; data[4]: the number of integration steps performed; data[5]: the number of integration steps rejected; data[6]: the number of integration steps skipped;

if upon completion of rke data[6] > 0, then results should be considered most critically;

Ji: int; entry: if$ is nonzero then the integration starts at xO with a trial step xe - xO; iffi is

zero then the integration is continued with a step length data[3] * sign(xe - x0);

out: void (*out)(n,x,xe,y,data); after each integration step performed, out can be used to obtain information from the solution process, e.g. the values of x, y[l:n], and data[3:6]; out can also be used to update data, but x and xe remain unchanged.

Copyright 1995 by CRC Press, Inc

Page 383: Numerical Library in C for Scientists and Engineers A

void rke (float *x, float *Xe, int n, float y[l , void (*der) (int, float, float [I ) , float data [I , int fi, void (*out) (int, float, float, float [I, float [I ) )

float *allocate-real-vector (int, int) ; void free-real-vector(f1oat * , int) ; int j,last,first,reject,test,ta,tb; float xt, h, hmin, ind, hl, ht, absh, fhm, discr, tol,mu,mul, fh, el, e2.

*kO,*kl,*k2,*k3,*k4;

1 absh=h=fabs (data [31) ; if (*xe < *x) h = -h; ind=fabs ( (*xe) - (*x) ) ; hmin=ind*data [ll +data [21 ; e1=12.0*data [ll /ind; e2=12. o*data [21 /ind; f irst=l; reject=O;

} while (1) {

if (test) { absh=f abs (h) ; if (absh < hmin) {

h = (*xe == *x) ? 0.0 : ((*xe > *x) ? hmin : -hmin); absh=hmin:

1 ta= (h >= (*xe) - (*x) ) ; tb= (h >= 0.0) ; if ((ta && tb) I / ( ! (ta I I tb))) {

last=l; h= (*xe) - (*x) ; absh=fabs (h) ;

) else last=O;

) test=l; if (!reject) {

for (j=l; j<=n; j++) kO[jI=y[jl; (*der) (n , *x, kO) ;

1 Lt=o.l84262134833347*h; xt = *x+ht; for (j=l; j<=n; j++) kl[jI=kO[jl*ht+y[jl ; (*der) (n,xt,kl) ; ht=0.690983005625053e-l*h; xt=4. o*ht+ (*x) ; for ( j = l ; j<=n; j++) k2[jl=(3.0*k~[jl+k0[jl)*ht+y[jl ; (*derj (n,xt, k2) ;- xt=0.5*h+ (*x) ; ht=O.l875*h; for (j=l; j<=n; j++)

k3 [j] = ( (1.74535599249993*k2 [jl -kl [jl ) *2.23606797749979+ k0 [jl )*ht+y[jl ;

(*der) (n,xt,k3) ; xt=0.723606797749979*h+(*x); ht=0.4*h; for (j=l; j<=n; j++)

k4 [j]=( ((0.517595468l66681*kO [j] -kl[jl ) *O.g27O5Og83l2484O+ k2 [j] ) *1.46352549156242+k3 fjl ) *ht+y [jl ;

Copyright 1995 by CRC Press, Inc

Page 384: Numerical Library in C for Scientists and Engineers A

(*der) (n,xt, k4) ; xt = (last ? *xe : *x+h); ht=2.0*h; for (j=l; jc=n; j++)

kl [jl=( ( ( (Z.O*k4 [jl+k2 [j]) *0.4l2022659l66SgS+kl []I * 2.23606797749979-k0 [j] ) *0.375-k3 [jl ) *ht+y []I ;

(*der) (n,xt, kl) ; reject=O; fhm=0.0; for (j=l; j<=n; j++) (

discr=fabs((l.6*k3 [jl-k2[jl-k4[j tol=fabs(kO[jl )*el+e2; reject = (discr > to1 I I reject) fh=discr/tol; if (fh > fhm) fhm=fh;

1 mu=l.O/ (l.O+fhm) +0.45; if (reject) (

data[S] += 1.0; if (absh c= hmin) (

data[6] += 1.0; hl=h; re ject=O; f irst=l; data [31 =hl; data[4] += 1.0; *x=xt ; (*out) (n, *x, *xe, y, data) ; if (*x == *xe) break;

} else h *= mu;

} else ( if (first) (

f irst=O; hl=h; h *= mu;

} else ( fh=mu*h/hl+mu-mul; hl=h; h *= fh;

1

for (j=l; jc=n; j++) y[jl=((k2[jl+k4tjl )*5.0+kO[jl+kl[jl )*ht+y[jl ;

data I31 =hl; data[4] +=.1.0; *x=xt ; (*out) (n, *x,*xe,y,data) ; if (*x == *xe) break;

1 I f ree-real-vector (k0,l) ; free-real-vector (kl, 1) ; free-real-vector (k2,l) ; free-real-vector(k3,l); free-real-vector (k4,l) ;

1

Solves an initial value problem for a single first order ordinary differential equation dy/& = f(x,y), where f(x,y) may become large, e.g. in the neighbourhood of a singularity, by means of a 5 t h order Runge-Kutta method [see 2641. The equation is assumed to be non-stiff.

rk4a integrates the given differential equation as it stands if I f(x,y) ( I 1 . If, however, I f(x,y) I > 1 then y is selected as the variable of integration, and the equation actually solved is &/& = I/f(x,y) . The procedure is provided with step size and error control. rk4a

Copyright 1995 by CRC Press, Inc

Page 385: Numerical Library in C for Scientists and Engineers A

integrates the differential equation from x = a b(a) being given), and the direction of integration (i.e. x increasing or decreasing, or y increasing or decreasing) specified at outset, until to within stated tolerances a zero of the function b(x,y) is encountered.

To explain the use of the function b(x,y), we remark that if it is desired to continue integration from x = a to x = c, then b(x,y) is simply taken to be x-c; if it is desired to continue integration until y(x) and a given function g(x) have equal values (so that the graphs of y and g intersect), then b(x,y) is taken to be y(x) - g(x); if it is believed but not known that the graphs of y(x) and g(x) intersect in the range x = a to x = c, b(x,y) can be taken to be (x-c)(y(x)-g(x)) and by subsequent inspection of x, y and g upon exit from rk4a, it can be decided whether the calculations were terminated because a point of intersection had been found or because the end of the range had been reached. The value of b(x,y) for the current values of x and y upon call of rk4a is not inspected: it is thus possible of progress systematically from one zero of b to the next.

Function Parameters: void rk4a (x,xa, b,y,ya,fj,e,4fi,xdir,pos)

x: float *; entry: the independent variable; exit: upon completion of a call, x is equal to the most recent value of the

independent variable; xu: float;

entry: the initial value of x; b: float (*b)(x,y);

the equation b=O hlfilled within the tolerances e[4] and e[5] specifies the end of the integration interval, at the end of each integration step b is evaluated and is tested for change of sign (it delivers the value of b(x,y) described above);

y: float *; entry: the dependent variable;

ya: float; entry: the value of y at x = xu;

fj: float (*h)(x,y); fxy gives the value of &/&,

e: float e[0:5]; entry: e[O], e[2]: relative tolerances for x and y respectively; e[l], e[3]: absolute tolerances for x and y respectively; e[4], e[5]: tolerances used in the determination of the zero of b;

d float d[0:4]; After completion of each step we have: if d[OPO then x is the integration variable; if d[O]<O then y is the integration variable; d[l] is the number of steps skipped; d[2] is the step size; d[3] is equal to the last value of x; d[4] is equal to the last value of y;

fi: int; entry: if$ is nonzero then the integration is started with initial values

Copyright 1995 by CRC Press, Inc

Page 386: Numerical Library in C for Scientists and Engineers A

x = xu, y = ya; i f f i is zero then the integration is started with x = d[3], Y = 441;

xdir,pos: int; entry: i f f i is nonzero then the integration starts in such a way that

if pos is nonzero and xdir is nonzero then x increases, if pos is nonzero and xdir is zero then y increases, if pos is zero and xdir is nonzero then x decreases, if pos is zero and xdir is zero then y decreases.

void rk4a (float *x, float xa, float (*b) (float, float) , float *y, float ya, float (*fxy) (float, float), float e [I , float d[] , int fi, int xdir, int pos)

{ void rk4arkstep(float *, float, float, float * , float, float,

float ( * ) (float, float), int, int, float *, float *, float * , float * , float *, float *, float *, float);

int i,iv,first,fir,rej,t,next,ext,extrapolate; float kO,kl,k2,k3,k4,k5,fhm,absh,discr,s,xl,condO,sl,condl,

yl, hmin, h, zl, tol, hl, mu, mul, el [31 , f zero, c, fc,bb, fb,a, fa,dd, fd, fdb, fda,w,mb,m,p,q;

J

d[ll =O.O; *x=xl=d [31 ; *y=yl=d 141 ; iv = d[Ol > 0.0; first=fir=l; hmin=e [OI +e Ell ; h=e [21 +e [31 ; if (h c hmin) hmin=h; while (1) (

zl= (*fxy) (*x, *y) ; if (fabs(z1) <= 1.0) (

if (!iv) ( d[21 = h /= zl; d[Ol=l.O; iv=first=l;

I J if (fir) {

t=( ((iv && xdir) I I ( ! (iv I I xdir))) ? h : h*zl) c 0.0; if (fi ? ((t && pos) I 1 ( ! (t I I pos))) : (h*d[21 c 0))

h = -h; I I i=1;

) else { if (iv) {

if (!fir) d[21 = h *= zl; d[Ol = -1.0; iv=O ; first=l;

1

if (fir) h=e 101 +e [ll ; t= ( ( (iv && xdir) I I ( ! (iv I I xdir) ) ) ? h : h*zl) c 0.0; if (fi ? ((t && pos) I I ( ! (t I I pos))) : (h*d[21 c 0)

h = -h; 1

next=o; while (1) (

absh=fabs (h) ;

Copyright 1995 by CRC Press, Inc

Page 387: Numerical Library in C for Scientists and Engineers A

if (absh c hmin) { h = (h == 0.0) ? 0.0 : ((h > 0.0) ? hmin : -hmin) ; absh=hmin;

I if (iv) {

rk4arkstep (x,xl, h, y, yl, zl, fxy, i, 0, &kO . &kl . &k2. &k3. &k4, &k5. &discr, mu) :

) else { rk4arkstep (y, yl, h,x,xl, l.o/zl, fxy, i, 1,

&kO,&kl,&k2,&k3,&k4,&k5,&discr,mu) ; tol=e [O] *fabs (k0) +e [ll *absh;

\ rej = discr > tol; mu=tol/ (tol+discr) +o.45; if ( ! re j ) break; if (absh c= hmin) {

if (iv) { *x=xl+h; *y=yl+kO ;

] else { *x=xl+kO ; *y=yl+h;

d[ll += 1.0; f irst=l; next=l; break;

h *= mu:

if (!next) { if (first) {

first=fir; hl=h; h *= mu;

] else { fhm=mu*h/hl+mu-mul; hl=h; h *= fhm;

1 if (iv)

rk4arkstep(x,xl,hl,y,yl,zl,fxy,2,0, &k0, &kl, &k2, &k3, &k4, &k5, &discr, mu) ;

else rk4arkstep (y, yl, hl,x,xl, zl, fxy, 2,1,

&kO, &kl, &k2, &k3, &k4, &k5, &discr,mu) ; mul=mu;

I if (fir) (

f ir=0 ; condo= (*b) ( *x , *y) ; if (!(fi 1 1 rej)) h=d[21;

] else { d 121 =h; condl= (*b) (*x, *y) ; if (condO*condl <= 0.0) break; condO=condl:

el [21 =e [51 ; sl = iv ? *x : *y; s = iv ? xl : yl; /* find zero * / bb=s ; if (iv) {

if (S == x1) fzero=condO;

else if (S == 51)

Copyright 1995 by CRC Press, Inc

Page 388: Numerical Library in C for Scientists and Engineers A

else { rk4arkstep(x,xl,s-xl,y,yl,zl,fxy,3,0,

&k0, &kl, &k2, &k3, &k4, &k5, &discr, mu) ; £zero= (*b) (*x, *y) ;

\ ) else (

if (S == yl) fzero=condO;

else if (s == s1)

fzero=condl; else {

rk4arkstep(y,yl,s-yl,x,xl,zl,fxy,3,1, &k0, &kl, &k2, &k3, &k4, &k5, &discr, mu) ;

1 I

fb=fzero; a=s=sl; if (iv) (

if (S == x1) fzero=condO;

else if (s == s1)

fzero=condl; else {

rk4arkstep(x,xl,s-~l,y,yl,zl,fxy,3,0, &k0, &kl, &k2, &k3, &k4, &k5, &discr, mu) ;

f zero= (*b) (*x, *y) ; 1

) else (' if (S == yl)

fzero=condO; else

if (S == s1) fzero=condl;

else ( rk4arkstep(y,yl,s-yl,x,xl,zl,fxy,3,1,

&ko, &kl, &k2, &k3, &k4, &k5, &discr, mu) ; £zero= (*b) (*x, *y) ;

\ 1

I

fa=£ zero; c=a; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) < fabs(fb)) { if (C ! = a) (

dd=a ; fd=fa;

1 a=bb; fa=fb; bb=s=c; fb=fc; c=a; fc=fa;

1 tol=fabs (el [ll *s) +fabs (el [21 ) ; m= (c+bb) *O. 5; mb=m-bb; if (fabs(mb) > tol) (

if (ext > 2) w=mb ;

else ( if (mb == 0.0)

tol=O.O; else

if (mb c 0.0) to1 = -tol; p= (bb-a) *fb; if (ext <= 1)

Copyright 1995 by CRC Press, Inc

Page 389: Numerical Library in C for Scientists and Engineers A

q=fa-fb; else {

fdb= (fd-fb) / (dd-bb) ; fda=(fd-fa) / (dd-a) ; p *= fda; q=fdb*fa-fda*fb;

I

; = ( p ~ ~ ~ ~ - ~ ~ ~ I I pc=q*tol) ? to1 : ((p<mb*q) ? p/q : mb); 1 dd=a ; fd=fa; a=bb; fa=fb; s = bb += w; if (iv) (

if (s == x1) f zero=condO ;

else if (S == 51)

fzero=condl; else {

rk4arkstep(x,xl,s-xl,y,yl,zl,fxy,3,0, &k0, &kl, &k2, &k3, &k4, &k5, &discr,mu) ;

f zero= (*b) (*x, *y) ;

) else ( 1

if (S == yl) fzero=condO;

else if (S == s1)

fzero=condl; else {

rk4arkstep (y, yl, s-yl,x,xl, zl, fxy, 3,1, &k0, &kl, &k2, &k3, &k4, &k5, &discr, mu) ;

fzero= (*b) (*x, *y) ; 1

fb=f zero; if ((fc >= 0.0) ? (fb >= 0.0) : (fb c= 0.0)) {

c=a; f c=fa; ext=O;

) else ext = (w == mb) ? 0 : ext+l;

) else break;

1 )* end of finding zero */ sl = i v ? *x : *y; if (iv)

rk4arkstep (x,xl, s-xl, y, yl, zl, fxy, 3'0, &kO,&kl,&k2, &k3,&k4,&k5, &discr,mu) ;

else rk4arkstep (y, yl, s-yl,x,xl, zl, fxy, 3,1,

&k0, &kl, &k2, &k3, &k4, &k5, &discr,mu) ; d [31= (*x) ; d [41= (*y) ;

1 void rk4arkstep(float *x, float xl, float h, float *y, float yl,

float zl, float (*fxy) (float, float), int d, int invf, float *kO, float *kl, float *k2, float *k3, float *k4, float *k5, float *discr, float mu)

1 1

/ * this function is internally used by RK4A * /

Copyright 1995 by CRC Press, Inc

Page 390: Numerical Library in C for Scientists and Engineers A

*kO= (invf ? (l.O/ (*fxy) (*x, *y) ) : (*fxy) (*x, *y) ) *h; } else

if (d == 1) *k0=zl*h;

else *kO *= mu;

*x=xl+h/4.5; *y=yl+ (*k0) /4.5; *kl=(invf ? (l.O/(*fxy) (*x, *y)) : (*fxy) (*x, *y) ) *h; *x=xl+h/3.0; *y=yl+( (*kO)+ (*kl) *3 .O) /12.0; *k2= (invf ? (l.O/ (*fxy) (*x, *y)) : (*fxy) (*x, *y) ) *h; *x=xl+h*0.5; *y=yl+( (*kO)+(*k2)*3.0)/8.0; *k3= (invf ? (l.O/ (*fxy) (*x, *y) ) : (*fxy) (*x, *y) ) *h; *x=xl+h*0.8: *y=yl+( (*k0j*53.0- (*kl)*135.0+(*k2)*126.O+(*k3) *56.0) /125.0; *k4=(invf ? (l.O/ (*fxy) (*x,*y)) : (*fxy) (*x, *y)) *h; if (d c = 1) {

*x=xl+h; *y=yl+ ( (*kO) *I33 .O- (*kl) *378.O+ (*k2) *276.O+

(*k3) *ll2.O+(*k4) *25.O) /l68.O; *k5= (invf ? (l.O/ (*fxy) (*x, *y) ) : (*fxy) (*x, * y ) ) *h; *discr=fabs( (*k0)*21.0- (*k2)*162.O+(*k3) *224.O-

(*k4) *l25.O+(*kS)*42.O) /l4.O; return;

*x=xl+h; *y=yl+ ( - (*kO) *63.O+ (*kl) *lag. 0- (*k2) *36.O-

(*k3) *ll2.O+(*k4) *5O.O) /28.O; *k5 = (invf ? (l.O/ (*fxy) (*x, *y) ) : (*fxy) (*x, *y) ) *h; *y=yl+((*kO) *35.0+(*k2)*162.0+(*k4) *l25.O+(*k5) *l4.0)/336.O;

Solves an initial value problem for a system of first order ordinary differential equations dx,(xJ/dx, = $(x), (j=l ,..., n) of which the derivative components are supposed to become large, e.g. in the neighbourhood of a singularities, by means of a 5 t h order Runge-Kutta method [Z64]. The system is assumed to be non-stiff.

rk4na integrates the given system of differential equations from x, = a (xj(a), j=l , ..., n being given) and the direction of integration (i.e. with 1 specified, 0 I I I n, x, increasing or decreasing) prescribed at outset until, to within stated tolerances, a zero of the function b(x) is encountered. (b(x) is, of course, effectively a function of the single variable x,).

The role of the function b is similar to that played in the implementation of rk4a; now, for example, we may take b(x) to be x, - x,, to determine the point at which x,(xo) and x,(xJ become equal.

At each integration step, the quantities I dxj(xa)/dxo 1 (j=O,l, ..., n) are inspected, and the variable of integration is taken to be xi,, where j' is that value of j corresponding to the maximum of these quantities. The system of equations actually solved has the form

dx/dx,. = J(x& (x) (j=O,l,. . . ,n; j#j 7.

Function Parameters: void rk4na (x,xa, b,@j, e, d,Ji,n,l,pos)

float x[O:n]; entry: x[O] is the independent variable, x[l], ..., x[n] are the dependent variables; exit: the solution at b=O; float xa[O:n]; entry: the initial values of x[0], ..., x[n];

Copyright 1995 by CRC Press, Inc

Page 391: Numerical Library in C for Scientists and Engineers A

float (* b)(n,x); b depends on x[0], ..., x[n]; if the equation b=O is satisfied within a certain tolerance (see parameter e), the integration is terminated; b is evaluated and tested for change of sign at the end of each step; float (*fjcj)(n,jA; fxj depends on x[O],..,x[n] and j , defining the right hand side of the differential equation; at each call it delivers: dxlj]/dx[O]; float e[0:2n+3]; entry: e[2j] and e[2j+l], OSjIn, are the relative and the absolute tolerance,

respectively, associated with xlj]; e[2n+2] and e[2n+3] are the relative and absolute tolerance used in the determination of the zero of b;

float d[O:n+3]; After completion of each step we have: d[O] is the number of steps skipped; d[2] is the step length; db+3] is the last value of xlj], j=O, ..., n; int; entry:

int; entry: int; entry:

pos: int; entry:

if$ is nonzero then the integration is started with initial condition xlj] = xalj]; if$ is zero then the integration is continued with xlj] = db+3];

the number of equations;

an integer to be supplied by the user, Ollln (see pos);

if$ is nonzero then the integration starts in such a way that x[l] increases if pos is nonzero and x[l] decreases if pos is zero;

if$ is zero then pos is of no significance.

void rk4na(float x[l , float xa[l, float (*b) (int, float [I ) , float (*fxj) (int, int, float [I ) , float e [I , float d[l , int fi, int n, int 1, int pos)

I float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat *, int) ; void free-real-matrix(f1oat **, int, int, int); void rk4narkstep(float, int, int, int, float,

float ( * ) (int, int, float[]), float [I, float [I, float [I, float [ I , float * * ) ;

int j,i,iv,iv0,fir,first,rej,change,t,next,ext,extrapolate; float h, condo, condl, fhm, absh, tol, fh,max, xO, xl, s, hmin, hl, mu,mul,

p, £zero, *xl, *discr, *y, **k,el[3] , c,fc,bb,fb,a,fa,dd,fd,fdb,fda,w,mb,m,q;

for (LO; ic=n; i++) d[i+3] =xa [il ; d[O] =d[ZI=O.O;

1 d[ll=0.0; for (i=O; ic=n; i++) x[i] =xl [il =d[i+31 ; iv=d [OI ;

Copyright 1995 by CRC Press, Inc

Page 392: Numerical Library in C for Scientists and Engineers A

first=fir=l; y[OI=1.0; next=O ; change=l ; while (1) (

if (!change) ( while (1) {

absh=fabs (h) ; if (absh < hmin) (

h = (h > 0.0) ? hmin : absh=fabs (h) ;

, rk4narkstep (h, i,n, iv,mu, fxj ,x,xl, y, discr, k) ; rej=O; fhm=0.0; for (i=O; i<=n; i++)

if (i !=iv) ( tol=e [2*i] *fabs (k [01 MI ) +e [2*i+ll *absh; rej=(tol c discr[il I I rej); fh=discr [il /tol; if (fh > fhm) fhm=fh;

1 mu=l.O/(l.O+fhm)+0.45; if (!rej) break; if (absh <= hmin) (

for (i=O; i<=n; i++) if (i ! = iv)

x [i] =xl [i] +k [OI ti1 ; else

x [i] =xl [il +h; d[ll += 1.0; f irst=l; next4 ; break;

1 h *= mu; i=O ;

1 if (!next) (

if (first) { first=fir; hl=h; h *= mu;

) else ( fh=mu*h/hl+mu-mul; hkh; h *= fh;

) rk4narkstep (h1,2,n, iv,mu, fxj ,x,xl, y, discr, k) ; mul=mu :

1 next=o; if (fir) {

fir=0 ; condo= (*b) (n,x) ; if ( ! (fi I \ rej)) h=d[21;

} else ( d [21 =h; condl= (*b) (n,x) ; if (condO*condl <= 0.0) break; condO=condl;

ivo=iv; for (j=1; j<=n; j++) y[j]=(*fxj) (n, j,x); max=fabs (v [ivl ) ; - . - .

for (i=O; i<=n; i++) if (fabs (y[il) > max) (

max=fabs (y [il ) ; iv=i ;

Copyright 1995 by CRC Press, Inc

Page 393: Numerical Library in C for Scientists and Engineers A

f irst=l; d 101 =iv; d[21 =h=y [ivl /y[ivOl *h;

1 xO=xl [ivl ; if (fir) {

hmin=e 101 +e Ill ; for (i=l; ic=n; i++) {

h=e [2*il +e [2*i+ll ; if (h < hmin) hmin=h;

I

i=1; 1 el [l] =e [2*n+21 ; el [2] =e [2*n+31 ; xl=x [ivl ; s=xo ; /* find zero */ bb=s; if (S == xO)

fzero=condO; else

if (S == XI) fzero=condl;

else { rk4narkstep (s-xl [ivl , 3 , n , iv,mu, fxj ,x,xl, y, discr, k) ; f zero= (*b) (n,x) ;

fb=f zero; a=s=xl; if (S == xO)

fzero=condO; else

if (s == XI) fzero=condl;

else { rk4narkstep(s-xl~ivl,3,n,iv,mu,fxj,x,xlr~~di~~rrk); £zero= (*b) (n,x) ;

1 I

fa=£ zero; c=a; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) < fabs(fb)) { if (C ! = a) (

dd=a ; fd=f a;

;ol=fabs (el [ll *s) +fabs (el [21 ) ; m= (c+bb) *O.5; mb=m-bb; if (fabs(mb) > toll {

if (ext z 2) w=mb ;

else { if (mb == 0.0)

tol=O . 0; else

if (mb < 0.0) to1 = -tol; p= (bb-a) *fb;

Copyright 1995 by CRC Press, Inc

Page 394: Numerical Library in C for Scientists and Engineers A

if (ext <= 1) q=fa-fb;

else ( fdb=(fd-fb)/ (dd-bb) ; fda= (fd-fa) / (dd-a) ; p *= fda; q=fdb*fa-fda*fb;

1

dd=a; fd=fa; a=bb ; fa=fb; s = bb += w; if (S == xO)

fzero=condO; else

if (S == XI) fzero=condl;

else { rkenarkstep(s-xl [ivl,3,n,iv,mu,fxj,x,xl, y,discr,k) ; £zero= (*b) (n,x) ;

l fbzfkero; if ((fc >=

c=a; £c=fa; ext=O;

) else ext = ( I

} else break;

I

0.0) ? (fb >= 0.0) : (fb <= 0.0)) {

w == mb) ? 0 : ext+l;

J

/ * end of finding zero */ xo=s; xl=x [ivl ; rk4narkstep(xO-xl [ivl ,3,n,iv,mu, fxj ,x,xl,y,discr,k) ; for (id; i<=n; i++) d [ii-31 =x [il ; f ree-realgector (xl, 0) ; free-real-vector(discr,O); f ree-real-vector (y, 0) ; f ree-real-matrix (k, 0,5,0) ;

1 void rklnarkstep(f1oat h, int d, int n, int iv, float mu,

float (*fxj) (int, int, float [I), float x[] , float xl [I, float y[l , float discr [I, float **k)

I / * this function is internally used by RK4NA */

int i, j; float p;

if (d != 2) ( if (d == 3) {

for (i=O; i<=n; i++) x[il =xl [il ; for (j=l; j<=n; j++) y[jl=(*fxj) (n, j,x); p=h/y [ivl ; for (i=O; ic=n; i++)

if (i != iv) k[Ol [il =y[il *p; } else

if (d == 1) { p=h/y [ivl ; for (i=O; i<=n; i++)

if (i != iv) k [Ol [il =p*y[il ; ) else

for (i=O; i<=n; i++) if (i != iv) kt01 [il *= mu;

for (i=O; ic=n; i++)

Copyright 1995 by CRC Press, Inc

Page 395: Numerical Library in C for Scientists and Engineers A

x[i]=xl[i]+((i == iv) ? h : k[Ol [il)/4.5; for (j=l; jc=n; j++) y[jl =(*fxj) (n, j,x) ; p=h/y livl ; for (i=O; ic=n; i++)

if (i ! = iv) k [ll [il =y [il *p; for (i=O; ic=n; i++)

x [il =xl [il+ ( (i == iv) ? h*4.O : (k[Ol [il+k [ll [il*3.0) ) /12.0;

for (j=l; jc=n; j++) y[jl=(*fxj) (n,j,x); p=h/y [ivl ; for (i=O; ic=n; i++)

if (i != iv) k [2l [il =y [il *p; for (i=O; ic=n; i++)

x [il =xl [il + ( (i == iv) ? h*0.5 : (k[Ol [i] +k[21 [il *3.0) /8.0) ;

for (j=l; j<=n; j++) y[jl=(*fxj) (n,j,x); p=h/y [ivl ; for (i=O; i<=n; i++)

if (i != iv) k[3l [il =y [il *p; for (i=O; ic=n; i++)

x[i]=xl[il+((i == iv) ? h*0.8 : (k[01 [il*53.0- k [l] [i] *I35 .O+k [2] [i] *126.O+k [31 [i] *56.0) /125.0) ;

for (j=l; jc=n; j++) y[jl=(*fxj) (n, j,x) ; p=h/y [ivl ; for (i=O; i<=n; i++)

if (i ! = iv) k[4l [il =y[il *p; if (d c= 1) (

for (i=O; ic=n; i++) x[i] =xl [il+ ( (i == iv) ? h : (k [Ol [il *I33 .O-

k [I] [i] *378.O+k [2] [i] *276.O+k [3] [i] *112.0+ k[41 [il*25.0)/168.0);

for (j=l; jc=n; j++) y[jl=(*fxj) (n, j,x); p=h/y [ivl ; for (i=O; ic=n; i++)

if (i ! = iv) kI5l [il =y[il *p; for (i=O; ic=n; i++)

if (i != iv) discr [il =fabs (k LO1 [il*2l. 0-k [21 [il*162.0+

k [3] [i] *224.0-k [4] [i] *125.O+k 151 [i] *42.0) /14.0; return;

1 for (i=O; i<=n; i++)

x[il =xl [il + ( (i == iv) ? h : (-k [Ol [il *63.O+k [ll [il *I89 .O-k [21 [il "36.0-k [31 [il *112.0+

k [41 [il *50.0) /28.O) ; for (j=l; jc=n; j++) y[jl=(*fxj) (n,j,x); p=h/y [ivl ; for (i=O; ic=n; i++)

if (i != iv) k[5] [il =y [il *p; for (i=O; ic=n; i++)

if (i != iv)

Solves an initial value problem for a system of first order ordinary differential equations dU/&, = J(x)/f,(x), O'=l,2,...,n)

of which the derivative components are supposed to become large, e.g. in the neighbourhood of a singularities, by means of a 5-th order Runge-Kutta method [Z64]. The system is assumed to be non-stiff.

rk5na integrates the given system of differential equations from x, = a (xj(a), j=l , ..., n, being given) and the direction of integration (i.e. with I specified, 0 I < n, x, increasing or decreasing) prescribed at outset until, to within stated tolerances, a zero of the function b(x) is encountered.

Copyright 1995 by CRC Press, Inc

Page 396: Numerical Library in C for Scientists and Engineers A

The arc length s is used as the variable of integration. Since ds2 = dx t + ...+ dxn2, it follows that ds = (dxdfo(x))a, where

The system of equations actually solved is dxjdx, = &(x)/a (j=O,l, ..., n).

Thus, points at which fo(x) = 0 and dxjdx, may become infinite cause no special trouble. The role of the function b is similar to that played by the same function in the

implementation of rk4na.

Function Parameters: void rk5na (x,xa, b,fxj,e,d,Ji,n,l,pos)

x: float x[O:n]; entry: the dependent variables;

xu: float xa[O:n]; entry: the initial values of x[0], ..., x[n];

b: float (*b)(n,x); b depends on x[Ol,. .. .,x[n]; if, within some tolerance, b=O then the integration is terminated; see parameter e;

fxj: float (*fxj)(n,j,x); jkj depends on x[O],..,x[n] and j , giving the value of dxb]/dx[O];

e: float e[0:2n+3]; entry: e[2j] and e[2j+I], OSjSn, are the relative and the absolute tolerance,

respectively, associated with xb]; while e[2n+2] and e[2n+3] are the relative and absolute tolerance used in the determination of the zero of b;

d float d[l:n+3]; After completion of each step we have: (d[l] ( is the arc length; d[2] is the step length; d0+3] is the latest value of xb], j=O, ..., n;

Ji: int; entry: if$ is nonzero then the integration is started with initial conditions x,ij]=xali./,

j=O, ..., n; if$ is zero then the integration is continued with xlj]=db+3]; n: int;

entry: the number of equations; E: int;

entry: an integer to be supplied by the user, l s l m (see pos); pos: int;

entry: i f 4 is nonzero then the integration starts in such a way that x[l] increases if pos is nonzero and x[l] decreases if pos is zero;

if$ is zero then pos is ignored.

void rk5na (float x [I , float xa [I , float (*b) (int, float [I ) . float (*fxj) (int, int, float[]), float e[l, float d[l. int fi, int n, int 1, int pas)

Copyright 1995 by CRC Press, Inc

Page 397: Numerical Library in C for Scientists and Engineers A

{ float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); void rk5narkstep (f loat, int, int, float,

float ( * ) (int, int, float [I), float [I, float [I, float [I, float [I, float * * ) ;

int j,i,first,fir,rej,t,ext,extrapolate; float fhm, s, SO, condo, sl, condl, h,absh, tol, fh,hl,mu,mul,

fzero,*y,*xl,*discr,**k,e1[31, c,fc,bb,fb,a,fa,dd,fd,fdb,fda,w,mb,m,p,q;

y=allocate-real-vector(0,n); xl=allocate-real-vector(0,n); discr=allocate-real-vector(0,n); k=allocate-real-matrix(0,5,0,n) ; if (fi) {

for (i=O; i<=n; i++) d [i+3l =xa [il ; d [ll =d [21 =O. 0;

1 ;or (i=O; i<=n; i++) x [il =xl [il =d [i+3l ; s=d[ll ; first=fir=l; h=e [O] +e [l! ; for (i=l; Ic=n; i++) {

absh=e t2*il +e [2*i+ll ; if (h > absh) h=absh;

1 if (fi) {

j=l; t=(*fxj) (n, j,x) *h < 0.0; if ( (t && pos) I I ! (t I I pos)) h = -h;

) else if (d[21*h < 0.0) h = -h;

i=O; while (1) {

rk5narkstep(h,i,n,mu,fxj,x,xl,y,discr,k); re j =O ; fhm=O .O; absh=fabs ( h ) ; for (i=O; 1<=n; i++) {

tol=e [2*i] *fabs (k [Ol [il ) +e [2*i+ll *absh; rej=(tol < discrril / I rej); fh=discr [il /tol; if (fh > fhm) fhm=fh;

\ mu=1.0/(1.0+fhm)+0.45; if (rej) {

h *= mu; i=l;

} else ( if (first) {

first=fir; hl=h; h *= mu;

} else { fh=mu*h/hl+mu-mul; hl=h; h *= fh;

1 rk5narkstep (hl, 2,n,mu, fxj ,x,xl, y, discr, k) ; mul=mu; s += hl; if (fir) (

f ir=O; if ( ! fi) h=d [21 ;

} else { d [21 =h; condl= (*b) (n,x) ; if (condO*condl <= 0.0) break; condO=condl;

1

Copyright 1995 by CRC Press, Inc

Page 398: Numerical Library in C for Scientists and Engineers A

el [l] =e [2*n+2] ; el 121 =e [2*n+31 ; s1=s ; s=so; / * find zero * / bb=s ; if (S == SO)

fzero=condO; else

if (S == 51) fzero=condl;

else { rk5narkstep (s-so, 3 ,n,mu, fxj ,x,xl, y, discr, k) ; £zero= (*b) (n,x) ;

fb=f zero; a=s=sl; if (S == SO)

fzero=condO; else

if (S == s1) fzero=condl;

else ( rk5narkstep (s-so, 3 ,n,mu, fxj ,x,xl, y,discr, k) ; f zero= (*b) (n,x) ;

\ I

fa=£ zero; c=a; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) < fabs(fb) { if (C ! = a) {

dd=a ; fd=fa;

1 tol=fabs (el [ll *s) +fabs(el[21 ) ; m= (c+bb) *0.5; mb=m-bb; if (fabs(mb) > tol) {

if (ext > 2) w=mb ;

else { if (mb == 0.0)

tol=O.O ; else

if (mb < 0.0) to1 = p= (bb-a) *fb; if (ext <= 1)

q=fa-fb; else {

fdb= (fd-fb) / (dd-bb) ; fda= (fd-fa) / (dd-a) ; p *= fda; q=fdb*fa-fda*fb;

Copyright 1995 by CRC Press, Inc

Page 399: Numerical Library in C for Scientists and Engineers A

1 dd=a; fd=fa; a=bb; fa=fb; s = bb += w; if (S == SO)

fzero=condO; else

if (S == s1) fzero=condl;

else { rk5narkstep (s-s0,3 ,n,mu, fxj ,x,xl, y, discr, k) ; £zero= (*b) (n,x) ;

1 I

fb=f zero; if ((fc >= 0.0) ? (fb >= 0.0) : (fb c= 0.0)) {

c=a; fc=fa; ext=O;

) else ext = (w == mb) ? 0 : ext+l;

) else break;

)* end of finding zero * / rk5narkstep (s-so, 3 ,n,mu, fxj ,x,xl, y, discr, k) ; for (i=O; ic=n; i++) d[i+31=x[il ; d [ll =s; free-real-vector (y, 0 ; f ree-real-vector (xl, 0) ; free-real-vector (discr, 0) ; free-real-matrix(k,0,5,0) ;

1 void rk5narkstep(float h, int d, int n, float mu,

float (*fxj) (int, int, float[]), float x[l, float float y [I , float discr [I , float **k)

I

/ * this function is internally used by RK5NA * /

int i, j; float p,s;

if (d ! = 2) { if (d == 1)

for (i=O; ic=n; i++) k[Ol [il *= mu; else (

for (i=O; ic=n; i++) x [il =xl [il ; for (j=O; jc=n; j++) y[jl=(*fxj) (n,j,x); s=o.o; for (j=O; jc=n; j++) s += y[jl*y[jl;

p=h/sqrt (s! ; for (i=O; ic=n; i++) k [2l [il =y [il *p; for (i=O; ic=n; i++) x [il =xl [il + (k [OI [il +k [21 [il *3.0) /8.0; for (j=O; jc=n; j++) y[jl=(*fxj) (n,j,x); s=o.o; for (j=O; jc=n; j++) s += y[jl*y[jl; p=h/sqrt (s! ; for (i=O; ic=n; i++) k [31 [il =y [il *p; for (i=O; i<=n; i++)

£or (i=o for (j=O s=o . 0 ; for (j=O p=h/sqrt for (i=O for (i=O for (j=O s=o.o; for (j=O

ic=n; i++) x [il =xl [i] +k [Ol [il /4.5; j<=n; j++) y[jl=(*fxj)(n,],x);

jc=n; j++) s += y[jl*y[jl; s! ; lc=n; i++) k [ll [il =y [il *p; ic=n; i++) x [il =xl [i] + (k [OI [il +k [ll [il *3.0) /12.0; jc=n; j++) y[jl =(*fxj) (n, j,x) ;

jc=n; j++) s += y[jl*y[jl;

Copyright 1995 by CRC Press, Inc

Page 400: Numerical Library in C for Scientists and Engineers A

x [i] =xl [i] + (k [O] [i] *53.O-k [l] [i] *l35.O+k [2] [i] *I26 .O+ k[31 [il "56.0) /125.0;

for (j=O; j<=n; j++) y[jl =(*fxj) (n, j ,x) ; s=o.o; for (j=O; j<=n; j++) s += y[jl*y[jl; p=h/sqrt (s! ; for (i=O; 1<=n; i++) k[41 [il =y[il *p; if ( d <= 1) {

for (i=O; i<=n; i++) x [i] =xl [i] + (k [Ol [il *I33 .O-k [I] [i] *378.O+k 121 [i] *276.O+

k [3] [i] *112.O+k [4] [i] *25.0) /168.0; for (j=O; j<=n; j++) y[jl=(*fxj) (n, j,x); S=O . 0; for (j=O; j<=n; j++) s += y[jl*y[jl; ~=h/sart (s) : - . - for (i=O; i<=n; i++) k [5l [il =y[il *p; for (i=O: i<=n: i++)

disc; [i] =fabs (k [01 [i] *21.O-k [21 [il *162.0+ k [3] [i] *224.0-k 141 [i] *125.O+k [5] [i] "42.0) /14.0;

return;

for (i=O: i<=n: i++) . . x [il =xl [il + (-k [OI [il *63.O+k [ll [il *189.0-k [21 [il*36.0-

k [31 [il *112.O+k [41 [il *SO. 0) /28.O; for (j=O; j<=n; j++) y[jl=(*fxj) (n,j,x); s=o.o; for (j=O; j<=n; j++) s += y[jl*y[jl; p=h/sqrt (s! ; for (i=O; 1<=n; i++) k [Sl [il =y [il *p; for (i=O; i<=n; i++)

x [i] =xl [i] + (k [Ol [il *35.O+k [21 [il *162.O+k [41 [il *125.0+ k [51 [il *l4.O) /336.O;

1

F. multistep

Solves an initial value problem for a system of first order ordinary differential equations dy,(x)/dx = A(x,y(x)) (i= 1,2,. . .,n)

fiom x = x, to x = xed (x, < x,,,), y(xJ being given, based on two linear multistep methods. For stiff problems it uses the backward differentiation method, and for non-stiff problems the Adams-Bashforth-Moulton method [He7 11.

During the implementation of a typical stage of the variant of the Adarns-Moulton method employed, (a) approximations to j$c,y(x)) at x = xp+, (v=O, ...,k; i=l, ..., n) are available, together with (b) approximations yi(pfk,vi to d"y,(x)/dx" at x = xP+, (v=O, ...,k; i=l ,..., n), and (c) approximations to the derivatives dyi(x)/dx" (v=O, ..., k; i=l ,..., n) at x=xP+,+, are determined by prediction and iterated correction. If the order k is preserved then thefp) are discarded, and the process is repeated.

At a typical stage in the implementation of the variant of the Curtiss-Hirschfelder method employed, approximations yi(pf') (v=O, ...,k; i=l ,..., n) to yi(x) at x = xP+, (v=O, ..., k; i=l, ..., n) are available, together with the derivative approximations (b) above, and the derivative approximations (c) above are also determined by prediction and iterated correction.

The above process of iterated correction may, if necessary, be accelerated by use of the Jacobian matrix whose elements are given by aA(x,y(x))/ayj(x) (i,j=l, ..., n).

The Adam-Moulton method is a relatively rapid process for high-accuracy computation of the solution of systems of differential equations with slowly varying dependent variables. The Curtiss-Hirschfelder method is suitable for the solution of stiff systems, whose solution vector contains one or more rapidly varying components. multistep uses a steplength and order control mechanism due to Gear (the steplength is xP+,+, - xp+, above; k is the order).

Copyright 1995 by CRC Press, Inc

Page 401: Numerical Library in C for Scientists and Engineers A

If so requested, multistep begins by attempting an unaccelerated Adams-Moulton method; if this is too time-consuming, acceleration using a Jacobian matrix is embarked upon; if this also fails, multistep switches to Gear's implementation of the Curtiss-Hirschfelder method, (after the determination of a Jacobian matrix at the commencement of one step, the same matrix is used to accelerate correction over as many subsequent steps as possible). However, it is possible to request multistep to use Gear's method at outset. Tactical considerations concerning steplength and order are reversible; strategic decisions concerning the method are not; once multistep has embarked upon Gear's method, it continues with it for the duration of the call.

Function Parameters: int multistep (x,xend,y, hmin, hmax,yamx,eps,first,save,deriv,available,jacobian,st~n, out)

multistep: if difficulties are encountered during the integration (i.e. save[-I] # 0 or save[-21 # 0) then multistep is set to zero, otherwise multistep is set to nonzero;

x: float *; entry: the independent variable; the initial value xO; exit: the final value xend;

xend: float; entry: the final value of x (xend 2 x);

y: float y[l:6n]; entry: the dependent variable; y[l:n] are the initial values of the solution of the

system of differential equations at x = xO; exit: y[l:n] are the final values of the solution at x = xend;

hmin, hmax: float; entry: the minimum and maximum steplength allowed, respectively;

ymax: float yrnax[l:n]; entry: the absolute local error bound divided by eps; exit: ymax[i] gives the maximal value of the entry value of ymax[i] and the values

of I y[i/ 1 during integration; eps: float;

entry: the relative local error bound; first: int *;

iffirst is nonzero then the procedure starts the integration with a first order Adams method and a steplength equal to hmin, upon completion of a call, Jrst is set to zero; iffirst is zero then the procedure continues integration;

save: float save[-38: 6n]; in this array the procedure stores information which can be used in a continuing call with first = zero; also the following messages are delivered: save[O]=O: an Adams method has been used; save[O]=l : the procedure switched to Gear's method; save[-l]=O: no error message; save[-l]=l: with the hmin specified the procedure cannot handle the nonlinearity

(decrease hmin!); save[-21: number of times that the requested local error bound was exceeded; save[-31: if save[-21 is nonzero then save[-31 gives an estimate of the maximal local

error bound, otherwise save[-3]=0; deriv: void (*deriv)(df;n,x,y); float df[], int n, float x, float y[];

Copyright 1995 by CRC Press, Inc

Page 402: Numerical Library in C for Scientists and Engineers A

this procedure should deliver dy[i]/ak in df[i]; available: int (*available)(n,x,yjacobian);

if an analytic expression of the Jacobian matrix is not available the available is set to zero, otherwise available is set to nonzero and the evaluation of this procedure must have the following side-effect: the entries of the Jacobian matrix d(dy[iJ/ak)/dyfi] are delivered in the array elements jacobian[i,j];

jacobian: float jacobian[l :n, 1:nl; at each evaluation of the user supplied function available with the result available equals nonzero, the Jacobian matrix has to be assigned to this array;

st# int; entry: if stiffequals nonzero then the procedure skips an attempt to solve the problem

with Adarns-Bashforth or Adarns-Moulton methods, directly using Gear's method;

n: int; entry: the number of equations;

out: void (*out)(h,k,n,x,y); float h, int k, int n, float x, float y[]; at the end of each accepted step of integration process this procedure is called, the last steplength used, h, and the order of the method, k, are delivered; at each call of the procedure out, the current values of the independent variable x and of the solution y[i](x) are available for use; moreover, in the neighbourhood of the current value of x, any value of y[i](x') can be computed by means of the following interpolation formula

Functions used: matvec, dec, sol.

int multistep(f1oat *x, float xend, float y[], float hmin, float hmax, float p a x [I , float eps, int *first, float save [I , void (*deriv) (float [I , int, float, float [I ) , int (*available) (int, float, float [I , float * * ) , float **jacobian, int stiff, int n, void (*out) (float, int, int, float, float [I ) )

1 I

int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int void free-integer-vector(int * , int); void free-real-vector(f1oat * , int); void free-real-matrix(f1oat ** , int, int, int); float matvec(int, int, int, float **, float [I) void dec(f1oat **, int, float [I, int [ I ) ; void sol (float **, int, int [I , float [I ) ; void multiste~reset(f1oat 1 1 . float [ I . float * .- .

float -*. float * . int *. float.' float. ' float * ,

Eloat, float, int, int, ' int) ; '

void multisteporder (float [I , float [I , float *, float *, float * , float * , float * , int * , float, int, int) ;

void multistepstep(int * , float *, float, float, float, float [I , float, float [I , float [I , float [I , int, int, int, int) ;

void multistepjacobian (int, float, float [I , float,

Copyright 1995 by CRC Press, Inc

Page 403: Numerical Library in C for Scientists and Engineers A

float [I, float [I, float [I, float ** , void ( * ) (float [I , int, float, float I1 ) , int ( * ) (int, float, float [I, float * * ) , int *, int *, int * ) ;

static float adams1[35] = I1.0, 1.0, 144.0, 4.0, 0.0, 0.5, 1.0, 0.5, 576.0, 144.0, 1.0, 5.0/12.0, 1.0, 0.75, 1.0/6.0, 1436.0, 576.0, 4.0, 0.375, 1.0, 11.0/12.0, 1.0/3.0, 1.0/24.0, 2844.0, 1436.0, 1.0, 251.0/720.0, 1.0, 25.0/24.0, 35.0/72.0, 5.0/48.0, 1.0/120.0, 0.0, 2844.0, 0.1);

static float adams2[35] = (1.0, 1.0, 9.0, 4.0, 0.0, 2.0/3.0, 1.0, 1.0/3.0, 36.0, 20.25, 1.0, 6.0/11.0, 1.0, 6.0/11.0, 1.0/11.0, 84.028, 53.778, 0.25, 0.48, 1.0, 0.7, 0.2, 0.02, 156.25, 108.51, 0.027778, 120.0/274.0, 1.0, 225.0/274.0, 85.0/274.0, 15.0/274.0, 1.0/274.0, 0.0, 187.69, 0.0047361);

static int adarns,withjacobian,m,sarne,kold; static float xold,hold,aO,tolup,tol,toldwn,tolconv; int evaluate,evaluated,decompose,decomposed,conv,i,j,l,k,knew,

fails, *p; float h,ch,chnew,error,dfi,c,a[6],*delta,*lastdelta,*df,**jac,

aux [41, *fixy, *fixdy, *dy, ss, aa;

if (*first) { *first = 0; m=n; save [-11 =save [-21 =save [-31=0.0; (*out) (O.O,O,n, *x,y) ; adams= ( !stiff) ; withjacobian= ( ! adams) ; if (withjacobian)

rnultistepjacobian(n,*x,y,eps,fixy,fixdy,dy,jacobian,deriv, available.&evaluate,&decomwose,&evaluated~;

else for (j=O; j<=34; j++) save[j-381 =adams2 [jl ;

Newstart: k=l ; same=2 ; multisteporder(a,save,&tolup,&tol,&toldwn,&tolconv,

&aO,&decornpose,eps,k,n); (*deriv) (df, n, *x, y) ; if (!withjacobian)

h=hmin; else {

ss=FLT MIN; for (<=I; i<=n; i++) {

aa=matvec(l,n, i, jacobian,df) /ymaxfil ; ss += aa*aa:

J

if (h>hmax) h=hrnax;

else if (h c hmin) h=hmin;

xold= (*x) ; hold=h; kold=k ; ch=l. 0 ; for (i=l; i<=n; i++) {

save [il =y [il ; save [m+il =y [m+il =df [il *h;

I (*out) (O.O,O,n,*x,y) ;

) else {

Copyright 1995 by CRC Press, Inc

Page 404: Numerical Library in C for Scientists and Engineers A

withjacobian= ( ! adams) ; ch=l. 0 ; k=kold; multistepreset(y,save,x,&ch,&c,&h,&decomposed,hmin,hmax,

hold,xold,m, k, n) ; multisteporder(a,save,&tolup,&tol,&toldwn,&tolconv,

&aO,&decompose,eps,k,n); decompose=withjacobian;

I f ails=O ; while (*x < xend) (

if ((*x)+h c= xend) *x += h;

else ( h=xend- (*XI ; *x = xend; ch=h/hold; c=1.0; for (j=m; j<=k*m; j+=m) {

c *= ch; for (i=j+l; ic=j+n; i++) y[il *= c;

\ same = ( (same c 3) ? 3 : same+l) ;

1 I * prediction * / for (1=1; l<=n; I++) (

for (i=l; i<= (k-1) *m+l; i+=m) for (j=(k-l)*m+l; j>=i; j-=m) y[jl += y[j+ml;

delta [ll=O. 0; 1 evaluated=O; / * correction and estimation local error * / for (1=1; 1c=3; I++) (

(*deriv) (df,n, *x, y) ; for (i=l; i<=n; i++) df [il =df [il *h-y [m+il ; if (withjacobian) {

if (evaluate) multistepjacobian(n,*x,y,eps,fixy,fixdy,dy,jacobian,

deriv,available,&evaluate,&decompose,&evaluated~ ; if (decompose) (

/ * decompose jacobian * / decompose=O; decornposed=l; c = -aO*h; for (j=l; j<=n; j++) {

for (i=l; i<=n; i++) jac [il [jl =jacobian [il [jl *c; jac[jl [jl += 1.0;

I J

aux [21 =FLT-EPSILON; dec(jac,n,aux,p) ;

conv=l; for (i=l; ic=n; i++) (

dfi=df [il ; y [i] += aO*dfi; y[m+il += dfi; delta[il += dfi; conv= (conv && (fabs (dfi) < tolconv*ymax [il ) ) ;

I

error=ss; break;

I / * acceptance or rejection * / if (!conv) (

if (!withjacobian) (

Copyright 1995 by CRC Press, Inc

Page 405: Numerical Library in C for Scientists and Engineers A

Copyright 1995 by CRC Press, Inc

Page 406: Numerical Library in C for Scientists and Engineers A

if (chnew > 1.1) { decomposed=O; if (k ! = knew) (

if (knew > k) for (i=l; ic=n; i++)

y[knew*m+il =delta [il *a [kl /knew; k=knew ; multisteporder(a,save,&tolup,&tol,&toldwn,

&tolconv, &aO, &decompose, eps, k,n) ; 1 same=k+l ; if (chnewfh > hmax) chnew=hmax/h; h *= chnew; c=1.0; for (j=m; jc=k*m; j+=m) (

c *= chnew; for (i=j+l; ic=j+n; i++) y[il *= c;

1

(Lx ! = xend) { xold= (*x) ; hold=h; kold=k; ch=l. 0 ; for (i=k*m+n; i>=l; i--) save[il=y[il; (*out) (h,k,n, *x, y) ;

$ave[~l=(adams ? 0.0 : 1.0); free-integer-vector(p,l); free-real-vector(delta,l); free-real-vector(lastdelta,l) ; free-real-vector (df, 1) ; free-real-vector(fixy,l); free-real-vector(fixdy,l) ; free-real-vector (dy, 1) ; free real matrix( jac, 1, n, 1) ; return ((save[-11 == 0.0) && (save[-21 == 0.0));

I void multistepreset(f1oat y[], float save[], float *x, float *ch,

float *c, float *h, int *decomposed, float hmin, float hmax, float hold, float xold, int m, int k, int n)

/ * this function is internally used by MULTISTEP */

int i, j;

if (*ch c hmin/hold) *ch = hmin/hold;

else if (*ch > hmax/hold) *ch = hmax/hold;

*x = xold; *h = hold* (*ch) ; * C = 1.0; for (j=O; jc=k*m; j + = m ) {

for (i=l; ic=n; i++) y[j+il =save [j+il * (*c) ; (*c) *= (*ch);

1

void multisteporder(f1oat a[], float save[], float *tolup, float *tol, float *toldwn, float *tolconv, float *aO, int *decompose, float eps, int k, int n)

I 1

/ * this function is internally used by MULTISTEP * /

int i, j; float c;

Copyright 1995 by CRC Press, Inc

Page 407: Numerical Library in C for Scientists and Engineers A

c=eps*eps; j= (k-1) * (k+8) /2-38; for (i=O; i<=k; i++) a [il =save [i+jl ; *tolup = c*save [j+k+ll ; *to1 = c*save [j+k+21 ; *toldwn = c*save [ j+k+31 ; *tolconv = eps/ (2*n* (k+2) ) ; *a0 = a [Ol ; *decompose = 1;

1 void multistepstep(int *knew, float *chnew, float tolup, float tol,

float toldwn, float delta [ I , float error, float lastdelta [ I , float y [I , float Pax[] , int fails, int m, int k, int n)

/ * this function is internally used by MULTISTEP * /

int i; float al,a2,a3,aa,ss;

if (k <= 1) al=0.0 ;

else { ss=FLT-MIN; for (i=l; i<=n; i++) (

aa=y [k*m+il /ymax [il ; ss += aa*aa;

1

~2=0.80*pow(tol/error,0.5/(k+l)); if (k >= 5 1 1 fails ! = 0)

a3=O. 0; else {

ss=FLT MIN; for (iil; i<=n; i++) (

aa= (delta [i] -1astdelta [il ) /ymax[il ; ss += aa*aa;

1

if (a1 > a2 && a1 > a3) { *knew = k-1; *chnew = al;

} else if (a2 >a3) {

*knew = k; *chnew = a2;

} else { *knew = k+l; *chnew = a3;

1 1

void multistepjacobian(int n, float x, float y[l, float eps, float fixy [ I , float fixdy [I , float dy [I , float **jacobian, void (*deriv) (float [I , int, float, float [I ) , int (*available) (int, float, float [I , float * * ) , int *evaluate, int *decompose, int *evaluated)

1 1

/ * this function is internally used by MULTISTEP * /

int i,j; float d;

*evaluate = 0; *decompose = *evaluated = 1; if ( ! (*available) (n,x, y, jacobian) ) (

for (i=l; i<=n; i++) fixy [il =y [il ; (*deriv) (fixdy,n,x,y) ; for (j=l; j<=n; j++), (

d=((eps > fabs(fixy[jl)) ? eps*eps : eps*fabs(fixy[jl)); y[jl += d;

Copyright 1995 by CRC Press, Inc

Page 408: Numerical Library in C for Scientists and Engineers A

G. diffsys

Integrates the system of first order ordinary differential equations & i W & = J ; ~ Y )

from x = xO to x = xe by means of a high order extrapolation method based on the modified midpoint rule. The method is suitable for high accuracy problems and is not suited for stiff equations.

diffsys is a slight modification of the algorithm in [BulS65]. By this modification integration from xO until xe can be performed by one call of diffsys. A number of integration steps are taken, starting with the initial step hO, in each integration step a number of solutions are computed by means of the modified midpoint rule. Extrapolation is used to improve these solutions, until the required accuracy is met. An integration step is rejected if the accuracy requirements are not fulfilled after nine extrapolation steps. In these cases the integration step is rejected, and integration is tried again with the integration step halved.

The algorithm is for each step a variable order method (the highest order is 14), and uses a variable number of function evaluations, depending on the order (minimum is 3, maximum is 217). The algorithm is less sensitive to too small values of the initial stepsize than the original algorithm (see [Fox72, HEFS721). However, bad guesses require still some more computations.

Function Parameters: void diffsys (we, n,y, derivative, aeta, reta,s, hO, output)

x: float *; entry: the independent variable; the initial value xO; exit: the final value xe;

xe: float; entry: the final value of x (xe 2 x);

n: int; entry: the number of equations;

y: float y[l:n]; entry: the dependent variable; y[l:n] are the initial values of the solution of the

system of differential equations at x = xO; exit: y[l:n] are the final values of the solution at x = xe;

derivative: void (*derivative)(n,x,y,cfy); this procedure should deliver the right hand side of the i-th differential equation at the point (x,y) as dy[i], i=l, ..., n;

aeta: float; entry: required absolute precision in the integration process;

reta: float; entry: required relative precision in the integration process;

s: float s[l:n]; the array s is used to control the accuracy of the computed values of y; entry: it is advisable to set s[i]=O, i=l, ..., n;

Copyright 1995 by CRC Press, Inc

Page 409: Numerical Library in C for Scientists and Engineers A

exit: the maximum value of I y[iJ 1 , encountered during integration, if this value exceeds the value of s[i] on entry;

hO: float; entry: the initial step to be taken;

output: void (*output)(n,x,xe,y,s); this procedure is called at the end of each integration step, the user can ask for output of parameters x, xe, y and s.

void diffsys(f1oat *x, float xe, int n, float y[l , void (*derivative) (int, float, float 11 , float [I ) , float aeta, float reta, float s [I, float hO, void (*output) (int, float, float, float [I, float 11 ) )

I L

float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat *, int); void free-real-rnatrix(f1oat **, int, int, int); int i,j,k,kk,jj,l,m,r,sr,konv,bO,bh,last,next; float a,b,bl,c,g, h,u,v, ta, fc, *ya, *yl, *ym, *dy, *dz, **dt,d[71r

**yg, **yh;

last=O; h=hO ; do {

next=O ; if (h*l.l >= xe- (*x)) (

last=l; hO=h; h=xe- ( *x) +FLT-EPSILON;

I (*derivative) (n, *x, y, dz) ; bh=O ; for (i=l; i<=n; i++) ya [il =y[il ; while (1) {

a=h+ (*x) ; fc=1.5; bO=O; m=l; r=2 ; sr=3 ;

d[ll=16.0/9.0; d[31=64.0/9.0; d[51=256.0/9.0;

) else ( d[l1=9.0/4.0; d[31=9.0; d[51=36.0;

I konv= 1 ; if (j > 6) (

1=6; d[61=64.0; fc *= 0.6;

) else ( l=j;

Copyright 1995 by CRC Press, Inc

Page 410: Numerical Library in C for Scientists and Engineers A

d [ll =m*m; \ m *= 2; g=h/m; b=g*2.0; if (bh && j < 8)

for (i=l; i<=n; i++) { ym [il =yh [j I [il ; yl[il=yg[jl [il ;

I else (

kk= (m-2) /2; m--; for (i=l; i<=n; i++) {

yl [il =ya [il ; ym [i] =ya [il +g*dz [il ;

1 ior (k=l; k<=m; k++) {

(*derivative) (n, (*x) +k*g,ym, dy) ; for (i=l; 1<=n; i++) {

u=yl [il +b*dy [il ; yl [il =ym [il ; ym [il =u; u=fabs (u) ; if (U > s [il ) s[iI =u;

j j++; for (i=l; ic=n; i++) (

yh[jjl [il=ym[il ; yg[jjl [il=yl[il;

1

I I (*derivative) (n, a,ym,dy) ; for (i=l; lc=n; i++) {

v=dt [il [Ol ; ta=c=dt [il LO]= (ym [il +yl [il +g*dy [il ) /2.0; for (k=l; k<=l; k++) {

bl=d [kl *v; b=bl-C;

I if (fabs (y [il -ta) > reta*s [il +aeta) konv=O; y [il =ta;

1 if (konv) (

next=l; break;

1

1 if (next) break; bh = !bh; last=O; h /= 2.0;

1

Copyright 1995 by CRC Press, Inc

Page 411: Numerical Library in C for Scientists and Engineers A

} while ( !last) ; f ree-real-vector (ya, 1) ; f ree-real-vector (yl, 1) ; free-real-vector (ym, 1) ; free-real-vector (dy, 1) ; f ree-real-vector (dz ,I) ; free-real-matrix (dt, 1, n, 0) ; free-real-matrix(yg, 0,7,1) ; free-real-matrix(yh, 0,7,1) ;

1

H. ark

Solves an initial value problem for a system of first order ordinary differential equations which is obtained from semi-discretization of an initial boundary value problem for a parabolic or hyperbolic equation, based on stabilized, explicit Runge-Kutta methods of low order [Be72, Vh7 1, VhBDS7 1, VhK7 11. Automatic stepsize control is provided but step rejection has been excluded in order to save storage. Because of its limited storage requirements and adaptive stability facilities the method is well suited for the solution of initial boundary value problems for partial differential equations.

ark solves the system of differential equations Dui(t) = f;(t,u(t)) (i=mO,mO+l, ..., m)

where D=d/dt, with u(tJ given, from t = to to t = te. The theory upon which the operation of ark is based is, in its early stages, the same as that supporting efrk. However, ark operates with a fixed stability polynomial

p,(z) = I + Jlz +...+ Jnf all of whose coefficients the user supplies at call of ark; furthermore, it is assumed that those eigenvalues of J(t) (the Jacobian matrix whose elements are given by

~ , ~ ( t ) = a ~ ; + ~ , ~ ~ ( t , ~ ( t ) ) / a ~ , + ~ ~ , ( t ) (i,j=l, ..., rn-m0+1) which lie in the closed left half-plane Real@) I 0 are either all pure real or pure imaginary for to I t I te.

With o(4 the spectral radius of J(t) with respect to its eigenvalues in the closed left half-plane, stability polynomials p,+) have been constructed such that the associated Runge- Kutta scheme (2) of efrk is stable if the stepsize (in t) h satisfies the inequality h I J(n)/u(J); J(n) is a constant associated with the polynomial p,,(z) in question, and in each case p,(z) has been so determined thatJ(n) assumes its maximum permissible value. Examples of such polynomials p,,(z) and associated constants J(n), together with the types of equations (i.e. those for which the eigenvalues in the closed left half-plane Real@) I 0 of the associated Jacobian matrix J(t) are either all pure real or all pure imaginary) to which they refer, and the order r of exactness (see the documentation to efrk) of the polynomial in question are given in the following table.

n Bi B2 323 J34 A B ( 4 type r 3 1 112 114 2 imaginary 2 4 1 112 116 1/24 242 imaginary 3 4 1 5/32 11128 118192 32 real 1 4 1 112 0.078 0.0036 12 real 2 4 1 112 116 0.0185 6 real 3 5 1 112 3/16 1/32 1.128 4 imaginary 2

Function Parameters: void ark (t,te,mO,m,u,derivutive,dutu,out)

Copyright 1995 by CRC Press, Inc

Page 412: Numerical Library in C for Scientists and Engineers A

t: float *; the independent variable t of the systems of ordinary differential equations

d d d t =f(t,u), u=uO at t=tO; entry: the initial value to; exit: the final value te;

te: float *; entry: the final value of t (te 2 t);

mO,m: int *; indices of the first and last equation of the system;

u: float u[mO:m]; entry: the initial values of the solution of the system of differential equations at t=tO; exit: the values of the solution at t = te;

derivative: void (*derivative)(mO, m, t,v); this procedure performs an evaluation of the right hand side of the system with dependent variables v[mO:m] and independent variable t, upon completion of derivative, the right hand side should be overwritten on v[mO:m];

data: float data[l: 1 O+data[l]]; in array data one should give: data[l]: the number of evaluations off(t, u) per integration step (data[l]>data[2J); data[2]: the order of accuracy of the method (data[2]13) (value of r above); data[3]: stability bound (value ofJ(n) above); data[4]: the spectral radius of the Jacobian matrix with respect to those eigenvalues

which are located in the non-positive half plane (value of o(J(x)) above); data[5]: the minimal stepsize; data[6]: the absolute tolerance; data[7]: the relative tolerance;

if both data[6] and dat[7] are negative then the integration is performed with a constant step data[5];

data[8]: data[8] should be zero if ark is called for a first time, for continued integration data[8] should not be changed;

data[l I],.. .,data[l O+data[l]]: polynomial coefficients (the values of Ri above in data[i+lO], i=l ,..., data[lJ);

after each step the following by-products are delivered: data[8]: the number of integration steps performed; data[9]: an estimate of the local error last made; data[lO]: information messages:

data[lO]=O: no difficulty; data[lO]=l: minimal steplength exceeds the steplength prescribed by stability

theory, i.e. data[5l>data[3]/data[4]; termination of ark; decrease minimal steplength;

if necessary, data[i], i=4, ..., 7, can be updated (after each step by means of procedure out);

out: void (*out)(mO,m,t,te, u,data); after each integration step performed information can be obtained or updated by this procedure.

Functions used: inivec, mulvec, dupvec, vecvec, elmvec, decsol.

Copyright 1995 by CRC Press, Inc

Page 413: Numerical Library in C for Scientists and Engineers A

void ark(f1oat *t, float *te, int *mO, int *m, float u[l, void (*derivative) (int *, int * , float *, float [I ) , float data [I , void (*out) (int * , int * , float * , float * , float [I, float [I ) )

1 L

float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int); void free-real-vector(f1oat * , int); void free-real-matrix (float ** , int, int, int) ; void inivec (int, int, float [I , float) ; void mulvec(int, int, int, float [I, float [ I , float) ; void dupvec(int, int, int, float [I, float 11 ) ; float vecvec (int, int, int, float [I, float [I ; void elmvec (int, int, int, float [I, float [I , float) ; void decsol (float ** , int, float [I, float [I ) ; float arkmui(int, int, int, float [I); float arklabda(int, int, int, int, float [I ) ; static float th1[8] = (1.0, 0.5, 1.0/6.0, 1.0/3.0, 1.0/24.0,

1.0/12.0, 0.125, 0.25); static float ecO,ecl,ec2,tauO,taul,tau2,taus,t2; int p,n, q, start, stepl, last, i, j, k, l,nl,m00; float thetanml,tau,betan,qinv,eta,*mu,*lambda,*thetha,*rO,*r,

**alfa, th[9] ,aux[4], s, ss, thetaO, tauacc, taustab, aa,bb, cc,ec,mt, lt;

p=data [21 ; ecl=ec2=0.0; betamdata [3] ; thetanml = (p == 3) ? 0.75 : 1.0; thetaO=l.O-thetanml; s=1.0; for (j=n-1; j>=l; j--) (

s = -s*thetaO+data[n+lO-j]; mu[jl=data[n+ll-jl/s; lambda [ j I =mu [ j I - theta0 ;

for (i=l; ic=8; i++) for (j=O; jc=n; j++)

if (i == 1) alfa[il [j+l]=l.O; else if (j == 0) alfa[il [j+l]=O.O; else if (i == 2 1 1 i == 4 1 1 i == 8)

alfa[i] [j+ll =pow(arkmui (j ,n,p, lambda), (i+2) /3) ; else if ((i == 3 1 1 i == 6) && j > 1) (

s=o.o; for (1=1; ls=j-1; 1++)

s += arklabda (j , l,n,p, lambda) * pow(arkmui (l,n,p,lambda) ,i/3) ;

alfa[il [j+ll =s; 1 else if (i == 5 && j > 2) {

s=o.o; for (1=2; l<=j-1; 1++) {

ss=o . 0 ; for (k=l; kc=l-1; k++)

ss += arklabda (1, k,n,p, lambda) * arkmui (k,n,p, lambda) ;

s += arklabda(j,l,n,p,lambda)*ss; 1 I

alfa [il [j+ll =s; 1

Copyright 1995 by CRC Press, Inc

Page 414: Numerical Library in C for Scientists and Engineers A

for (1=1; lc=j-1; I++) s += arklabda (j, l,n,p, lambda) *arkmui (l,n,p, lambda) ;

alfa [i] [j+ll =s*arkmui (j ,n,p, lambda) ; 1 else alfa [il [j+ll =O. 0;

nl = ((n c 4) ? n+l : ((n c 7 ) ? 4 : 8 ) ) ; for (i=l; ic=8; i++) th[il =thl [i-11 ; if (p == 3 && n c 7) th[ll =th[21=0.0; aux [21 =FLT-EPSILON; decsol (alfa,nl, aux, th) ; inivec (O,n, thetha, 0.0) ; dupvec (0,111-l,l, thetha, th) ; if (!(p == 3 &&n c 7)) {

thetha [O] -= theta0; thetha [n-11 - = thetanml; q=p+1;

) else q=3 ;

qinv=l.O/q; start= (data [El == 0.0) ; data [lo1 =O. 0; last=O; dupvec(*mO,*m, O,r,u) ; (*derivative) (mO,m, t, r) ; do I

/ * stepsize * / eta=sqrt (vecvec (*m0, *m, O,u,u) ) *data [71 +data [6] ; if (eta > 0.0) (

if (start) ( if (datak81 == 0) {

tauacc=data [51 ; stepl=l;

} else if (stepl) {

tauacc=pow (eta/ec2, qinv) ; if (tauacc > lO.O*tau2)

tauacc=lO.O*tau2; else

stepl=o; ) else {

bb= (ec2-ecl) /taul; cc = -bb*t2+ec2; ec=bb* (*t) +cc; tauacc = (ec c 0.0) ? tau2 : pow(eta/ec,qinv) ; start=O;

I

j else j aa=((ecO-ecl)/tau0+(ec2-ecl)/taul)/(taul+tau0); bb= (ec2-ecl) /taul- (2.0*t2-taul) *aa; cc = - (aa*t2+bb) *t2+ec2; ec=(aa* (*t)+bb) * (*t)+cc; tauacc = ((ec < 0.0) ? taus : pow(eta/ec,qinv)); if (tauacc > 2.0*taus) tauacc=2.0*taus; if (tauacc c taus/2.0) tauacc=taus/2.0;

) else tauacc=data [5l ;

if (tauacc c data [Sl ) tauacc=data [51 ; taustab=betan/data [41 ; if (taustab c data [5l ) {

data [lo1 =l. 0; break;

tau = ((tauacc > taustab) ? taustab : tauacc); taus=tau; if (tau >= (*te)-(*t)) {

tau= (*te) - (*t) ; last=l;

\ I

tauo=taul; taul=tau2; tau2=tau; / * difference scheme * / rnulvec(*mo, *m,O,ro,r, thetha[Ol) ;

Copyright 1995 by CRC Press, Inc

Page 415: Numerical Library in C for Scientists and Engineers A

if (p == 3) elmvec (*mO, *m, 0,u, r, 0.25*tau) ; for (i=l; ic=n-1; i++) {

mt=mu [il *tau; lt=lambda [il *tau; for (j=(*mO) ; jc=(*m) ; j++) r[jl =lt*r[jl+u[jl ; s= (*t) +mt; (*derivative) (mO,m,&s,r) ; if (thetha[il ! = 0.0) elmvec(*mO, *m, 0, ro,r, thetha[il ) ; if (i == n) {

data[91 =sqrt (vecvec(*mO, *m,O,ro,ro)) *tau; ecO=ecl; ecl=ec2; ecZ=data [9l /pow (tau, q) ;

. I 1 elmvec (*mO, *m, 0,u, r, thetanml*tau) ; dupvec (*mO, *m,O,r,u) ; s= (*t) +tau; (*derivative) (mO,m, &s, r) ; if (thetha [nl ! = 0.0) elmvec (*m0, *m, O,ro,r, thetha [nl ) ; data [91 =sqrt (vecvec (*mO, *m, 0, ro, ro) ) *tau; ecO=ecl; ecl=ecZ; ec2=data 191 /pow(tau, q) ; t2= (*t) ; if (last) (

last=O; (*t) = (*te) ;

) else (*t) += tau;

data[81 += 1.0; (*out) (mO,m, t, te,u, data) ;

) while ((*t) ! = (*te)); free-real-vector(mu,l); free-real-vector (lambda, 1) ; free-real-vector (thetha, 0) ; free~real~vector(ro,mOO); free-real-vector(r,mOO); free-real-matrix(alfa, 1,8,l) ;

I float arkmui(int i, int n, int p, float lambda[])

/ * this function is internally used by ARK * /

return ( (i==n) ? 1.0 : ( (icl 1 1 i>n) ? 0.0 : ((pc3) ? lambda[i] : ((p==3) ? lambda[il+0.25 : 0.0))));

I float arklabda(int i, int j, int n, int p, float lambda[]) I

/ * this function is internally used by ARK * /

float arkmui (int, int, int, float [ I ) ;

return ( (pc3) ? ( (j==i-1) ? arkmui (i,n,p, lambda) : 0.0) : ((p==3) ? ((i==n) ? ((j==O) ? 0.25 : ((j==n-1) ? 0.75 : 0.0)) : ((j==O) ? ((i==l) ? arkmui(l,n,p,lambda) : 0.25) : ((j==i-1) ? lambda[il : 0.0))) : 0.0)) ;

I. efrk

Solves an initial value problem for a system of first order ordinary differential equations by means of an exponentially fitted explicit Runge-Kutta method of first, second or third order. efrk is a special purpose procedure for stiff equations with a known, clustered eigenvalue spectrum; automatic error control is not provided. A detailed description of the method is given in [De72], see also [BeDHKW73, BeDHV74, DekHH721.

Copyright 1995 by CRC Press, Inc

Page 416: Numerical Library in C for Scientists and Engineers A

efrk solves the system of differential equations Dui(t) = J(t,u(t)) i=mO,mO+l, ..., m (1)

where D d d t , with u(tJ given, from t = to to t = te. Consider the N-th order Runge-Kutta scheme

where h, = t,,,-t,. For the purposes of theoretical investigation, we work in a space whose coordinates are numbered mO,mO+l, ..., m, and it is assumed that, f being a suitable differentiable function, u("+'j given by formula ( 2 ) may be expressed as the sum of a power series in the variable h,, with coefficients involving the derivatives of ufnj:

U(n+l j = u(nj + J,(Ddnl)hn + J,(D2ufnl) h: + J3P)D2dn)h,' + %J,,,(D~U(~~-~)D~U(~~)~,' +... ( 3 ) where Pj is the (m-mO+l)x(m-mO+I) Jacobian matrix whose elements are aJ;(t,,u("j(t))/aui(n)(t) (i,j=mO,mO+l, ..., m). Expanding each of the p) in ( 2 ) in ascending powers of h,, it is found that the Bj, pj and hij of ( 2 ) and the Bj and Bij of ( 3 ) are connected by the system of relationships

By imposing appropriate conditions upon the Ri and Rij, the €Ij, pj and hij are determined, and the Runge-Kutta scheme ( 2 ) is established.

One type of condition concerns the extent of agreement between the series (3) and the Taylor series expansion of u(tn+h J in ascending powers of h,, given that u satisfies equation ( 1 ) . If such agreement is to persist up to and including the terms in h,' (the scheme ( 2 ) is

Copyright 1995 by CRC Press, Inc

Page 417: Numerical Library in C for Scientists and Engineers A

then said to be r-th order exact) the fii and Bij must have the following values r J3I J32 J33 J 3 3 , 1 8 4 J 4 , 1 J 4 , 2 J 3 4 , 3

1 1 2 1 112 3 1 112 116 113 4 1 112 116 113 1/24 1/12 118 114

A further type of condition concerns stability. Let u'("") be the vector produced by means of the scheme (2) from the vector u'ln), and u'"") similarly from u'("), where e(") = y'(") - y 4 7 ) is ~h~~ '(n+U - y'(n+U = (h p"')e'"' + 0 eW 2

N n ( ) as e"') + 0, where pN(z) = I + J3,z + J$ + ... + JNZ'" . The scheme (2) is stable if lpN(hn6) I 5 1 for all eigenvalues 6 of p) in the closed left half- plane Real(6) 1 0.

If all of the above 6 are very small, a relatively large stepsize hn may be taken without violating the above stability condition. For the treatment of such differential equations, it is appropriate to choose the Bi and Bij, and by implication the Oj, pj and hij in (2) so as to ensure r-th order exactness for the highest possible value of r. If the above 6 are not small (this phenomenon accompanies stiff equations and many systems arising from the numerical solution of partial differential equations) it is wiser to sacrifice a certain degree of exactness in order to obtain stability. One works with a stability polynomial whose first few coefficients 13, are fixed (thus ensuring a certain degree of exactness) and determines the remaining coefficients Bi in such a way that the stability condition lpN(hn6) I 5 1 is satisfied for the largest possible stepsize hn.

The problem of determining the coefficients Ri which satisfy the above criteria has been successfully resolved, by a process of exponential fitting, in two cases. The two cluster case in which, during an integration step, the above 6 are to be found in two circles, one with center at the origin, and the other with center z, upon the negative real axis, and the three- cluster case in which three circles at the origin and z, and the conjugate of z, in the left-half plane, are concerned.

For certain systems of differential equations of the form (I), the Jacobian matrix J"') (and hence its distribution of eigenvalues) does not vary greatly over the range of integration; it is then possible to prescribe at outset a center z, and the diameter of a circle with center at z, (or two centers z, and conjugate(z,), and equal diameters of two circles) for which, over the entire range of integration, the above 6 remain within the circle in question. For other examples, new estimates of z, and the diameter must be determined at the commencement of each integration step, and a new Runge-Kutta scheme must be constructed (efrk carries this construction out). efrk caters for both cases.

Equation (1) may refer to a system in which the initial and final indices (mo and m) are fixed over the range of integration. It is, however, possible that these indices should vary during the course of the computation. (An example in which this occurs (it concerns the numerical solution of a partial differential equation) is given to illustrate the use of the procedure ark.) In such a case, the procedure which evaluates the derivatives (1) must also modify mO and m in a suitable manner.

When supplied with appropriate data: (i) the values of the fixed first r coefficients Bi, i=l, ..., r, of the stability polynomial pN(z)

(these may be extracted from the above table); (ii) the degree of exponential fitting: if z, is negative real, I, the number supplied, is the

degree of exponential fitting; if imag(z,)#O, I is twice this degree (and must therefore be even; in both cases r+l is the total number of evaluations of the set of$ in (1));

(iii) the value of z, in the form z, = ad8, where z, is the center of a circular region

Copyright 1995 by CRC Press, Inc

Page 418: Numerical Library in C for Scientists and Engineers A

containing a cluster of eigenvalues 6 of the Jacobian matrix Jrn) as described above during the first integration step (this is step below);

(iv) the diameter of the above circular region; (v) the value of an integer variable thirdorder: the value of thirdorder is nonzero if the user

requires a third order exact polynomial p,(z) to be used (in this case, the supplied value of r must be 2 3 and the appropriate coefficients Di, i=0,1,2,3, must be supplied), and thirdorder is zero otherwise;

(vi) an upper bound to1 for the rounding errors in the computations of one Runge-Kutta step;

(vii) an upper bound step for the stepsize (the stepsize actually used during the computations may be reduced by stability constraints);

(viii) tO and te, the initial and final values o f t ; (ix) mO and m, the indices of the first and last equations in the set (2) holding when

t=tO; (x) the initial values u,(tO) (i=mO,mO+ l,...,m); efrk constructs an appropriate Runge-Kutta scheme of the form (3) at the commencement of the first integration step and integrates the system (I), either retaining the constructed scheme throughout, or constructing a new scheme if the estimates of z, and the diameter supplied during the course of the computation change sufficiently.

The user is also asked to provide a function output which is called by efrk at the conclusion of each integration step. output is intended partly as a monitoring device, and may also be used to change the values of o and 4 in the representation z, = uei+ and of the diameter of the circle with center z , enclosing a cluster of eigenvalues during the computation.

Function Parameters: void efik (t,te,mO,m, u,sigma,phi,diameter,derivative, k,step,r, 1, beta,thirdorder,tol, output)

t: float *; the independent variable t of the systems of ordinary differential equations

dddt = f(t,u); entry: the initial value to; exit: the final value te;

te: float; entry: the final value o f t (te 2 t);

m0,m: int; indices of the first and last equation of the system;

u: float u[mO:m]; the dependent variable; entry: the initial values of the solution of the system of differential equations at t=tO; exit: the values of the solution at t = te;

sigma: float *; entry: the modulus of the point at which exponential fitting is desired (the value of

o above); for example an approximation of the center of the left hand cluster; exit: value of 5 for the last step;

phi: float *; entry: the argument of the center of the left hand cluster (the value of 4 above); in

the case of two complex conjugated clusters, the argument of the center in the second quadrant should be taken;

exit: value of 4 for the last step; diameter: float *;

Copyright 1995 by CRC Press, Inc

Page 419: Numerical Library in C for Scientists and Engineers A

entry: the diameter of the left hand cluster of eigenvalues of the Jacobian matrix of the system of differential equations; in case of non-linear equations diameter should have such a value that the variation of the eigenvalues in this cluster in the period (t, t+step) is less than half the diameter;

exit: value of the diameter for the last step; derivative: void (*derivative)(mO, m,t, u);

this procedure should deliver the value of f(t,u) in the point (t,u) in the array u; k: int*;

counts the number of integration steps taken; entry: an (arbitrarily) chosen value of kO, e.g. kO = 0; exit: kO + the number of integration steps performed;

step: float *; the stepsize chosen will be at most equal to step; this stepsize may be reduced by stability constraints, imposed by a positive diameter, or by considerations of internal stability;

r: float; entry: the degree of exactness of the Runge-Kutta scheme to be employed (value of

r above); r+l is the number of evaluations of f(t,u) on which the Runge-Kutta scheme is based; for r=1,2,23, first, second and third order accuracy may be obtained by an appropriate choice of the array beta;

I: float; entry: if phi=4*tan"(l) then I is the order of the exponential fitting, otherwise I is

twice the order of the exponential fitting; note that I should be even in the latter case;

beta: float beta[O:r+l]; entry: the elements betari], i=O, ..., r, should have the value of the r+l first coefficients

of the stability polynomial; thirdorder: int;

entry: if third order accuracy is desired then thirdorder should have the value nonzero, in combination with appropriate choices of r (r 2 3) and the array beta (beta[i]=lli!, i=0,1,2,3); in all other cases thirdorder must have the value zero;

tol: float; entry: an upper bound for the rounding errors in the computations in one Runge-

Kutta step; in some cases (e.g. large values of sigma and r) to1 will cause a decrease of the stepsize;

output: void (*output)(mO,m,t,te,u,sigma,phi,diameter,k,step,r,~; this procedure is called at the end of each integration step; the user can ask for output of some parameters, for example t, k, u, r, I and compute new values for sigma, phi, diameter and step.

Functions used: elmvec, dec, sol.

void efrk(f1oat *t, float te, int mO, int m, float u[l, float *sigma, float *phi, float *diameter, void (*derivative) (int, int, float, float [ I ) , int *k, float *step, float r, float 1, float betatl, int thirdorder, float tol, void (*output) (int, int, float, float,

Copyright 1995 by CRC Press, Inc

Page 420: Numerical Library in C for Scientists and Engineers A

float [ I , float * , float *, float *, int, float *, int, int) )

int *allocate-integer-vector (int, int) ; float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int *, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat ** , int, int, int) ; void elmvec(int, int, int, float [I, float [I, float) ; void sol (float **, int, int [I, float [I ) ; void dec(f1oat ** , int, float [ I , int [I ) ; int n,first,last,complex,change,*p,i,j,cl,c3; float theta0,thetanml,h,b,bO,phiO,phil,cosphi,sinphi,eps,

betar, *mu, *labda, *pt, *fac, *betac, *rl, **a, aux141 , dd,hstab,hstabint,c,temp,c2,e,bl,zi,cosiphi,siniphi, cosphil, *d,bb,mt, lt, tht;

p=allocate integer vector (1,l) ; mu=allocat<real~v~ctor(0,r+l-1); labda=allocate-real-vector(O,r+l-1); pt=allocate-real-vector(0,r); fac=allocate-real-vector(0,l-1); betac=allocate-real-vector(0,l-1); rl=allocate-real-vector(m0,m); d=allocate-real-vector(1,l); a=allocate-real-matrix (1, 1, 1, 1) ;

n=r+l; first=l; bO = -1.0; betar=pow (beta [rl ,l. O/r) ; last=O; eps=FLT-EPSILON; phiO=phil=4 .O*atan(l. 0) ; do I

/ * stepsize * / h= (*step) ; dd=fabs ( (*sigma) *sin (*phi) ; complex=( ((1/2) * 2 == 1) && 2.0*dd > *diameter) ; if (*diameter > 0.0) {

temp= (*sigma) * (*sigma) / ( (*diameter) * ( (*diameter) *O .25+dd) ) ; hstab=pow (temp, l*O.S/r) /betar/ (*sigma) ;

) else hstab=h;

dd = (thirdorder ? pow(2 .O*tol/eps/beta [rl ,l. O/ (n-1) ) * pow(4.0, (1-1.0) / (n-1.0)) : pow(tol/eps, (l.O/r) /betar)) ;

hstabint=fabs (dd/ (*sigma) ) ; if (h > hstab) h=hstab; if (h > hstabint) h=hstabint; if ( (*t) +h > te* (1.0- (*k) *eps) ) {

last=l; h=te- (*t) ;

b=h* (*sigma) ; dd= (*diameter) *O. l*h; dd *= dd; if (h < (*t) *eps) break; change=((bO == -1.0) I

( (b-bo) * (b-b0) +b*bO* ( (*phi) -phi0) * ( (*phi 0 > dd) ) ; if (change) {

/ * coefficient * / bO=b; phiO= (*phi) ; if (b >= 1.0) {

if (complex) { / * solution of complex equations * / if (phi0 ! = phil) {

/ * elements of matrix * / phil=phiO ; cosphi=cos (phil ; sinphizsin (phil) ; cosiphi=l.O; siniphi=O.O;

Copyright 1995 by CRC Press, Inc

Page 421: Numerical Library in C for Scientists and Engineers A

for (i=O; i<=l-1; i++) { cl=r+l+i ; c2=1.0 ; for (j=l-1; j>=l; j-=2) {

a [j] [1-il =c2*cosiphi; a [j+l] [1-i] =c2*siniphi; c2 *= c1;

1

cosphil=cosiphi*cosphi-siniphi*sinphi; siniphi=cosiphi*sinphi+siniphi*cosphi; cosiphi=cosphil;

1 aux[2]=0.0; dec(a,l,aux,p);

1 / * right hand side * / e=exp (b*cosphi) ; bl=b*sinphi- (r+l) *phil; cosiphi=e*cos (bl) ; siniphi=e*sin (bl) ; bl=l. O/b; zi=pow (bl, r) ; for (j=l; j>=2; j-=2) (

d[j] =zi*siniphi; d [j-11 =zi*cosiphi; cosphil=cosiphi*cosphi-siniphi*sinphi; siniphi=cosiphi*sinphi+siniphi*cosphi; cosiphi=cosphil; zi *= b;

I I cosiphi=zi=l.O; siniphi=O.O; for (i=r; i>=O; i--) {

cl=i; c2=beta [il ; c3=( (2*i > 1-21 ? 2 : 1-2*i) ; cosphil=cosiphi*cosphi-siniphi*sinphi; siniphi=cosiphi*sinphi+siniphi*cosphi; cosiphi=cosphil; for (j=l; j>=c3; j-=2) {

d [j] += zi*c2*siniphi; d[j-11 -= zi*c2*cosiphi; C2 * = a ; C1--;

} zi *= bl;

\ $01 (a,l,p,d) ; for (i=l; i<=l; i++) beta[r+il =d[l+l-il *b1;

} else ( /* form beta * / if (first) {

/ * form constants * / f irst=O; fac[01=1.0; for (i=l; i<=l-1; i++) fac [il =i*fac [i-11 ; pt [rl =l*fac [l-11 ; for (i=l; i<=r; i++) ~t [r-i] =pt [r-i+ll* (l+i) /i;

1

i f (1 == 1) ( c=l.O-exp(-b) ; for (j=l; j<=r; j++) c=beta [jl -c/b; beta [r+ll =c/b;

) else if (b > 40.0)

for (i=r+l; i<=r+l; i++) { c=o.o; for (j=O; j<=r; j++)

c=beta[jl*pt[jl/(i-j)-c/b; beta [i] =c/b/fac [l+r-il /fac [i-r-11 ;

1 else (

dd=c=exp (-b) ;

Copyright 1995 by CRC Press, Inc

Page 422: Numerical Library in C for Scientists and Engineers A

betac [l-11 =dd/fac 11-11 ; for (i=l; ic=l-1; i++) {

c=b*c/i; dd += c; betac [l-1-il =dd/fac [l-1-il ;

1 bb=l . 0 ; for (i=r+l; i<=r+l; i++) {

for (j=O; j<=r; j++) c=(beta[j]-((j < 1) ? betac[jl : 0.0))*

pt [jl /(i-j) -c/b; beta [i] =c/b/fac [l+r-il /fac [i-r-ll+

((i < 1) ? bb*betac[il : 0.0) ;

J

1 labda [O] =mu [O] =O. 0; if (thirdorder) {

theta0=0.25; thetanml=0.75; if (b c 1.0) {

c=mu [n-1]=2.0/3.0; labda [n-ll=5.0/12 .O; for (j=n-2; j>=l; j--1 {

c=mu[j]=c/ (c-0.25) / (n-j+l) ; labda[jl=c-0.25;

1 } else {

c=mu [n-11 =beta [21*4.0/3.0; labda [n-11 =c-0.25; for (j=n-2; j>=l; j--) {

c=mu [j] =c/ (c-0.25)*beta[n-j+ll /beta[n-jl/ ((j < 1) ? b : 1.0);

labda[jl=c-0.25;

} else { theta0=0.0; thetanml=l.O; if (b < 1.0)

for (j=n-1; j>=l; j--) mu[jI=labda[jl=l.O/(n-j+l); else {

labda [n-11 =mu [n-11 =beta [21 ; for (j=n-2; j>=l; j--)

mu [j] =labda [j I =beta In- j+ll /beta [n- j I / ((1 < 1) ? b : 1.0);

1 i

1 (*k) ++; /* difference scheme * / i = -1; do I

i++; mt=mu [il *h; lt=labda [il *h; for (j=mO; jc=m; j++) rl[jl=u[jl+lt*rl[jl ; (*derivative) (mO,m, (*t)+mt,rl) ; if (i == 0 ) ) i == n-1) {

tht= ( (i == 0) ? thetaO*h : thetanml*h) ; elmvec (mO,m, 0,u, rl, tht) ;

I } while (i < n-1); (*t) += h; (*output) (mO,m,*t,te,u,sigma,phi,diameter,*k,step,r,l);

} while ( ! last) ; free-integer-vector(p,l); f ree-real-vector (mu, 0) ; free-real-vector (labda, 0) ; free-real-vector (pt, 0) ; f ree-real-vector (fac, 0) ;

Copyright 1995 by CRC Press, Inc

Page 423: Numerical Library in C for Scientists and Engineers A

free-real-vector (betac, 0 ) ; f ree-real-vector (rl, mO) ; free-real-vector (d, 1) ; free-real-matrix(a, l,l, 1) ;

1

5.4.2 First Order - Jacobian matrix available

A. efsirk

Solves an initial value problem, given as an autonomous system of first order differential equations

Dy(x) = f b ) (1) where D = d/dx andJy, E Rm, with y(x,) prescribed, over the interval xO 5 x 5 xe by means of an exponentially fitted, A-stable, semi-implicit Runge-Kutta method of third order [BeDHKW73, BeDHV74, Vh721. This procedure is suitable for the integration of stiff equations. The algorithm uses for each step two function evaluations and if the input parameter linear is zero one evaluation of the Jacobian matrix. The stepsize is not determined by the accuracy of the numerical solution, but by the amount by which the given differential equation differs from a linear equation. The procedure does not reject integration steps.

The method used has the form yn+l = yn + (1/4)hkf,(yJ + (314)hIbn + A/,?)(hnJJhnff,(yJ) (2)

where 3'' = x,, + h,, and with y, = y(x,J, J, = afbJ/ayn,

The stability function for the above method is

and the parameter a,(") in A,,'"'(z) is determined by use of the relationship

where 6, is the eigenvalue of J, in the left half plane with largest absolute value, so that

where z, = hn6,. The right hand side vector in equation (1) is computed by means of a user supplied

Copyright 1995 by CRC Press, Inc

Page 424: Numerical Library in C for Scientists and Engineers A

function derivative. The Jacobian matrix J , is computed by another user supplied function jacobian. If the variable linear in the parameter list is given the value nonzero upon call then jacobian is called upon when n=O in formula ( 2 ) and not otherwise; if linear has the value zero then jacobian is called at the commencement of each step of the integration method. When linear has the value zero upon call, the stepsize h,, is determined as follows by use of a second method alternative to (2) for the numerical solution of equations (1). This method produces approximations y', to y(xJ and has the form

Y 'n+/ = ~n + vo(nlhJiJ + vlP')hfin + A/,o(hJJhlfO) +

v2'"'A/,o(hn J J h f i J + v3'"'hfin+3. (3 When

the stability function of the method (3), namely 1 0 1.0 01) R(z) R1(z) = 1 + v,b!'z + v1(")z(l + A , (z)) + v,")A (z)z + v, z

is R(z) above. If yn+, and y',,, were to be determined by use of the schemes (2) and (3) respectively with step length h ',, in both cases, then, since the method (3) is second order exact, Ily',,+l - yn+/ (1 = c,h';, where cn is independent of the variable h',. If c,, = c,,, an optimal steplength h ',, may be determined by use of the relationships

h ',, = (tol/~J''~ = ( t ~ l / c , J ~ / ~ = hn-l(tol/ 11 y ',,-y,, or, approximately,

h ',, = ( (4/3)tol / (to1 + 11 y I,,-yn 11) + 1/3) hn-/ (4) where to1 is an acceptable local tolerance (taken by efsirk to be to1 = II, + v, 11 yll 1 1 , where % and rl, are absolute and relative tolerances prescribed by the user). Thus yJn is determined by use of formula (4). With two limits hmin and hmax prescribed by the user, h, is taken to be h ',, if hmin 5 h ',, 5 hmax, to be hmin if h ',,<hmin, and to be hmax if hl,>hmax.

When linear has the value nonzero upon call, a constant value h,, = h,, is used in formula (2), and the reference values y',, are not determined.

Function Parameters: void efsirk (x,xe,m,y,delta,derivative,jacobian~,n,aeta,reta,hmin,hmax,linear,output)

x: float *; entry: the independent variable; the initial value xO; exit: the final value xe;

xe: float; entry: the final value of x;

m: int; entry: the number of differential equations;

y: float y[l:m]; the dependent variable; during the integration process the computed solution at the point x is associated with the array y; entry: the initial values of the solution of the system; exit: the final values of the solution;

Copyright 1995 by CRC Press, Inc

Page 425: Numerical Library in C for Scientists and Engineers A

delta: float *; delta denotes the real part of the point at which exponential fitting is desired;

alternatives: delta= (an estimate of) the real part of the, in absolute value, largest eigenvalue of the

Jacobian matrix of the system; delta< -lot4, in order to obtain asymptotic stability; delta= 0, in order to obtain a higher order of accuracy in case of linear or almost

linear equations; derivative: void (*derivative)(m,a,deIta);

in efsirk when derivative is called a[i] contains the values of y[i]; upon completion of a call of derivative, the array a should contain the values of f(yl; note that the variable x should not be used in derivative because the differential equation is supposed to be autonomous;

jacobian: void (*jacobian)(rn,j,y,deIta); in efsirk when jacobian is called the array y contains the values of the dependent variable; upon completion of a call of jacobian, the array j should contain the values of the Jacobian matrix of f(yl;

j : float j[l:m, 1 :m]; j is an auxiliary array which is used in the procedure jacobian;

n: int *; counts the integration steps;

aeta,reta: float; entry: required absolute and relative local accuracy;

hmin, hmax: float; entry: minimal and maximal stepsize by which the integration is performed;

linear: int; entry: if linear is nonzero then the procedure jacobian will only be called if n = 1;

the integration will then be performed with a stepsize hmax; the corresponding reduction of computing time can be exploited in case of linear or almost linear equations;

output: void (*output)(x,xe,m,y,delta,j,n); the user can ask for output of parameters.

Functions used: vecvec, matvec, matmat, gsselm, solelm.

void efsirk(f1oat *x, float xe, int m, float y [ l , float *delta, void (*derivative) (int, float [ I , float *) , void (*jacobian) (int, float **, float [ I , float * ) , float **j , int *n, float aeta, float reta, float hmin, float hmax, int linear, void (*output) (float, float, int, float [ I ,

float, float **, int)) I ' int *allocate-integer-vector(int, int);

float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void f ree-integer-vector (int *, int) ; void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int) ; float vecvec (int, int, int, float [ I , float [ I ) ; float matmat (int, int, int, int, float ** , float **) ;

Copyright 1995 by CRC Press, Inc

Page 426: Numerical Library in C for Scientists and Engineers A

float matvec(int, int, int, float ** , float [I ) ; void gsselm(f1oat **, int, float [I, int [I, int [I ) ; void solelm(£ loat **, int, int [I , int [I , float [I ) ; int k,l,lin,*ri,*ci; float s t e p , h , m u O , m u l , m u 2 , t h e t a 0 , t h e t a l , ~ ~ l , ~ ~ 2 , ~ ~ 3 , ~ k ~ f k ~ ~ l , ~ 2 ~

d,*f,*k0,*labda.**jl,aux[8l,discr,eta,s,zl,z2,e,alphal,a,b;

aux [2] =FLT-EPSILON; aux[4]=8.0; for (k=l; k<=m; k++) f [kl =y [kl ; *n = 0; (*output) (*x,xe,m, y, *delta, j, *n) ; ::e?=O. 0 ;

(*n) ++; /* difference scheme * / (*derivative) (m, f, delta) ; /* step size * / if (linear)

s=h=hmax; else

if (*n == 1 1 hmin == hmax) s=h=hmin;

else { eta=aeta+reta*sqrt (vecvec (l,m, 0, y, y) ) ; cl=nu3*step; for (k=l; k<=m; k++) labda[kl += cl*f [kl-ylkl; discr=sqrt (vecvec (1, m, 0, labda, labda) ) ; s=h= (eta/ (0.75* (eta+discr) ) +O. 33) *h; if (h < hmin)

s=h=hmin; else

if (h > hmax) s=h=hmax; 1

if ('(*x) +s > xe) s=xe- (*x) ; lin= ( (step == s) && linear) ; step=s; if ( !linear / *n == 1) (*jacobian) (m, j , y,delta) ; if (!lin) {

/ * coefficient */ zl=step* (*delta) ; if (*n == 1) 22=zl+zl; if (fabs(z2-zl) > l.0e-6*fabs(zl) 1 1 22 -1.0) {

a=zl*zl+l2.0; b=6.0*~1; if (fabs(z1) < 0.1)

alphal=(zl*zl/l40.0-1.0)*z1/30.0; else if (zl < 1.0e-14)

alphal=1.0/3.0; else if (zl < -33.0)

alphal= (a+b) / (3.0*zl* (2.0+21) ) ; else {

e=((zl c 230.0) ? exp(z1) : FLT MAX); alphal= ((a-b) *e-a-b)/( ((2.0-zl)~e-2.0-zl)*3.0*~1) ;

1

Copyright 1995 by CRC Press, Inc

Page 427: Numerical Library in C for Scientists and Engineers A

cl=step*mul; d=step*step*mu2; for (k=l; kc=m; k++) (

for (1=1: lc=m; I++)

61=step*step*mu0; d=step*2.0/3.0; for (k=l; kc=m; k++) (

k0 [kl =fk=f [kl ; labda [k] =d*fk+cl*matvec (l,m, k, j , f) ;

1 solelm (j 1, m, ri, ci, labda) ; for (k=l; k<=m; k++) f [kl =y [kl +labda [kl ; (*derivative) (m, f, delta) ; cl=thetaO*step; c2=thetal*step; d=nul*step; for (k=l; k<=m; k++) {

yk=y [kl ; fk=f [kl ; labda [k] =yk+d*fk+nu2*labda [kl ; y [k] =f [kl =yk+cl*kO [kl +c2*fk;

1 I*x) += step; (*output) (*x,xe,m,y, *delta, j, *n) ;

) while (*x < xe) ; free-integer-vector(ri,l); free-integer-vector(ci,l) ; free-real-vector(f,l); free-real-vector(k0,l); free-real-vector(labda,l); free-real-matrix( jl, l,m, 1) ;

1

B. eferk

Solves an initial value problem, given as an autonomous system of first order differential equations

DY&) = f(yl (1) where D = d d j , andf;y, E Rm, with y(xo) prescribed, over the interval xO I x 5 xe by means of an exponentially fitted, semi-implicit Runge-Kutta method of third order [BeDHKW73, BeDHV74, DekHH72, Vh721. This procedure is suitable for the integration of stiff differential equations. The algorithm uses for each step two function evaluations and if the input parameter linear is zero one evaluation of the Jacobian matrix. The stepsize is determined by an estimation of the local truncation error based on the residual function. Integration steps are not rejected.

The method used is one of a class having the form Yn+l = Yn + 90fz)hrLbJ + 8Lz)hfbn + A~,ofz)kf@J)

where, with 2"' = xn + h, y,, = y(xJ and z = hnJn where Jn = af@J/ayn, 8 , 8, and A , , being polynomials. Such a method is first order exact if 8,(0) + 8,(0) = I , second order exact if also 8, '(0) + 8',(0) + B,(O)A,,,(O) = 1/2, and third order consistent if also

BOf1(O) + 8, "(0) + 28,(0)A,,o '(0) + 28, '(O)A,,,(O) = 113 and

B,(O)A,,~(O) = 1/3. The choice flo(z) = 1/4, B,(z) = 3/4 is made and the method used by eferk has the form The stability function for this method is with p = 3. The Rj may be determined by exponential fitting of order r, at the s points zj

Copyright 1995 by CRC Press, Inc

Page 428: Numerical Library in C for Scientists and Engineers A

(j=l, ..., s), so that

where

Approximately

That part of the stability region (i.e. the domain over which I R,(z) 1 I 1 ) in the neighbourhood of z, is a small circle with z, as center and radius pj where

Copyright 1995 by CRC Press, Inc

Page 429: Numerical Library in C for Scientists and Engineers A

If exponential fitting takes place at one point z, alone Po = lz, 1 Ip!zo' 1 "(m-p).

If fitting takes place at two complex conjugate points z, and conjugate(z,), with arg(A,) =

tJ po = 1 Z, 1 I (p!ziP)/2sin 4 1 2'(m-p).

Since these stability regions are small, it is necessary to determine z, precisely. Furthermore the regions prescribe a maximal step length h,,a, for stability: if d6, is the distance between the smallest eigenvalue of Jn and the point of fitting 6, then, when p = 3,

The step-choice strategy is based upon the following considerations. If y,+,(h) is the value of the solution to equation (1) at x = x, + h with initial values y,+,(O) = y, produced by use of the scheme (2) , and t,(h) = &,+,(h)/dh - f(y,+,(h)) then h, 11 t,(h) 11 is a good estimate of the local error 11 y(xn+h) - y,+,(h) 11, and p, '(h) = h I R(Wn)f(yJ - f(y,+J 1 is a good estimate of h, 11 4,(h) 11. With h,, to1 = II, + ~l, 11 yn 11, (where II, and I& are absolute and relative tolerances prescribed by the user) and p,'(h,) available, the quantity

with j=O for nonlinear equations, and j=l for approximately linear equations, is determined. With two limits hmin and hmax prescribed by the user, the steplength h,+, is taken to be h,,, ' if hmin I h,,+, ' 5 hmax; if h,,,,' lies outside this range, h,+, is hmax if h,,,, ' > hmax and hmin if h,+,'<hmin.

It can occur that the system of equations (1) is derived from the system Dy(x)=g(x,y) with y(x,) = yo, where y, g E Rm-I, simply by taking the first m-1 components of y in (1) to be those of y, and the m-th component of y to be x. In this case, the m-th component off in (1) is always 1, and certain simplifications in the formulae can be exploited. If it is known that equations (1) have been derived in the above manner then the variable aut in the parameter list of eferk should be given the value zero upon call, otherwise nonzero.

Function Parameters: void eferk

(x,xe, m,y,sigma,phi,derivative,j,jacobian, k, I,aut, aeta,reta, hmin, hmax, linear, output) x: float *;

entry: the independent variable; the initial value xO; exit: the final value xe;

xe: float; entry: the final value of x (xe 2 x);

m: int;

Copyright 1995 by CRC Press, Inc

Page 430: Numerical Library in C for Scientists and Engineers A

entry: the number of equations; y: float y[l:m];

the dependent variable; entry: the initial values of the system of differential equations: y[i] at x=xO; exit: the final values of the solution: y[i] at x=xe;

sigma: float *; the modulus of the point at which exponential fitting is desired, for example the largest negative eigenvalue of the Jacobian matrix of the system of differential equations;

phi: float; the argument of the complex point at which exponential fitting is desired;

derivative: void (*derivative)(m,y); this procedure should deliver the right hand side of the i-th differential equation at the point (y) as y[i];

j : float j[l:m,l:m]; the Jacobian matrix of the system; array j should be updated in the procedure jacobian;

jacobian: void (*jacobian)(m,j, y,sigma); in this procedure the Jacobian at the point (y) has to be assigned to the array j ;

k: int *; counts the integration steps taken;

I: int; entry: ifphi=4*tan"(l) then I is the order of the exponential fitting, else I is twice the

order of the exponential fitting; aut: int;

entry: if the system has been written in autonomous form by adding the equation dy[m]/dx = 1 to the system then aut may have the value zero, else aut should have the value nonzero;

aeta: float; entry: required absolute precision in the integration process, aeta has to be positive;

reta: float; entry: required relative precision in the integration process, reta has to be positive;

hmin: float; entry: the steplength chosen will be at least equal to hmin;

hmax: float; entry: the steplength chosen will be at most equal to hmax;

linear: int; entry: the procedure jacobian is called only if linear is zero or k = 0; so if the system

is linear then linear may have the value nonzero; output: void (*output)(x,xe,m,y,j, k);

this procedure is called at the end of each integration step; the user can ask for output of some parameters, for example, x, y, j, k.

Functions used: vecvec, matvec, dec, sol.

void eferk(f1oat *x, float xe, int rn, float y [ l , float *sigma, float phi, void (*derivative) (int, float [ I ) , float **j, void (*jacobian) (int, float **, float [ I , float * ) , int *k, int 1, int aut, float aeta, float reta, float hmin, float hmax, int linear,

Copyright 1995 by CRC Press, Inc

Page 431: Numerical Library in C for Scientists and Engineers A

void (*output) (float, float, int, float [I , float ** , int) )

int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int * , int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); float vecvec (int, int, int, float [ I , float [I ) ; float matvec(int, int, int, float ** , float [I ) ; void dec(f1oat ** , int, float [ I , int [I ) ; void sol (float ** , int, int [I, float [I ) ; int ml, i, change, last, *p, cl, q; float h,b,bo,phiO,cosphi,sinphi,eta,discr,fac,pi,*beta,*betha,

*betac,*kO,*d,*dl,*d2,**a,aux[4l,s,cos2phi,sina,e,zi, c2,cosiphi,siniphi,cosphil,*dd,eminl,bl,b2,aO,al,a2,a3, c, ddd, betai,bethai;

bO = phi0 = -1.0; pi=4.0*atan(l. 0) ; betac [ll =betac [l+l] =betac [l+21 =betac [l+3l =O. 0; beta [o] =l.O/6 .O; betha [OI =O. 5; fac=l.O; for (i=2; ic=l-1; i++) fac *= i; ml=(aut ? m : m-1); *k = 0; last=O; do (

for (i=l; ic=m; i++) d[il =y [il ; (*derivative) (m, d) ; if ( !linear I / *k == 0) ( * jacobian) (m, j , y, sigma) ; / * step size * / eta=aeta+reta*sqrt (vecvec (l,ml, 0, y, y) ) ; if (*k == 0) {

discr=sqrt (vecvec (l,ml, 0, d, d) ) ; h=eta/discr;

) else { s=o.o; for (i=l; ic=ml; i++) (

ddd=d [il -d2 [il ; s += ddd*ddd;

1 I discr=h*sqrt (s) /eta; h *= (linear ? 4.0/(4.0+discr)+0.5 :

4.0/ (3.0+discr) +l. O/3.O) ; 1 if (h c hmin) h=hmin; if (h > hmax) h=hmax; b=fabs (h* (*sigma) ) ; change=(fabs(l.O-b/b0) > 0.05 1 1 phi ! = phi0); if (l.l*h >= xe- (*x)) {

change=last=l; h=xe- (*x) ;

1 if (!change) h=h*bO/b; if (change) {

/ * coefficient * / bO=b=fabs (h* (*sigma) ) ; if (b >= 0.1) (

if (phi ! = pi && 1 == 2 1 1 fabs(phi-pi) > 0.01) ( / * solution of complex equations */ if (1 == 2) (

Copyright 1995 by CRC Press, Inc

Page 432: Numerical Library in C for Scientists and Engineers A

phiO=phi ; cosphi=cos (phi0) ; sinphi=sin (phi0) ; e=exp (b*cosphi) ; zi=b*sinphi-3.0*phiO; sins= ( (fabs (sinphi) c 1.0e-6) ? -e* (b+3.0) :

e*sin (zi) /sinphi) ; cos2phi=2.0*cosphi*cosphi-1.0; betha [2] = (0. 5+ (2.0*cosphi+ (1.0+2.0*cos2phi+

sina) /b) /b) /b/b; sina=((fabs(sinphi) c 1.0e-6) ? e*(b+4.0) :

sina*cosphi-e*cos(zi)); betha [l] = - (cosphi+ (1.0+2.O*cos2phi+

(4.0*cosphi*cos2phi+sina) /b) /b) /b; beta[l] =betha[2] +2.0*cosphi* (betha[ll -1.016.0) /b; betat21 =(1.0/6.0-betha [ll ) /b/b;

) else { if (phi0 ! = phi) (

/ * elements of matrix */ phiO=phi; cosphi=cos (phi01 ; sinphi=sin (phi0) ; cosiphi=l.O; siniphi=O.O; for (i=O; ic=l-1; i++) {

cl=4+i; c2=1.0; for (q=l-1; q>=l; q-=2) (

a [ql [l-il =c2*cosiphi; a [q+l] [l-i] =c2*siniphi; C2 *= c1; C1--;

1 cosphil=cosiphi*cosphi-siniphi*sinphi; siniphi=cosiphi*sinphi+siniphi*cosphi; cosiphi=cosphil;

\ aux[21=0.0; dec(a,l,aux,p) ;

1 / * right hand side * / e=exp (b*cosphi) ; zi=b*sinphi-4.O*phi0; cosiphi=e*cos (zi) ; siniphi=e*sin (zi) ; zi=l.O/b/b/b; for (q=l; q>=2; q-=2) {

dd [q] =zi*siniphi; dd [q-11 =zi*cosiphi; cosphil=cosiphi*cosphi-siniphi*sinphi; siniphi=cosiphi*sinphi+siniphi*cosphi; cosiphi=cosphil; zi *= b;

siniphi=2.O*sinphi*cosphi; cosiphi=2.0*cosphi*cosphi-1.0; cosphil=cosphi*(2.0*cosiphi-1.0); dd[l] += sinphi* (1.0/6.0+(cosphi+(l.0+2 .O*

cosiphi* (1.0+2. o*cosphi/b) ) /b) !b) ; dd [l-11 -= cosphi/6.0+ (0 .5*cosiphi+ (cosphil+

(2. ~*cosiphi*cosiphi-1.0) /b) /b) /b; dd[l-21 += sinphi* (0. 5+(2 .O*cosphi+

(2.0*cosiphi+l. 0) /b) /b) ; dd [l-31 -= 0.5*cosphi- (cosiphi+cosphil/b) /b; if (1 >= 5) (

dd [l-41 += sinphi+siniphi/b; dd [l-51 -= cosphi+cosiphi/b; if (1 >= 7) (

dd[l-61 += sinphi; dd[l-71 - = cosphi;

Copyright 1995 by CRC Press, Inc

Page 433: Numerical Library in C for Scientists and Engineers A

for (i=l; ic=l; i++) { beta [il =dd [l+l-il *zi; betha [il = (i+3) *beta [il ; zi /= b;

1

' / * £orm beta * / if (1 == 1) {

betha[ll=(0.5- (1.0- (1.0-exp(-b) )/b)/b)/b; beta [ll = (1.0/6.0-betha [ll ) /b;

) else if (1 == 2) 1 e=exp (-b) ; eminl=e-1.0; betha [ll = (1.0- (3.0+e+4.0*eminl/b) /b) /b; betha [21= (0.5- (2.0+e+3.0*eminl/b) /b) /b/b; beta [2] = (1.0/6.0-betha [ll ) /b/b; beta [ll = (l.0/3.O- (1.5- (4.0+e+5.0*eminl/b) /b) /b) /b;

) else { betac [l-11 =c=ddd=exp (-b) /fac; for 1 - 1 ; 1 ; i - {

c=i*b*c/ (1-i) ; betac [i-11 =ddd=ddd*i+c;

1

. . . . . ddd=l /b ; for (i=l; ic=l; i++) {

beta [il = (a3/i-a2/ (i+l) +al/ (i+2) -aO/ (i+3) ) *ddd+ betac [i+31 ;

betha [il = (b2/i-bl/ (i+l) +b0/ (i+2) ) *ddd+ betac [i+21 ;

ddd=ddd* (1-i) /i/b;

) el'se for (i=l; i<=l; i++) {

betha [il =beta [i-11 ; beta [il =beta [i-ll / (i+3) ;

1 J

(*output) (*x,xe,m,y, j,*k) ; / * difference scheme * / if (ml c m) {

d2 [ml =1.0; kO [m] =y [m] +2.O*h/3.0 ; y[m] += 0.25*h;

(*derivative) (m, k0) ; for (q=l; q<=m; q++) y[ql += 0.7S*h*kO lql ; (*k) ++; (*x) += h;

Copyright 1995 by CRC Press, Inc

Page 434: Numerical Library in C for Scientists and Engineers A

} while ( !last) ; (*output) (*x,xe,rn,y,j ,*k) ; free-integer-vector(p,l); free-real-vector (beta, 0) ; free-real-vector(betha,O); free-real-vector(betac,O) ; f ree-real-vector (k0,l) ; free-real-vector (d, 1) ; f ree-real-vector (dl, 1) ; free-real-vector (d2,l) ; free-real-vector (dd, 1) ; free-real-rnatrix(a, l,l, 1) ;

I

C. linigerlvs

Solves an initial value problem, given as an autonomous system of first order differential equations

DYW = f b ) (1) where D = d/du andJy, E Rm, with y(x,) prescribed, over the interval xO 4 x 4 xe by means of an implicit, first order accurate, exponentially fitted one-step method. Automatic stepsize control is provided. This procedure is suitable for the integration of stiff differential equations. The algorithm is based on [LiW70]. The stepsize strategy requires many extra array operations. The user may avoid this extra work by giving the parameters aeta and reta a negative value and prescribing a stepsize hmax.

The method used has the form ~ n + / = ~n + h ( P A + (1 (I (2)

where, with x" = x, + nh (n=0,1, ... ), yn = y(x J and f, = f b J . Equation (1) may be written as

D y = f , + J n b - Y J +. . . Jn being the Jacobian matrix af@J/ayn. The linearized version of (1) is thus Dy' = f(yy where f b ') =f,-Jan+Ja '. The exact solution of the linearized equation with y '(x J =yn is

Y'(x) = Yn - (x - xJ e2 (Jn6 - xJ)f, where e2(z) = (ez-l)/z so that yn+,' = yn - he2(hJJf,. With y," a computed value ofy, (i.e. of yn ') the scheme (2) yields

(I - ( l -pJhJJ~n+/" = (I + pnhJJynV + ~ K - J ~ Y J . Thus

~ n + / " - ~ n + / ' = Rn(hJJkv - ~n Y + h(Rn(2)(hJJ - e,(hJJ)f, (3 where Rn is the stability function

Rn(4 = (1 + P,?.) 1 (1 - P-PJz) and Rn(')(z) = (Rn(z) - I)/z. If all eigenvalues of Jn not in the neighbourhood of the origin are clustered about the single point an, and pn is determined by the condition

the second term on the right hand side of equation (3) is negligible, and IIyn+/ll - Yn+i ' I I 2 I I Rn(hJ,S I I IIyn" - yn' I I .

When 6, E (-co,O), ~ c , E [O,%] and I Rn(z) I < 1 for z E (-oo,O). Thus, with such 6, and pn determined by exponential fitting in this way, the scheme (2) is stable.

yn+, in formula (2 ) is determined by setting yn+l(0) = yn and using the Newton scheme [I - ( I - ~ J h J n + i ~ ) l ~ n + / ~ = Yn - yn+/" + ~ n h h + ( l - ~ ~ J h f , + , ~ ) (l=O,l,...) (4)

Copyright 1995 by CRC Press, Inc

Page 435: Numerical Library in C for Scientists and Engineers A

where A,,+~(') = J21+1(1+1) - yn+l('), and J,,," is an approximation to the Jacobian matrix ~f(y,+,~')/Dy~+,". This scheme is continued until either 11 A,,,," 11 I q, + 11 yn+,fl 11 q,, where qa and qr are absolute and relative tolerances prescribed by the user, or I = itmax, where itmax is a similarly prescribed integer.

The Jacobian matrix J,,," occurring in formula (4) is updated at every iteration and every integration step.

Function Parameters: void linigerlvs

(x,xe,m,y,sigma,derivative,j,jacobian, itmax, hmin, hmax,aeta,reta, info, output) x: float *;

entry: the independent variable; the initial value xO; exit: the final value xe;

xe: float; entry: the final value of x (xe 2 x);

m: int; entry: the number of equations;

y: float y[l:m]; the dependent variable; entry: the initial values of the system of differential equations: y[i] at x=xO; exit: the final values of the solution: y[i] at x=xe;

sigma: float *; the modulus of the point at which exponential fitting is desired, for example the largest negative eigenvalue of the Jacobian matrix of the system of differential equations;

derivative: void (*derivative)(m,y,sigma); this procedure should deliver the right hand side of the i-th differential equation at the point @) as y[i];

j : floatj[l:m,l:m]; the Jacobian matrix of the system; array j should be updated in the procedure jacobian;

jacobian: void (*jacobian)(m,j,y,sigma); in this procedure (an approximation to) the Jacobian has to be assigned to the array j;

itmax: int; entry: an upper bound for the number of iterations in Newton's process, used to solve

the implicit equations; hmin: float;

entry: minimal stepsize by which the integration is performed; hmax: float;

entry: maximal stepsize by which the integration is performed; aeta: float;

entry: required absolute precision in the integration process; reta: float;

entry: required relative precision in the integration process; if both aeta and reta have negative values then integration will be performed with a stepsize equal to hmax, which may be varied by the user; in this case the absolute values of aeta and reta will control the Newton iteration;

info: float info[l:9]; during integration and upon exit this array contains the following information: inforl]: number of integration steps taken;

Copyright 1995 by CRC Press, Inc

Page 436: Numerical Library in C for Scientists and Engineers A

info[2]: number of derivative evaluations used; info[3]: number of Jacobian evaluations used; info[4]: number of integration steps equal to hmin taken; info[S]: number of integration steps equal to hmax taken; info[6]: maximal number of integrations taken in the Newton process; info[7]: local error tolerance; info[8]: estimated local error; info[9]: maximum value of the estimated local error;

output: void (*output)(x,xe,m,y,sigma,j, info); this procedure is called at the end of each integration step; the user can ask for output of some parameters, for example, x, y, j, info.

Functions used: inivec, mulvec, mulrow, dupvec, matvec, elmvec, vecvec, dec, sol.

void linigerlvs(f1oat *x, float xe, int m, float YE], float *sigma, void (*derivative) (int, float [I , float * ) , float **j, void (*jacobian) (int, float ** , float 11 , float * ) , int itmax, float hmin, float hmax, float aeta, float reta, float info [I , void (*output) (float, float, int, float [I , float,

float ** , float [I 1 ) I

int *allocate-integer-vectorlint, int) ; float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int * , int); void free-real-vector(f1oat * , int); void free real matrix(f1oat ** , int, int, int); void inivGc(inF, int, float [I, float); void mulvec (int, int, int, float [I , float [I , float void mulrow (int, int, int, int, float **, float ** , void dupvec(int, int, int, float [I, float [I); float vecvec (int, int, int, float 11 , float 11 ) ; float matvec(int, int, int, float **, float [I ) ; void elmvec (int, int, int, float [I , float [I , float void dec(f1oat ** , int, float [I, int [I) ; void sol(f1oat ** , int, int [I, float [I); void linigerlvscoef(int, float'**, float **, float [I, int [I,

float, float, float *, float * , float *, float * ) ; int i,st,lastjac,last,first,evaljac,evalcoef,*pi,k,q; float h,hew,mu,mul,beta,p,e,el,eta,etal,discr,*dy,*~l,*~r,*f,

**a,aux [41 , hl, b;

first=evaljac=l; last=evalcoef=O; inivec(l,9,info,0.0) ; eta=reta*sqrt (vecvec (l,m, O,y, y) ) +aeta; etal=eta/sqrt (fabs (reta) ) ; dupvec(l,m,O,f,y) ; (*derivative) (m, f, sigma) ; info [21 =l. 0;

::=;; /* step size * / if (eta < 0.0) (

hl=h; h=hew=hmax;

Copyright 1995 by CRC Press, Inc

Page 437: Numerical Library in C for Scientists and Engineers A

info[5] += 1.0; if (l.l*hnew > xe-(*x)) (

last=l; h=hnew=xe- (*x) ;

1 evalcoef= (h ! = hl) ;

) else if (first) ( h=hnew=hmin; first=O; info[4] += 1.0;

) else ( b=discr/eta; hl=h; if (b < 0.01) b=0.01; hnew = (b > 0.0) ? h*pow(b, -l.O/p) : hmax; if (hnew < hmin) (

hnew=hmin; info[4] += 1.0;

) else if (hnew > hmax) (

hnew=hmax; info[51 += 1.0;

I

if (i. l*hnew >= xe- (*x) ) { last=l; h=hnew=xe- (*x) ;

) else if (fabs (h/hnew-1.0) > 0.1) h=hnew;

evalcoef = (h ! =hl) ; 1 info[ll += 1.0; if (evaljac) {

( * jacobian) (m, j , y, sigma) ; info[31 += 1.0; h=hnew; linigerlvscoef (m, a, j, aux,pi, h, *sigma, &mu, &mul, &beta, &p) ; evaljac=O; lastjac=st;

) else if (evalcoef)

linigerlvscoef (m,a, j ,aux,pi, h, *sigma, &mu m u , beta, p ; i=l; do (

/ * iteration * / if (reta < 0.0) (

if (i == 1) ( mulvec(l,rn,O,dy,f,h); for (k=l; kc=m; k++) yl [kl =y [kl +mu*dy [kl ; sol(a,m,pi,dy) ; e=1.0;

) else { for (k=l; k<=m; k++) dy[kl =yl [kl -y[kl +mul*f[kl ; if (e*sqrt (vecvec (l,m, 0, y, y) ) > eltell {

evaljac=(i >= 3 ) ; if (i > 3) (

info[3] += 1.0; (*jacobian) (m, j, y, sigma) ; for (q=l; q<=m; q++) (

mulrow(l,m,q,q,a, 1,-mul) ; a[ql [ql += 1.0;

1 aux [21 =O. 0; dec (a,m,aux,pi) ;

1 1

sol(a,m,pi,dy) ; 1 el=e; e=sqrt (vecvec (1,m, 0, dy, dy) ) ; elmvec(l,rn, 0, y,dy, 1.0) ; eta=sqrt(vecvec(l,m,O,y,y))*reta+aeta; discr=O.O; dupvec(l,m,O,f ,y) ; (*derivative) (m, f, sigma) ;

Copyright 1995 by CRC Press, Inc

Page 438: Numerical Library in C for Scientists and Engineers A

info[21 += 1.0; ) else (

if (i == 1) { / * linearity * / for (k=l; k<=m; kc+) dy [kl =y [kl -mul*f [kl ; sol(a,m,pi,dy) ; elmvec(l,m,O,dy,y,-1.0); e=sqrt (vecvec (l,m, O,dy, dy) ) ; if (e*(st-lastjac) > eta) {

(*jacobian) (m, j, y, sigma) ; lastjac=st; infor31 += 1.0; h=hnew; linigerlvscoef (m, a, j ,aux,pi, h, *sigma, &mu, Lmul,

&beta, &p) ; / * linearity * / for (k=l; k<=m; k++) dy[kl =y[kl -mul*f [kl ; sol (a,m,pi, dy) ; elmvec(l,m,O,dy,y, -1.0) ; e=sqrt (vecvec (1, m, 0, dy, dy) ) ;

1 I

evaljac= (e* (stcl-lastjac) > eta) ; mulvec(l,m,O,dy,f,h); for (k=l; k<=m; k++) yl [kl =y [kl +mu*dy [kl ; sol (a,m,pi,dy) ; for (k=l; k<=m; k++) yr [k] =h*beta*matvec (1, m, k, j , dy) ; sol (a,m,pi, yr) ; elmvec(l,m,O,yr,dy,l.O) ;

) else { for (k=l; k<=m; k++) dy [kl =yl [kl -y[kl +mul*f[kl ; if (e > etal && discr > etal) {

info[31 += 1.0; (*jacobian) (m, j, y, sigma) ; for (q=l; q<=rn; q++) {

mulrow(l,m,q,q,a, j, -mul) ; a [ql [ql += 1.0;

1 aux[2]=0.0; dec (a,m,aux,pi) ;

elmvec(l,m,O,y,dy,l.O); eta=sqrt (vecvec (l,m, O,y,y) ) *reta+aeta; etal=eta/sqrt (reta) ; dupvec(l,m,O,f,y) ; (*derivative) (rn, f, sigma) ; info[2] += 1.0; for (k=l; k<=m; k++) dy [kl =yr [kl -h*f [kl ; discr=sqrt (vecvec (1, m, 0, dy, dy) ) /2.0 ;

if (i > info [6l ) info 161 =i; i++;

) while (e > fabs(eta) && discr > 1.3*eta && i <= itmax); info [71 =eta; info [8] =discr; (*x) += h; if (discr > info [9l ) info [gl =discr; (*output) (*x,xe,m, y, *sigma, j, info) ; st++;

} while ( !last) ; free-integer-vector (pi, 1) ; f ree-real-vector (dy, 1) ; f ree-real-vector (yl, 1) ; free-real-vector (yr, 1) ; f ree-realvector (f , 1) ; free-real-matrix(a, l,m, 1) ;

1 void linigerlvscoef (int m, float **a, float **j , float aux [I ,

int pi[], float h, float sigma, float *mu, float *mul, float *beta, float *p)

Copyright 1995 by CRC Press, Inc

Page 439: Numerical Library in C for Scientists and Engineers A

/* this function is internally used by LINIGERlVS * /

int q; float b,e;

*p = 2.0+2.0/(b-2.0) ; } else if (b < 0.04) {

e=b*b/30.0; *p = 3 .O-e; *mu = 0.5-b/12.0*(1.0-e/2.0); *beta = 0.5+b/6.0* (1.0-e) ;

} else { e=exp(b) -1.0; *mu = l.O/b-l.O/e; *beta = (1.0-b/e) * (l.O+l.O/e) ; *p = ((*beta) - (*mu)) /(O.5- (*mu)) ;

for (q=l; q<=m; q++) { rnulrow(l,m,q,q,a, j, - (*mul)) ; a[ql [ql += 1.0;

I

aux[2]=0.0; dec (a,rn,aux,pi) ;

1

Solves an initial differential equations

value problem, given as an autonomous system of first order

m(x) = f(rl (1) where D 5 dl& andJy, E Rm, with y(xo) prescribed, over the interval xO S x S xe by means of an implicit, second (or possibly third) order accurate, exponentially fitted one-step method [see BeDHKW73, DekHH72, LiW701. No automatic stepsize control is provided. This procedure is suitable for the integration of stiff differential equations.

The method used has the form yn+/ = yn + (1/2)h[(l-aJf, + (l+aJf,+J + (I/4)h2[(bn-aJJ& - (bn+aJJn+f,+J (2)

where, with X = x, + nh (n=0,1, ... ), yn = y(xJ, f, = f b J and J,, = afhJ/ayn. An analysis similar to that given in the documentation of linigerlvs reveals that the stability function for the above method has the form

R(z) = [I + (1/2)(1-aJz + (l/4) (bn-a#] / [I - (1/2)(1 +a J z + (1/4)(bn+aJ2]. Exponential fitting is now possible at two points: with distinct nonzero z, and z,,

R ( q , ) = e L O and R ( z , ) = e z '

if a,, = 2[g('J-g(zJl/[z ,g(zJ-zog(zJ1, bn = 2(z,-zd/[z,g(zJ-zog(zJl where g(z) = 2(1-e')/[e'(2-z)-(2+z)].

It may be shown that the method (2) is stable in three cases. In the first (a) the eigenvalues of J,, not in the neighbourhood of the origin are clustered about two points 6,'"' and 6,"') on the negative real axis; an and bn are then obtained as above by setting zo=h6,'"!

"0. 1 1 9

(b) the above eigenvalues are clustered about two complex conjugate points 6,'"1=ud4, 6,01)=ue~i~ in the left half plane x12 < q5 < 3x12; an and bn are then determined as in (a); and

Copyright 1995 by CRC Press, Inc

Page 440: Numerical Library in C for Scientists and Engineers A

(c) the above eigenvalues are clustered about a single point 6,'"' on the negative real axis; a, and b, are then obtained by limiting relationships of the above form with z, = h6,'"' and z,=o.

In case (a) and (b) above, the method (2) is second order accurate; in case (c) it is third order accurate.

y,,, in formula (2) is determined by setting y,+,(") = y, and using the modified Newton scheme

[41 - 2h(1+aJJ,+,~ + h2(bn+aJ(~n+,"~2]~Yn+,(') =

h[2(I+aJI - h(b,+a~~,+,")]h+~") + 4yn + 2h(l-a& + h2(b,-aJJk - 4yn+,(') where A,+,(') = yn+l'2+1) - Y,+,(') and J,+,(" is an approximation to the Jacobian matrix af('+,(')/i3yn+,('). This scheme is continued until conditions analogous to those given in the documentation to linigerlvs are satisfied.

Function Parameters: void liniger2 (x,xe,m,y,sigmal,sigma2,f;evaluate,j,jacobian, k, itmax,step,aeta,reta,output)

x: float *; entry: the independent variable; the initial value xO; exit: the final value xe;

xe: float; entry: the final value of x (xe 2 x);

m: int; entry: the number of equations;

y: float y[l:m]; the dependent variable; entry: the initial values of the system of differential equations: y[i] at x=xO; exit: the final values of the solution: y[i] at x=xe;

sigmal: float *; the modulus of the point at which exponential fitting is desired, this point may be complex or real and negative;

sigma2: float *; sigma2 may define three different types of exponential fitting; fitting in two complex conjugated points, fitting in two real negative points, or fitting in one point combined with third order accuracy; if third order is desired then sigma2 should have the value 0; if fitting in a second negative point is desired then sigma2 should have the value of the modulus of this point; if fitting in two complex conjugated points is desired then sigma2 should be minus the value of the argument of the point in the second quadrant (thus a value between -n and 4 2 ) ;

j float (*j)(m,y, i,sigmal,sigma2); int i; this procedure should deliver the right hand side of the i-th differential equation as J

derivative: void (*derivative)(m, y,sigma); this procedure should deliver the right hand side of the i-th differential equation at the point b) as y[i];

evaluate: int (*evaluate)(itnum); int itnum; evaluate should be assigned the value nonzero if it is desired that the Jacobian of the system is updated in the itnum-th iteration step of the Newton process;

j : float j[l:m, l:m];

Copyright 1995 by CRC Press, Inc

Page 441: Numerical Library in C for Scientists and Engineers A

the Jacobian matrix of the system; array j should be updated in the procedure jacobian; jacobian: void (*jacobian)(m,j,y,sigmal,sigma2);

in this procedure the Jacobian has to be assigned to the array j; or an approximation of the Jacobian, if only second order accuracy is required;

k: int *; counts the number of integration steps taken;

itmax: int; entry: an upper bound for the number of iterations in Newton's process, used to solve

the implicit equations; step: float;

entry: the length of the integration step, to be prescribed by the user; aeta: float;

entry: required absolute precision in the Newton process, used to solve the implicit equations;

reta: float; entry: required relative precision in the Newton process, used to solve the implicit

equations; output: void (*o~tp~t)(x,xe,m,y,sigmal,sigma2,j,k);

this procedure is called at the end of each integration step; the user can ask for output of some parameters, for example, x, y, j, k.

Functions used: vecvec, matvec, matmat, dec, sol.

void liniger2(float *x, float xe, int m, float ~ [ l , float *sigmal, float *sigma2, float (*f) (int, float [I , int, float * , float * ) , int (*evaluate) (int) , float **j, void (*jacobian) (int, float ** , float [ I , float * , float * ) , int *k, int itmax, float step, float aeta, float reta, void (*output) (float, float, int, float [I , float, float,

float ** , int)) I

int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int) ; void free-integer-vector(int *, int); void free-real-vector(f1oat *, int) ; void free-real-matrix (float **, int, int, int) ; float vecvec(int, int, int, float [I, float [I 1 ; float matvec (int, int, int, float ** , float [I ) ; float matmat (int, int, int, int, float **, float * * ) ; void dec(f1oat **, int, float [I, int [I); void sol (float **, int, int [ I , float [I ) ; void linigerlcoef(int, float **, float ** , float [I, int [ I ,

float, float, float, float * , float * , float *, float *, float * ) ;

int i, last, *pi, itnum; float h,hl,cO,cl,c2,c3,c4,*dy,*yl,*fl,**a,aux[41,

jfl,eta,discr;

Copyright 1995 by CRC Press, Inc

Page 442: Numerical Library in C for Scientists and Engineers A

(*k) ++; / * step size * / h=step; if (l.l*h >= xe-(*x)) {

last=l; h=xe- (*x) ; (*x) =xe ;

} else (*x) += h;

/ * newton iteration * / itnum=O ; while (1) {

itnum++ ; if ( (*evaluate) (itnum) ) (

(*jacobian) (m, j, y, sigmal, sigma2) ; l~niger2coef(m,j,a,aux,pi,h,*sigmal,*sigma2,

&CO,&C~,&C~,&C~,&C~) ; } else

if (itnum == 1 && h ! = hl) liniger2coef(m,j,a,aux,pi,h,*sigmal,*sigma2,

&CO, &Cl,&C2, &C3, & ~ 4 ) ; for (i=l; i<=m; i++) fl [il = (*f) (m, y, i, sigmal, sigma2) ; if (itnum == 1)

for (i=l; i<=m; i++) { jfl=matvec(l,m,i, j, fl) ; dy[i]=h*(fl[il -c4*jf1) ; yl [il =y [il +cZ*fl [il +c3*jfl;

1 I

else for (i=l; i<=m; i++)

dy [i] =yl [i] -y [i] +cl*fl [il -cO*matvec (l,m, i, j, fl) ; sol (a,m,pi,dy) ; for (i=l; 1<=m; i++) y [il += dy [il ; if (itnum >= itmax) break; eta=sqrt(vecvec(l,m,O,y,y))*reta+aeta; discr=sqrt (vecvec (l,m, 0, dy, dy) ) ; if (eta >= discr) break;

1 hl=h; (*output) (*x,xe,m, y, *sigmal, *sigma2, j, *k) ;

while ( !last) ; free-integer-vector(pi,l) ; free-real-vector (dy, 1) ; free-real-vector (yl, 1) ; free-real-vector (f 1,l) ; free-real-matrix (a, l,m, 1) ;

void liniger2coef(int m, float **j, float **a, float aux[l , int pi [ I , float h, float sigmal, float sigma2, float *cO, float *cl, float *c2, float *c3, float *c4)

{ / * this function is internally used by LINIGER2 * /

int i,k,out,doublefit; float bl,b2,r,rl,r2,ex,zeta,eta,sinl,cosl,sinhrcosh,d,p,q;

if (!out) { if (b2 < 0.0) {

/ * complex * / eta=fabs(bl*sin(sigmaZ)); zeta=fabs (bl*cos (sigma21 ) ; if (eta < bl*bl*l.Oe-6) (

bl=b2=zeta; doublefit=l;

Copyright 1995 by CRC Press, Inc

Page 443: Numerical Library in C for Scientists and Engineers A

1 if (!doublefit)

if (zeta > 40.0) ( p=l.o-4.0*zeta/bl/bl; q=4.0*(1.0-zeta)/bl/b1+1.0;

) else ( ex=exp (zeta) ; sinl=sin (eta) ; cosl=cos (eta) ; sinh=0.5*(ex-l.O/ex); cosh=O. 5* (ex+l. O/ex) ; d=eta*(cosh-cosl) -0.5*bl*bl*sinl; p=(zeta*sinl+eta*sinh-

4.0*zeta*eta/bl/bl*(cosh-cosl) )/d; q=eta*( (cosh-cosl-zeta*sinh-eta*sinl)*

4.0/bl/bl+cosh+cosl)/d; 1

] else if (bl c 1.0 I I b2 < 0.1) { / * third order * / q=1.0/3.0; if (bl > 40.0)

r=bl/ (bl-2.0) ; else (

ex=exp (-bl) ; r=bl* (1.0-ex) / (bl-2 .O+ (bl+2 .O) *ex) ;

1 p=r/3.0-2.0/bl;

] else if (fabs (bl-b2) < bl*bl*l.Oe-6) doublefit=l;

else { if (bl > 40.0)

r=bl/ (bl-2.0) ; else (

ex=exp (-bl) ; r=bl* (1.0-ex) / (bl-2.O+ (bl+2.0) *ex) ;

I rl=r*bl; if (b2 > 40.0)

r=b2/(b2-2.0) ; else {

ex=exp ( -b2 ) ; r=b2* (1.0-ex) / (b2-2 .O+ (b2+2.0) *ex) ;

1

if (doublefit) ( bl=O. 5* (bl+b2) ; if (bl > 40.0)

r=bl/ (bl-2.0) ; else {

ex=exp (-bl) ; r=bl* (1.0-ex) / (bl-2.O+ (bl+2.0) *ex) ;

I rl=r; if (bl > 40.0) ex=O.O; r2=bl/ (1.0-ex) ; r2=1.0-ex*r2*r2; q=l. 0/ (rl*rl*r2) ; p=rl*q-2.0/bl;

1 )

J

*cO = 0.25*h*h* (p+q) ; *cl = 0.5*h* (l.O+p) ; *c2 = h- (*cl); *c3 = 0.25*h*h* (q-p) ; *c4 = 0.5*h*p; for (i=l; i<=m; i++) (

for (k=l; k<=m; k++) a[i] [kl= (*cO) *matmat (l,m,i,k, j, j) - (*cl) *j [il [kl ;

a [ i l [il += 1.0; I

Copyright 1995 by CRC Press, Inc

Page 444: Numerical Library in C for Scientists and Engineers A

aux[21=0.0; dec (a,rn,aux,pi) ;

I

E. gms

Solves an initial value problem, given as an autonomous system of first order differential equations

DyW = f(Y) (1) where D denotes differentiation with respect to the indicated argument and y, f E Rr, with y(xJ prescribed, over the interval xO 5 x 5 xe by means of a third order, exponentially fitted, generalized multistep method with automatic stepsize control [VhV74, Vw741. This procedure is suitable for the integration of stiff differential equations.

The procedure gms describes an implementation of a third order three-step generalized linear multistep method with quasi-zero parasitic roots and quasi-adaptive stability function. The procedure supplies the additional starting values and performs a stepsize control which is based on the non-linearity of the differential equation. By this control the Jacobian matrix is incidentally evaluated. It is possible to eliminate the stepsize control. Then, one has to give the number of integration steps per Jacobian evaluation. For linear equations the stepsize control is automatically eliminated, while the procedure performs one evaluation of the Jacobian. However, in this case the three-step scheme is reduced to a one-step scheme. The procedure uses one function evaluation per integration step and it does not reject integration steps. Each change in the steplength or each reevaluation of the Jacobian costs one LU-decomposition. It is possible to fit exponentially, this fitting is equivalent to fitting in the sense of Liniger and Willoughby, only when the Jacobian matrix is evaluated at each integration step. When the system to be integrated is non-linear and the Jacobian matrix is not evaluated at each integration step, it is recommended to fit at infinity (input parameter delta I -10").

The method used is one of a class having the form

where, with 2"' = x, + h,, y, = y(xJ, J,* is an approximation to the Jacobian matrix J,=af(YJ/ay,, R and the B, being rational functions.

Considerations of stability demand that 11 B,(~J,') 11 (I=l, ..., k) be as small as possible: the stabilizing condition B,(z) + 0 as Real(z) + -m (I=l, ..., k) is imposed.

The method (2) is k-th order accurate if, with = (x,,-, - xJ/h, (I=O,l,. . .,k- 1)

and the conditions

C ' = (l/j!) (j=l ,.. .,k) C,"" = 0 (j= 1 ,..., k; i=O ,... j- 1) lim D'R(z) = 1 (z + 0) (i=O, ..., k)

are satisfied or, alternatively, with

Copyright 1995 by CRC Press, Inc

Page 445: Numerical Library in C for Scientists and Engineers A

G ~ ( Z ) = [ R ( Z ) - ~ + O ( Z ~ " ) ~ / Z , ~ , + ~ ( z ) = ~ ~ , ( ~ ) - l - ~ ( z k " ~ ) / z u=l, ..., k-1) (4) as z + 0. The one-step scheme

Yn+/ = Yn + (J)-l.!R(hnJn? - IIfbJ is second order accurate if J,* = Jn exactly, and (3) is satisfied for some k > 1.

The local truncation error of the scheme (2) at x = xn is

The choice of BI(z) resulting from taking the 0 terms in the expressions (4) for the G, to be zero minimizes the local truncation error, and in this case

c , ( z ) l ! l k - 1 cn(z )=l lk !+O(z) and cr) = 0 (j=O,l, ..., k-1; i=1,2 ,... ), c f ) = 0 (i=2,3 ,... ). The local truncation error then becomes

The stability function R used by gms is

The parameter a'") is determined by exponential fitting at the point z = hn6, where 6, is the eigenvalue of greatest absolute value on the negative real axis of J,':

2 1 ezn(zf -6zn+12) - (z, +6zn+12) R(hn6,) = ehnan if a(") = -

3 ~ n ezn(2-z,) - (2+~,)

where zn = hn6,. If a@) = 0, R is fourth order consistent; otherwise third. Taking the denominator of R(z) to be Q(z), the G, have, when k-3, the form

G,(z) =(glj+g2y)/Q(z) where glj = 14, g2,, = -dn)/2, g2,2 = g2,3 = -(I + 3dn))/12, and then where b,1 = 1, b ,1 = b , i = 0, b1,2 = -(ql+qJ/qlqz, b,2 = -qJ(q12-qlq3~ b,2 = -qi/(q;-q,qJ, b1,3 = I/qlq2, b2,3 = l/(ql2-qlq3, b3,3 = '/(q;-q1qJa

Copyright 1995 by CRC Press, Inc

Page 446: Numerical Library in C for Scientists and Engineers A

The three step, third order scheme of the class ( 2 ) with minimized local truncation error then becomes

with k=3. When k=2, the b,,. are given by b , , = I, b , , = 0, b,,, = 1 - 1/91, b , ~ = 1/91.

Copyright 1995 by CRC Press, Inc

Page 447: Numerical Library in C for Scientists and Engineers A

The user is asked to provide an initial stepsize ha. J0* = J, is then evaluated exactly, and the one-step scheme is used to determine y,. The two-step scheme (resulting from the substitution k=2 above) is used to determine y,, and thereafter the three-step scheme (5) is used.

The user is also asked to provide two limits hmin and hmax for the minimal and maximal stepsizes respectively. If these are equal (their particular values are then ignored) the computations are continued using the scheme (5) with constant stepsize h,. In this case the user must also provide an integer value nsjev; the approximation J,' is then updated every nsjev steps.

The user is also asked to allocate a value to the parameter linear upon call. If this value is nonzero then a constant stepsize h and a constant Jacobian J,' = Jo are used throughout the computation.

If the value allocated to linear is zero then the following method of estimating a stepsize is used. If y',,, were to be determined by use of a two step scheme (with k 2 above) and y,,, were to be computed by use of the three-step scheme (5) with stepsize h,' in both cases, then I1 yn+, - y,,, ' I( ~ 5 . c,h, '3 where c, is independent of h,'. Thus with a permitted local tolerance tol, and assuming c,, = c,, the maximal value of h,' is given by

h, ' = (tol/~,J'/~ = (tol/~,J'~ = h,,(tol/ll yn-yn ' = hn~1[((4/3)tol)/(tol + 11 yn-yn ' 11) + 1/31 where y,' has been computed as above (from y,,) by means of a two-step method with stepsize h,,. The bound to1 = q, + q, 11 y, 11 is used, where q, and q, are absolute and relative tolerances prescribed by the user. A new stepsize is chosen (i.e. h, is taken to be h,' rather than h,,) if 1 (h,,-h, Y/h,, I > 0.1. A new J,' is determined if (i) h, is to be changed and a new J,' was not determined at the preceding step and (ii) I0 1 h,,-h, ' 1 < 0.1 1 h,, 1 . (Naturally h, is taken to be hmin or hmax as is appropriate, if h,' lies outside the range hmin 5 h, ' 5 hmax).

Formula (5) represents a system of linear equations. The matrix Q(hJ,,') is decomposed in LU form and y,,, is obtained from this decomposition. The parameters jev and lu record the current number of evaluations of J,' and of LU decompositions (since h, may be changed while J,' remains unchanged, these two numbers may differ).

Function Parameters: void gms

(x,xe, r,y, h, hmin, hmax, delta, derivative jacobian, aeta, reta, njev, lu, nsjev, linear, out) x: float *;

entry: the independent variable; the initial value xO; exit: the final value xe;

Copyright 1995 by CRC Press, Inc

Page 448: Numerical Library in C for Scientists and Engineers A

xe: float; entry: the final value of x (xe 2 x);

r: int; entry: the number of differential equations;

y: float y[l:r]; the dependent variable; entry: the initial value of y; exit: the solution y at the point x after each integration step;

h: float; entry: the steplength when the integration has to be performed without the stepsize

mechanism, otherwise the initial steplength (see hmin and hmax below); hmin,hmax: float;

entry: minimal and maximal steplength by which the integration is allowed to be performed; by putting hrnin=hrnax the stepsize mechanism is eliminated; in this case the given values for hmin and hmax are irrelevant, while the integration is performed with the steplength given by h;

delta: float *; entry: the real part of the point at which exponential fitting is desired; alternatives: delta= (an estimate of) the real part of the largest eigenvalue in modulus of the

Jacobian matrix of the system; delta5 -lo", in order to obtain asymptotic stability; delta= 0, in order to obtain a higher order of accuracy in case of linear equations;

derivative: void (*derivative)(r,y,deIta); this procedure should replace the i-th component of the solution y by the i-th component of the derivative fh), i=l, ..., r;

jacobian: void (*jacobian)(r,j,y, delta); in gms when this procedure is called, the array y contains the values of the dependent variable; upon completion of a call of jacobian the array j should contain the values of the Jacobian matrix of f(yl;

aeta, reta: float; entry: measure of the absolute and relative local accuracy required;

these values are irrelevant when the integration is performed without the stepsize mechanism;

n: int *; exit: the number of integration steps;

jev: int *; exit: the number of Jacobian evaluations;

lu: int *; exit: the number of LU-decompositions;

nsjev: int; entry: number of integration steps per Jacobian evaluation;

the value of nsjev is relevant only when the integration is performed without the stepsize mechanism and the system to be solved is non-linear;

linear: int; entry: linear equals nonzero when the system to be integrated is linear, otherwise

zero; if linear is nonzero the stepsize mechanism is automatically eliminated;

out: void (*out)(x,xe,r,y, delta,n,jev, lu);

Copyright 1995 by CRC Press, Inc

Page 449: Numerical Library in C for Scientists and Engineers A

this procedure is called after each integration step; the user can ask for output of some parameters, for example, x, y, delta, n, jev, lu.

Functions used: vecvec, matvec, matmat, elrnrow, elmvec, dupvec, gsselm, solelm, colcst, mulvec.

void gms(f1oat *x, float xe, int r, float y[l, float h, float hmin, float hmax, float *delta, void (*derivative) (int, float [I, float * ) , void ( * jacobian) (int, float ** , float [I , float * ) , float aeta, float reta, int *n, int *jev, int *lu, int nsjev, int linear, void (*out) (float, float, int, float [I, float,

int, int, int))

int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int); void free-integer-vector(int *, int); void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int); float vecvec(int, int, int, float [I, float [I ) ; float matvec(int, int, int, float **, float [I); float matmat (int, int, int, int, float **, float **) ; void elmrow(int, int, int, int, float ** , float **, float); void elmvec (int, int, int, float [I, float [I, float) ; void dupvec (int, int, int, float [I , float [I ) ; void gsselm(f1oat **, int, float [I , int [I, int [I ) ; void solelm (float **, int, int [I , int [I , float [I ) ; void colcst (int, int, int, float **, float) ; void mulvec(int, int, int, float [I , float [I, float) ; void gmsopconstruct(int *, int *, int, float **,

float **, float **, float [I, float [ I , int [ I , int [I, int *, int *, int *, float * , float *, float, float, float *, float * , void (*) (int, float **, float [I, float * ) ) ;

void gmscoefficient(f1oat *, float *, float, int, int, float *, float *, float, float, float **, float **, int) ;

void grnsdiffscheme(int, int, int, float [I, float [I , int *, int *, float [I , float, float **, float **, float, float [I, float **, float **, float **, int [I, int [I, float *, void ( * ) (int, float [I , float *) ) ;

int k,l,nsjevl,count,countl,kchange,update,change,reeval, strategy, *ri, *ci;

float a,alfa, sl, s2,xO,xlO,xll,eta,h0,hl,ql, q2, discr,aux[lO] ,**bdl,**bd2,*yl,*y~,**hjac,**h2jac2, **rqz, *yl. *fl;

/ * initialization * / (*lu) = ( * jev) = (*n) =nsjevl=kchange=0; xo= (*x) ; discr=0.0; k=l; hl=hO=h;

Copyright 1995 by CRC Press, Inc

Page 450: Numerical Library in C for Scientists and Engineers A

count = -2; aux [2] =FLT-EPSILON; aux[41=8.0; dupvec(l,r,O,yl,y); reeval=change=l; strategy= ( (hmin ! = hmax) && !linear) ; ql = -1.0; q2 = -2.0; countl=O ; xlO=xll=O.O; (*out) (*x,xe, r, y, *delta, *n, *jev, *lu) ; (*x) += hl; /* operator construction * / gmsopconstruct(&reeval,&update,r,hjac,h2jac2,rqz,y,a~,ri,ci,

lu, jev, &nsjevl,delta, &alfa, hl,hO, &sl, &s2 a c o b a n ; bdl [ll [l] =I. 0; bd2 [11 111 = -alfa*0.5; if (!linear)

gmscoefficient(&xll,&x10,xO,change,*n,&ql,&q2,hl, alfa,bdl,bd2, strategy) ; -.

while (1) ( gmsdiffscheme(k,count,r,fl,y1,n,&nsjev1,yO,alfa,bdl,

bd2, hl, y, hjac, h2jac2, rqz, ri, ci, delta,derivative) ; if (strategy) count++; if (count == 1) {

/ * test accuracy * / k=2 ; dupvec(l,r,O,yl,y); gmsdiffscheme(k,count,r,fl,yl,n,&nsjev1,yO,alfa,bdl,

bd2,hl,y,hjac,h2jac2,rqz,ri,ci,delta,derivative) ; k=3 ; eta=aeta+reta*sqrt (vecvec (1, r, 0, yl, yl) ; elmvec(l,r,O,y,yl,-1.0); discr=sqrt (vecvec (1, r, 0, y, y) ) ; dupvec(l,r,O,y,yl);

(*out) (*x,xe, r, y, *delta, *n, *jev, *lu) ; if ( (*x) >= xe) break; / * step size * / xo= (*x) ; hO=hl; if ((*n <= 2) && !linear) (k)++; if (count == 1) {

a=eta/ (0.75* (eta+discr) ) +O. 33; hl = (a <= 0.9 1 1 a >= 1.1) ? a*hO : hO; count=O; reeval= (a c = 0.9 && nsjevl ! = 1) ; countl = (a >= 1.0 I I reeval) ? 0 : countl+l; if (countl == 10) (

countko ; reeval=l; hl=a*hO;

1

) el'se { hl=h; reeval= ( (nsjev == nsjevl) && !strategy && !linear) ;

1 J

if (strategy) hl = (hl > hrnax) ? hmax : ((hl < hmin) ? hmin : hl) ;

(*x) += hl; if ( (*x) >= xe) (

hl=xe-x0; (*x) =xe ;

1 if ( (*n <= 2) && !linear) reeval=l; if (hl ! = hO) {

update=l; kchange=3;

1 I

if (reeval) update=l; change=( (kchange > 0) && !linear) ; kchange--; if (update)

/ * operator construction 4 /

Copyright 1995 by CRC Press, Inc

Page 451: Numerical Library in C for Scientists and Engineers A

gmsopconstruct (&reeval, &update,r, hjac.h2jac2,rqz8 y,aux, ri, ci, lu, jev, &nsjevl, delta, &alfa, h1, h0, &sl, &s2, jacobian) ;

if (!linear) gmscoefficient(&xll,&x10,xO,change,*n,&ql,&q2,hl,

alfa,bdl,bd2, strategy) ; /* next integration step */ for (1=2; 1>=1; I--) {

dupvec(l*r+l, (l+l) *r, -r,yl,yl) ; dupvec(l*r+l, (1+1) *r,-r, f1,fl) ;

kree-integer-vector (ri, 1) ; f ree-integer-vector (ci, 1) ; free-realvector (yl, 1) ; f ree-real-vector (yo, 1) ; free-real-vector (yl, 1) ; free real vector(f1,l); free-realPmatrix(bdl, l,3,1) ; f ree~real~matrix (bd2,1,3,1) ; free-real-matrix(hjac, 1, r. 1) ; f ree-real-matrix(h2 jac2,l, r, 1) ; f ree-real-matrix (rqz, 1, r, 1) ;

I void gmsopconstruct(int *reeval, int *update, int r,

float **hjac, float **h2jac2, float **rqz, float y[l, float a m [I , int ri [ I , int ci [I, int *lu, int *jev, int *nsjevl, float *delta, float *alfa, float hl, float hO, float *sl, float *s2, void (*jacobian) (int, float **, float [I, float *) )

1 \

/ * this function is internally used by GMS * /

int i, j; float a,al, zl,e,q;

if (*reeval) { (*jacobian) (r,hjac,y,delta) ; (*lev) ++; *nsjevl = 0; if (*delta c= 1.0e-15)

(*alfa)=1.0/3.0; else (

zl=hl* (*delta) ; a=zl*zl+l2.0; al=6.0*zl; if (fabs(z1) < 0.1)

(*alfa)=(zl*zl/l40.0-1.0)*zl/30.0; else if (zl c -33.0)

(*alfa) = (a+al) / (3.0*21* (2.0+21) ) ; else {

e=exp (21) ; (*alfa) = ( (a-al) *e-a-al) / ( ( ( 2 .O-21) *e-2 .O-21) *zl*3.O) ;

, I

a=hl/h0; al=a*a; if (treeval) a=hl; if (a != 1.0)

for (j=i; jc=r; j++) colcst(l,r, j,hjac,a) ; for (i=l; ic=r; i++) {

for (j=l; jc=r; j++) { q=h2jac2 Iil [j] =(*reeval ? matmat (l,r,i, j,hjac,hjac) :

h2 jac2 [il [jl *all ; rqz [il [jl =(*s2) *q;

Copyright 1995 by CRC Press, Inc

Page 452: Numerical Library in C for Scientists and Engineers A

void gmscoefficient(f1oat *xll, float *x10, float xO, int change, int n, float *ql, float *q2, float hl, float alfa, float **bdl, float **bd2, int strategy)

I /* this function is internally used by GMS * /

float a,q12,q22,qlq2,x12;

x12= (*xl1) ; (*xl1) = (*xlO) ; ( *x10 ) =xo ; if (change) {

if (n > 2) { (*ql) = ( (*xll) - (*xlO) ) /hl; (*q2) = (x12- (*x10) ) /h1;

I

void gmsdiffscheme(int k, int count, int r, float El[], float yl [I , int *n, int *nsjevl, float y0 [I , float alfa, float **bdl, float **bd2, float hl, float y[] , float **hjac, float **h2jac2, float **rqz, int ri [ I , int ci [I , float *delta, void (*derivative) (int, float [I, float *) )

{ /* this function is internally used by GMS * /

int i,l;

if (count != 1) { dupvec(l,r,O,fl,yl) ; (*derivative) (r, f1,delta) ; (*n) ++; (*nsjevl) ++;

1 mulvec(1,r,O,yO,yl, (l.O-alfa)/2.0-bdl[11 [kl) ; for (1~2; l<=k; I++) elmvec(l,r,r* (1-1) ,yo, yl, -bdl [ll [kl ) ; for (1~1; lc=k; 1++) elmvec(l,r,r* (1-1) ,yO,fl,hl*bd2 [l] [kl ) ; for (i=l; i<=r; i++) y[il=matvec(l,r,i,hjac,y0); mulvec(1,r,O,yO,yl, (1.0-3.0*alfa)/12.0-bd2[1] [kl); for (1~2; lc=k; I++) elmvec(l,r,r* (1-1) ,yO,yl, -bd2 [ll [kl ) ; for (i=l; ic=r; i++) y[il += matvec(l,r,i,h2jac2, yo) ; dupvec(l,r,O,yO,yl) ; for (1=1; l<=k; I++) elmvec (l,r,r* (1-1) ,yo, fl,hl*bdl [ll [kl ) ; elmvec(l,r,0,y.y0,l.0); solelm(rqz, r, ri, ci, y) ;

1

Copyright 1995 by CRC Press, Inc

Page 453: Numerical Library in C for Scientists and Engineers A

Solves an initial value problem, given as an autonomous system of first order differential equations

dy,(t)/dt = m y (0) (i=I ,..., n) with y(tJ prescribed, over the interval tO I t I tend by means of an implicit midpoint rule with smoothing and extrapolation. Automatic stepsize control is provided. This procedure is suitable for the integration of stiff differential equations.

The integration method [see BeDHV74, Li731 is based on the computation of two independent solutions with stepsizes h and h12 by the implicit midpoint rule. Passive smoothing and passive extrapolation is performed to obtain stability and high accuracy. The algorithm uses for each step at least three hnction evaluations, and on change of stepsize or at slow convergence in the iteration process an approximation of the Jacobian matrix (computed by divided differences or explicitly specified by the user). If the computed local error exceeds tolerance, the last step is rejected. Moreover, two global errors are computed.

Function Parameters: void impex (n, to, tend,yO,deriv,available, hO,hmax,presch,eps, weights, update, fail,control)

n: int; entry: the number of equations;

to: float; entry: the initial value of the independent variable;

tend float; entry: the final value of the independent variable;

yo: float yO[l:n]; entry: the initial values of the system of differential equations: yO[i] at t=tO;

deriv: void (*deriv)(t,y,j)z); this procedure should deliver the values of f(t,y) in the array f[l:n];

available: int (*availab le)(t,y,a,n); if an analytic expression of the Jacobian matrix at the point (t,y) is not available then this procedure should deliver the value zero; otherwise this procedure should deliver the value nonzero, and the Jacobian matrix should be assigned to the array a[l:n,l:n];

hO: float; entry: the initial stepsize;

hmax: float; entry: maximal stepsize by which the integration is performed;

presch: int; entry: indicator for choice of stepsize;

the stepsize is automatically controlled ifpresch equals zero; otherwise the stepsize has to be prescribed, either only initially or also by the procedure control;

eps: float; entry: bound for the estimate of the local error;

weights: float weights[l :n]; entry: the initial weights for the computation of the weighted Euclidean norm of the

errors; note that the choice weights[i]=l implies an estimation of the absolute error, whereas weights[i/=y[i/ defines a relative error;

update: void (* update)(weights,y2, n); this procedure may change the arrays weights, according to the value of an approximation to y(t), given in the array y2[1:n];

fail: int *; exit: if the procedure fails to solve the system of equations, fail will have the value

Copyright 1995 by CRC Press, Inc

Page 454: Numerical Library in C for Scientists and Engineers A

nonzero upon exit; this may occur upon divergence of the iteration process used in the midpoint rule, while integration is performed with a user defined prescribed stepsize;

control: void (*control)(tprint, t, h, hnew,y,error, n, tend); control is called on entry to impex and fhrther as soon as the inequality tprint I t holds; during a call of control, printing of results and change of stepsize (if presch has the value nonzero) is then possible; the meaning of the parameters of control is: tprint: float *;

entry: the value of the independent variable at which a call of control is desired; exit: a new value (tprint > t) at which a call of control is desired;

t: float; the actual value of the independent variable, up to which integration has been performed;

h: float; halve the actual stepsize;

hnew: float; the new stepsize; if presch is nonzero then the user may prescribe a new stepsize by changing hnew;

y: float y[l:5,1:n]; the value of the dependent variable and its first four divided differences at the point t are given in this array;

error: float error[l:3]; the elements of this array contain the following errors: error[l]: the local error; error[2]: the global error of second order in h; error[3]: the global error of fourth order in h;

n: int; the number of equations;

tend float; the final value of the independent variable.

Functions used: inivec, inimat, mulvec, mulrow, dupvec, duprowvec, dupmat, vecvec, matvec, matmat, elmvec, elmrow, dec, sol.

void impex(int n, float to, float tend, float yo [ I , void (*deriv) (float, float [ I , float [ I , int), int (*available) (float, float [ I , float **, int) , float hO, float hmax, int presch, float eps, float weights [ I , void (*update) (float [ I , float [ I , int) , int *fail, void (*control) (float *, float, float, float, float **,

float [ I , int, float)) f

int *allocate-integer-vector(int, int); float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, intl ; void f ree-integer-vector (int * , int) ; void free-real-vector(f1oat *, int); void free-real-matrix(f1oat ** , int, int, int) ; void inivec (int, int, float [ I , float) ; void inimat (int, int, int, int, float **, float) ; void mulvec (int, int, int, float [ I , float [ I , float) ; void mulrow(int, int, int, int, float **, float **, float) ;

Copyright 1995 by CRC Press, Inc

Page 455: Numerical Library in C for Scientists and Engineers A

void dupvec (int, int, int, float [I , float [I ) ; void duprowvec(int, int, int, float **, float [I ) ; void dupmat (int, int, int, int, float **, float **) ; float vecvec (int, int, int, float [I , float [I ) ; float matvec(int, int, int, float ** , float [I) ; float matmat (int, int, int, int, float **, float * * ) ; void elmvec (int, int, int, float [I, float [I, float) ; void elmrow(int, int, int, int, float **, float **, float) ; void dec (float **, int, float [ I , int [I ) ; void sol(f1oat **, int, int [I, float 11); int impexrecomp (float **, float, float, float [I , int 11 ,

int, int (*)(float, float [I, float **, int), void ( * ) (float, float [I, float [I, int));

int impexlargestep (int, float 11 , float, float *, float *, float *, float [I, float [ I , float [I, float, float, float [I , float [I , float [I , float [I, float [I, float [I, int [I, int [I, float [I , float **, float ** , float, void ( * ) (float, float [I, float [I, int), int ( * ) (float, float [I, float ** , int));

void impexbackdiff (int, float [I, float [I, float [I, float [I, float [I, float [I, float [I, float [I, float **, float **) ;

int i,k,eci,*psl,*ps2,start,two,halv; float t, tl, t2, t3, tp, h, h2, hnew,alf, lq, *y, *z, *sl, *s2, *S3, *Ul,

*~3,*~1,*~2,*~3,*ehr,**r,**rf,**a2.err[41, alfl,c0,cl,c2,~3,**kof,e[51 ,d[51 , b O , b l , b 2 , b 3 , ~ , s l ~ ~ s n ~ ~ r ;

if (presch) h=hO ;

else { if (hO > hmax)

h=hmax; else

h=hO ; if (h z (tend-to) /4.O) h=(tend-to) 14.0;

\ hnew=h; alf=O .O; t=tp=to; inivec(l,3,err,0.0); inivec(l,n,ehr,O.O) ; duprowvec(l,n, l,r,yO) ; (*control) (&tp, t, h, hnew, r,err,n, tend) ; Init : / * initialization * / h2=hnew; h=h2/2.0 ; dupvec (1,n. O,sl,yO) ; dupvec(l,n,O,s2,yO); dupvec(l,n,O,s3,yO); dupvec(l,n,O,wl,yO) ; duprowvec(l,n, l,r, yo) ; inivec(l,n,ul,O.O) ; inivec(l,n,w2,0.0) ;

Copyright 1995 by CRC Press, Inc

Page 456: Numerical Library in C for Scientists and Engineers A

t3=2.0*t2+1.0; if (impexrecomp (al, h, t, sl,psl,n, available, deriv) goto Miss; if (impexrecomp(a2,h2,t,wl,ps2,n,available,deriv)) goto Miss; start=l; for (eci=O; ecic=3; eci++) {

/ * one large step * / if (impexlargestep (n, y, t, &tl, &t2,&t3, sl, s2, s3, h, h2,

z,ul,u3,wl,w2,~3,psl,ps2,weights, al,a2,eps,deriv,available)) goto Miss;

t += h2; if (eci > 0) {

/ * backward differences */ impexbackdiff (n,ul,u3,wl,w2,w3,sl,s2,s3,r,rf); (*update) (weights, s2,n) ;

1 1

eci=4 ; Mstp : if (hnew != h2) {

eci=l; / * change of information */ cl=hnew/h2; c2=c1*c1; c3=c2*c1; kof 121 [21 =cl; kof [21 [31= (cl-c2) /2 .O; kof [21 [41=~3/6.0-c2/2 .O+c1/3 .O; kof 131 [31 =c2: - - - - . kof [31 [41 =c2-c3; kof [41 141 =c3; for (i=l; ic=n; i++) ul [il =r 121 [il +r [31 [il/2.O+r [41 [il/3.0; alfl=matvec(l,n,l,rf,ul)/vecvec(l,n,~,ul,ul~ ; alf= (alf+alfl) *cl; for (i=l; i<=n; i++) {

e [l] =rf [l] [i] -alfl*ul [il ; e [2] =rf [2] [i] -alfl*2.0*r [31 [il ; e [3] =rf [31 [il -alfl*4.0*r 141 [il ; e 141 =rf [41 [il ; d [ll =r [ll [il ; rf [I] [il = e [ll *= c2; for (k=2; k<=4; k++) {

r [k] [i] =d[k] =matmat (k,4,k,i, kof ,r) ; rf [k] [i] =e [kl =c2*matvec (k, 4, k, kof, e) ;

1

~2 [ij =sl [il - (d [2i+e'~1/2.0) ; s3 [i] =s2 [i] - (a121 +e 121 ) + (dI31 +e 131 /2 $0) ;

) t3=t-hnew; t2=t-hnew/2.0; tl=t; h2=hnew; h=h2/2.0; err[ll=O.O; if (halv) {

for (i=l; i<=n; i++) ps2 dupmat (l,n, 1,n,a2,al) ;

if (two) { for (i=l; i<=n; i++) psl dupmat (l,n,l,n,al,a2) ;

1 else if (impexrecomp(al,hnew/2.0,t,sl,psl,

n,available,deriv)) goto Miss; if (!halv)

if (impexrecomp (a2, hnew, t, wl, ps2, n,available,deriv)) goto Miss;

/ * one large step */ if (impexlargestep (n, y, t, &tl, &t2,&t3, sl, s2,s3, h,h2,

Copyright 1995 by CRC Press, Inc

Page 457: Numerical Library in C for Scientists and Engineers A

z,ul,u3,wl,w2,~3,psl,ps2,weights, al,a2,eps,deriv,available)) goto Miss;

)* one large step * / if (irnpexlargestep(n,y,t,&tl,&t2,&t3,sl,s2,~3,h,h2,

z,ul,u3,wl,w2,~3,psl,ps2,weights, al, a2, eps, deriv, available) ) goto Miss;

/ * backward differences */ irnpexbackdif f (n, ul, u3, wl, w2,w3, sl, s2, s3, r, rf) ; (*update) (weights, s2,n) ; / * error estimates * / ~o=cl=c2=c3=o.o; for (i=l; ic=n; i++) {

wzweights [il *weights [il ; bO=rf [41 [il /36.0; cO += bO*bO*w; lr=fabs (b0) ; bl=rf [I1 [il +alf *r (21 ti1 ; cl += bl*bl*w; b2=rf [31 [il : - - - - . c2 += b2*b2*w; sll=fabs (rf 111 [il -rf 121 [il ) ; sn = (s11 < 1.0e-10) ? 1.0 : fabs(rf [I] [il -r[4l [i1/6.0) /sll; if (sn > 1.0) sn=l.O; if (start) {

sn *= sn*sn*sn; lr *= 4.0;

1 ehr [il =b3=sn*ehr [il +lr; c3 += b3*b3*w;

bO=err [ll ; err [ll =bl=sqrt (c0) ; err [21 =sqrt (cl) ; err [31 =sqrt (c3) +sqrt (c2) /2 .O; lq=eps/( (b0 c bl) ? bl : bO) ; if (bO c bl && lq >= 80.0) lq=10.0; if (eci c 4 && lq > 80.0) lq=20.0; halv=two=O; if (!presch) {

if (lq < 1.0) { / * reject */ if (start) {

hnew=pow (lq, l.O/5.0) *h/2.0; goto Init;

} else { for (k=l; kcd; k++) elmrow(l,n,k,k+l,r,r,-1.0); for (k=l; kc=3; k++) elmrow(l,n,k,k+l,r,r,-1.0); for (k=l; kc=4; k++) elmrow(l,n,k,k+l,rf,rf,-1.0); t -= h2; halv=l; hnew=h; goto Mstp;

1 } else {

/ * step size */ if (lq < 2.0) {

halv=l; hnew=h;

) else { if (lq > 80.0)

hnew= ( (lq > 5120.0) ? pow(lq/5.0,1.0/5.0) : 2.0) *h2; if (hnew > hrnax) hnew=hmax; if (tend > t && tend-t c hnew) hnew=tend-t; two= (hnew == 2.0*h2) ;

Tryck : if (tp <= t) (*control) (&tp,t,h,hew,r,err,n,tend); if (start) start=O; if (hnew == h2) t += h2;

Copyright 1995 by CRC Press, Inc

Page 458: Numerical Library in C for Scientists and Engineers A

eci++ ; if (t c tend+h2)

goto Mstp; else

goto End; Miss : *fail = presch; if ( ! (*fail) ) {

if (eci > 1) t - = h2; halv=two=O; hnew=h2/2.0; if (start)

goto Init; else

goto Tryck; 1 End : free-integer-vector(ps1,l); free-integer-vector(ps2,l); f ree-real-vector (y, 1) ; f ree-real-vector ( z , 1) ; f ree-real-vector (sl, 1) ; f ree-real-vector (s2,l) ; free-real-vector (s3,l) ; free-real-vector (ul, 1) ; free-real-vector (~3.1) ; f ree-real-vector (wl, 1) ; free-real-vector (w2,l) ; free-real-vector (w3,l) ; free-real-vector (ehr, 1) ; free-real_matrix(r,l,5,1); free-real-matrix(rf, 1,5,1) ; f ree-real-matrix (al, 1, n, 1) ; f ree_real_matrix(a2,1, n, 1) ; f ree-real-matrix (kof ,2,4,2) ;

I int impexrecomp(f1oat **a, float h, float t, float y[l , int psIl ,

int n, int (*available) (float, float [I , float **, int) , void (*deriv) (float, float [I , float [I , int) )

I / * this function is internally used by IMPEX * /

int i,j; float sl,aux[4] ,ss, *fl, *f2;

sl=h/2.0; if ( ! (*available) (t,y,a,n)) {

f l=allocate-real-vector (1, n) ; f2=allocate-real-vector(1,n); (*deriv) (t,y,fl,n) ; for (i=l; ic=n; i++) {

ss=l. 0e-6*y [il ; if (fabs (ss) < 1.0e-6) ss=l.Oe-6; y[il += ss; (*deriv) (t,y,f2,n); for (j=l; jc=n; j++) a[jl [il=(f2[jl -flIjl)/ss; y[il -= ss;

1 I

f ree-real-vector (f 1'1) ; free-real-vector (f 2,l) ;

\ for (i=l; ic=n; i++) {

mulrow(l,n,i,i,a,a, -sl) ; a [il [il += 1.0;

I aux [2 1 =FLT-EPSILON; dec (a,n,aux,ps) ; if (auxf31 c n)

return 1; else

return 0; 1

Copyright 1995 by CRC Press, Inc

Page 459: Numerical Library in C for Scientists and Engineers A

int impexlargestep(int n, float y[l , float t, float *tl, float *t2, float *t3, float sl [I , float s2 [I, float s3 [I , float h, float h2, float z [I, float ul [I, float u3 [I , float wl [I, float w2 [I , float w3 [I, int psl [I, int ps2 [I , float weights[], float **al, float **a2, float eps, void (*deriv) (float, float [I, float [I, int), int (*available) (float, float [I , float **, int) )

f / * this function is internally used by IMPEX * /

int impexiterate (float [ I , float [ I , float **, float, float, float [I , int [ I , int, float, void ( * ) (float, float [I, float [I, int) , int ( * ) (float, float [I , float **, int) ) ;

float a,b,c;

a= (t+h- (*tl) ) / ( (*tl) - (*t2) ) ; b=(t+h- (*t2) ) / ( (*tl) - (*t3)) ; C= (t+h- (*tl) ) / ( (*t2) - (*t3) ) *b; b *= a; a += l.O+b; b=a+c-1.0; mulvec(l,n,O,z,sl,a) ; elmvec(l,n,O,z,s2, -b) ; elmvec(l,n,O,z,s3,c) ; if (impexiterate (z, sl, al, h, t+h/2.0,weights,psl,

n, eps, deriv, available) ) return 1;

if (impexiterate (z, y, al, h, t+3.0*h/2.0,weights,psl, n,eps,deriv,available)) return 1;

dupvec (l,n, O,u3 ,ul) ; dupvec(l,n, O,ul,y) ; dupvec(l,n, O,s3,s2) ; dupvec(l,n,O,s2,sl); dupvec(l,n,O,sl, z) ; elmvec(l,n,O, z,wl,l.O) ; elmvec(l,n,O,z,s2,-1.0) ; if (impexiterate(z,wl,a2,h2,t+h,weights,ps2,

n, eps, deriv, available) ) return 1; (*t3)=(*t2) ; (*t2) = (*tl) ; (*tl) =t+h2; dupvec(l,n,O,w3,~2) ; dupvec(l,n,O,w2,wl); dupvec(l,n,O,wl,z); return 0;

1 int impexiterateffloat z[l, float y[l, float **a, float h, float t,

float weights [I , int ps [I , int n, float ePs, void (*deriv) (float, float [I, float [I, int), int (*available) (float, float [I , float **, int) )

1 I

/* this function is internally used by IMPEXLARGESTEP (IMPEX) */

int i,it,lit,fail; float max,maxl,conv,*dz,*fl,temp;

fl=allocate-real-vector(1,n) ; dz=allocate-real-vector(1,n); for (i=l; i<=n; i++) z [il = (z [il +y [ill /2.0; it=lit=l; conv=l .0 ; fail=O; while (1) {

Copyright 1995 by CRC Press, Inc

Page 460: Numerical Library in C for Scientists and Engineers A

deriv(t, z,fl,n) ; for (i=l; 1c=n; i++) f 1 [i] =dz [i] = z [il -h*fl [il/2.0-y [il ; sol(a,n,ps,dz) ; elmvec(l,n,O,z,dz, -1.0); max=O. 0 ; for (i=l; ic=n; i++) {

tempzweights [il *dz [il ; rnax += temp*temp;

&ax=sqrt (max) ; if (max*conv c eps/l0.0) break; it++; if (it ! = 2) {

conv=max/maxl; if (conv > 0.2) {

if (lit == 0) { fail=l; break;

lit=O; conv= 1 .0 ; it=l; if (impexrecomp(a,h,t,z,ps,n,available,deriv)) {

fail=l; break;

1 1

1 maxl=max ;

1 if (!fail)

for (i=l; ic=n; i++) z [il=2.0*z [il -y [il ; f ree-real-vector (f 1,l) ; f ree-real-vector (dz, 1) ; return fail;

1 void impexbackdiff(int n, float ul[l, float u3 [I, float wl[l,

float w2 [I , float w3 [ I , float sl [I , float s2 [I , float s3 [I, float **r, float **rf)

1 L

/* this function is internally used by IMPEX */

int i,k; float bO,bl,b2,b3;

for

1 1

(i=l; ic=n; i++) ( bl= (ul [i] +2.0*s2 [i] +u3 [il ) /4.0; b2= (wl [i]+Z.O*wZ [i] +w3 [il ) /4.0; b3= (s3 [i] +2.0*u3 [il +s2 [i] ) /4.0; b2= (b2-b1) /3.0; bO=bl-b2; b2 -= (sl [il -2.O*s2 [il +s3 [il ) /l6.O; bl=2.0*b3- (b2+rf [l] [il ) - (bO+r [ll [il ) /2.0; b3=0.0; for (k=l; kc=4; k++) (

bl - = b3; b3=r [kl [il ; r [kl [il =bO; bO -= bl;

1 I r [51 [il =bO; for (k=l; kc=4; k++) {

b3sf [kl [il ; rf [kl [il =b2; b2 -= b3;

1 rf [51 [il =b2;

5.4.3 First Order - Several derivatives available

Copyright 1995 by CRC Press, Inc

Page 461: Numerical Library in C for Scientists and Engineers A

A. modifiedtaylor

Solves an initial (boundary) value problem, given as a system of first order differential equations

~ u O ( t ) = h")(u,t) (j=mO,mO+l, ..., m) (1) where D=d/dt, with u(tJ prescribed, over the interval to I t 5 te, by means of a one-step Taylor method [Vh70a, VhBDS71, VhK711. This procedure is suitable for the integration of large systems arising from partial differential equations, provided that higher order derivatives can be easily obtained.

The method used has the form

where, with uk being an approximation to u(tJ, c," = Diu(t) at t=tk, and rk is the stepsize, so that tk+, = tk + rk (k=0,1, ...). The method is p-th order consistent if Bj = I/j! Cj=O,l, ...,p).

In the following 1 1 . 1 1 denotes either the maximum or Euclidean norm. Which of these is used during the execution of modlfiedtaylor depends upon the input parameter norm upon call: 1 in the first case, # I in the second.

The stepsize is determined by considerations of accuracy and stability. With regard to the former, it is assumed that the local error p(r) = 11 u(tk+J - uk+] I( is approximated by the discrepancy jlv(t,+,J - u,, I ) , where v(t) is the analytic solution to equation (1) with the initial values v(tJ = u,. For the p-th order exact method (2)

are taken to be approximations to the discrepancy. It is further assumed that these estimates of the discrepancy may themselves be approximated by expressions of the form

pkV(7 J = Cr; (k l ) , pk'(rJ = (Btk + C)r; (k=2) (4)

p,'(TJ = (AtkZ + Btk + C)r$ ( k 3 ) where A, B, C are constants determined from fitting the given estimates at previous values of tk, q being n if p = n and p+l otherwise. With the estimates (4) of the discrepancy in hand, the stepsize racc, obtained from considerations of accuracy is to be determined by use of a relationship of the form

P k '(7k) = Vk ( 5 ) where II, = qab, + uk 11, rl,b, and II,, being absolute and relative tolerance provided by the user. modifiedtaylor takes

rucc, = T.&j 11 c," 11 at the first step,

racc, = min(1 Oracc ,, (VJ 11 c f ) 11 )(ql/p, '(70)) 'Iq)

Copyright 1995 by CRC Press, Inc

Page 462: Numerical Library in C for Scientists and Engineers A

at the second, and racck = min(l0racc (%I/ 11 c,(Ii 11 )(rlJP ' ( ~ ~ - 3 ) " ~ )

at subsequent step until the value of the left hand expression in equation (5) exceeds that of the expression upon the right; then equation (5) is used.

The stepsize bound rstab, determined from considerations of stability is given by tstab, = J(n) / u(JJ

where J(n) is the range constant of the stability polynomial

associated with the method (2), and u(JJ is an upper bound for the spectral radius with respect to the eigenvalues in the left half-plane of the Jacobian matrix J, whose elements are

~ ~ ( ~ J ) = a h ( ~ - ~ ~ + ~ ) ( u , t ) / a u ~ - ~ ~ + ~ ) ( t ) (i,j=1,2, ..., m-mO+l) as t ranges over [t, t,+rbd,], rbd, being a bound for 7,.

The user should provide values of rmin, a lower bound for the stepsize, and a > 1, a stepsize amplification factor. rmin is overridden by considerations of stability, but not of accuracy (thus max(rmin, racc,) is one of the lower bounds for the stepsize). The stepsize is taken to be min(max(racc. rmin), rstab,) when k=O and

7, = r n a ~ ( % r ~ - ~ , min(max(racc, rmin), ?stabb (YT~.])) thereafter. The upper bound rbd, upon r, required in the determination of u(JJ above, is racc, when k=O and ark-, otherwise.

The successive derivatives DuO)(t) (i=l, ..., n; j=m0, ..., m) are computed by use of a procedure derivative provided by the user.

Function Parameters: void modifiedtaylor

(t,te,mO,m, u,sigma, taumin,derivative, k,data,alfa,norm,aeta,reta,eta,rho, out) t: float *;

the independent variable; entry: initial value to; exit: the final value te;

te: float; entry: the final value of t (te 2 t);

m0,m: int; entry: indices of the first and last equation of the system to be solved;

u: float u[mO:m]; the dependent variable; entry: the initial values of the solution of the system of differential equations at t=tO; exit: the values of the solution at t=te;

sigma: float (*sigma)(t,mO,m); this procedure should deliver the spectral radius of the Jacobian matrix with respect to those eigenvalues which are located in the left half-plane; if sigma tends to infinity, procedure mod$edtaylor terminates;

taumin: float; entry: minimal step length by which the integration is performed (value of rmin

above); however, actual stepsizes will always be within the interval

Copyright 1995 by CRC Press, Inc

Page 463: Numerical Library in C for Scientists and Engineers A

[min(hmin,hstab),hstab], where hstab (= data[O]/sigma) is the steplength prescribed by stability considerations;

derivative: void (*derivative)(t, mO, m, i, a); when this procedure is called, array a[mO,m] contains the components of the (i-1)-th derivative of u at the point t; upon completion of derivative, array a should contain the components of the i-th derivative of u at the point t;

k: int *; exit: indicates the number of integration steps performed; on entry k=O;

data: float data[-2:data[-211; entry: data[-21: the order of the highest derivative upon which the Taylor method is based

(value of n above); data[-11: order of accuracy of the method (value of p above); data[O]: stability parameter (value of J(n) above); data[l], . . ., data[data[-211: polynomial coefficients (values of J, above, j= 1 ,..,n);

alfa: float; entry: growth factor for the integration step length (value of a above);

norm: int; entry: if norm=l then discrepancy and tolerance are estimated in the maximum norm,

otherwise in the Euclidean norm; aeta: float (*aeta)(t,mO,m);

this procedure should return the absolute accuracy (value of a,, above); reta: float (*reta)(t,mO,m);

this procedure should return the relative accuracy; (value of II,, above); if both aeta and reta are negative, accuracy conditions will be ignored;

eta: float *; exit: computed tolerance;

rho: float *; exit: computed discrepancy;

out: void (*out)(t,te,mO,m, u,k,eta,rho); after each integration step the user can print some parameters such as t, u, k, eta, rho.

Function used: vecvec.

void modifiedtaylor(f1oat *t, float te, int mO, int m, float u[l, float (*sigma) (float, int, int) , float taumin, void (*derivative) (float, int, int, int, float [ I ) , int *k, float data [ I , float alfa, int norm, float (*aeta) (float, int, int) , float (*reta) (float, int, int) , float *eta, float *rho, void (*out) (float, float, int, int, float [ I ,

int, float, float))

' float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); float vecvec (int, int, int, float [ I , float [ I ; int i,n,p,q,start,stepl,last,j; float ecO,ecl,ec2,tauO,taul,tau2,taus,t2,t0,ta~,ta~i,ta~e~,

ecl,betan,gamma,*c,*beta,*betha,ifac,tauacc,taustab, aa,bb,cc,ec,s,x,b;

Copyright 1995 by CRC Press, Inc

Page 464: Numerical Library in C for Scientists and Engineers A

i=O; start= (*k == 0) ; to= (*t) ; / * coefficient * / ifac=l. 0 ; gamma=0.5; p=data [-11 ; betaredata [Ol ; q = (p c n) ? p+l : n; for (j=l; jc=n; j++) (

beta [jl =data []I ; ifac /= j; betha[jl =ifac-beta[jl ;

1 if (p == n) betha[nl =ifac; last=O; do

/ * step size * / s=o.o; if (norm == 1)

for (j=mO; j<=m; j++) { x=fabs (u[jl) ; if (X > S) S=X;

1 else

s=sqrt (vecvec (m0, m, 0, u, u) ) ; / * local error bound * / *eta = (*aeta) (*t,mO,m) + (*reta) (*t,mO,m) *s; if (*eta > 0.0) {

if (start) ( if (*k == 0) (

for (j=mO; j<=m; j++) c[jl=u[jl; i=1; (*derivative) (*t,mO,m, i, c) ; s=o.o; if (norm == 1)

for (j=mO; j<=m; j++) ( x=fabs(c [jl ) ; if (X > S) S=X;

else' s=sqrt (vecvec (mO,m, 0, c, c) ) ;

tauacc= (*eta) /s; stepl=l;

} else if (stepl) ( tauacc=pow( (*eta) /(*rho), l.0/q) *tau2; if (tauacc > lO.O*tau2)

tauacc=lO.O*tau2; else

stepl=O; } else (

bb= (ec2-ecl) /taul; cc=ec2-bb*t2; ec=bb* (*t) +cc; tauacc = (ec < 0.0) ? tau2 : pow( (*eta) /ec,l.O/q) ; start=O;

1

bb= (ec2-ecl) /taul-aa* (2.0*t2-taul) ; cc=ec2-t2* (bb+aa*t2) ; ec=cc+ (*t) * (bb+ (*t) *aa) ; tauacc = (ec < 0.0) ? taus : pow ( (*eta) /ec, l.O/q) ; if (tauacc > alfa*taus) tauacc=alfa*taus; if (tauacc < gamma*taus) tauacc=gamma*taus;

I elLe tauacc=te- (*t) ;

if (tauacc < taumin) tauacc=taumin; taustab=betan/ (*sigma) (*t ,mO,m) ; if (taustab c 1.0e-12* ( (*t) -to) ) (

Copyright 1995 by CRC Press, Inc

Page 465: Numerical Library in C for Scientists and Engineers A

(*out) (*t, te,mO,m,u, *k, *eta, *rho) ; break;

I tau = (tauacc > taustab) ? taustab : tauacc; taus=tau; if (tau >= te- (*t)) {

tau=te- (*t) ; last=l;

1 tauo=taul; taul=tauZ; tauZ=tau; (*k) ++; i=O ; / * difference scheme * / for (j=mO; jc=m; j++) c[jl=u[jl; taui=l .O; do (

taui *= tau; b=beta [il *taui; if (*eta > 0.0 && i >= p) (

/ * local error construction * / if (i == p) {

ecl=O.O; tauec=l.O;

1 if (i > p+l) tauec *= tau; s=O . 0 ; if (norm == 1)

for (j=mO; jc=m; j++) { x=fabs(c[jl); if (X > S) S=X;

1 else'

s=sqrt(vecvec(m0,m,0,c,c)); ecl += fabs (betha [il ) *tauec*s; if (i == n) {

ecO=ecl; ecl=ecZ ; ecZ=ecl; *rho = ecl*pow (tau, q) ;

1

;or (j=mo; jc=m; j++) u[jl += b*c[jl; ) while (i < n); t2= (*t) ; if (last) {

last=O; (*t) =te;

) else (*t) += tau;

(*out) (*t, te,mO,m,u, *k, *eta, *rho) ; ) while (*t ! = te) ; free real vector (beta, 1) ; f reeIrealIvector (betha, 1) ; f ree-real-vector (c,mO) ;

I

B. eft

Solves an initial value problem, given as a system of first order differential equations Du")(t) = 8)(u,t) (j=mO,mO+l, ..., m) (1)

where D=d/dt, with u(tJ prescribed, over the interval to 4 t 4 te, by means of a third order, first order consistent, exponentially fitted Taylor series method [see Vh70b, VhBDS711. Automatic stepsize control is provided. This procedure is suitable for the integration of stiff differential equations, provided that higher order derivatives can be easily obtained.

Copyright 1995 by CRC Press, Inc

Page 466: Numerical Library in C for Scientists and Engineers A

The method used has the form u,,, = u, + c,(lihk + J,(hd~,(~)h; + J3(hJci3)h k3 (2)

where, with u, being an approximation to u(tJ, c," = Du(Q at t=t,, and h, is the stepsize, so that t,,, = t, + h, (k=0,1, ... ).

It is supposed that over the range t,St St,+hbd,, where hbd, is an upper bound for h,, those eigenvalues of the Jacobian matrix J,, whose elements are

~, ( i j ) = ago"O+l)(u,t) / a~~-~O+"(t) (i,j=1,2, ..., m-mo+l),

lying in the left half-plane and not in the neighbourhood of the origin are clustered within two circles with centers at

(0 < a, < oo, nI2 < 4, < n) of equal radii d6,. The coefficients J2(hJ and J3(hJ are determined by imposing the condition that, with

P,(z) = I + z + J2(hJz2 + J3(hJz3 P3(z) = e' when z = hk6, z = hkconj(6,); it then follows that

where b = hk6,. When b is small, J2(h J = 1/2 - b2/24, J,(hJ = 1/6 + bcos4J12. In the following, 11 .I/ denotes either the maximum or Euclidean norm. Which of these

is used during the execution of eft depends upon the value of the parameter norm upon call: 1 in the first case, $1 in the second.

The coefficients J2(hJ, J3(h J in the scheme (2) depend upon h,: the discrepancy p '(uJ between the local analytic solution of equation (1) and its approximation yielded by use of the scheme (2) is not accurately estimated by substitution of the local solution into formula (2) (this process yields useful results only when the coefficients of the stability polynomial of the numerical integration procedure being used are constant, as is the case with, for example, modiJiedtaylor). The discrepancy is now to be estimated in terms of a residual function {(h) (i.e. a measure of the difference between the values of the expressions upon the two sides of equation (1)) resulting from use of the scheme (2) in which the steplength is taken to be an independent variable. Taking uJ(h) to be an approximation to u(t,+h) produced by use of formula (2),

u '(h) = u, + c,(/i + J,(h)~,(~)h, + J,(h)~,(~)h~ from which

DU '(h) = cf) + J "(h) c," + J ', (h)ci3)h2 where, with b = a&,

The residual function S',(h) is defined by the formula

Copyright 1995 by CRC Press, Inc

Page 467: Numerical Library in C for Scientists and Engineers A

so that h 11 Ik(h) 11 = 11 g(U '(h),tk+h)h - c,'"h - ;(h)~,(~)h~ - P ',(h)~,'~)h~ 11 .

If the discrepancy p ',(h) is defined to be

then approximately p ',(h) = h 11 fk(h) 11 . An upper bound hacc, upon h, derived from considerations of accuracy is thus given by

P 'dhaccJ = 7k = 70 + qre II ~k II (6) where, ~l, and qre being prescribed absolute and relative tolerances, p ; is as defined by formulae (3,4,5). The value of p ',(h) is predicted from previous determinations by use of the formula

p '(h) = (Ah + Bt + C)hQm where with b = ah (a being the spectral radius of the Jacobian matrix derived from equation (1) at the point t) and Q(b) = 4 - 2bl3 if 0 < b < 312, (30-2b)/9 if 312 I b < 6 and 2 otherwise, the coefficients A, B and C are determined by three substitutions tk-,, h,,; tk-,, h,; tk-,, h,,. If h,, has the critical value h, = hk-;/hk-,, the value of A determined as above becomes infinite. For this reason h, is, at each stage, excluded from the interval [(l -t/~)h,, (1 +t/e)h,], where E is the machine precision. Also it may occur that A is negative; in this case the extrapolation formula p '(h) = ChQ@) is used. Except when A is negative, hacc, is determined from the equation

eft takes

' l o hacc, = - Il cots II

at the first step

at the second, and

Copyright 1995 by CRC Press, Inc

Page 468: Numerical Library in C for Scientists and Engineers A

at subsequent steps until the value of the left hand side in equation (6) (predicted as above) exceeds that of the expression upon the right; then equation (6) is used to determine hacc,.

When sin+, is not small, I P3(z) I 5 1 over the disc 1 z - ha, 1 S 1 / 2sin+,; when sin+, is small, I P3(z) I 5 1 when 1 z + h6,l 5 (huJ1". Thus if the eigenvalues of the Jacobian matrix J, (defined above) clustered about two points 6,, conjugate(6,) lie within discs of radius d6, the method (2) is stable if h, < hstab, where

hstab, = min [uJ(d6,sin+J, 4u;/dC] 1 a,. The user should provide values of hmin, a lower bound for the stepsize, and a > 1, a stepsize amplification factor. hmin is overridden by considerations of stability but not of accuracy (thus max(hmin,hacc,) is one of the lower bounds for the stepsize). The stepsize is taken to be min(max(hacc,,hmin),hstab,) when k=O, and h, = max(h, ,/2,min(max(hacc,,hmin),hstab,arJ1,,)) thereafter, where until formula (6) is used to determine hacc, (see above) ark is the user's amplification factor a , and thereafter

The upper bound hbd, upon h, required in the determination of u(JJ above, is hacc, when k=O and ar,h,, otherwise.

It may occur that the user wishes to integrate equation (1) over a succession of intervals [tof'),te"] (I=0,1, ...) where trl)=te". In this case he should set k=O prior to the first call of eft and leave k unchanged at subsequent calls. During these subsequent calls, eft continues normal operation (without special determinations of hacc,, hacc,, etc.). The current value of h, at return from a call of eft is allocated by this procedure to hstart, for use at the start of the next call.

The successive derivatives Diuo)(t) (i=1,2,3; j=mO, ..., m) are computed by use of a procedure derivative which the user must provide.

Function Parameters: void eft

(t, te,mO,m, u,sigma,phi,diameter,derivative, k,ava,norm,aeta,reta,eta,rho, hmin, hstart, out) t:

te:

float *; the independent variable; entry: initial value to; exit: the final value te; float; entry: the final value of t (te 2 t);

m0,m: int; entry: indices of the first and last equation of the system to be solved;

u: float u[mO:m]; the dependent variable; entry: the initial values of the solution of the system of differential equations at t=tO; exit: the values of the solution at t=te;

Copyright 1995 by CRC Press, Inc

Page 469: Numerical Library in C for Scientists and Engineers A

sigma: float (*sigma)(t,mO,m); this procedure should deliver the modulus of the (complex) point at which exponential fitting is desired (value of a, above); for example an approximation to the modulus of the center of the left hand cluster;

phi: float; entry: the argument of the (complex) point at which exponential fitting is desired

(value of 4, above); phi should have a value in the range [.x/2,n]; diameter: float (*diameter)(t, mO, m);

this procedure should deliver the diameter of the left hand cluster (value of d& above); derivative: void (*derivative)(t, mO, m, i,a);

i assumes the values 1,2,3 and a is a one-dimensional array a[mO:m]; when this procedure is called, array a contains the components of the (i-1)-th derivative of u at the point t; upon completion of derivative, array a should contain the components of the i-th derivative of u at the point t;

k: int *; exit: indicates the number of integration steps performed; on entry k-0;

alfa: float; entry: maximal growth factor for the integatibn step length (value of a above);

norm: int; entry: if norm=l then discrepancy and tolerance are estimated in the maximum norm,

otherwise in the Euclidean norm; aeta: float (*aeta)(t, mO, m);

this procedure should return the absolute local accuracy (value of q, above); aeta should be positive;

reta: float (*reta)(t, mO, m); this procedure should return the relative local accuracy; (value of g, above); reta should be positive;

eta: float *; exit: computed tolerance;

rho: float *; exit: computed discrepancy;

hmin: float; entry: minimal stepsize by which the integration is performed;

however, a smaller step will be taken if hmin exceeds the stepsize hstab, prescribed by the stability conditions; if hstab becomes zero, the procedure terminates;

hstart: float *; entry: the initial stepsize;

however, if k = 0 on entry then the value of hstart is not taken into consideration; exit: a suggestion for the stepsize (current value of h, above), if the integration

should be continued for t > te; hstart may be used in successive calls of the procedure, in order to obtain the solution in several points tel, te2, etc.;

out: void (*out)(t,te,mO,m, u, k,eta,rho); after each integration step the user can print some parameters such as t, u, k, eta, rho.

Functions used: inivec, dupvec, vecvec, elmvec.

Copyright 1995 by CRC Press, Inc

Page 470: Numerical Library in C for Scientists and Engineers A

void eft (float *t, float te, int mO, int m, float u[l , float (*sigma) (float, int, int) , float phi, float (*diameter) (float, int, int) , void (*derivative) (float, int, int, int, float 11 ) , int *k, float alfa, int norm, float (*aeta) (float, int, int), float (*reta) (float, int, int) , float *eta, float *rho, float hmin, float *hstart, void (*out) (float, float, int, int, float [I,

int, float, float) )

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void inivec (int, int, float [I , float) ; void dupvec (int, int, int, float [I , float [I ) ; float vecvec (int, int, int, float 11 , float [I ) ; void elmvec (int, int, int, float 11 , float [I , float) ; int kl,last,start,j,i,ext,extrapolate; float q,ec0,ecl,ec2,h,hi,hO,hl,h2,betan,t2,sigmal,phil,*c,

*ro, beta [41 ,betha [41 , s,x, hacc, hstab, hcr, hmax, a, b, cc, bl,bZ,bb,e,betaz,beta3, ~o,fc,bo,fb,aO,fa,dO,fd,fdb,fda,w,mb,tol,~m,pO,qO;

start=l; last=O; dupvec (mO,m, 0, c,u) ; (*derivative) (*t,mO,m, 1,c) ; if (*k == 0) (

/ * local error bound * / s=o.o; if (norm == 1)

for (j=mO; j<=m; j++) { x=fabs(u[jl) ; if (X > s) s=x;

1 else'

s=sqrt (vecvec (mO,m, O,u,u) ) ; *eta = (faeta) (*t,mO,m)+(*reta) (*t,mO,m)*s; s=o.o; if (norm == 1)

for (j=mO; jc=m; j++) ( x=fabs(c[jl 1 ; if (X > s) s=x;

\ else'

s=sqrt (vecvec (mO,m, 0, c, c) ) ; *hstart = (*eta)/s;

1 do (:

/ * difference scheme * / hi=1.0; sigmal= (*sigma) (*t,mO,m) ; phil=phi; / * step size * / if (!start) (

/ * local error bound * / s=o.o; if (norm == 1)

for (j=mO; j<=m; j++) ( x=fabs(u[jl ) ; if (X > s) S=X;

else' s=sqrt (vecvec (m0, m, 0, u, u) ) ;

*eta = (*aeta) (*t,mO,m)+(*reta) (*t,mO,m)*s;

if (start) hl=h2=hacc=(*hstart);

Copyright 1995 by CRC Press, Inc

Page 471: Numerical Library in C for Scientists and Engineers A

ec2=ecl=l.0; kid; startd;

) else if (kl < 3) ( hacc=pow( (*eta) / (*rho), l.O/q) *h2; if (hacc > lO.O*hZ)

hacc=lO.O*h2; else

kl++ ; ) else {

a= (hO* (ec2-ecl) -hl* (ecl-ecO) ) / (h2*h0-hl*hl) ; h=h2* ( (*eta c *rho) ? pow( (*eta) / (*rho), l.O/q) : alfa) ; if ( a > 0 . 0 ) (

b=(ec2-ecl-a*(h2-hl))/hl;

hacc=O. 0; hmax=h; / * find zero * / bO=hacc; fb=pow (hacc, q) * (a*hacc+b* (*t) +cc) - (*eta aO=hacc=h; fa=pow (hacc, q) * (a*hacc+b* (*t) +cc) - (*eta cO=aO ; fc=fa; ext=O; extrapolate=l; while (extrapolate) {

if (fabs(fc) c fabs(fb)) ( if (cO ! = aO) {

dO=aO; fd=fa;

1

I

tol=l. 0e-3*h2; mm=(cO+bO) *0.5; mb=mm-b0 ; if (fabs (mb) > tol) {

if (ext > 2) w=mb;

else ( if (mb == 0.0)

tol=O.O; else

if (mb c 0.0) to1 = -tol; p0= (b0-a0) *fb; if (ext c= 1)

qO=fa-fb; else {

fdb= (fd-fb) / (do-bO) ; fda= (fd-fa) / (do-a0) ; pO *= fda; qO=fdb*fa-fda*fb;

) if (PO c 0.0) (

po = -PO; qo = -qo;

1

) dO=aO ; fd=fa; aO=bO ; fa=fb; hacc = bO += w; fb=pow (hacc, q) * ( ( if ((fc >= 0.0)

co=aO :

a*hacc+b* (*t) +cc) - (*eta) ; ? (fb >= 0.0) : (fb c= 0.0)) (

Copyright 1995 by CRC Press, Inc

Page 472: Numerical Library in C for Scientists and Engineers A

fc=fa; ext=O;

) else ext = (w == mb) ? 0 : ext+l;

} else break;

h=c0 ; if (!((fc >= 0.0) ? (fb c= 0.0) : (fb >= 0.0)))

hacc=hmax; } else

hacc=h; if (hacc c 0.5*h2) hacc=0.5*h2;

1 if (hacc c hmin) hacc=hmin;

if~~(h*$igmal > 1.0) ( a=fabs ( (*diameter) (*t,mO,m) /S~~~~~+FLT-EPSILON) /2.0; b=2.0*fabs (sin (phil) ;

if (hstab c 1.0e-14: (*t)) break; if (h > hstab) h=hstab;

hcr=h2*h2/hl; if (kl > 2 && fabs(h-hcr) c FLT-EPSILON*hcr)

h = (h c hcr) ? hcr* (1.0-FLT-EPSILON) : hcr*(l.O+FLT-EPSILON);

if ((*t)+h > te) { last=l; *hstart = h; h=te- (*t) ;

1 hO=hl; hl=h2 ; h2=h; / * coefficient * / b=h*sigmal; bl=b*cos (phil) ; bb=b*b; if (fabs(b) c 1.0e-3) (

beta2=0.5-bb/24.0; beta3=1.0/6.0+b1/12.0; betha[31 =O.5+bl/3 .O;

} else if (bl c -40.0) ( beta2=(-2.0*b1-4.0*bl*bl/bb+l.O)/bb; beta3=(1.0+2.0*bl/bb)/bb; betha [3] =l. 0/bb;

} else { e=exp (bl) /bb; b2=b*sin(phil) ; beta2=(-2.0*b1-4.0*bl*bl/bb+l.O)/bb; beta3=(1.0+2.0*bl/bb)/bb; if (fabs(b2/b) c 1.0e-5) (

beta2 - = e* (bl-3.0) ; beta3 += e* (bl-2.0) /bl; betha [3] =l.O/bb+e* (b1-1.0) ;

) else { beta2 - = e*sin(b2-3.0*phil)/b2*b; beta3 += e*sin (b2-2.0*phil) /b2; betha [3] =l. O/bb+e*sin(b2-phil) /b2*b;

1 1

beta [ll =betha [ll =l. 0; beta [21 =beta2; beta [31 =beta3; betha [21 =l. 0-bb*beta3; b=fabs (b) ; q = (b c 1.5) ? 4.0-2.0*b/3.0 :

((b c 6.0) ? (30.0-2.0*b)/9.0 : 2.0); for (i=l; ic=3; i++) (

hi *= h; if (i > 1) (*derivative) (*t,mO,m,i,c) ; / * local error construction * /

Copyright 1995 by CRC Press, Inc

Page 473: Numerical Library in C for Scientists and Engineers A

if (i =P 1) inivec(m0,m,r0,0.0) ; if (i < 4) elmvec(mO,rn, O,ro,c,betha[il *hi) ; if (i =s 4) {

elmvec(mO,m, O,ro,c, -h) ; s=o.o; if (norm == 1)

for (j=mO; j<=m; j++) ( x=fabs(ro[jl); if (X > S) S=X;

J

else s=sqrt (vecvec (mO,m, 0, ro, ro) ) ;

*rho=s; ecO=ecl; ecl=ec2 ; ec2= (*rho) /pow (h, q) ;

1 elmvec (mO,m, O,u,c,beta [il *hi) ;

I t2= (*t) ; (*k) ++; if (last) (

last=O; (*t) =te; start=l;

) else (*t) += h;

dupvec (m0 ,m, 0, c, u) ; (*derivative) (*t,mO,rn, 1, c) ; / * local error construction * / elm~ec(mO,m,0,r0,c,-h); s=o.o; if (norm == 1)

for (j=mO; j<=rn; j++) ( x=fabs(ro[jl) ; if (X > s) S=X;

1 else

s=sqrt (vecvec (m0 ,m, 0, ro, ro) ) ; *rho=s; ecO=ecl; ecl=ec2 ; ec2= (*rho) /pow (h, q) ; (*out) (*t, te,mO,m,u, *k, *eta, *rho) ;

) while (*t ! = te) ; f ree-real-vector (ro,mO) ;

1

5.4.4 Second order - No derivatives right hand side

Solves an initial value problem for a single second order ordinary differential equation dy/& = f(x,y,&/&), from x=a to x=b, y(a) and &(a)/da being given, by means of a 5 t h order Runge-Kutta method with steplength and error control [Z64].

Function Parameters: void rk2 (x,a,b,y,ya,z,za,j$z,e,dJ)

x: float *; the independent variable;

a: float; entry: the initial value of x;

b: float; entry: the end value of x, (b I a is allowed);

Copyright 1995 by CRC Press, Inc

Page 474: Numerical Library in C for Scientists and Engineers A

y: float *; the dependent variable; exit: the value of y(x) at x = b;

ya: float; entry: the initial value of y at x=a;

z: float *; the derivative @/&; exit: the value of z(x) at x = b;

za: float; entry: the initial value of @/& at x=a;

jiyz: float (*jiyz)(x,y,z); the right hand side of the differential equation; jiyz depends on x, y, z, giving the value of dy/&;

e: float e[I:4]; entry: e[l] and e[3] are used as relative, e[2] and e[4] are used as absolute

tolerances for y and @I&, respectively; d: float d[I:5];

exit: d[l]: the number of steps skipped; d[2]: the last step length used; d[3]: equal to b; d[4]: equal to y(b); d[5]: equal to @I&, for x = b;

Ji: int; entry: ifJi is nonzero then the integration starts at x=a with a trial step b-a;

ifJi is zero then the integration is continued with, as initial conditions, x=d[3], y=d[4], z=d[5], and a, ya and za are ignored.

void rk2(float *x, float a, float b, float *y, float ya, float *z, float za, float (*fxyz) (float, float, float), float e [I , float d[l , int fi)

l int last,first,reject,test,ta,tb; float el,e2,e3,e4,xl,yl,zl,h,ind,hmin,hl,absh,kO,kl,k2,k3,k4,

k5,discry,discrz,toly,tolz,mu,mul,fhy,fhz;

if (fi) { d [3] =a; d [4] =ya; d [51 =za;

1 d [ll =O. 0; xl=d 131 ; yl=d [41 ; zl=d[51 ; if (fi) d[21 =b-d[31 ; absh=h=fabs (d [2l ) ; if (b-xl c 0.0) h = -h; ind=fabs (b-xl) ; hmin=ind*e [ll +e 121 ; hl=ind*e [3l +e 141 ; if (hl < hmin) hmin=hl; el=e [ll /ind; e2=e [21 /ind; e3=e [31 /ind; e4=e [41 /ind; first=l;

Copyright 1995 by CRC Press, Inc

Page 475: Numerical Library in C for Scientists and Engineers A

6hile (1) { if (test) {

absh=f abs (h) ; if (absh c hmin) {

h = (h > 0.0) ? hmin : -hmin; absh=hmin;

1 ta= (h >= b-xl) ; tb=(h >= 0.0); if ((ta && tb) I I ( ! (ta I I tb))) {

d [21 =h; last=l; h=b-xl ; absh=fabs (h) ;

) else last=O;

test=l; *x=xl; *y=yl; *z=zl; k0= (*fxyz) (*x, *y, *z) *h; *x=xl+h/4.5; *y=yl+(zl*18.0+k0*2,0)/81.0*h; *z=zl+k0/4.5; kl= (*fxyz) ( *x , *y, *z) *h; *x=xl+h/3 .0 ; *y=yl+(zl*6.0+k0)/18.O*h; *z=zl+ (kO+kl*3.O) /12.0; k2= (*fxyz) (*x, *y, *z) *h; *x=xl+h*0.5; *y=yl+(zl*8.0+kO+k2)/16.0*h; *z=zl+ (kO+k2*3.O) /8.0; k3= (*fxyz) (*x, *y, *z) *h; *x=xl+h*0.8; *y=yl+(zl*100.0+k0*12.0+k3*28.0)/125.0*h; *z=zl+(k0*53.0-kl*135.O+k2*126.0+k3*56.0)/125.0; k4= (*fxyz) (*x, *y, *z) *h; *x = (last ? b : xl+h) ; *y=yl+(zl*336.0+k0*21.0+k2*92.0+k4*55.0)/336.O*h; *z=zl+(k0*133.0-kl*378.0+k2*276.0+k3*112.0+k4*25.0)/168.0; k5= (*fxyz) (*x, *y, *z) *h; discry=fabs((-kD*21.O+k2*108.0-k3*112.0+k4*25.0)/56.O*h); discrz=fabs(k0*21.0-k2*162.0+k3*224.0-k4*125.0+k5*42.0)/14.0; toly=absh* (fabs (21) *el+e2) ; tolz=fabs(kO)*e3+absh*e4; reject=(discry > toly I I discrz > tolz); fhy=discry/toly; fhz=discrz/tolz; if (fhz > fhy) fhy=fhz; mu=l.O/(l.O+fhy)+O.45; if (reject) {

if (absh c= hmin) { d[ll += 1.0; *y=yl; *z=zl; f irst=l; if (b =I *x) break; xl = *x; yl = *y; zl = *z;

) else h *= mu;

) else { if (first) {

first=O; hl=h; h *= mu;

) else {

Copyright 1995 by CRC Press, Inc

Page 476: Numerical Library in C for Scientists and Engineers A

fhy=mu*h/hl+mu-mul; hl=h; h *= fhy;

1 mul=mu; *y=yl+(zl*56.0+k0*7,0+k2*36.0-k4*15.0)/56.O*hl; *z=zl+(-k0*63.0+kl*189.0-k2*36.0-k3*112.0+k4*50.0~/28.0; k5= (*fxyz) (*x, *y, *z) *hl; *y=yl+(zl*336.0+k0*35.0+k2*108.0+k4*25.0)/336.0*h1; *z=zl+(k0*35.0+k2*162.0+k4*125.0+k5*14.0)/336.0; if (b == *x) break; x1 = *x; yl = *y; z1 = *z;

1

Solves an initial value problem for a system of second order ordinary differential equations dyj(x)/dx2 =J(x,y,dy(x)/&), (j=1,2, ..., n), from x=a to x=b, y(a) and dy(a)/da being given, by means of a 5-th order Runge-Kutta method [Z64].

Upon completion of a call of rk2n we have: x=d[3]=b, y/3]=db+3] the value of the dependent variables for x=b, zo]=d[n+j+3], the value of the derivatives of yo] at x=b, j= l ,..., n, rk2n uses as its minimal absolute step length hmin = min(e[2 7-l]*k+e[2 *jfi with 15312*n and k = I b - (if fi is nonzero then a else d[3fi I .

If a step of length I h 1 I hmin is rejected then a step sign(h)*hmin is skipped. A step is rejected if the absolute value of the computed discretization error is greater than

(Izli/l *e[2*j-l]+e[2*jn* lhllk or if that term is greater than

( Ifxvzj 1 *e[2*G;+n)-l]+e[2*G;+n)A* I h 1 lk, for any value of j , 1 <j<n, (k= 1 b-a I ).

Function Parameters: void rk2n (x, a, b,y,ya,z,za,fxvzj, e, dfi, n)

x: float *; the independent variable; exit: upon completion of a call of rk2n, it is equal to b;

a : float; entry: the starting value of x;

b: float; entry: the end value of x;

y: float y[l:n]; the vector of dependent variables; exit: the values of yo] at x = b, j= l ,..., n;

ya: float ya[l:n]; entry: the initial values of yb], i.e, values at x=a;

z: floatz[l:n]; the first derivatives of the dependent variables; exit: the value of (d/&)yU] at x = b, j= l , ..., n;

Copyright 1995 by CRC Press, Inc

Page 477: Numerical Library in C for Scientists and Engineers A

za: float za[l:n]; entry: the initial values of zlj;], i.e. the values at x=a;

fxvzj: float (*fxvzj)(W,x,y,z); fxyj depends on x,j,yb],zlj;], (j=l, ..., n), giving the value of dYlj;]/&;

e: float e[I:4*n]; the element e[2*j-I] is a relative and e[2*j] an absolute tolerance associated with ylj;]; e[2*(n+j)-I] is a relative and e[2*(n+j)] an absolute tolerance associated with zlii/;

d float d[1:2*n+3]; exit: d[l]: the number of steps skipped;

d[2]: the last step length used; d[3]: equal to b; d[4], . . .,d[n+3]: equal to y[l] ,..., y[n] for x = b; d[n+4], ..., d[2*n+3]: equaltothederivativesz[l], ..., z[n]forx=b;

$: int; entry: iffi is nonzero then the integration starts at x=a with a trial step b-a;

if$ is zero then the integration is continued with, as initial conditions, x=d[3], ylj;]=dL+3], zlj]=d[n+3+j], and step length h=d[2]*sign(b-d[3n, and a, ya and za are ignored;

n: int; entry: the number of equations.

void rk2n(float *x, float a, float b, float y[l, float ya[l, float z[l, float zafl, float (*fxyzj) (int, int, float, float [I, float [I), float e [I , float d [I , int fi, int n)

{ float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); int j,jj,last,first,reject,test,ta,tb; float xl,h,ind,hmin,hl,absh,fhm,discry,discrz, toly, tolz,

mu,mul, fhy, fhz, *yl, *zl, *kO, *kl, *k2, *k3, *k4, *k5, *ee;

yl=allocate-real-vector(1,n); zl=allocate-real-vector(1,n); kO=allocate-real-vector(1,n); kl=allocate-real-vector(1,n); k2=allocate-real-vector(1,n); k3=allocate-realvector(1,n); k4=allocate-real-vector(1,n); k5=allocate-real-vector (1, n) ; ee=allocate-real_vector(l,4*n); if (fi) {

d[31 =a; for (jj=l; jj<=n; jj++) {

d[jj+31=ya[jjlj d[n+jj+3l=zaf]j] ;

1

if (fi) d[21 =b-d[31 ; absh=h=fabs (d [21 ) ; if (b-xl < 0.0) h = -h; ind=fabs (b-xl) ; hmin=ind*e [ll +e [21 ;

Copyright 1995 by CRC Press, Inc

Page 478: Numerical Library in C for Scientists and Engineers A

for (jj=2; jj<=2*n; jj++) ( hl=ind*e[2*jj-l]+e [2*j jl ; if (hl c hmin) hmin=hl;

1 while (1) (

if (test) ( absh=fabs (h) ; if (absh c hrnin) {

h = (h > 0.0) ? hmin : -hmin; absh=f abs (h) ;

1 ta=(h >= b-xl) ; tb=(h >= 0.0) ; if ( (ta && tb) I I ( ! (ta / / tb) ) ) {

d [21 =h; last=l; h=b-xl; absh=fabs (h) ;

) else last=O;

for (j=l; j<=n; j++) k0 [jl=(*fxyzj) (n, j,*x,y,z)*h; *x=xl+h/4.5; for (jj=l; jj<=n; jj++! (

y[jj]=yl[lll+(zl[]]l*18.0+kO[jjl*2.0)/8~.~*~; z[jj]=zl[jjl+kO[jjl/4.5;

\ for (j=l; jc=n; j++) kl [jl=(*fxyzj) (n, j,*x,y,z) *h; *x=xl+h/3.0: - ~ . ~

for (jj=l; ;j<=n; jj++! ( y[jj] =yl[j]l+(zl[]]l*6.0+kO [jjl )/l8.0*h; z[jj]=zl[jjl+(k0[~~l+kl[jjl*3.O~/l2.O;

\ J

for (j=l; jc=n; j++) k2 [j]=(*fxyzj) ( n , j,*x,y,z) *h; *x=xl+h*0.5: for (jj=l; ;j<=n; jj+t! (

y[jjl=yl[jjl+(zl[]]l*8.0+k0[jjl+k2[jjl)/l6.O*h; z[jj]=zl[jj]+(k0[jjl+k2[jjI*3.0)/8.0;

\

, , for (jj=l; ;]<=n; jj++) (

y[jj]=yl[jj]+(zl[jjl*l00.0+k0~jjl*12.0+

for (j=l; j<=n; j++) k4 [j] =(*fxyzj) (n, j, *x,y, z)*h; *x = (last ? b : xl+h) ; for (jj=l; jj<=n; jj++) {

y[jj]=yl[jj]+(zl[jjl*336.0+kO[jj]*21.0+k2~jjl*92.0+ k4 [j jl "55.0) /336.O*h;

z[jj]=zl[jj]+(k0[jjl*133.O-kl[jjl*378.O+k2~jjl*276.O+ k3[jj]*112.0+k4[jjl*25.0)/168.0;

1 I for (j=l; j<=n; j++) k5[jl=(*fxyzj) (n, j,*x,y,z)*h; reject=O; fhm0.0; for (jj=l; jj<=n; jj++) (

discry=fabs((-kO[jjl*21.0+k2[jjl*108.0-k3 [jjl*l12.0+ k4[jjl*25.0)/56.0*h);

Copyright 1995 by CRC Press, Inc

Page 479: Numerical Library in C for Scientists and Engineers A

discrz=fabs(k0[jjl*21.0-k2[jjl*162.0+k3 [jjl*224.O- k4[jjl*125.O+k5[jj1*42.0)/14.0;

toly=absh*(fabs(zl[jjl )*ee[2*jj-ll+ee[2*jjl); tolz=fabs(kO [j jl ) *ee [2* (j j+n) -11 +absh*ee [2* (j j+n) I ; reject= ( (discry > toly) I (discrz > tolz) I I reject) ; fhy=discry/toly; fhz=discrz/tolz; if (fhz > fhy) fhy=fhz; if (fhy > fhm) fhm=fhy;

1 mu=l.O/ (l.O+fhm) +0.45; if (reject) {

if (absh c= hmin) { d[ll += 1.0; for (]]=I; jjc=n; jj++) {

y[jjl =yl [j jl ; z[jjl=zl[jjl;

1 f irst=l; if (b == *x) break; xl = *x; for (]]=I; jjc=n; jj++) {

ylrjjl = y[jjI ; zl[jjl = zIjj1;

I } el'se

h *= mu; ) else (

if (first) { first=O; hl=h; h *= mu;

} else { fhm=mu*h/hl+mu-mul; hl=h; h *= fhm;

1 mul=mu; for (jj=l; jj<=n; jj++) {

y[jjl=yl[jjl+(zl~jjl*56.O+k0[jjl*7.O+k2~jjl*36.O- k4 [jjl*15.0)/56.0*hl;

z[jjl=zl[jjl+(-k0[jj]*63.O+kl[jjl*l~O-k2~jj~*36.O- k3[jj]*l12.O+k4[jj]*50.0)/28.0;

I 1

for (j=l; j.c=n; j++) k5 [jl=(*fxyzj) (n, j,*x,y,z)*hl; for (jj=l; jjc=n; jj+t! {

y~jjl=yl[jjl+(zl[j]l*336.0+kO[jjl*35.0+k2~jjl*lO8.O+ k4[jjl*25.0)/336.O*hl;

z[jjl=zl[jj]+(kO[jjl*35.O+k2[jjl*162.O+k4~jjl*l25.O+ k5[jjl*14.0)/336.0;

1 if (b == *x) break; xl = *x; for (jj=l; jjc=n; jj++) {

yl[jjl = y[jjl; zl[jjl = z[jjl;

d[31 = *x; for (jj=l; jjcfn; jj++) {

d[j j+31 =Y[JJ] ; d[n+j j+31 =z tj jl ;

kree-real-vector (yl, 1) ; f ree-real-vector (zl, 1) ; f ree-real-vector (k0,l) ; free real vector (kl, 1) ; freeIrealIvector (k2,1) ; f ree-real-vector (k3,l) ; free-real-vector(k4,l); free real vector(k5,l); free~realIvector(ee,l);

Copyright 1995 by CRC Press, Inc

Page 480: Numerical Library in C for Scientists and Engineers A

Solves an initial value problem for a single second order ordinary differential equation without first derivative

&/dJ = f(x,y), from x=a to x=b, y(a) and dy(a)/da being given, by means of a 5 t h order Runge-Kutta method [Z64].

Upon completion of a call of rk3 we have x=d[3]=b, y=d[4]=y[b], z=d[5], i.e. the value of Q/du for x=b. rk3 uses as its minimal absolute step length

hmin = min (e[2 *j-l]*k+e[2 *jn with 11j12 and k= I b - ( i f 3 is nonzero then a else d[3n 1 . If a step of length I h I shmin is rejected then a step sign(h)*hmin is skipped. A step is rejected if the absolute value of the last term taken into account is greater than (1 &/du 1 *e[l]+e[2n* I h 1 lk or if that term is greater than ( Ih ( *e[3]+e[4J* I h 1 lk where k= 1 b-a I .

Function Parameters: void rk3 (x,a,b,y,ya,z,za,fxy,e,dfi)

x: float *; the independent variable; exit: upon completion of a call of rk3, it is equal to b;

a: float; entry: the initial value of x;

b: float; entry: the end value of x, (b 1 a is allowed);

y: float *; the dependent variable; exit: the value of y(x) at x = b;

ya: float; entry: the initial value of y at x=a;

z: float *; the derivative dy/du; exit: the value of dy/& at x = b;

za: float; entry: the initial value of dy/& at x=a;

fxy: float (*fxy>(x,y); fxy depends on x and y, giving the value of dg/du2;

e: float e[I:4]; entry: e[l] and e[3] are used as relative tolerances, e[2] and e[4] are used as

absolute tolerances for y and dy/& respectively; d float d[l:5];

exit: d[l]: the number of steps skipped; d[2]: the last step length used; d[3]: equal to b; d[4]: equal to y(b); d[5]: equal to &/&, for x = b;

Ji: int; entry: if$ is nonzero then the integration starts at x=a with a trial step b-a;

Copyright 1995 by CRC Press, Inc

Page 481: Numerical Library in C for Scientists and Engineers A

ifJi is zero then the integration is continued with, as initial conditions, x=d[3], y=d[4], z=d[5], and steplength h=d[2]*sign(b-d[3J), a, ya and za are ignored.

void rk3 (float *x, float a, float b, float *y, float ya, float *z, float za, float (*fxy) (float, float), float e[l , float d[l , int fi)

{ int last,first,reject,test,ta,tb; float el, e2, e3, e4 ,XI, yl, zl, h, ind, hmin, hl, absh, k0, kl, k2, k3, k4,

k5,discry,discrz,toly,tolz,mu,mul,fhy,fhz;

1

d[ll =O.O; xl=d [3] ; yl=d [41 ; zl=d [51 ; if (fi) d[21 =b-d[31 ; absh=h=fabs (d 121 ) ; if (b-xl c 0.0) h = -h; ind=fabs (b-xl) ; hmin=ind*e [ll +e [21 ; hl=ind*e [31 +e [41 ; if (hl c hmin) hmin=hl; el=e [ll /ind; e2=e [21 /ind; e3=e [31 /ind; e4=e 141 /ind; first=reject=l;

$bile (1) { if (test) {

absh=fabs (h) ; if (absh < hmin) {

h = (h > 0.0) ? hmin : -hmin; absh=hmin;

1 ta=(h >= b-xl) ; tb=(h >= 0.0) ; if ( (ta && tb) I ( ! (ta I I tb) ) ) {

d [21 =h; last=l; h=b-xl; absh=fabs (h) ;

) else last=O;

1 test=l; if (reject) {

*x=xl; *y=yl; k0= (*fxy) (*x, *y) *h;

) else kO=kS*h/hl;

*x=x1+0.276393202250021*h; *y=yl+(zl*0.276393202250021+k0*0.038196601125Oll~*h; kl= (*fxy) (*x, *y) *h; *~=x1+0.723606797749979*h; *y=y1+(z1*0.723606797749979+k1*0.261803398874989)*h; k2= (*fxy) (*x, *y) *h; *x=xl+h*0.5; *y=yl+(zl*0.5+k0*0.046875+k1*0.079824155839840-

k2*0.001699155839840)*h;

Copyright 1995 by CRC Press, Inc

Page 482: Numerical Library in C for Scientists and Engineers A

k4= (*fxy) (*x, *y) *h; *x = (last ? b : xl+h) ; *y=yl+(zl+k0*0.309016994374947+k2*0.190983005625053~*h; k3= (*fxy) (*x, *y) *h; *y=yl+(zl+k0*0.083333333333333+k1*0.301502832395825+

k2*0.115163834270842)*h; k5= (*fxy) (*x, *y) *h; discry=fabs((-k0*0.5+k1*1.809016994374947+

k2*0.690983005625053-k4*2.0)*h); discrz=fabs ((k0-k3) *2.0- (kl+k2) *10.0+k4*16.0+k5*4.0) ; toly=absh* (fabs (21) *el+e2) ; tolz=fabs (k0) *e3+absh*e4 ; reject=(discry > toly I I discrz > tolz); fhy=discry/toly; fhz=discrz/tolz; if (fhz > fhy) fhy=fhz; mu=l.O/ (l.O+fhy)+0.45; if (reject) {

if (absh c= hmin) { d[l] += 1.0; *y=yl; *z=zl; f irst=l; if (b == *x) break; x1 = *x; yl = *y; z1 = *z;

) else h *= mu;

) else ( if (first) (

f irst=O; hl=h; h *= mu;

) else ( fhy=mu*h/hl+mu-mul; hl=h; h *= fhy;

)

if (b == *x) break; xl = *x:

Solves an initial value problem for a system of second order ordinary differential equations without first derivative

d2V,(x)/& = &Y), 0'= 1 2 ,..., n) from x=a to x=b, y(a) and dy(a)/da being given, by means of a 5-th order Runge-Kutta method [Z64].

Upon completion of a call of rk3n we have: x=d[3]=b, yfi]=dfi+3] the value of the dependent variables for x=b, z/j]=d[n+j+3], the value of the derivatives of yfi] at x=b. rk3n uses as its minimal absolute step length

hmin = min (e[Z*j-l]*k+e[Z*jl) with lSjS2n and

Copyright 1995 by CRC Press, Inc

Page 483: Numerical Library in C for Scientists and Engineers A

k = I b - (if fi is nonzero then a else d[38 I . If a step of length I hl 2 hmin is rejected then a step sign(h)*hmin is skipped. A step

is rejected if the absolute value of the last term taken into account is greater than ( I zb] 1 *e[Z*j-I]+e[2*jfi* I h 1 lk

or if that term is greater than ( I&j 1 *e[2*Q+n)-l]+e[2*C;+n)J)* I h 1 lk,

for any value of j , 1 y l n , (k= 1 b-a 1 ).

Function Parameters: void rk3n (x,a,b,y,ya,z,za,&j,e,dfi,n)

x: float *; the independent variable; exit: upon completion of a call of rk3n, it is equal to b;

a: float; entry: the starting value of x;

b: float; entry: the end value of x (b 2 a is allowed);

y: float y[l :n]; the vector of dependent variables; exit: the values of yb] at x = b, j=l , ..., n;

ya: float ya[l:n]; entry: the initial values of yb], i.e. values at x=a;

z: float z[l:n]; the first derivatives of the dependent variables, zb] = dyb]/&; exit: the value of zb](x) at x = b, j=l ,..., n;

za: float za[l :n]; entry: the initial values of zb], i.e. the values at x=a;

&j: float (*&j)(n,j,x,y); jiyj depends on x,y[l ],y[2], ...,y[n ]j, giving the value of dg~b]/&~;

e:

d

fi:

n:

float e[l:4*n]; the element e[2*j-I] is a relative and e[2*j] is an absolute tolerance associated with yo]; e[2*(n+j)-I] is a relative and e[2*(n+j)] is an absolute tolerance associated with zDJ; float d[I:2*n+3]; exit: d[l]: the number of steps skipped; d[2]: the last step length used; d[3]: equals to b; d[4] ,..., d[n+3]: equal to y[l] ,..., y[n] for x = b; d[n+4], ..., d[2*n+3]: equal to the derivatives z[l], ..., z[n] for x = b; int; entry: iffi is nonzero then the integration starts at x=a with a trial step b-a;

i f f i is zero then the integration is continued with, as initial conditions, x=d[3], yb]=db+3], z,fjJ=d[n+3+j], and step length h=d[2]*sign(b-d[3J), and a, ya and za are ignored;

int; entry: the number of equations.

Copyright 1995 by CRC Press, Inc

Page 484: Numerical Library in C for Scientists and Engineers A

! IE+CC+UIP= [CClv ! [E+CClP= [CCI TA

} (++CF !u=>CC !r=CC) 203 ! [El P=Tx

!O'O=[TlP

1 (

Copyright 1995 by CRC Press, Inc

Page 485: Numerical Library in C for Scientists and Engineers A

~x=x1+0.276393202250021*h; for (jj=l; jj<=n; jj++)

y [jj] =yl [j jl+ (zl [j j] *0.276393202250021+ k0 [j j] *O .038196601125011) *h;

for (j=l; j<=n; j++) kl[j]=(*fxyj) (n, j,*x,y)*h; *x=x1+0.723606797749979*h; for (jjll; jj<=n; jj++)

y[j]l=yl[jj]+(zl[jj] *0.723606797749979+ kl [j j] *O .26l8O3398874989) *h;

for (j=l; j<=n; j++) k2 [jl =(*fxyj) (n, j,*x,y)*h; *x=xl+h*0.5; for (j j=l; j j<=n; j j++)

y[jj]=yl[jjl+(zl[jj]*0.5+k0[jjI*0.046875+kl[jjl* 0.079824155839840-k2~ii1*0.001699155839840~*h; - - - -

for (j=l; j<=n; j++) k4 [j]=(*fxyj) (n, j,*x,y)*h; *X = (last ? b : xl+h) ; for (jj=l; jj<=n; jj++)

y [jj]=yl[j j]+(zl[jjl+kO [jjl *O03O9Ol6994374947+ k2 [ii] *O .19098300562SO53) *h; - -

for (j=l; jc=n; j++) k3[jI=(*fxyj)(n,j,*x,y)*h; for (jj=l; jj<=n; jj++)

y[j j]zyl [jj]+(zl[j j] +k0[jjl*0.083333333333333+kl~jjl* 0.301502832395825+k2[jjI*O.115163834270842~*h;

for (j=l; j<=n; j++) k5[jl=(*fxyj) (n, j,*x,y)*h; reject=O; fhm=O. 0; for (jj=l; jj<=n; jj++) {

discry=fabs ( (-k0 [j jl *O.5+kl [j j] *1.809016994374947+ k2 [j j] *O.690983005625053-k4 [j j] *2.0) *h) ;

discrz=fabs((kO[jjl-k3[jjl)*2.0- (kl[jjl+k2[jjl)*lO.O+ k4[jjl*l6.O+k5[jj1*4.0);

toly=absh*(fabs(zl[jj] )*ee[2*jj-ll+ee[2*jjl) ; tolz=fabs (ko [j jl ) *ee [2* (j j+n) -11 +absh*ee [2* (j j+n) I ; reject=((discry > toly) I (discrz > tolz) I I reject); fhy=discry/toly; fhz=discrz/tolz; if (fhz > fhy) fhy=fhz; if (fhy > fhm) fhm=fhy;

1 &=i.0/ (1.0+fhm)+0.45; if (reject) {

if (absh <= hmin) { d[ll += 1.0; for (jj=l; jj<=n; jj++) {

y[jjl=yl [jjl ; z[jjl=zl[jjl;

1 first=l; if (b == *x) break; x1 = *x; for (jj=:

yl [jj zl [j j

1 ) else

h *= mu; } else {

if (first) { f irst=O; hl=h; h *= mu;

} else ( fhy=mu*h/hl+mu-mul; hl=h; h *= fhy;

1 for (jj=l; jj<=n; jj+t!

z [j j] =zl [jj]+(kO [I j]+k3 [j j1 )*O.O83333333333333+ (kl [j j] +k2 [j j] ) *O .416666666666667;

Copyright 1995 by CRC Press, Inc

Page 486: Numerical Library in C for Scientists and Engineers A

if (b == *x) break; xl = *x:

1 f ree-realvector (yl, 1) ; free-real-vector(z1,l); free-real-vector (k0,l) ; f ree-real-vector (kl, 1) ; f ree-real-vector (k2,l) ; f ree-real-vector (k3,l) ; free-real-vector (k4,l) ; f ree-real-vector (k5,l) ; f ree-real-vector (ee, 1) ;

1

5.4.5 Initial boundary value problem

arkmat

Solves an initial value problem, given as a system of first order (non-linear) differential equations

D U(t) = F(t, U(t)) (1) where D=d/dt and U is an nxm matrix, with U(td prescribed, over the range to I t 5 te, by means of a stabilized Runge-Kutta method [Vh71]. This procedure is suitable for the integration of systems where the dependent variable and the right hand side are stored in a rectangular array instead of a vector. The integration stepsize used will depend on (a) the type of system to be solved (i.e. hyperbolic or parabolic); (b) the spectral radius of the Jacobian matrix of the system; (c) the indicated order of the particular Runge-Kutta method. arkmat is especially intended for systems of differential equations arising from initial boundary value problems in two dimensions, e.g. when the method of lines is applied to this kind of problem, the right hand side of the resulting system is much easier to describe in matrix than in vector form.

The method used is associated with one of four prescribed ninth degree stability polynomials (the choice being open to the user): the first has a degree of polynomial exactness equal to 9; the second and third have absolute values less than unity when their arguments lie in the range [-R(9),0] for the maximal values of R(9), and have degrees of polynomial exactness equal to 1 and 2 respectively (such polynomials are suitable for the numerical solution of parabolic partial differential equations, the eigenvalues of the Jacobian matrix derived from the right hand side of equation (1) ( F and U being expanded to vector form) which lie in the closed left half-plane being real); the fourth polynomial has absolute value less than unity when its argument lies in the range i[-8,8] (it is suitable for the numerical solution of hyperbolic partial differential equations, the eigenvalues of the derived Jacobian matrix lying in the closed left half-plane being confined to the imaginary axis). The Runge-Kutta scheme employed has the form (with N=9 below)

F k . 0 = F(tb Uk)

Copyright 1995 by CRC Press, Inc

Page 487: Numerical Library in C for Scientists and Engineers A

Uk+l = Uk + Fk,n-l

where Uk = U(t$ and t,,, = tk + r (k-0,1, ...), the stepsize r being prescribed. The coefficients Xi are derived from the coefficients Bi of the stability polynomial

chosen, by use of the relationships Xi = JN-i+l /&-i (i=l, ... jV-1).

The choice (among the four described above) of stability polynomial is determined by the values allocated to the input parameters type and order upon call of arkmat. If type=l the first polynomial is chosen, if type=2 and o r d e ~ l the second, if type=2 and order=:! the third, and if type=3, the fourth (if type2, the value of order is ignored). The fixed stepsize r is determined partly by the range constant J(n) of the stability polynomial associated with the method being used, and partly by the value of the input parameter spr (this will in general be a multiple of the spectral radius with respect to the eigenvalues in the closed left half-plane of the Jacobian matrix derived from equation (1) upon call of arkmat. If type=l, r4.31spr; if type=;! and order=l, ~ 1 5 6 l s p r ; if type=2 and o r d e ~ 2 , 1=64/spr, and if type=3, ~ 8 1 s p r .

Function Parameters: void arkmat (t, te, m, n, u, der, type, order, spr, out)

t: float *; the independent variable; entry: initial value to; exit: the final value te;

te: float; entry: the final value of t;

m: int; entry: the number of columns of u;

n: int; entry: the number of rows of u;

u: float u[l:n,l:m]; entry: the initial values of the solution of the system of differential equations at t=tO; exit: the values of the solution at t=te;

der: void (*der)(m,n, t,v,fi); this procedure must be given by the user and performs an evaluation of the right hand side F(t,v) of the system; upon completion of der, the right hand side should be stored in the array f&[l:n,l:m];

type: int; entry: the type of the system of differential equations to be solved; the user should

supply one of the following values: type=l: if no specification of the type can be made; type=2: if the eigenvalues of the Jacobian matrix of the right hand side are

negative real; type=3: if the eigenvalues of the Jacobian matrix of the right hand side are purely

imaginary; order: int *;

Copyright 1995 by CRC Press, Inc

Page 488: Numerical Library in C for Scientists and Engineers A

the order of the Runge-Kutta method used; entry: for type=;! the user may choose order=l or o r d e ~ 2 ; order should be 2 for the

other types; exit: if order is set to another value, it is assumed to be (if type=2 then 1 else 2);

spr: float *; entry: the spectral radius of the Jacobian matrix of the right hand side, when the

system is written in one dimensional form (ie. vector form); the integration step will equal constantlspr (see above); if necessary spr can be updated (after each step) by means of the procedure out;

out: void (* out)(t, te, m, n, u, type, order,spr); float t, float te, int m, int n, float u[l:n,l:m], int type, int order, float *spr; after each integration step the user can print some parameters such as t, u, type, order, or possibly update spr.

Functions used: elmcol, dupmat.

void arkmat(f1oat *t, float te, int m, int n, float **u, void (*der) (int, int, float, float **, float * * ) , int type, int *order, float *spr, void (*out) (float, float, int, int, float ** , int, int, float * ) )

I float **allocate real matrix(int, int, int, int); void free-real-m~trix~float ** , int, int, int); void elrncol (int, int, int, int, float ** , float ** , float) ; void dupmat (int, int, int, int, float **, float * * ) ; int sig, 1, last, ta, tb, i; float tau,lambda[lOl , **uh, **du,mlt; static float lbd1[91 =(l.0/9.O, 1.0/8.0, 1.0/7.0, 1.0/6.0,

1.0/5.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 4.3); static float lbd2[91=(0.1418519249e-2, 0.3404154076e-2,

0.0063118569, 0.01082794375, 0.01842733851, 0,03278507942, 0.0653627415, 0.1691078577, 156.0);

static float l b d 3 [ 9 ] = ( 0 . 3 5 3 4 3 5 5 9 0 8 e - 2 , 0.8532600867e-2, 0.015956206, 0.02772229155, 0.04812587964, 0.08848689452, 0.1863578961, 0.5, 64.0);

static float lbd4[9]={1.0/8.0, 1.0/20.0, 5.0/32.0, 2.0/17.0, 17.0/80.0, 5.0/22.0, 11.0/32.0, 1.0/2.0, 8.0);

/ * initialize */ if (type ! = 2 && type ! = 3) type=l; if (type ! = 2)

*order = 2; else

if (*order ! = 2) *order = 1; switch ( (type == 1) ? 1 : type+ (*order) -1) {

case 1: for (i=O; ic=8; i++) lambda [i+ll =lbdl [il ; break; case 2: for (i=O; ic=8; i++) larnbda[i+ll=lbd2[il ; break; case 3 : for (i=O; ic=8; i++) lambda [i+ll =lbd3 [il ; break; case 4 : for (i=O; ic=8; i++) lambda [i+ll =lbdl [il ; break;

1 sig = ((te == *t) ? 0 : ((te > *t) ? 1 : -1)); last=O; do (

tau=((*spr == 0.0) ? fabs(te-(*t)) : fabs (lambda 191 / (*spr) ) ) *sig;

ta = (*t)+tau >= te; tb = tau >= 0.0; if ((ta && tb) I I ( ! (ta I I tb))) (

tau=te- (*t) ; last=l;

Copyright 1995 by CRC Press, Inc

Page 489: Numerical Library in C for Scientists and Engineers A

I / * difference scheme */ (*der) (m,n, *t,u,du) ; for (i=l; ic=8; i++) {

mltslambda [il *tau; dupmat (l,n,l,m,uh,u) ; for (1=1; lc=m; 1++) elmcol (l,n, l,l,uh, du,mlt) ; (*der) (m,n, (*t)+mlt,uh,du) ;

1 ;or ( 1 ~ 1 ; l<=m; 1++) elmcol(l,n,l,l,u,du,tau); *t = (last ? te : (*t)+tau); (*out) (*t,te,m,n,u,type,*order,spr) ;

} while ( !last) ; free-real-matrix (uh, 1, n, 1) ; f ree-real-matrix (du, 1, n, 1) ;

I

5.5 Two point boundary value problems

5.5.1 Linear methods - Second order self adjoint

A. femlagsym

Solves a second order self-adjoint linear two point boundary value problem by means of Galerkin's method with continuous piecewise polynomials [BakH76, He75, StF731. femlagsym computes approximations y, (n=O, ...JV) to the values at the points x = x,,, where

- a < a = x o < x l < ... < x N = b < oo of the real valued function y(x) which satisfies the equation

-Db(x)Dy(x)) + r(x)y(x) = f(x) (1) where D=dldx, with boundary conditions

ely(a) + e2Dyfa) = e,, e4y(b) + epy(b) = e, (el, e4 * 0). (2) It is assumed that (a) p(x)> 0 on the interval [x,,, x,], n=1, ...& (b) p(x), r(x) and f(x) are required to be sufficiently smooth on [x,xN] except at the grid

points where p(x) should be at least continuous; in that case the order of accuracy (2, 4 or 6) is preserved;

(c) r(x) 2 0 on [x,xN1; if, however, the problem has pure Dirichlet boundary conditions (i.e, e[2]=e[5]=0) this condition can be weakened to the requirement that r(x) > -pO*(d(xXJ)2, where pO is the minimum of p(x) on [xo,x,]; one should note that the problem may be ill-conditioned when r(x) is quite near that lower bound; for other negative values of r(x) the existence of a solution remains an open question.

The theory upon which the method is based is explained with reference to the more general equation

-D(p(x)Dy(x)) + q(x)Dy(x) + r(xly(x) = f(x) (3 of which equation (1) and the equations treated by other procedures Cfemlag, femlagskew) are special cases. y(x) is approximated by a sum involving Nk+l functions and +,,,j:

Copyright 1995 by CRC Press, Inc

Page 490: Numerical Library in C for Scientists and Engineers A

Inserting this expansion into equation (3), multiplying throughout by &,,(x) and integrating by parts, there follows

Let W,(6) and t," be the weights and arguments of the k+l Radau-Lobatto quadrature formula over [0,1], so that for suitable g

where tofi) = 0, tkF) = I, wOfi) = wkN. Denote the interval [xn.,,xn] by In and its length xn - x ,,-, by A, (n=1 ,..,A'), and let En,/) = x,,, + ~YF'A,, (n=l, ... p, v=O ,..., k) (these displaced Radau- Lobatto points lie in In, and

= xn-/, En,kF) = Xn = Zn+~,ofi)> En,?) - En,?) = (tn,YO - t n , T l k ) ~ n -

The functions 4, , and 4,, (n=l, ... JV, l=l, ..., k-1; n=N, I=l, ..., k) above are taken to be polynomials of degree k over the interval I, and In (n=l, ...a respectively and zero elsewhere in [a,b]; 4,, (n=1, ...,N- 1) is a polynomial of degree k over In, another such polynomial over In+,, and is zero elsewhere in [a,b]. These polynomials are fixed by the conditions

~o@l ,oo) = 4,(a) = 1, 4,@,,,") = 0 (v=l ,...,k) n n = 7 44,@n.,F!, = 0 (O 5 v 5 k ( ~ z I))

for n=1, ... ,N, I=l, ..., k-I; n=N, k l , ..., k, and +n,k@n,kfk)) = I

4n,k@n,,fi!, = 0 (v=O, ..., k-I), 4n,k@n+l,?)) = 0 (v=I,...,k)

Copyright 1995 by CRC Press, Inc

Page 491: Numerical Library in C for Scientists and Engineers A

for n=1, ...a- 1. Setting

where the superscripts (v) and (z,v) imply that the terms corresponding to r=v and r=r, r=v are to be omitted, the polynomials +,,, + , , are given explicitly by the formulae

(X E I,; I < k)

Their derivatives at the displaced Radau-Lobatto points lying in the intervals over which they are not identically zero are given by

D+n,/@n,,F!, = '(v, l ) An (1 < k) W n , , @ n , , F ! , = '(v,k) / An, D $ n , , @ n + , , F q = X'(v,O) An+l .

Over intervals in which the + , , are zero, the derivative of +,,, is, of course, also zero. The numbers X(v), X1(v,l) are problem independent; they may be, and have been, computed in advance.

The first of the boundary conditions (2) implies that

Copyright 1995 by CRC Press, Inc

Page 492: Numerical Library in C for Scientists and Engineers A

When n=1 ,... ,N- 1, 1=1 ,..., k; n=N, 1=1 ,..., k- 1, the expression denoted by square brackets in formula (5) vanishes, since 4,,(a) = 4,,(b) = 0. With n-1, the following term is equal to

for I=l, ..., k; when n > 1, this term vanishes. For n=l, ... ,N, l=l, ..., k-1 the next term is equal to

and when n=1, ...,N- 1, I=k it is equal to the sum of the above expression with I=k and

The value of the expression upon the right hand side of equation (5) is ~p ' f@~ ,pq for n=l, I=0 ,..., k, and n=1, ... ,N, l=l, ..., k-1, and is equal to w,,@'~@~,,@))(A, + A,,+,J for n=1, ... ,N-1, Z=k.

The second of the boundary conditions (2) implies that

In summary, the two boundary conditions (2) and Nk-1 equations derived from equation (3) with n=1, ... ,N-1, I=l, ..., k and n=N, I=l, ..., k-1 yield Nk+l linear equations for the Nk+l coefficients a, and amj (m=1, ...A, j=l, ..., k). The first k-1 of these equations involve a, and aij (j=l, ..., k) alone. By transferring the terms involving a, and a,,, to the right hand side, and premultiplying by the inverse of the matrix multiplying the vector (a,,,,...,al,k~,), this vector my be isolated. Its components may be eliminated from the next equation which involves the two sets a I j and (j=l ,..., k). The following k-1 equations involve (j=l ,..., k) alone. The vector (a,,, ..., a,,,) may again be isolated and its components eliminated from the equation from which a,,, ..., a,,,, have been eliminated, and also from the next equation which involves the two sets a,j, a j j (j=l, ..., k). The process may be continued, and a tridiagonal system of equations for a, and a,, (m=1, ...,PI) is obtained. The process of

Copyright 1995 by CRC Press, Inc

Page 493: Numerical Library in C for Scientists and Engineers A

elimination may be carried out as soon as each complete set of equations involving am,,, ..., a,,, has been constructed (computer storage space is thereby saved). When k 1 , no elimination takes place; when k=2 and 3 (the other two values of k permitted by femlagsym) the matrix elimination process is particularly simple and is programmed independently (rather than by calls of matrix operation procedures).

The tridiagonal system of equations is solved by a method of Babuska [see Bab721. Stripping some redundant sequences from the original exposition, the set of equations Ay=f, where

A. . = c + I a

AiZi+, = bi (i=l, ..., n-1), A,,, = 71 - 61, A,,i = 7, - ci., - b, (i=2 ,..., n-I),

Anin = T,, - cl1 may be solved by means of the construction of four sequences g,, xi, g,' and xi as follows: with xI=7,, g, =fi

gi+: =A+/ - gicJ(~i-bJ, xi+, = 7i+l - xicJ(~i-bu) (i=l,...,n-l) and with x,', g, = f,

gi* = f; - bigi+,*/(Xi+,*-cJ, xi* = ri - biX,+l*/(Xi+,*-~i) (i=n-1, ..., 1) and then

~i = (gi + gig -fJ / (xi + xi* - T$ (i=n, ..., 1). The above process can be further economized (three one-dimensional arrays, with another to contain they, are required). The coefficients a , , a,,, (n=l, ...a obtained by means of the above process are, in order, the required approximations y, (n=O, ...a (since IP,~,,(XJ = 6,,).

Function Parameters: void femlagsym (x,y, n,p, r,fjorder, e)

float x[O:n]; entry: a = x, < x, < ... < x, = b is a partition of the interval [a'b]; float y[O:n]; exit: y[i], i=O, 1 ,..., n, is the approximate solution at x[i] of the differential equation

(1) with boundary conditions (2); int; entry: the upper bound of the arrays x and y (value of N above), n > 1; float (*p)(x); the procedure to compute p(x), the coefficient of Dy(x) in equation (1); float (*r)(x); the procedure to compute r(x), the coefficient of y(x) in equation (1); float (*J>(x); the procedure to compute f(x), the right hand side of equation (1);

order: int; entry: order denotes the order of accuracy required for the approximate solution of

the differential equation; let h = max(x[i]-x[i-18, then ly[i] - y(x[i]))( 5 c* harder , i=O, ..., n; order can be chosen equal to 2, 4 or 6 only;

e: float e[l:6]; entry: e[l], ..., e[6] describe the boundary conditions (values of e,, i=1, ..., 6, in (2));

e[l] and e[4] are not allowed to vanish both.

void femlagsym(f1oat x[l , float y [ I , int n, float (*p) (float), float (*r) (float), float (*f) (float), int order, float e [ l )

Copyright 1995 by CRC Press, Inc

Page 494: Numerical Library in C for Scientists and Engineers A

I float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int) ; int 1,ll; float xll,xl,h,al2,bl,b2,taul,tau2,ch,tl,g,yl,pp,pl,p2,p3,p4,

rl, r2, r3, r4, fl, f2, f3, £4, el,e2, e3,e4, e5, e6, *t, *sub, *chi, *gi, h2,x2, h6, h15,b3, tau3, cl2, c32, a13,a22, a23 ,x3, h12, h24,det, cl3, c42, c43, al4,a24, a33, a34, b4, tau4, aux;

1=1; xl=x 101 ; el=e [ll ; e2=e [21 ; e3=e [31 ; e4=e [41 ; e5=e [51 ; e6=e [61 ; while (1 c = n ) {

11=1-1; xll=xl; xl=x [ll ; h=xl-xll; if (order == 2) {

/ * element mat vec evaluation 1 * / if (1 == 1) {

p2= (*p) (~11) ; r2= (*r) (xll) ; f2= (*f) (xl1) ;

h2=h/2.0; bl=h2*fl; b2=h2*f2; taul=h2*rl; tau2=h2*r2; a12 = - 0.5* (pl+p2) /h;

} else if (order == 4) { / * element mat vec evaluation 2 * / if (1 == 1) (

p3= (*p) (xll) ; r3= (*r) (xll) ; f 3 = ( * f ) ( x l l ) ;

1

h6=h/6.0 ; h15=h/1.5; pl=p3; p2=(*p) (x2 p3= (*p) (xl rl=r3; r2= (*r) (x2 r3= (*r) (xl fl=f 3 ; f2=(*f) (x2 f3= (*f) (xl bl=h6*f 1; b2=h15*f2; b3=h6*f3 :

Copyright 1995 by CRC Press, Inc

Page 495: Numerical Library in C for Scientists and Engineers A

a23 = - (pl/3.O+p3) *2.0/h; c12 = -a12/a22; c32 = -a23/a22; a12=a13+c32*a12; bl += c12*b2; b2=b3+c32*b2; taul += c12*tau2; tau2=tau3+c32*tau2;

} else { / * element mat vec evaluation 3 */ if (1 == 1) {

pe= (*p) ( x n ) ; r4= (*r) (xll) ; f4= (*f) (xl1) ;

I I x2=~11+0.27639320225*h; x3=x1-x2+x11; h12=h/12.0; h24=h/2.4 ; pl=p4 ; p2= (*p) (x2) ; p3=(*p) (x3) ; p4= (*p) (xl) ; rl=r4 ; r2= (*r) (x2) ; r3=(*r) (x3) ; r4= (*r) (xl) ; fl=f4; f2=(*f) (x2) ; f3=(*f) (x3) ; f4=(*f) (xl) ; bl=hl2*fl; b2=h24*£2; b3=h24*f3 ; b4=h12*f4; taul=hl2*rl; tau2=h24*r2; tau3=h24*r3; tau4=h12*r4 ; a12 = -(4.04508497187450*p1+0.57581917135425*p3+

0.25751416197911*p4)/h; a13=(1.5450849718747*pl-1.5075141619791*~2+

0.6741808286458*~4)/h; al4= ( (p2+p3) /2.4- (pl+p4) /2.0) /h; a22=(5.454237476562*pl+p3/0.48+0.79576252343762*~4)/h+tau2; a23 = - (pl+p4) / (h*O.48) ; a24=(0.67418082864575*~1-1.507514161979lO*p3+

1.54508497187470*p4)/h; a33=(0.7957625234376*pl+p2/0.48+5.454237476562*p4)/h+tau3; a34 = -(0.25751416197911*p1+0.57581917135418*p2+

4.0450849718747*p4)/h; det=a22*a33-a23*a23; c12=(a13*a23-a12*a33)/det; c13=(a12*a23-a13*a22)/det; c42=(a23*a34-a24*a33)/det; c43=(a24*a23-a34*a22)/det; taul += c12*tau2+c13*tau3; tau2=tau4+~42*tauZ+c43*tau3; a12=a14+~42*a12+~43*a13; bl += c12*b2+c13*b3; b2=b4+~42*b2+~43*b3;

if (1 == 1 I f 1 == n) { /* boundary conditions */ if (1 == 1 && e2 == 0.0) {

taukl. 0; bl=e3/el; b2 -= a12*bl; tau2 -= a12; a12=0.0;

} else if (1 == 1 && e2 != 0.0) { aux=pl/e2 ; taul -= aux*el; bl -= e3*aux;

Copyright 1995 by CRC Press, Inc

Page 496: Numerical Library in C for Scientists and Engineers A

) else if (1 == n && e5 == 0.0) { tau2=l. 0; b2=e6/e4; bl - = a12*b2; taul -= a12; a12=0.0;

) else if (1 == n && e5 ! = 0.0) ( aux=p2/e5 ; tau2 += aux*e4; b2 += aux*e6;

1 )

/ * forward babushka */ if (1 == 1) {

chi 101 =ch=tl=taul; t [Ol =tl; gi [O] =g=yl=bl; y [Ol =yl; sub [Ol =al2: pp=a12/ (chial2) ; ch=tau2-ch*pp; g=b2-g*pp; tl=tau2; yl=b2 ;

) else ( chi[lll = ch += taul; gi [ll] = g += bl; sub [ll] =a12 ; pp=al2/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; t [ll] =tl+taul; tl=tau2; y [ll] =yl+bl; yl=b2 ;

I * backward babushka */ pp=yl; y [nl =g/ch; g=PP ; ch=tl; l=n-1; while (1 >= 0) (

pp=sub [ll ; pp /= (ch-pp); tl=t [ll ; ch=tl-ch*pp; yl=y [ll ; g=yl-g*pp; y[i] = (gl [ll +g-yl) /(chi [ll +ch-tl) ; 1- - ;

1 f ree-real-vector (t, 0) ; free-real-vector (sub, 0) ; free-real-vector (chi, 0) ; free-real-vector (gi, 0) ;

1

B. femlag

Solves a second order self-adjoint linear two point boundary value problem by means of Galerkin's method with continuous piecewise polynomials [Bab72, BakH76, He75, StF731. femlag computes approximations y , (n=O, ...,N) to the values at the points x = x,,, where

-a, < a = x , < x , < . . .< x , = b < a,

of the real valued function y(x) which satisfies the equation

Copyright 1995 by CRC Press, Inc

Page 497: Numerical Library in C for Scientists and Engineers A

-D2y(x) + r(x)y(x) = f(x) (1) where D=ciY&, with boundary conditions

e,y(a) + e2@(a) = e,, ey(b) + e,@(b) = e, (el, e, # 0). (2) It is assumed that r(x) 2 0 (a I x I b); if e2 = e, = 0, this condition may be relaxed to

r(x) > -(~/(b-a))~ (a I x I b). The general theory underlying the method used is that described in femlagsym. Now,

however, (since p(x) in equation (1) of femlagsym is unity) the term

in expression (7) of femlagsym becomes

The value of the sum in this expression is problem independent and may be determined in advance (a similar remark holds with respect to expression (6) in femlagsym); the computations may be simplified.

Function Parameters: void femlag (x,y, n, rdorder, e)

x: float x[O:n]; entry: a = x, < x, < ... < x, = b is a partition of the segment [a,b];

y: float y[O:n]; exit: y[i], i=O,l, ..., n, is the approximate solution at x[i] of the differential equation

(1) with boundary conditions (2); n: int;

entry: the upper bound of the arrays x and y (value of N above), n > 1; r: float (*r)(x);

the procedure to compute r(x), the coefficient of y(x) in equation (1); f: float (*j)(x);

the procedure to compute f(x), the right hand side of equation (1); order: int;

entry: order denotes the order of accuracy required for the approximate solution of the differential equation; let h = max(x[i]-x[i-I]), then

1 y[i] - y(x[i]) 1 I c*hord", i=O, ..., n; order can be chosen equal to 2, 4 or 6 only;

e: float e[I:6]; entry: e[I], ..., e[6] describe the boundary conditions (values of ei, i=1, ..., 6, in (2));

neither e[I] nor e[4] is allowed to vanish.

void femlag(f1oat x [ I , float y[l , int n, float (*r) (float), float (*f) (float), int order, float e[l)

I float *allocate real vector(int, int); void free-real-vector(f1oat * , int);

Copyright 1995 by CRC Press, Inc

Page 498: Numerical Library in C for Scientists and Engineers A

int 1,ll; float xll,xl, h, al2, bl, b2, taul, tau2, ch, tl, g, yl,pp, el, e2, e3, e4, e5,

e6,*t,*sub,*chi,*gi,f2,r2,rl,f1,h2,r3,f3,~2,h6,h15,b3,tau3, c12,a13,a22,a23,r4,f4,x3,h12,h24,det,c13,c42,c43,a14,a24, a33,a34,b4,tau4;

1=1; xl=x[O] ; el=e [ll ; e2=e [21 ; e3=e 131 ; e4=e [41 ; e5=e [51 ; e6=e 161 ; while (1 c = n) {

11=1-1; xll=xl; xl=x [ll ; h=xl-xll; if (order == 2) {

/ * element mat vec evaluation 1 * / if (1 == 1) (

f2=(*f) (xl1) ; r2= (*r) (xll) ;

I a12 = -l.O/h; h2=h/2.0; rl=r2; r2= (*r) (xl) ; fl=f2; f2= (*f) (xl) ; bl=h2*f 1; b2=h2*f2; taul=h2*rl; tau2=h2*r2;

} else if (order == 4) ( / * element mat vec evaluation 2 * / if (1 == 1) {

r3= (*r) (xll) ; f3= (*f) (xl1) ;

1 x2= (x11+x1) /2.0; h6=h/6.0; h15=h/1.5; rl=r3; r2= (*r) (x2) ; r3=(*r) (xl) ; fl=f 3 ; f2=(*f) (x2) ; f3=(*f) (xl); bl=h6*fl; b2=h15*f2; b3=h6*f3; taul=h6*rl; tau2=h15*r2; tau3=h6*r3; a12 = a23 = -8.O/h/3.0; a13 = -a12/8.0; a22 = -2.O*a12+tau2; cl2 = -a12/a22; a12=a13+c12*a12; b2 *= ~ 1 2 ; bl += b2; b2 += b3; tau2 *= c12; taul += tau2; tau2=tau3+tau2;

} else ( / * element mat vec evaluation 3 * /

Copyright 1995 by CRC Press, Inc

Page 499: Numerical Library in C for Scientists and Engineers A

if (1 == 1) { r4= (*r) (xll) ; f4= (*f) (xl1) ;

1 x2=~11+0.27639320225*h; x3=xl-x2+x11; rl=r4 ; r2= (*r) (x2) ; r3= (*r) (x3) ; r4= (*r) (xl) ; fl=f4; f2=(*f) (x2) ; f3=(*f) (x3); f4=(*f) (xl) ; h12=h/12.0; h24=h/2.4; bl=hl2*fl; b2=h24*£2; b3=h24*£3; b4=h12*£4; taul=hl2*rl; tau2=h24*r2; tau3=h24*r3 ; tau4=h12*r4; a12 = a34 = -4.8784183052078/h; al3=a24=0.7117516385412/h; a14 = -0.16666666666667/h; a23=25 .O*al4; a22 = -2.O*a23+tau2; a33 = -2.O*a23+tau3; det=a22*a33-a23*a23; c12=(a13*a23-a12*a33)/det; c13=(a12*a23-a13*a22)/det; c42=(a23*a34-a24*a33)/det; c43= (a24*a23-a34*a22) /det; taul += c12*tau2+~13*tau3; tau2=tau4+~42*tau2+~43*tau3; a12=a14+~42*a12+~43*a13; bl += c12*b2+c13*b3; bZ=b4+~42*b2+~43*b3;

(1 == 1 I I 1 == n) { /* boundary conditions */ if (1 == 1 && e2 == 0.0) (

taukl. 0; bl=e3/el; b2 - = a12*bl: tau2 - = a12; a12=0.0 ;

) else if (1 == 1 && e2 ! = 0.0) ( taul - = el/e2; bl - = e3/e2;

} else if (1 == n && e5 == 0.0) { tau2=l. 0; b2=e6/e4; bl - = a12*b2; taul - = a12; a12=0.0 ;

} else if (1 == n &&e5 ! = 0.0) ( tau2 += e4/e5; b2 += e6/eS;

1 1

/ * forward babushka * / if (1 == 1) {

chi [O] =ch=tl=taul; t [Ol =tl; gi [OI =g=yl=bl; y [Ol =yl; sub [Ol =a12 ; pp=al2/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; tl=tau2 :

Copyright 1995 by CRC Press, Inc

Page 500: Numerical Library in C for Scientists and Engineers A

yl=b2 ; ) else {

chi 1111 = ch += taul; gi [lll = g += bl; sub [lll =al2; pp=al2/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; t 1111 =tl+taul; tl=tau2; y [lll =yl+bl; yl=b2;

1

)* backward babushka * /

l=n-1; while (1 z = 0) {

pp=sub 111 ; PP / = (ch-pp) ; tl=t [ll :

kree-real-vector (t, 0) ; free-real-vector(sub,O); free-real-vector (chi, 0) ; free-real-vector (gi, 0) ;

1

C. femlagspher

Solves a second order self-adjoint linear two point boundary value problem with spherical coordinates by means of Galerkin's method with continuous piecewise polynomials [Bab72, BakH76, He75, StF731. femlagspher computes approximations y,, (n=O, ...m to the values at the points x = x,, where

-a, < a = x , < x , < ... < x N = b < co of the real valued function y(x) which satisfies the equation

-D(YcDy(x))/x "' + r(x)y(x) = f(x) (1) where D=ddx, with boundary conditions

e,y(a) + e,Dy(a) = e,, e~v(b) + e,Dy(b) = e, (el, e, # 0). (2) It is assumed that r(x) and f(x) are sufficiently smooth on [x,xN] except at the grid points; furthermore r(x) should be nonnegative.

The solution is approximated by a function which is continuous on the closed interval [xo,xN] and a polynomial of degree less than or equal to k on each segment [x,-,x,] (j=l, ...a. This piecewise polynomial is entirely determined by the values it has at the knots x, and on k-1 interior knots on each segment [x,,,~,]. These values are obtained by the solution of an order+l diagonal linear system with a specially structured matrix. The entries of the matrix and the vector are inner products which are approximated by some piecewise k-point Gaussian quadrature. The evaluation of the matrix and the vector is done segment by segment: on each segment the contributions to the entries of the matrix and the vector are computed and embedded in the global matrix and vector. Since the function values on the interior points of each segment are not coupled with the function values outside that

Copyright 1995 by CRC Press, Inc

Page 501: Numerical Library in C for Scientists and Engineers A

segment, the resulting linear system can be reduced to a tridiagonal system by means of static condensation. The final tridiagonal system, since it is of finite difference type, is solved by means of Babuska's method. For further details, see the documentation of femlagsym.

Function Parameters: void femlagspher (x,y,n,nc,r,Jorder, e)

x: float x[O:n]; entry: a = x, < x, < ... < x, = b is a partition of the interval [a,b];

y: float y[O:n]; exit: y[i], i=O,l, ..., n, is the approximate solution at x[i] of the differential equation

(1) with boundary conditions (2); n: int;

entry: the upper bound of the arrays x and y (value of N above), n > 1; nc: int;

entry: if nc = 0, Cartesian coordinates are used; if nc = 1, polar coordinates are used; if nc = 2, spherical coordinates are used;

r: float (*r)(x); the procedure to compute r(x), the coefficient of y(x) in equation (1);

f: float (*j)(x); the procedure to compute f(x), the right hand side of equation (1);

order: int; entry: order denotes the order of accuracy required for the approximate solution of

the differential equation; let h = max(x[i]-x[i-ll), then ly[i] - y(x[i]) 1 I ~*h"'~", i=O, ..., n; order can be chosen equal to 2 or 4 only;

e: float e[I:6]; entry: e[l], ..., e[6] describe the boundary conditions (values of ei, i=1, ..., 6 , in (2));

e[l] and e[4] are not allowed to vanish both.

void femlagspher(f1oat x[l, float y [ l , int n, int nc, float (*r) (float) , float ( * f ) (float) , int order, float e [I )

I 1

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int) ; int 1,ll; float xll,xl,h,al2,bl,b2,taul,tau2,ch,tl,g,yl,pp,tau3,b3,al3,a22,

a23,c32,cl2,el,e2,e3,e4,e5,e6,*t,*sub,*chi,*gi,xm,vl,vr,wl, wr,pr,rm,fm,xl2,xlxr,xr2,xlm,xrm,vlm,vrm,wlm,wrm,flm,frm,rlm, rrm,pll,pl2,pl3,prl,pr2,pr3,qll,q12,q13,rlmpll,rlmpl2,rrmprl, rrmpr2 ,vlmqll,vlmql2 ,vrmqrl,vrmqr2, qrl, qr2, qr3, a, a2, a3, a4, b,b4,p4h,p2,p3,p4,auxl,aux2,a5,a6,a7,a8,b5,b6,b7,b8,ab4, a2b3,a3b2,a4b,p5,p8,p8h,aux,plm,prrn;

Copyright 1995 by CRC Press, Inc

Page 502: Numerical Library in C for Scientists and Engineers A

e5=e [51 ; e6=e [61 ; while (1 <= n) (

114-1; xll=xl; xl=x [ll ; h=xl -xll; if (order == 2) (

/ * element mat vec evaluation 1 * / if (nc == 0)

vl=vr=0.5; else if (nc == 1) (

vl= (xll*2.0+x1) /6.0; vr=(xll+xl*2.0)/6.0: . .

) else ( x12=xll*x11/12.0; xlxr=xll*xl/6.0;

I wl=h*vl; wr=h*vr; pr=vr/ (vl+vr) ; xm=xll+h*pr; fm= (*f ) (xm) ; rm= (*r) (xm) ; taul=wl*rm; tau2=wr*rm; bl=wl*fm; b2=wr*fm; a12 = - (vl+vr) /h+h* (1.0-pr) *pr*rm;

) else ( / * element mat vec evaluation 2 * / if (nc == 0) (

xlm=xll+h*0.2113248654052; xrm=xll+xl-xlm; vlm=vrm=0.5; pll=pr3=0.45534180126148; pl3=prl = -0.12200846792815; p12=pr2=1.0-pll-p13; qll = -2.15470053837925; q13 = -0.15470053837925; ql2 = -qll-q13; qrl = -q13; qr3 = -qll; qr2 = -ql2;

} else if (nc == 1) ( a=xll; a2=a*a; a3=a*a2 ; a4=a*a3 ; b=xl; b2=b*b; b3=b*b2 ; b4=b*b3 ; p2=lO. O* (a2+4.O*a*b+b2) ; p3=6.0* (a3+4.O* (a2*b+a*b2) +b3) ; p4=sqrt(6.0*(a4+10.0*(a*b3+a3*b)+28.0*a2*b2+b4)); p4h=p4*h; xlm= (p3 -p4h) /p2 ; xrm= (p3+p4h) /p2 ; auxl= (a+b) /4.0; aux2=h*(a2+7.0*a*b+b2)/6.0/~4; vlm=auxl-aux2; vrm=auxl+aux2;

) else ( a=xll ; a2=a*a; a3=a*a2; a4=a*a3 ; a5=a*a4 ; a6=a*a5; a7=a*a6 ;

Copyright 1995 by CRC Press, Inc

Page 503: Numerical Library in C for Scientists and Engineers A

. . p8h=p8*h; aux2= (h* (a5+7. O* (a4b+ab4) +28. O* (a3b2+a2b3) +b5) ) /4.8/p8; xlm= (p5-p8h) /p4;

if (nc > O ) { plm= (xlm-xll) /h; prm= (xrm-xll) /h; aux=2.O*plm-1.0; pll=aux* (plm-1.0) ; pl3=aux*plm; p12=1.0-pll-p13; aux=2.0*prm-1.0; prl=aux* (prm-1 .0) ; pr3=aux*prm; pr2A.0-prl-pr3; aux=4.0*plm; qll=aux-3.0; ql3=aux-1.0; q12 = -qll-q13; aux=4.0*prm; qrl=aux-3.0; qr3=aux-1.0; qr2 = -qrl-qr3;

1 wlm=h*vlm; wrm=h*vrm; vlm /= h; vrm /= h; flm= (*f) (xlm) *wlm; f rm=wrm* (*f) (xrm) ; rlm= (*r) (xlm) *wlm; rrm=wrm* (*r) (xrm) ; taul=pll*rlm+prl*rrm; tau2=pl2*rlm+pr2*rrm; tau3=pl3*rlm+pr3*rrm; bl=pll*flm+prl*frm; b2=pl2*flm+pr2*frm; b3=~13*flm+~r3*frm;

Copyright 1995 by CRC Press, Inc

Page 504: Numerical Library in C for Scientists and Engineers A

bl += c12*b2; b2=b3+~32*b2; taul += c1Zctau2; tauZ=tau3+~32*tau2;

1 if (1 == 1 I I 1 == n) (

/* boundary conditions * / if (1 == 1 && e2 == 0.0) {

taul=l .0 ; bl=e3/el; b2 - = a12*bl; tau2 - = al2; a12=0.0 ;

) else if (1 == 1 && e2 ! = 0.0) ( aux=((nc == 0) ? 1.0 : pow(x[O],nc))/e2; bl - = e3*aux; taul -= el*aux;

) else if (1 == n && e5 == 0.0) { tau24.0; b2=e6/e4 ; bl - = al2*b2; tau1 - = a12; a12=0.0 ;

) else if (1 == n && e5 ! = 0.0) { aux= ( (nc == 0) ? 1.0 : pow (x [nl , nc) ) /e5; tau2 += aux*e4; b2 += aux*e6;

)* forward babushka * / if (1 == 1) {

chi [OI =ch=tl=taul; t [Ol =tl; gi [Ol =g=yl=bl; y [Ol =yl; sub 101 =al2; pp=al2/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; tl=tau2; yl=b2 ;

) else { chi [lll = ch += taul; gi [lll = g += bl; sub [lll =al2; pp=al2/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; t [lll =tl+taul; tl=tau2; y[lll =yl+bl; yl=b2 ;

j * backward babushka * / PP=Y~ ; Y [nl =g/ch;

la-1; while (1 >= 0) {

pp=sub Ell ; pp /= (ch-pp); tl=t [ll ; ch=tl-ch*pp; yl=y[ll ; g=yl-g*pp; y[l] =(gi [ll +g-yl) / (chi [ll +ch-tl) ; I--;

1 free-real-vector (t, 0) ; f ree-real-vector (sub, 0) ; f ree-real-vector (chi, 0) ;

Copyright 1995 by CRC Press, Inc

Page 505: Numerical Library in C for Scientists and Engineers A

f ree-real-vector (gi, 0 ) ; 1

5.5.2 Linear methods - Second order skew adjoint

femlagskew

Solves a second order skew-adjoint linear two point boundary value problem by means of Galerkin's method with continuous piecewise polynomials [Bab72, BakH76, He75, StF731. femlagskew computes approximations yn (n=O, ...JV) to the values at the points x =

x,, where - w < a = x, < x, < ... < x, = b < oo

of the real valued function y(x) which satisfies the equation -D2y(x) + q(x)Dy(x) + r(x)y(x) = f(x) (1)

where D=ddx, with boundary conditions e,.v(a) + e,Dy(a) = e,, ey(b) + e,Dy(b) = e, (el, e4 + 0). (2)

It is assumed that (a) r(x) 2 0 (a I x I b), if e, = e, = 0 then this condition may be relaxed to

r(x) > -(xl(b-a))* (a I x I b); (b) q(x) is not allowed to have very large values in some sense: the product q(x)*(x,-x,.,)

should not be too large on the interval [xj,,x,], otherwise the boundary value problem may degenerate to a singular perturbation or boundary layer problem, for which either special methods or a suitably chosen grid are needed;

(c) q(x), r(x) and f(x) are required to be sufficiently differentiable on the domain of the boundary value problem; however, the derivatives are allowed to have discontinuities at the grid points, in which case the order of accuracy (2, 4 or 6) is preserved;

(d) if q(x) and r(x) satisfy the inequality r(x) 2 Dq(x)/2, the existence of a unique solution is guaranteed, otherwise this remains an open question.

The general theory underlying the method used is that described in femlagsym. Now a term q(x)Dy(x) is being treated (it is absent from equation (1) in femlagsym), however, the simplification described in femlag is possible.

Function Parameters: void femlagskew (x,y, n, q,r,Jorder, e)

x: float x[O:n]; entry: a = x, < x, < ... < xn = b is a partition of the segment [a,b];

y: float y[O:n]; exit: y[i], i=O, 1 ,..., n, is the approximate solution at x[i] of the differential equation

(1) with boundary conditions (2); n: int;

entry: the upper bound of the arrays x and y (value of N above), n > 1; q: float (*q)(x);

the procedure to compute q(x), the coefficient of Dy(x) in equation (1); r: float (*r)(x);

the procedure to compute r(x), the coefficient of y(x) in equation (1); j float (*f)(x);

the procedure to compute f(x), the right hand side of equation (1); order: int;

Copyright 1995 by CRC Press, Inc

Page 506: Numerical Library in C for Scientists and Engineers A

entry: order denotes the order of accuracy required for the approximate solution of the differential equation; let h = max(x[i]-x[i-IJ), then

ly[iJ - y(x[i]) 1 I c*Wrder, i=O, ..., n; order can be chosen equal to 2, 4 or 6 only;

e: float e[I:6]; entry: e[l], ..., e[6] describe the boundary conditions (values of ei, i=1, ..., 6, in (2));

neither e[l] nor e[4] is allowed to vanish.

void femlagskew(f1oat x[l, float y[l, int n, float (*q) (float), float (*r) (float) , float (*f) (float) , int order, float e [I )

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); int 1,ll; float xll,xl,h,al2,a2l,bl,b2,taul,tau2,ch,tl,g,yl,pp,el,e2,e3,e4,

e5, e6, *t, *super, *sub, *chi, *gi,q2, r2, £2, ql, rl, £1, h2, s12, q3, r3, f3, sl3, s22,x2, h6, h15, c12, c32,a13,a31, a22,a23,a32, b3, tau3,q4, r4, £4, s14, s23,x3, h12, h24,det, cl3, c42,c43,a14, a24, a33,a34,a41,a42,a43,b4,tau4;

1=1; xl=x [O] ; el=e [ll ; e2=e [21 ; e3=e [ 31 ; e4=e [41 ; e5=e [51 ; e6=e [61 ; while (1 <= n) {

xll=xl; 11=1-1; xl=x [ll ; h=xl-xll; if (order == 2) {

/ * element mat vec evaluation 1 * / if (1 == 1) {

q2= (*q) (~11) ; r2= (*r) (xll) ; f2=(*f) (xl1) ;

1 J h2=h/2 .O; sl2 = -l.O/h; q1=q2 ; q2= (*q) (xl) ; rkr2 ; r2= (*r) (xl) ; fl=f2; f2=(*f) (xl) ; bl=h2*f 1; b2=h2*f2; taul=h2*rl; tau2=h2*r2; a12=s12+q1/2.0; a2ks12-q2/2.0;

) else if (order == 4) { / * element mat vec evaluation 2 * / if (1 == 1) {

q3= (*q) (~11) ; r3= (*r) (xll) ; f3= (*f) (~11) ;

1

Copyright 1995 by CRC Press, Inc

Page 507: Numerical Library in C for Scientists and Engineers A

h6=h/6.0; h15=h/1.5; ql=q3 ; q2= (*q) (x2) ; q3= (*q) (xl) ; rl=r3 ; r2= (*r) (x2) ; r3= (*r) (xl) ; fl=f3 ; f2= (*f) (x2) ; f3= (*f) (xl) ; bl=h6*f 1; b2=h15*f2; b3=h6*f3; taul=h6*rl; tau2=h15*r2; tau3=h6*r3; sl2 = -1.O/h/0.375; S13 = -~12/8.0; 522 = -2.0*512; a12=s12+q1/1.5; a13=s13-q1/6.0; a21=s12-q2/1.5; a23=s12+q2/1.5; a22=s22+tau2; a31=s13+q3/6.0; a32=s12-q3/1.5; c12 = -a12/a22; c32 = -a32/a22; a12=a13+c12*a23; a21=a31+c32*a21; bl += c12*b2; b2=b3+c32*b2; tau1 += cl2*tau2; tau2=tau3+c32*tau2;

} else { / * element mat vec evaluation 3 */ if (1 == 1) {

q4= (*q) ( ~ 1 1 ) ; r4= (*r) (xll) ; f4= (*f) (xl1) ;

1 ~2=~11+0.27639320225*h; x3=x1-x2+x11; h12=h/12.0; h24=h/2.4; gl=q4 ; q2= (*q) (x2) ; q3= (*q) (x3) ; q4= (*q) (xl) ; rl=r4 ; r2= (*r) (x2) ; r3= (*r) (x3) ; r4= (*r) (xl) ; fl=f4; f2=(*f) (x2); f3=(*f) (x3); f4=(*f) (xl); ,912 = -4.8784183052080/h; ~13=0.7117516385414/h; s14 = -0.16666666666667/h; s23=25.O*sl4; ~ 2 2 = -2.0*~23; bl=hl2*fl; b2=h24*£2; b3=h24*f3; b4=h12*£4; taul=hl2*rl; tau2=h24*r2; tau3=h24*r3; tau4=h12*r4; al2=~12+0.67418082864578*ql; a13=~13-0.25751416197912*q1; a14=s14+q1/12.0;

Copyright 1995 by CRC Press, Inc

Page 508: Numerical Library in C for Scientists and Engineers A

a21=~12-0.67418082864578*q2; a22=s22+tau2; a23=~23+0.9316949906249O*q2; a24=s13-0.25751416197912*q2; a3l=sl3+O. 25751416l979l2*q3; a32=s23-0.93169499062490*q3; a33=s22+tau3; a34=~12+0.67418082864578*q3; a41=s14-q4/12.0; a42=~13+0.25751416197912*q4; a43=s12-0.67418082864578*q4; det=a22*a33-a23*a32; c12=(a13*a32-a12*a33)/det; c13=(a12*a23-a13*a22)/det; c42=(a32*a43-a42*a33)/det; c43=(a42*a23-a43*a22)/det; taul += c12*tau2+c13*tau3; tau2=tau4+~42*tau2+~43*tau3; a12=a14+~12*a24+~13*a34; a2l=a41+~42*aZl+c43*a31; bl += c12*b2+c13*b3; b2=b4+~42*b2+~43*b3;

1 if (1 == 1 I I 1 == n) {

/ * boundary conditions * / if (1 == 1 && e2 == 0.0) {

taukl. 0 ; bl=e3/el; a12=0.0 ;

) else if (1 == 1 && e2 ! = 0.0) { taul - = el/e2; bl - = e3/e2;

) else if (1 == n && e5 == 0.0) { tau2=l. 0 ; a21=0.0 ; b2=e6/e4;

) else if (1 == n && e5 ! = 0.0) ( tau2 += e4/e5; b2 += e6/e5;

, I / * forward babushka * / if (1 == 1) {

chi [O] =ch=tl=taul; t [O] =tl; gi [O] =g=yl=bl; y [Ol =yl; sub [OI =a21; super [Ol =al2; pp=a2l/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; tl=tau2; yl=b2 ;

) else { chi [lll = ch += taul; gi [lll = g += bl; sub [lll =a21; super [lll =al2; pp=a2l/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; t [lll =tl+taul; tl=tau2; y 1111 =yl+bl; yl=b2 ;

i * backward babushka * / pp=yl; y [nl =g/ch; g=PP ; ch=tl;

Copyright 1995 by CRC Press, Inc

Page 509: Numerical Library in C for Scientists and Engineers A

l=n-1; while (1 >= 0) (

pp=super [ll/ (ch-sub [11 ) ; tl=t [ll ; ch=tl-ch*pp; yl=y [ll ; g=yl-g*pp; y[l] = (gi [ll +g-yl) /(chi [ll +ch-tl) ; I--;

I free real vector (t, 0) ; f reeIrealIvector (super, 0) ; free real vector (sub, 0) ; f ree~real~vector (chi, 0) ; f ree-real-vector (gi, 0) ;

1

5.5.3 Linear methods - Fourth order self adjoint

femhermsym

Solves a fourth order self-adjoint linear two point boundary value problem by means of Galerkin's method with continuous differentiable piecewise polynomial functions [BakH76, He75, StF731. femhermsym computes approximations y, and dy, (n=O, ...JV) to the values at the points x = x,, where

- w < a = x , < x , < ... < x N = b < ee of the real valued function y(x) and its derivative Dy(x), where y satisfies the equation

-D2(p(x)dy(x)) - D(q(x)Dy(x)) + r(x)y(x) = f(x) (1) where D=ddx, with boundary conditions

y(a) = el, Dy(4 = e,, y(b) = e,, Dy(b) = e,. (2) It is assumed that (a) p(x) should be positive on the interval [xo,xN], and q(x) and r(x) should be nonnegative

there; (b) p(x), q(x), r(x) and f(x) are required to be sufficiently smooth on the interval [xo,xN]

except at the knots, where discontinuities of the derivatives are allowed; in that case the order of accuracy is preserved.

The solution is approximated by a function which is continuously differentiable on the closed interval [xo,xN] and a polynomial of degree less than or equal to k (k = 1 + orderf2) on each closed segment [xj-,,x,] G=l, ...JV). This function is entirely determined by the values of the zeroth and first derivative at the knots xj and by the value it has at k-3 interior knots on each closed segment [xj-,,x,]. The values of the function and its derivative at the knots are obtained by the solution of an order+l diagonal linear system of (k-1)N-2 unknowns. The entries of the matrix and the vector are inner products which are approximated by piecewise k-point Lobatto quadrature. The evaluation of the matrix and the vector is performed segment by segment. If k>3 then the resulting linear system can be reduced to a pentadiagonal system by means of static condensation. This is possible because the function values at the interior knots on each segment [xj-,,x,] do not depend on function values outside that segment. The final pentadiagonal system, since the matrix is symmetric positive definite, is solved by means of Cholesky's decomposition method.

The theory upon which the method of solving the above boundary value problem is based on an extension of that described in femlagsym. The function y(x) is now approximated not, as was the case for the method of femlagsym (see formula (4) there) by a function which is simply continuous and equal to a polynomial of degree k over the

Copyright 1995 by CRC Press, Inc

Page 510: Numerical Library in C for Scientists and Engineers A

interval [x,.,,~,], but by a (necessarily continuous) function whose first derivative possesses these properties. Radau-Lobatto quadrature is used, systems of linear equations are derived, and coefficients concerning internal points of [xn,,xn] are eliminated just as is described in femlagsym. Now, however, the resulting system of linear equations involving coefficients equal to the yn and dy, is pentadiagonal and is solved by Cholesky's decomposition method.

Function Parameters: void femhermsym (x,y, n,p,q,r,Jorder, e)

x: float x[O:n]; entry: a = x, < x, < ... < xn = b is a partition of the segment [a,b];

y: float y[I:2n-21; exit: y[2i-I] is an approximation to y(x[i]), y[2i] is an approximation to dy(x[i]),

where y(x) is the solution of the equation (1) with boundary conditions (2); n: int;

entry: the upper bound of the arrays x (value of N above), n > 1; p : float (*p)(x);

the procedure to compute p(x), the coefficient of D2y(x) in equation (1); p(x) should be strictly positive;

q: float (*q)(x); the procedure to compute q(x), the coefficient of Dy(x) in equation (1); q(x) should be nonnegative;

r: float (*r)(x); the procedure to compute r(x), the coefficient of y(x) in equation (1); r(x) should be nonnegative;

J float (*J(x); the procedure to compute f(x), the right hand side of equation (1);

order: int; entry: order denotes the order of accuracy required for the approximate solution of

the differential equation; let h = max(x[i]-x[i-In, then 1 y[2i-I] - y(x[ij) I I c l *hard", ly[2i] - Dy(x[i]) I I c2*harder, i=l, ..., n-I; order can be chosen equal to 4, 6 or 8 only;

e: float e[I:4]; entry: e[l], ..., e[4] describe the boundary conditions (values of ei, i=1, ..., 4, in (2)).

Function used: chldecsolbnd.

void femhermsym (float x [I , float y [ I , int n, float (*p) (float) , float (*q) (float), float (*r) (float), float (*f) (float), int order, float e [I )

1 ' float *allocate-real-vector(int, int);

void free-real-vector(f1oat * , int) ; void chldecsolbnd (f loat [ I , int, int, float [I , float 11 ) ; void femhermsymeval (int, int, float ( * I (float) ,

float ( * ) (float), float ( * ) (float), float ( * ) (float), float *, float * , float *, float *, float * , float *, float * , float *, float * , float * , float *, float * , float *, float *, float *, float);

int l,n2,v,w; float *a, em [41 ,all, a12, a13, a14, a22, a23, a24, a33, a34, a44, ya, yb, za,

zb, bl, b2, b3, b4, dl, d2, el, rl, r2 ,xll,xl;

Copyright 1995 by CRC Press, Inc

Page 511: Numerical Library in C for Scientists and Engineers A

w=v=o ; n2 =n+n- 2 ; xll=x [O] ; xl=x[11 ; ya=e [ll ; za=e [21 ; yb=e [31 ; zb=e [41 ; / * element matvec evaluation * / femhermsymeval (order, 1,p, q, r, f, &all, &a12, &al3, &al4, &a22,

&a23, &a24, &a33, &a34, &a44, &bl, &b2, &b3, &b4, &xl,xll) ; em [21 =FLT-EPSILON; rl=b3-a13*ya-a23*za; dl=a33 ; d2=a44 ; rZ=b4-al4*ya-a24*za; el=a34 ; I++; while (1 < n) {

xl l=xl; xl=x [ll ; / * element matvec evaluation * / femhermsymeval (order,l,p,q,r, f, &all, &a12, &a13, &a14, &a22,

&a23, &a24, &a33, &a34, &a44, &bl, &b2, & b 4 , &xl,xll) ; a [w+ll =dl+all; a [w+41 =el+a12 ; a [w+71 =a13 ; a [w+lO] =a14 ; a [w+51 =d2+a22; a [w+81 =a23 ; a [w+ll] =a24 ; a [w+141 =O. 0; y [v+ll =rl+bl; y [v+21 =r2+b2 ; rl=b3 ; r2=b4 ; v += 2; w += 8; dl=a33 ; d2=a44; el=a34 :

l=n; xll=xl; xl=x [ll ; /* element matvec evaluation * / femhermsymeval (order, l,p, q, r, f, &all 2 , &al3, &a14, &a22,

&a23, &a24, &a33, &a34, &a44, &bl, &b2, &b3, &b4, &xl, xll) ; y 11-12-11 =rl+bl-al3*yb-al4*zb; y [nZ] =rZ+b2-a23*yb-a24*zb; a [w+ll =dl+all; a [w+41 =el+a12 ; a [w+S] =d2+a22; chldecsolbnd(a,n2, 3,em, y) ; free-real-vector (a, 1) ;

1 void femhermsymeval (int order, int 1, float (*p) (float) ,

float (*q) (float), float (*r) (float), float (*f) (float), float *all, float *a12, float *a13, float *a14, float *a22, float *a23, float *a24, float *a33, float *a34, float *a44, float *bl, float *b2, float *b3, float *b4, float *xl, float xll)

/ * this function is internally used by FEMHERMSYM */

static float p3,p4,p5, q3,q4,q5, r3,r4, r5, f3, f4, f5;

if (order == 4) ( float x2,h,h2,h3,pl,p2,ql,q2,rl,r2,fl,f2,bll,b12,b13,b14,b22,

b23,b24,b33,b34,b44,sll,s12,s13,s14,s22,~23,~24,~33,~34,

Copyright 1995 by CRC Press, Inc

Page 512: Numerical Library in C for Scientists and Engineers A

)* element bending matrix */ pl=p3 ; p2=(*p) (x2) ; p3= (*p) (*xl) ; bll=6. O* (pl+p3) ; b12=4.0*p1+2.0*p3; b13 = -bll; b14=bll-b12; b22=(4.0*pl+p2+p3)/1.5; b23 = -b12; b24=b12-b22; b33=bll; b34 = -b14; b44=b14-b24; / * element stiffness matrix * /

sll=l :5*q2; s12=q2/4.0; ~ 1 3 = -Sll; s14=S12; s24=q2/24.0; ~22=q1/6.0+~24; s23 = - ~ 1 2 ; s33=sll; 534 = -s12; s44=~24+q3/6.0; / * element mass matrix * / rl=r3; r2= (*r) (x2) ; r3= (*r) (*xl) ; mll= (rl+r2) /6.0; m12=r2/24.0; m13=r2/6.0; m14 = -ml2; m22=r2/96.0; m23 = -m14; m24 = -m22; m33=(r2+r3)/6.0; m3 4 =ml4 ; m44=m22; / * element load vector * / fl=f3; f2=(*f) (x2) ; f3=(*f) (*xl); *bl=h*(f1+2.0*f2)/6.0; *b3=h* (f3+2.O*f2) /6.O; *b2=h2*£2/12.0; *b4 = - (*b2); *all=bll/h3+sll/h+mll*h; *a12=b12/h2+~12+m12*h2; *a13=b13/h3+~13/h+ml3*h; *a14=b14/h2+~14+m14*h2; *a22=b22/h+s22*h+m22*h3; *a23=b23/h2+~23+m23*h2; *a24=b24/h+s24*h+m24*h3; *a34=b34/hZ+s34+m34*h2; *a33=b33/h3+~33/h+m33*h; *a44=b44/h+s44*h+m44*h3;

} else if (order == 6) ( float h, h2, h3 ,x2,x3 ,pl,p2 ,p3, ql, q2, q3, rl, r2, r3, fl, £2, £3, bll, b12,

b13,b14,b15,b22,b23,b24,b25,b33,b34,b35,b44,b45,b55,s11,

Copyright 1995 by CRC Press, Inc

Page 513: Numerical Library in C for Scientists and Engineers A

~ 1 2 , ~ 1 3 , ~ 1 4 , ~ 1 5 , ~ 2 2 , ~ 2 3 , ~ 2 4 , ~ 2 5 , ~ 3 3 , ~ 3 4 , ~ 3 5 , ~ 4 4 , ~ 4 5 , ~ 5 5 , mll,m12,m13 ,m14,m15,m22,m23 ,m24,m25,m33 ,m34,m35,m44,m45, m55,a15,a25,a35,a45,a55,cl,c2,~3,~4,bS;

if (1 == 1) { p4= (*p) ( ~ 1 1 ) ; q4= (*q) ( ~ 1 1 ) ; r4= (*r) (xll) ; f4= (*f) (xl1) ;

I h= (*xl) -xll; h2=h*h; h3 =h*h2 ; x2=0.27639320225*h+xll; ~ 3 = x 1 1 + (*xl) -x2 ; / * element bending matrix * / pl=p4 ; p2= (*p) (x2) ; p3=(*p) (x3) ;

b23=6.6666666666667e0*~1-3.-7791278464167e0*p2+ 2.4579451308295e-l*p3+3.6666666666667eO*p4;

b25 = - (b12+b23) ; b24 = - (b22+b23+b25/2.0) ; b33=8.3333333333333eO*pl+1.4422084194666el*p2+

1.1124913866726e-l*p3+4.0333333333333el*p4; b35 = - (b13+b33) ; b34 = - (b23+b33+b35/2.0) ; b45 = - (b14+b34) ; b44 = - (b24+b34+b45/2.0) ; b55 = -(b15+b35); / * element stiffness matrix * / ql=q4 ; q2= (*q) (x2) ; q3= (*q) (x3) ;

8.3333333333338eL2*q4; s45 = - (s14+~34) ; 955 = - (s15+~35) ; /* element mass matrix * / r b r 4 ; r2= (*r) (x2) ; r3= (*r) (x3) ; r4= (*r) (*xl) ; m11=8.3333333333333e-2*r1+1.0129076086083e-l*r2+

7.3759058058380e-3*r3; m12=1.3296181273333e-2*r2+1.3704853933353e-3*r3; m13 = -2.7333333333333e-2*(r2+r3); m14=5.0786893258335e-3*r2+3.5879773408333e-3*r3; m15=1.3147987115999e-1*r2-3.5479871159991e-2*r3; m22=1.7453559925000e-3*r2+2.5464400750059e-4*r3; m23 = -3.5879773408336e-3*r2-5.0786893258385e-3*r3;

Copyright 1995 by CRC Press, Inc

Page 514: Numerical Library in C for Scientists and Engineers A

m24=6.6666666666667e-4*(r2+r3); m25=1.7259029213333e-2*r2-6.5923625466719e-3*r3; m33=7.375905805838Oe-3*r2+1.0129076086083e-l*r3+

8.3333333333333e-2*r4; m34 = -1.3704853933333e-3*r2-1.3296181273333e-2*r3; m35 = -3.5479871159992e-2*r2+1.3147987115999e-l*r3; m44=2.5464400750008e-4*r2+1.7453559924997e-3*r3; m45=6.5923625466656e-3*r2-1.7259029213330e-2*r3; m55=0.17066666666667eO*(r2+r3); / * element load vector * / fl=f 4 ; f2=(*f) (x2); f3=(*f) (x3); f4=(*f) (*xl) ; *bl=8.3333333333333e-2*f1+2.0543729868749e-l*f2-

5.5437298687489e-2*f3; *b2=2.6967233145832e-2*£2-1.0300566479175e-2*f3;

b5=2.6666666666667e-1*(f2+f3); *all=h2*(h2*mll+sll)+bll; *a12=h2*(h2*ml2+~12)+b12; *a13=h2* (hZ*ml3+sl3) +bl3; *a14=h2*(h2*m14+~14)+b14; a15=h2* (h2*m15+s15) +bl5; *a22=h2*(h2*m22+~22)+b22; *a23=h2*(h2*m23+~23)+b23; *a24=h2*(h2*m24+~24)+b24; a25=h2* (h2*m25+s25) +b25; *a33=h2*(h2*m33+~33)+b33; *a34=h2*(h2*m34+~34)+b34; a35=h2* (h2*m35+s35) +b35; *a44=hZ*(h2*m44+~44)+b44; a45=h2* (h2*m45+545) +b45; a55=hZ*(h2*m55+~55)+b55; / * static condensation * / cl=a15/a55; c2=a25/a55; c3=a35/a55; c4=a45/a55; *bl= ( (*bl) -cl*b5) *h; *b2= ( (*b2) -~2*b5) *h2; *b3= ( (*b3) -~3*b5) *h; *b4= ( (*b4) -~4*b5) *h2; *all= ( (*all) -cl*al5) /h3; *a12= ( (*a12) -cl*a25) /h2; *a13= ( (*al3) -cl*a35) /h3; *a14= ( (*a14) -cl*a45) /h2; *a22= ( (*a22) -c2*a25) /h; *a23= ( (*a23) -c2*a35) /h2; *a24= ( (*a24) -cZ*a45) /h; *a33=( (*a33) -c3*a35) /h3; *a34=( (*a34) -c3*a45) /h2; *a44= ( (*a44) -c4*a45) /h;

} else { float x2, x3, x4, h, h2, h3, pl, p2, p3, p4, q1, q2, q3, q4, rl, r2, r3,r4,

fl,f2,f3,f4,bll,b12,b13,b14,b15,b16,b22,b23,b24,b25,b26, b33,b34,b35,b36,b44,b45,b46,b55,b56,b66,s11,s12,s13,s14, S 1 5 , ~ 1 6 , ~ 2 2 , ~ 2 3 , ~ 2 4 , ~ 2 5 , ~ 2 6 , ~ 3 3 , ~ 3 4 , ~ 3 5 , ~ 3 6 , ~ 4 4 , ~ 4 5 , ~ 4 6 , s55,s56,s66,mll,m12,m13,m14,m15,m16,m22,m23,m24,m25,m26, m33,m34,m35,m36,m44,m45,m46,m55,m56,m66,~15,~16,~25,~26, c35,c36,c45,c46,b5,b6,a15,a16,a25,a26,a35,a36,a45,a46, a55,a56,a66,det;

if (1 == 1) { p5= (*p) (~11) ; q5= (*q) (~11) ; r5= (*r) (xll) ; f5=(*f) (xl1) ;

I h= (*xl) -xll; h2=h*h; h3=h*h2; x2=xll+h*0.172673164646;

Copyright 1995 by CRC Press, Inc

Page 515: Numerical Library in C for Scientists and Engineers A

x3=xll+h/2.0; x4=x11+ (*XI) -x2; / * element bending matrix * / pl=p5; p2= (*p) (x2) ; p3= (*p) (x3) ; p4=(*p) (x4) ; p5= (*p) (*xl) ; bll=105.8*p1+9.8*p5+7.3593121303513e-2*p2+

2.2755555555556el*p3+7.0565656088553eO*p4; b12=27.6*p1+1.4*p5-3.41554824811e-l*p2+

2.8444444444444eO*p3+1.0113960946522eO*p4; b13 = -32.2*(pl+p5)-7.2063492063505e-l*(p2+p4)+

2.2755555555556el*p3; bl4=4.6*p1+8.4*~5+1.0328641222944e-l*p2-

2.8444444444444eO*p3-3.3445562534992eO*p4; b15 = - (bll+bl3) ; b16 = - (blZ+b13+bl4+b15/2.0) ; b22=7.2*pl+0.2*p5+1.5851984028581eO*p2+

3.5555555555556e-l*p3+1.4496032730059e-1*p4; b23 = -8.4*p1-4.6*~5+3.3445562534992eO*p2+

2.8444444444444eOlp3-1.0328641222944e-1*p4; b24=1.2* (pl+p5) -4.7936507936508e-l* (p2+p4) -

3.5555555555556e-1*p3; b25 = - (b12+b23) ; b26 = - (b22+b23+b24+b25/2.0) ; b33=7.0565656088553eO*p2+2.2755555555556el*p3+

7.3593121303513e-2*p4+105.8*p5+9.8*pl; b34 = -1.4*p1-27.6*p5-1.0113960946522eO*p2-

2.8444444444444eO*p3+3.41554824811OOe-1*p4; b35 = - (b13+b33); b36 = - (b23+b33+b34+b35/2.0) ; b44=7.2*p5+pl/5.0+1.4496032730059e-l*p2+

3.5555555555556e-l*p3+1.585198402858leO*p4; b45 = - (bl4+b34) ; b46 = - (b24+b34+b44+b45/2.0) ; b55 = - (bl5+b35) ; b56 = -(b16+b36); b66 = - (b26+b36+b46+b56/2.0) ; / * element stiffness matrix * / ql=q5 ; q2= (*q) (x2) ; q3=(*q) (x3) ; q4= (*q) (x4) ; q5= (*q) (*xl) ; ~11=3.0242424037951eO*q2+3.1539909130065e-2*q4; ~12=1.2575525581744e-1*q2+4.1767169716742e-3*q4; 913 = -3.0884353741496e-l* (q2+q4) ; s14=4.0899041243062e-2*q2+1.2842455355577e-2*q4; SlS = - ( ~ 1 3 + ~ l l ) ; ~16=5.9254861177068e-1*q2+6.0512612719116e-2*q4; s22=5.2292052865422e-3*q2+5.5310763862796e-4*q4+q1/20.0; 523 = -1.2842455355577e-2*q2-4.0899041243062e-2*q4; s24=1.7006802721088e-3*(q2+q4); S25 = - ( ~ 1 2 + ~ 2 3 ) ; s26=2.4639593097426e-2*q2+8.0134681270641e-3*q4; s33=3.1539909130065e-2*q2+3.0242424037951e0*q4; s34 = -4.1767169716742e-3*q2-1.2575525581744e-l*q4; S35 = - ( ~ 1 3 + ~ 3 3 ) ; s36 = -6.0512612719116e-2*q2-5.9254861177068e-l*q4; s44=5.5310763862796e-4*q2+5.2292052865422e-3*q4+q5/20.0; S45 = - ( ~ 1 4 + ~ 3 4 ) ; ~46=8.0134681270641e-3*q2+2.4639593097426e-2*q4; S55 = - ( ~ 1 5 + ~ 3 5 ) ; s56 = - (s16+~36); ~66=1.1609977324263e-l*(q2+q4)+3.5555555555556e-l*q3; / * element mass matrix * / rl=r5 ; r2= (*r) (x2) ; r3= (*r) (x3) ; r4= (*r) (x4) ; r5= (*r) (*xl) ; m11=9.7107020727310e-2*r2+1.5810259199180e-3*r4+r1/20.0; m12=8.2354889460254e-3*r2+2.1932154960071e-4*r4;

Copyright 1995 by CRC Press, Inc

Page 516: Numerical Library in C for Scientists and Engineers A

m13=1.2390670553936e-2*(r2+r4); m14 = -1.7188466249968e-3*r2-1.0508326752939e-3*r4; m15=5.3089789712119e-2*r2+6.7741558661060e-3*r4; m16 = -1.7377712856076e-2*r2+2.2173630018466e-3*r4; m22=6.9843846173145e-4*r2+3.0424512029349e-5*r4; m23=1.0508326752947e-3*r2+1.7188466249936e-3*r4; m24 = -1.4577259475206e-4*(r2+r4); m25=4.5024589679127e-3*r2+9.3971790283374e-4*r4; m26 = -1.4737756452780e-3*r2+3.0759488725998e-4*r4; m33=1.5810259199209e-3*r2+9.7107020727290e-2*r4+r5/20.0; m34 = - 2 . 1 9 3 2 1 5 4 9 6 0 1 3 1 e - 4 * r 2 - 8 . 2 3 5 4 e - 3 * r 4 ; m35=6.7741558661123e-3*r2+5.3089789712112e-2*r4; m36 = -2.2173630018492e-3*r2+1.7377712856071e-2*r4; m44=3.0424512029457e-5*r2+6.9843846173158e-4*r4; m45 = -9.3971790283542e-4*r2-4.5024589679131e-3*r4; m46=3.0759488726060e-4*r2-1.4737756452778e-3*r4; m55=2.9024943310657e-2*(r2+r4)+3.5555555555556e-l*r3; m56=9.5006428402050e-3*(r4-r2); m66=3.1098153547125e-3*(r2+r4); / * element load vector * / fkf.5; f2=(*f) (x2); f3=(*f) (x3); f4=(*f) (x4) ; f5= (*f) (*xl) ; *b1=1.6258748099336e-l*f2+2.0745852339969e-2*f4+fl/20.0; *b2=1.3788780589233e-2*£2+2.8778860774335e-3*f4; *b3=2.0745852339969e-2*f2+1.6258748099336e-l*f4+f5/20.0; *b4 = -2.8778860774335e-3*f2-1.3788780589233e-2*£4; b5=(£2+f4)/11.25+3.5555555555556e-1*£3; b6=2.9095718698132e-2*(f4-f2); *all=h2* (h2*mll+sll) +bll; *a12=h2*(h2*mlZ+s12)+b12; *a13=h2*(h2*m13+s13)+b13; *a14=h2*(h2*m14+~14)+b14; a15=h2* (hZ*m15+s15) +b15; a16=h2* (h2*m16+s16) +bl6; *a22=hZ*(h2*m22+~22)+b22; *a23=h2*(hZ*m23+~23)+b23; *a24=h2*(h2*m24+~24)+b24; a25=h2*(h2*m25+~25)+b25; a26=h2* (h2*m26+s26) +b26; *a33=h2*(h2*m33+~33)+b33; *a34=h2*(h2*m34+~34)+b34; a35=h2* (h2*m35+s35) +b35; a36=h2* (hZ*m36+s36) +b36; *a44=h2*(h2*m44+~44)+b44; a45=h2* (h2*m45+s45) +b45; a46=h2* (h2*m46+s46) +b46; a55=h2*(h2*m55+~55)+b55; a56=h2*(h2*m56+~56)+b56; a66=hZ* (h2*m66+s66) +b66; / * static condensation * / det = -a55*a66+a56*a56; c15=(a15*a66-a16*a56)/det; cl6= (a16*a55-a15*a56) /det; c25= (a25*a66-a26*a56) /det; c26=(a26*a55-a25*a56)/det; c35=(a35*a66-a36*a56)/det; c36=(a36*a55-a35*a56)/det; c45=(a45*a66-a46*a56)/det; c46=(a46*a55-a45*a56)/det:

Copyright 1995 by CRC Press, Inc

Page 517: Numerical Library in C for Scientists and Engineers A

5.5.4 Non-linear methods

nonlinfemlagskew

Solves a nonlinear two point boundary value problem with spherical coordinates EBab72, Bak77, BakH76, StF731. nonlinfemlagskew solves the differential equation

D(xncDy(x))/P = f(x,y,Dy(x)), a < x < b, (1) where D=ddx, with boundary conditions

e ~ v ( 4 + e2Dy(a) = e,, ey(b) + e,Dy(b) = e, (el, e, # 0). (2) The functions J; d m and df/dz are required to be sufficiently smooth in their variables on the interior of every segment [ X ~ , X ~ + ~ ] (i=O, ..., n-1).

Let y[O](x) be some initial approximation of y(x); then the nonlinear problem is solved by successively solving

-D(x""Ddkl(x))/x nc + +(~>,y[kl(~)J?Y[klW *g[kl(x) + fi(x>,y[kl(x),Dyrkl(x)) *Dg[kl(x) = D(x"cDyrkl(x)/x"c - f(~>yrkl~Dyrkl(x,), Xo < X < X,,

with boundary conditions elg[kl(xd + e,Dg[kl(xo) = 0, e4g[kl(xJ + e,Dg[kl(x J = 0

with Galerkin's method (see femlagsym) and putting y[k+ll(x) = y[kl(~) + g[kl(x), k=O,l,...

This is the so-called Newton-Kantorowitch method.

Function Parameters: void nonlinfemlagskew (x,y, n,J;JL,fi, nc, e)

x: float x[O:n]; entry: a = xo < x, < ... < x, = b is a partition of the segment [a,b];

y: float y[O:n]; entry: y[i], i=O,l, ..., n, is an initial approximate solution at x[i] of the differential

equation (1) with boundary conditions (2); exit: y[i], i=O,l, ..., n, is the Galerkin solution at x[i] of the differential equation (1)

with boundary conditions (2); n: int;

entry: the upper bound of the arrays x and y, n > 1; j float (*j)(x,y,z); float x,y,z;

the procedure to compute the right hand side of (1); (f(x,y,) is the right hand side of equation (1));

&: float (*JL)(x,y,z); float x,y,z; the procedure to compute JL(x,y,z), the derivative off with respect to y;

fi: float (*fi)(x,y,z); float x,y,z; the procedure to compute fi(x,y,z), the derivative off with respect to z;

nc: int; entry: if nc = 0, Cartesian coordinates are used;

if nc = 1, polar coordinates are used; if nc = 2, spherical coordinates are used;

e: float e[l:6];

Copyright 1995 by CRC Press, Inc

Page 518: Numerical Library in C for Scientists and Engineers A

entry: e[I], ..., e[6] describe the boundary conditions (values of ei, i=1, ..., 6 , in (2)); e[l] and e[4] are not allowed to vanish both.

Function used: dupvec.

void nonlinfemlagskew (f loat x [I , float y [I , int n. float (*f) (float, float, float), float (*fy) (float, float, float), float (*fz) (float, float, float), int nc, float e [I )

I float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void dupvec(int, int, int, float [ I , float [I ) ; int l,ll,it; float xll,xl, h, al2, a21, bl, b2, taul, tau2, ch, tl,g, yl,pp,

zll, zl,el,e2,e4, e5,eps, rho, *t, *super, *sub, *chi, *gi, *z, xm,vl,vr,wl,wr,pr,qm,rm,fm,x112,xllxl,x12,zm,zaccm;

dupvec(O,n.O, z,y) ; el=e ill ; e2=e (21 ; e4=e [41 ; e5=e [51 ; it=1; do (

1 4 ; xl=x [OI ; zl=z LO1 ; while (1 c= n) {

xll=xl; 11=1-1; xl=x 111 ; h=xl-xll ; z11=21; zl=z [11 ; /* element mat vec evaluation 1 * / if (nc == 0)

vl=vr=0.5; else if (nc == 1) {

vl=(xll*2.0+x1)/6.0; vr= (xll+xl*2.0) /6.0;

} else { x112=xll*x11/12.0; xllxl=xll*xl/6.0; x12=x1*x1/12.0; vl=3.0*x112+x11x1+x12; vr=3.0*xl2+xllxl+xll2;

1 1

wl=h*vl ; wr=h*vr; pr=vr/ (vl+vr) ; xm=xll+h*pr; zm=pr*zl+ (1.0-pr) *zll; zaccm= (21-zll) /h; qm= (*fz) ( x m , zm, zaccm) ; nn= (*fy) (xm, zm, zaccrn) ; fm= (*f) (xm, zm, zaccm) ; taul=wl*rm; tau2=wr*rm; bl=wl*fm- zaccm* (vl+vr) ; b2=wr*fm+zaccm*(vl+vr);

Copyright 1995 by CRC Press, Inc

Page 519: Numerical Library in C for Scientists and Engineers A

a12 = - (vl+vr) /h+vl*qm+ (1.0-pr) *pr*rm* (wl+wr) ; a21 = - (vl+vr) /h-vr*qm+ (1.0-pr) *pr*rm* (wl+wr) ;

if (1 == 1 I I 1 == n) ( / * boundary conditions * / if (1 == 1 &&e2 == 0.0) {

taukl.0; bl=a12=0.0;

) else if (1 == 1 && e2 ! = 0.0) ( taul -= el/e2;

) else if (1 == n && e5 == 0.0) ( tau2=1.0 ; b2=a21=0.0;

) else if (1 == n && e5 ! = 0.0) ( tau2 += e4/e5;

1 1

/* forward babushka */ if (1 == 1) (

chi 101 =ch=tl=taul; t 101 =tl; gi [Ol =g=yl=bl; y [Ol =yl; sub 101 =a21; super [O] =a12 ; pp=a2l/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; tl=tau2 ; yl=b2 ;

] else { chi[lll = ch += taul; gi [lll = g += bl; sub [ll] =a21; super [lll =al2; pp=a2l/ (ch-al2) ; ch=tau2-ch*pp; g=b2-g*pp; t ill1 =tl+taul; tl=tau2 ; y [lll =yl+bl; yl=b2 ;

1 i++;

1 /* backward babushka */ pp=yl; y lnl =g/ch; g=PP ; ch=tl; l=n- 1 ; while (1 >= 0) (

pp=super ill / (ch-sub [ll) ; tl=t [ll ; ch=tl-ch*pp; yl=y [ll ; g=yl-g*pp; y [ll = (gi [ll +g-yl) / (chi [ll +ch-tl) ; 1--;

I eps=O. 0; rho=l.O; for (1=0; l<=n; I++) (

rho += fabs ( z [ll ) ; eps += fabs(y[ll); 2111 -= y[ll ;

1 rho *= FLT-EPSILON; it++;

} while (eps > rho) ; dupvec(O,n,O,y,z); f ree-real-vector (t, 0) ; free-real-vector(super,O); free-real-vector(sub,O); f ree-real-vector (chi, 0 ) ;

Copyright 1995 by CRC Press, Inc

Page 520: Numerical Library in C for Scientists and Engineers A

f ree-real-vector (gi, 0) ; free-real-vector (z,O) ;

1

5.6 Two-dimensional boundary value problems

5.6.1 Elliptic special linear systems

A. richardson

Solves a system of linear equations with a coefficient matrix having positive real eigenvalues by means of a non-stationary second order iterative method: Richardson's method [CoHHS73, Vh681. Since Richardson's method is particularly suitable for solving a system of linear equations that is obtained by discretizing a two-dimensional elliptic boundary value problem, the procedure richardson is programmed in such a way that the solution vector is given as a two-dimensional array u/j,l], Ij Sj S uj, IN I 1 I ul. The coefficient matrix is not stored, but each row corresponding to a pair (13 is generated when needed. richardson can also be used to determine the eigenvalue of the coefficient matrix corresponding to the dominant eigenfunction.

richardson either (a) determines an approximation u, to the solution of the system of equations

A u = f (1) where A is an NxN matrix (N=(uj-Ij+l)*(ul-ll+l); Ij, I1 1 I) whose eigenvalues hi are such that 0 < A, < A, < ... < A, = b, and u is a vector whose components up) are stored in the locations of a two-dimensional real array U by means of the mapping u~~("'-~~+')'"~+') in location Q,l) (j=Ij,Ij+l, ..., uj; I=ll,ll+l, ..., ul) or (b) estimates the eigenvalue A, of the matrix A just described.

In both cases a sequence of vectors uk ( k l , ..., n) is constructed from an initial member uo (if the parameter inap is given the value nonzero upon call of richardson, the components of uo are those stored in the locations of U prior to call; if inap is given the value zero, uo is the unit vector (1,1, ..., 1)) by means of the recursion

u, = Bouo - wovo uk+l = J k " k + (I - B k h k - l - wkvk @I

where vk = Auk - f (3)

and, with 0 < a < b, yo = (a + b)/(b - a) B o = 1, wo = 2/(b+a), B k = 2~oTkhJ/Tk+iOd, wk = 4Tkfj~J/((b-a)Tk+i&J),

Tk(yl = cos(k arccosb)) being a Tscheyscheff polynomial. Individually the u, vk satisfy the recursions

Ul = g o - ~ 0 4 ~ 0 + wd- uk+, = 6% - ~ U u k + (1 -BJuk-l + 4

VI = Po - ~DA)vo Vk+l = @k - W W k - (1 - Bbvk-I .

The residue vectors vk are then given explicitly by the formula Vk = Ck(a,b;A)vo

where Ck(a,b;A) = Tk((b+a-2A)/(b-a))/Tk((b+a)/(b-a)) .

Copyright 1995 by CRC Press, Inc

Page 521: Numerical Library in C for Scientists and Engineers A

Of all k-th degree polynomials pk with pk(0)=I, C,(a,b;X) is that for which maxlpk(X) I (a l X 5 b) is a minimum.

If, in the above, a < A,, 11 vk 11 tends to zero as k increases, and uk tends to the solution u of equation (1). The mean rate of convergence over k steps may be defined to be

- 1 1 v 1 I v 1 ) I k (where In is the natural logarithm) and the measure of this quantity computed during the implementation of richardson is

rk = -(1/(2k))pn{ 11 k 11 2 l 11 v~ 11 + ln{ 11 vk 11 a1 11 v~ 11 dl. If, however, A, < a, 11 vk 11 may not tend to zero, but an estimate of X, may be extracted from the uk and v,. If, in the decomposition of v, in terms of the eigenvalues of e, or A,

c,;cO, then A,, where ~k = II vk II 1 I( ~ k - ~ k - I II 4 = ~kV(ab) - ~d/(Va+db)*/4 - PJ

tends to A,. The estimates used in the implementation of richardson are & = (Ad2) + AJm))/2 where with 7 = 2, oo in both cases,

Pk(T) = 11 Vk 11 11 Uk-Uk-/ 11 ,, = /.4k(Ti@(ab) - pp)/(Va+4b)2/4 - /kk(T)) . In both cases it is required that b should be an upper bound for the eigenvalues h, of

A: it is remarked that, denoting the elements of A by A,,,, for all hi

Function Parameters: void richardson (u,Ij, uj, 11, ul, inap,residual,a, b,n,discr, k, rateconv,domeial out)

u: float u[Ij: uj,ll:ul]; after each iteration the approximate solution calculated by richardson is stored in u; entry: if inap is chosen to be nonzero then an initial approximation of the solution,

otherwise arbitrary; exit: the final approximation of the solution;

j : int; entry: lower and upper bound for the first subscript of u;

1 , int; entry: lower and upper bound for the second subscript of u;

inap: int; entry: if the user wishes to introduce an initial approximation then inap should be

chosen to be nonzero, choosing inap to be zero has the effect that all components of u are set equal to 1 before the first iteration is performed;

residual: void (*residual)(Ij, uj, 11, ul, u); suppose that the system of equation at hand is Au=J for any entry u the procedure residual should calculate the residual Au-fin each point j, I, where Ij Sj S uj, 11 I I I uul, and substitute these values in the array u;

qb : float;

Copyright 1995 by CRC Press, Inc

Page 522: Numerical Library in C for Scientists and Engineers A

entry: if one wishes to find the solution of the boundary value problem then in a and b the user should give a lower and upper bound for the eigenvalues for which the corresponding eigenfunctions in eigenfunction expansion of the residual Au-J; with u equals the initial approximation, should be reduced;

if the dominant eigenvalue is to be found then one should choose a greater than this eigenvalue;

n: int *; entry: gives the total number of iterations to be performed;

discr: float discr[l:2]; exit: after each iteration richardson delivers in discr[l] the Euclidean norm of the

residual (value of I( vn 1 1 , above), and in discr[2] the maximum norm of the residual (value of 11 v, 11, above);

k: int *; exit: counts the number of iterations richardson is performing;

rateconv: float *; exit: after each iteration the average rate of convergence is assigned to rateconv

(value of rn above); domeigval: float *;

exit: after each iteration the dominant eigenvalue, if present, is assigned to domeigval (value of An above); if there is no dominant eigenvalue then the value of domeigval is meaningless; this manifests itself by showing no convergence to a fixed value;

out: void (*out)(u, lj, uj, 11, ul, n, discr, k,rateconv, domeigval); by this procedure one has access to the following quantities: for Olkln the k-th iterand in u, the Euclidean and maximum norm of the k-th residual in discr[l] and discr[2], respectively; for O<kln also the average rate of convergence and the approximation to the dominant eigenvalue, both with respect to the k-th iterand in u, in rateconv and domeigval, respectively; moreover, out can be used to let n be dependent on the accuracy reached in approximating the dominant eigenvalue.

void richardson(f1oat **u, int lj, int uj, int 11, int ul, int inap, void (*residual) (int, int, int, int, float **) , float a, float b, int *n, float discr[l, int *k, float *rateconv, float *domeigval, void (*out) (float ** , int, int, int, int, int *, float [ I ,

int, float, float)) I

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); int j,l; float x,y,z,y0,c,d,alfa,omega,omega0,eigmax,eigeucl,euclres,maxres,

rcmax,rceucl,maxres0,euclresO,**v,**res,auxresO,auxv,auxu, auxres,eucluv,maxuv;

alf a=2.0 ; omega=4.0/ (b+a) ; yo= (b+a) / (b-a) ; x=0.5* (b+a) ; y= (b-a) * (b-a) /l6.0; Z=4.O*yO*yO;

Copyright 1995 by CRC Press, Inc

Page 523: Numerical Library in C for Scientists and Engineers A

c=a*b; c=sqrt (c) ; d=sqrt (a) +sqrt (b) ; d=d*d; if (!hap)

for (j=lj; j<=uj; j++) for (1=11; lc=ul; I++) u[jl 111 =1.0;

*k=O ; for (j=lj; jc=uj; j++)

for (1=11; l<=ul; 1++) res[jl [ll=u[jl [ll ; (*residual) (lj,uj,ll,ul,res) ; omega0=2.0/ (b+a) ; maxres0=euclres0=0.0; for (j=lj; j<=uj; j++)

for (1=11; l<=ul; 1++) { auxresO=res [ jl [l] ; v [jl [I] =u [jl 111 -omegaO*auxresO; auxresO=fabs (auxreso) ; maxresO = (maxresO c auxres0) ? auxresO : maxres0; euclresO += auxresO*auxresO;

1 euclresO=sqrt (euclreso) ; discr [ll =euclresO; discr [21 =maxresO; (*out) (u, lj ,uj, ll,ul,n, discr, *k, *rateconv, *domeigval) ; while (*k < *n) (

(*k) ++; / * calculate parameters alfa and omega for each iteration * / alfa=z/ (2-alfa) ; omega=l .O/ (x-omega*y) ; /* iteration * / eucluv=euclres=maxuv=maxres=O.O; for (j=lj; j<=uj; j++)

for (141; l<=ul; I++) res [jl [ll =v[jl [ll ; (*residual) (lj,uj,ll,ul,res); for (j=lj; j<=uj; j++)

for (1=11: lc=ul: I++) { . . &XV=U [ j] [11 ;' auxu=v[jl [ll ; auxres=res [ j I [l] ; auxv=alfa*auxu-omega*aures+(l.O-alfa v [ j I [I1 =auxv; u [ j I [ll =auxu; auxuzfabs (auxu-awv) ; auxres=fabs (auxres) ; maxuv = (maxuv < auxu) ? auxu : maxuv maxres = (maxres < auxres) ? auxres : maxres; eucluv += auxu*auxu; euclres += auxres*auxres;

1 eucluv=sqrt(eucluv); euclres=sqrt (euclres) ; discr [ll =euclres; discr [21 =maxres; maxuv=maxres/maxuv; eucluv=euclres/eucluv; eigmax=maxuv* (c-maxuv) / ( 0.2 5*d-maxuv) ; eigeucl=eucluv*(c-eucluv)/(0.25*d-eucluv); *domeigval=O.5*(eigmax+eigeucl) ; rceucl = -log (euclres/euclresO) / (*k) ; rcmax = -log (maxres/maxresO) / (*k) ; *rateconv=0.5*(rceucl+rcmax); (*out) (~,lj,~j,ll,~1,n,discr,*k,*rateconv,*domeigval);

1 I f ree-real-matrix (v, 1 j , uj , 11) ; free-real-matrix(res,lj,uj,ll);

1

B. elimination

Determines an approximation ujn to the solution of the system of equations

Copyright 1995 by CRC Press, Inc

Page 524: Numerical Library in C for Scientists and Engineers A

Au = f (1) where A is an NxN matrix (N=(uj-Ij+l)*(ul-N+I); Ij, 11 I 1) whose eigenvalues hi are such that 0 < A, < A, < ... < A, = b, and u is a vector whose components uC) are stored in the locations of a two-dimensional real array U by means of the mapping u(~-~)~~'-"+~)+'-"+~) in location ( j , l ) (j=lj,lj+l, ..., uj; l=ll,ll+l, ..., ul).

elimination is to be used in conjunction with richardson, one of whose possible functions is precisely the solution of the problem described above. In the implementation of richardson, a sequence of vectors uk and residual vectors vk, where vk = Auk - J; is produced by use of recursion (2,3) of the documentation to richardson and, with 0 < a < b,

Vk = Ck(a, b;A)v o, uk = u + A"Ck(a, ~ ;A)v , where of all polynomials p, with pk(0) = I, p,(X) = C,(a,b;A) is that for which max I p k N 1 (a l A 5 b) is a minimum; explicitly

Ck(a, b;A) = T,((b+a-2A)/(b-a))/T,((b+a)/(b-a)) . Decomposing v, in terms of the eigenvectors e, of A,

If a < A,, then u, + u. An upper bound b for the hi may easily be given (see formula (4) of richardson). A lower bound for the Xi may also be obtained from the remark that the Xi lie in the adjunction of the discs

In the above, however, it is required that the lower bound a should be positive, and this may not be true of the lower bound derived from the expressions (2).

In one of its modes of application (with a > A,) richardson yields an approximation to A,, and hence a lower bound a' for the A,. Applying richardson yet again, with a ' in place of a and u, used as the initial approximation ul0 to produce a new sequence of approximations u ; and residual vectors v Ik, the residuals

C,,(a',b;A) has the same properties with respect to [a', b] as C,(a,b;A} has with respect to

Copyright 1995 by CRC Press, Inc

Page 525: Numerical Library in C for Scientists and Engineers A

[a,b]: u ' ~ . + u. Assuming that a < A,, the terms involving j=2,3, ... in formulae (3) are negligible:

vJn. = C,(a,b,;XJC,.(a',b;Xh (4)

uJn. = u + Cn(a,b,;XJCn.(a:b;XI)XI-'el . By taking

a* = a'(u3 = {2XI + b[cos(n/(2n3)-I]) / {cos(n/(Zn~)+l) Cnb(aa,b;XJ = 0, and the second term upon the right hand side of formula (4) may be eliminated.

The above process requires a total of n+nJ vector constructions. The mean rate of convergence may therefore be defined as

R(n,n') = - ln(llv:,,)Illlv,Il) 1 (n+n') (where In is the natural logarithm). The question now arises as to what value of n ' maximizes this rate of convergence. Adopting the above assumption

R(n, n 3 = -[l/(n+n 3])lCln(C,, (a, b; A,)) + ln(C,, .(a '(n 3, b;X 3)). Since T,,{(b-a)/(b+a)) = cosh{2d(a/b)) where a << b and n is large, maxlCn(a,b;X) = cosh{2d(a/b))-I (a I X I b) and -ln{C,,(a,b;XJ) = 2d(a/b) - m(2). Thus, approximately

R(n,n 3 = 2\/(a/b) - ln(2)/(n+n 3 - {2\/(a/b) - In 1 ~,[(b+a*(n '))/(b-a*(n I)) ] I )/(n+n 3. For a fixed total number of constructions (i.e. n+n' constant), R(n,n') is maximized when n '=p and

W d b ) - (dldp)ln l T,l(b+a '@))/(b-a '@))I l = h/(a/b) + [arc cos (w@) ) - {bnsin(7cl(2p)))l{2p(b-a~(l -w@) t))]tan{~ arccosw(pl) ( 5 )

is zero, where w(pl = {bcos(d(2p)) + a) / (b - a). The smallest positive zero p ' of the function (5) is found and n ' is taken to be p' .

In summary elimination is to be used as follows: firstly, richardson is called with a>X, and the procedure out required by richardson having a form suitable for the estimation of A, (e.g. increasing n by steps of unity until two successive estimates of A, agree sufficiently closely); richardson then allocates the derived estimate of A, to domeigval. With the parameters u, lj,. . .,domeigval untouched, but with the procedure out required by elimination now having a form suitable for the solution of equation (1) (e.g. inspecting discr[l] and discr[2] when k=n+nJ, and increasing n ' by unity, and repeating this operation should this be necessary) the user now calls elimination.

Function Parameters: void elimination (u, lj, uj, 11, ul,residual,a, b, n,discr, k,rateconv,domeigwI, out)

u: float u[lj:uj, ll:ul]; after each iteration the approximate solution calculated by elimination is stored in u; entry: an initial approximation of the solution which is obtained by use of richardson; exit: the final approximation to the solution;

j : int; entry: lower and upper bound for the first subscript of u;

I , int; entry: lower and upper bound for the second subscript of u;

residual: void (*residual)(lj, uj, 11, ul, u); suppose that the system of equation at hand is Au=f; for any entry u the procedure residual should calculate the residual Au-fin each point j, I, where lj I j I uj, 11 I I I ul, and substitute these values in the array u;

Copyright 1995 by CRC Press, Inc

Page 526: Numerical Library in C for Scientists and Engineers A

a, b: float; a and b should have the same values as in the preceding call of richardson (see the description of richardson);

n: int *; exit: the number of iterations the procedure elimination needs to eliminate the

eigenfunction belonging to the dominant eigenvalue is assigned to n; discr: float discr[l:2];

exit: after each iteration elimination delivers in discr[l] the Euclidean norm of the residual and in discr[2] the maximum norm of the residual;

k: int *; exit: counts the number of iterations elimination is performing;

rateconv: float *; exit: after each iteration the average rate of convergence is assigned to rateconv;

domeigval: float *; before a call of elimination the value of the eigenvalue for which the corresponding eigenfunction has to be eliminated should be assigned to domeigval; if after application of elimination there is a new dominant eigenfunction, then domeigval will be equal to the corresponding eigenvalue; otherwise the value of domeigval becomes meaningless;

out: void (* out)(u, IJ', uj, 11, ul, n, discr, k,rateconv, domeigval); by this procedure one has access to the following quantities: for O l b n the k-th iterand in u, the Euclidean and maximum norm of the k-th residual in discr[l] and discr[2], respectively; for O<kln also the average rate of convergence with respect to the k-th iterand in u, in rateconv; for k=n, possibly the dominant eigenvalue of the coefficient matrix of the equation Au=f; in domeigval.

Function used: richardson.

void elimination(f1oat **u, int lj, int uj, int 11, int ul, void (*residual) (int, int, int, int, float * * ) , float a, float b, int *n, float discr[l, int *k, float *rateconv, float *domeigval, void (*out) (float ** , int, int, int, int, int *, float [ I ,

int, float, float) ) I I

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int) ; void richardson(f1oat ** , int, int, int, int,

int, void ( * ) (int, int, int, int, float * * ) , float, float, int * , float [I , int *, float *, float * , void ( * ) (float ** , int, int, int, int, int *, float [I,

int, float, float) ) ; float optpol (float, float, float, float) ; int ext,extrapolate; float pi, auxcos, c,d,

cc, fc, bb, fb, aa, fa, dd, fd, fdb, fda,w,mb, tol,m,p,q;

c=1.0; if (optpol(c,a,b,*domeigval) c 0.0) {

d=O.S*pi*s rt (fabs (b/ (*domeigval) ) ) ; while (1) 7

d += d; / * finding zero * / bb=c ;

Copyright 1995 by CRC Press, Inc

Page 527: Numerical Library in C for Scientists and Engineers A

fb=optpol (c, a, b, *dorneigval) ; aa=c=d; fa=optpol(c,a,b, *dorneigval) ; cc=aa; fc=fa; ext=O ; extrapolate=l; while (extrapolate) (

if (Eabs (fc) c fabs (fb) ) ( if (CC ! = aa) (

dd=aa; fd=fa;

1

1 tol=c*l.Oe-3; rn=(cc+bb) *0.5; rnb=rn-bb; if (fabs(rnb) > tol) {

if (ext > 2) w=mb ;

else { if (mb == 0.0)

tol=O.O; else

if (mb < 0.0) to1 = -tol; p= (bb-aa) *fb; if (ext <= 1)

q=fa-fb; else {

fdb= (fd-fb) / (dd-bb) ; fda=(fd-fa) /(dd-aa) ; p *= fda; q=fdb*fa-fda*fb;

I if (p < 0.0) {

P = -p; q = -q;

1 w=(pcFLT-MIN I I p<=q*tol) ? to1 :

((p<mb*q) ? p/q : mb) ; 1 dd=aa ; fd=fa; aa=bb; fa=fb; c = bb += w; fb=optpol (c, a, b, *domeigval) ; if ((fc >= 0.0) ? (fb >= 0.0) : (fb c= 0.0)) (

cc=aa; fc=fa; ext=O;

) else ext = (w == mb) ? 0 : ext+l;

) else break;

1 d=cc; if ((fc >= 0.0) ? (fb <= 0.0) : (fb >= 0.0)) (

*n=f loor (c+O. 5) ; break;

1 I

) else *n=1;

auxcos=cos (0.5*pi/ (*n) ) ; richardson(u,lj,uj,ll,ul,l,residual,

(2. O* (*dorneigval) +b* (auxcos-1.0) ) / (auxcos+l. 0) ,b,n, discr,k, rateconv, dorneigval, out) ;

Copyright 1995 by CRC Press, Inc

Page 528: Numerical Library in C for Scientists and Engineers A

1 float optpol(f1oat x, float a, float b, float domeigval) t

/ * this function is internally used by ELIMINATION * /

float pi,w,y;

pi=3.14159265358979; w= (b*cos (0.5*pi/x) +domeigval) / (b-domeigval) ; if ( W c -1.0) w = -1.0; if (fabs(w) c = 1.0) (

y=acos (w) ; return 2.0*sqrt (a/b) +tan (x*y) * (y-b*pi*sin (O.S*pi/x) *

0.5/ (x* (b-domeigval) *sqrt (fabs (1.0-w*w) ) ) ) ; ) else (

y=log(w+sqrt(fabs(w*w-1.0))); return 2.0*sqrt (a/b) -tanh (x*y) * (y+b*pi*sin (O.S*pi/x) *

0. S/ (x* (b-domeigval) *sqrt (fabs (w*w-1.0) ) ) ) ;

1 1

5.6 Parameter estimation in differential equations

5 -6.1 Initial value problems

peide

Estimates unknown variables in a system of first order differential equations by using a given set of observed values [Vn75]. The unknown variables may appear nonlinearly both in the differential equations and its initial values.

peide determines the components p,, p,, ..., pm of psRm occurring in the system of differential equations

dy,(t,p)/dt = &y,p) (j=l ,..., n) ( 1 ) &(t,p), j=l, ..., n, being prescribed) for which the sum of squares

i.e. the square of the Euclidean norm of the residual vector whose components are mi@) = ~ @ ( f l ) , ~ ) = 'O)(flq (i=l ,...,nabs) (3

is a minimum, where the bfi)(to),p)) form a selection of values of components ofy(t,p) taken at prescribed values of t = f l ) , and y 'o)(tfi9 are observed values of these components. The above selection is specified by an array of integers {cobs[i]) fixing the component suffices of the observed values, and an array of real numbers {tobs[iJ) fixing the values of t at which the observations have been made. Thus if observations of all components of y(t,p) at the points t=t ',, ..., t ',,, are available, we have cobs[l]=l, cobs[2]=2, ..., cobs[n]=n, cobs[n+l]=l, cobs[n+2]=2, ..., cobs[nN]=n, tobs[l]=tobs[2]= ...= tobs[n]=tL tobs[n+ I]= ... =tobs[2n]=t ',, ..., tobs[nN]=t ',, with nobs=nN. If the first component of y(t,p) alone has been observed at t=t ',, ..., t ',, we have cobs[l]=cobs[2]= ... =cobs[N]=I, tobs[l]=tJ,, ..., tobs[N]=t',,, and nobs=N. Adopting this scheme, it is possible that the distribution of components ofy(t,p) for which observations are available may vary from one argument t of observation to another.

The numerical integration of the system of equations (1) is carried out by Gear's

Copyright 1995 by CRC Press, Inc

Page 529: Numerical Library in C for Scientists and Engineers A

method. The vector p = p ' yielding a minimum of the function (2) is located by use of the Levenberg-Marquardt algorithm: the user is asked to provide an initial approximation p(O) to p' ; a sequence of vectors (pw} (k=0,1 ...) is produced for which a member, pfi', is an acceptable approximation to p '.

It may occur that it is difficult to prescribe an excellent initial approximation p(Oi t o p ', and for this reason the user may instruct peide to cany out fitting, during the early stages of the computation, over a system of subranges of the total argument range t = 6') to t =

t~lobs) . The user is then asked to prescribe a system of break-points (integers) bp[i'] (i '=1,2, ..., nbp) which, in particular, specify a nondecreasing sequence of values oft , namely 7/" = Ppfi7) (il=l ,..., nbp), for which observed values of selected components of y(t,p) are available. The original minimization problem is now extended so as to concern functions y(t,p),ptl) defined for p) 5 t < p') respectively (i=O,l, ..., nbp) where Po) = 6') and Pbp+') - - t(n~bs) , p t l ~ ~ m + n b p being an extension of p . Each of these functions satisfies a system of

equations of the form (1) over its range of definition. The components of the initial values y,(t,7"0),p'(0g at t=FO)=tf') are simply the initial values y,(t,p) (j=l, ..., n) for the original problem. During the first traversal of the range [I(/i,t@Obs)] the initial values bj(t,p),p'*o))} at t = p) for the integration of the system corresponding to (1) over the range [p) ,p+"] are y j ( , ' l , p ' O (obtained from integration up to the end point of the preceding interval) for all j except that, j ' say, corresponding to a component for which an observed value is available, when the initial value is simply taken to be the observed value. The components o f p l l ~ ~ m + n b p are given by p': = p i (i=l, ..., n) andpt',,,+,. = y(p',Tfi>,p) (i=l, ..., nbp). Setting iIt(i) = i ' for all i for which p '5f l )<p '+ ' ) , the function now to be minimized is

nobx Iv ( o ( ~ ' o , ~ ~ " " ~ ' ) - ' ( l~(t '")2 +

i = l

i.e. the square of the Euclidean norm of the residual vector whose components are resi(p '3 = y(iyt~), 13 - 10) (t(i9 (i=l ,...,nabs)

resn,b,+i ,(' '3 = ~ { ~ ' b p " 7)(p 7, p 13 - y(bPli P(p > , p ? ,p 13) (i 1 ( 5 )

,...,nbp > where M is a weight factor. After each traversal of the range [to, PbS1] a new vector p'@) is determined by use of the Levenberg-Marquardt algorithm.

During traversals of the range subsequent to the first, the vector p used in the systems of equations corresponding to (1) is made up of the first rn components of p . The initial values y,(t, p7,p'@9 at t = 7"" for the integration of the system corresponding to (1) over the range [p7 ,~o '+ ' ) ] are again y,(py,~fi'-'),p'@9 for all j except j ' as above, when the new initial value is taken to be pt',,,+,.. The iterations of the Levenberg-Marquardt algorithm are continued until the vectors (ptfl)} have approached a limit sufficiently closely. The second sum in expression (4) corresponds to a continuity requirement. After the above ptfl) have attained a limit sufficiently closely, the weight factor M is increased (i.e. the continuity requirements are made more stringent). A new terminating sequence of further vectors (pm} is derived, again M is increased, and so on. When, at a certain break-point bp[it7,

1 PPI~ " Z ( p "7, fl "'-/),p l@9 y_y(b~li "7)(p "7,p "?p I becomes sufficiently small (i.e. the discontinuity at that break-point has virtually

Copyright 1995 by CRC Press, Inc

Page 530: Numerical Library in C for Scientists and Engineers A

disappeared) the term corresponding to i ' = i'" is removed from expression (4), and the component with suffix m+i "' is discarded from p", the computations being continued with reduced sum and vector. This process is continued until all break-points have been discarded, and the original minimization problem is solved by a final use of the Levenberg- Marquardt algorithm. Naturally cases occur for which an excellent approximation p'O) t o p " is available, and in such a case (by setting nbp=O) the user may avoid the above excursion. For the sake of completeness, it is mentioned that certain of the above break points may correspond to equal values of t, (the components of y(t,p) for which observed values are available at this value o f t having differing suffices). In such a case in the above exposition certain of the intervals of the form [ ~ ' , p " ' ) ] reduce to a single point. Numerical integration of equations of the form (1) over such an interval is dispensed with, but the process of eliminating discontinuities as described is retained.

That the initial values y,(t,p) (j=l, ..., n) for the equations (1) may depend upon p is also permitted (see the procedure ystart below).

Function Parameters: void peide

(n, m,nobs,nbp,par,res, bpjtjinv, in, out,deriv,jacdf~,jacdfdp,callystart,data,monitor) n: int;

entry: the number of differential equations; m: int;

entry: the number of unknown variables; nobs: int;

entry: the number of observations; nobs should satisfy nobs 1 m; nbp: int *;

entry: the number of break-points; if no break-points are used then set nbp = 0; exit: with normal termination of the process nbp = 0;

otherwise, if the process has been broken off (see out[ll), the value of nbp is the number of break-points used before the process broke off;

par: float par[l:m+nbp]; entry: par[l:m] should contain an initial approximation to the required parameter

vector (values of p,/0! i=l, ..., m, above); exit: par[l:m] contains the calculated parameter vector;

if out[l] > 0 and nbp > 0 then par[m+l:m+nbp] contains the values of the newly introduced parameters before the process broke off;

res: float res[l:nobs+nbp]; exit: res[l:nobs] contains the residual vector at the calculated minimum (res[i]

contains y"'(p),p') - yo)(to)), i=l, ..., nobs, in the above); if out[l] > 0 and nbp > 0 then res[nobs+l:nobs+nbp] contains the additional continuity requirements at the break-points before the process broke off (res[nobs+i '] contains p1i7(p', 7("-'),p1fi)) -y@~[~~)(p? ~ ~ ? ~ " @ i ) , iJ=1, ..., nbp, in the above);

bp: int bp[O:nbp]; entry: bp[i], i=l, ..., nbp, should correspond to the index of that time of observation

which will be used as a brvk-point (1 I bp[i] I nobs); the break-points have to be ordered such that bp[i] 5 bpb] if i 5 j;

exit: with normal termination of the process bp[l:nbp] contains no information; otherwise, if out[l] > 0 and nbp > 0 then bp[iJ, i=l, ..., nbp, contains the index

Copyright 1995 by CRC Press, Inc

Page 531: Numerical Library in C for Scientists and Engineers A

of that time of observation which was used as a break-point before the process broke off;

jtjinv: float jtjinv[l:m, I:m]; exit: the inverse of the matrix J'*J where J denotes the matrix of partial derivatives

dres[i]/dpar[k] (i=l ,...,nabs; k=l ,..., m) and J' denotes the transpose of 4 this matrix can be used if additional information about the result is required; e.g. statistical data such as the covariance matrix, correlation matrix and confidence intervals can easily be calculated from jtjinv and out[2];

in: float in[0:6]; entry: in[O]: the machine precision; in[l]: the ratio: the minimal steplength for the integration of the differential equations

divided by the distance between two neighboring observations; mostly, a suitable value is lo4;

in[2]: the relative local error bound for the integration process; this value should satisfy in[2] 5 in[3]; this parameter controls the accuracy of the numerical integration; mostly, a suitable value is in[3]/100;

in[3]: the relative tolerance for the difference between the Euclidean norm of the ultimate and penultimate residual vector; see in[4] below;

in[4]: the absolute tolerance for the difference between the Euclidean norm of the ultimate and penultimate residual vector;

the process is terminated if the improvement of the sum of squares is less than in[3] * (sum of squares) + in[4] * in[4]; in[3] and in[4] should be chosen in accordance with the relative and absolute errors in the observations; note that the Euclidean norm of the residual vector is defined as the square root of the sum of squares;

in[5]: the maximum number of times that the integration of the differential equations is performed;

in[6]: a starting value used for the relation between the gradient and the Gauss- Newton direction; if the problem is well conditioned then a suitable value for in[6] will be 0.01; if the problem is ill conditioned then in[6] should be greater, but the value of in[6] should satisfy: in[O] < in[6] 5 l/in[O];

out: float out[l:7]; exit: out[l]: this value gives information about the termination of the process;

out[l]=O: normal termination; if out[l] > 0 then the process has been broken off and this may occur because of the following reasons:

out[l]=l: the number of integrations performed exceeded the number given in in[5];

out[l]=2 the differential equations are very nonlinear; during an integration the value of in[]] was decreased by a factor 10000 and it is advised to decrease in[l], although this will increase computing time;

out[l]=3 a call of deriv delivered the value zero; out[l]=4 a call of jacdfdy delivered the value zero; out[l]=5 a call of jacdfdp delivered the value zero; out[l]=6 the precision asked for cannot be attained; this precision is possibly

chosen too high, relative to the precision in which the residual vector is calculated (see in[3J;

Copyright 1995 by CRC Press, Inc

Page 532: Numerical Library in C for Scientists and Engineers A

out[2]: the Euclidean norm of the residual vector calculated with values of the unknowns delivered;

out[3]: the Euclidean norm of the residual vector calculated with the initial values of the unknown variables;

out[4]: the number of integrations performed, needed to obtain the calculated result; if out[4] = 1 and out[l] > 0 then the matrix jtjinv cannot be used;

out[5]: the maximum number of times that the requested local error bound was exceeded in one integration; if it is a large number then it may be better to decrease the value of in[l];

out[6]: the improvement of the Euclidean norm of the residual vector in the last integration step of the process of Marquardt;

0ut[7]: the condition number of J'*J, i.e, the ratio of its largest to smallest eigenvalues;

deriv: int (*deriv)(n,m,par,y, t,dJ); entry: par[l:m] contains the current values of the unknowns and should not be

altered; y[l:n] contains the solutions of the differential equations at time t and should not be altered;

exit: an array element df[i] (i=l, ..., n) should contain the right hand side of the i-th differential equation;

after a successful call of deriv, the procedure should deliver the value nonzero; however, if deriv delivers the value zero then the process is terminated (see out[ll); hence, proper programming of deriv makes it possible to avoid calculation of the right hand side with values of the unknown variables which cause overflow in the computation;

jacdfdy: int (*jacdfdy)(n, m,par,y, t,jj); float &[I :n, 1 :n]; entry: for parameters par, y and t, see deriv above; exit: an array element JL[i,j] (i,j=l, ..., n) should contain the partial derivative of the

right hand side of the i-th differential equation with respect to yb], i.e. df[i//dybl;

the integer value should be assigned to this procedure in the same way as is done for the value of deriv;

jacdfdp: int (*jacdfdp)(n,m,par, y, t, fp); float fp[l:n, 1 :m]; entry: for parameters par, y and t, see deriv above; exit: an array element fp[i,j] should contain the partial derivative of the right hand

side of the i-th differential equation with respect to parb], i.e. df[i]/dparb]; the integer value should be assigned to this procedure in the same way as is done for the value of deriv;

callystart: void (*callystart)(n,m,par,y,ymax); entry: par[l:m] contains the current values of the unknown variables and should not

be altered; exit: y[l:n] should contain the initial values of the corresponding differential

equations; the initial values may be functions of the unknown variables par; in that case, the initial values of dy/dpar also have to be supplied; note that dy[i]/dparb] corresponds with y[5*n+j*n+i] (i=l ,..., n, j=l ,..., m);

ymax[i], i=l, ..., n, should contain a rough estimate to the maximal absolute value of y[i] over the integration interval;

data: void (*data)(nobs, tobs,obs,cobs);

Copyright 1995 by CRC Press, Inc

Page 533: Numerical Library in C for Scientists and Engineers A

this procedure takes the data to fit into the procedure peide; entry: nobs has the same meaning as in peide; exit: tobs: float tobs[O:nobs];

the array element tobs[O] should contain the time, corresponding to the initial values of y given in the procedure callystart; an array element tobs[i], l l i lnobs, should contain the i-th time of observation; the observations have to be ordered such that tobs[i] 5 tobsb] if i 5 j;

cobs: int cobs[l:nobs]; an array element cobs[i] should contain the component of y observed at time tobs[i]; note that 1 I cobs[i] I n;

obs: float obs[l :nabs]; an array element obs[i] should contain the observed value of the component cobs[i] of y at the time tobs[i];

monitor: void (*monitor)(post,ncol,nrow,par,res,weight,nis); int post, ncol, nrow, weight, nis;

this procedure can be used to obtain information about the course of the iteration process; if no intermediate results are desired then a dummy procedure satisfies; inside peide, the procedure monitor is called at two different places and this is denoted by the value of post; post=l: monitor is called after an integration of the differential equations; at this place

are available: the current values of the unknown variables par[l:ncol], where ncol=m+nbp, the calculated residual vector res[l:nrow], where nrow=nobs+nbp, and the value of nis, which is the number of integration steps performed during the solution of the last initial value problem;

post=2: monitor is called before a minimization of the Euclidean norm of the residual vector with the Levenberg-Marquardt algorithm is started; available are the current values of par[l:ncol] and the value of the weight, with which the continuity requirements at the break-points are added to the original least squares problem.

Functions used: inivec, inimat, mulvec, mulrow, dupvec, dupmat, vecvec, matvec, elmevc, sol, dec, mulcol, tamvec, mattam, qrisngvaldec.

void peide(int n, int m, int nobs, int *nbp, float parll, float res[l, int bpll, float **jtjinv, float in [I , float out [I , int (*deriv) (int, int, float [I, float [I, float, float [I ) , int (*jacdfdy) (int, int, float [I ,float [I ,float, float * * ) , int (*jacdfdp) (int, int, float [I ,float [I , float, float * * ) , void (*callystart) (int,int, float [I, float [I, float [I ) , void (*data) (int, float [I , float [I , int [I ) , void (*monitor) (int, int,int, float [ I , float [I ,int, int) )

int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-integer-vector(int * , int); void free-real-vector(f1oat * , int) ; void free-real-rnatrix(f1oat **, int, int, int) ; int peidefunct(int nrow, int ncol, float par[], float res[l,

int n, int m, int nobs, int *nbp, int first, int *sec,

Copyright 1995 by CRC Press, Inc

Page 534: Numerical Library in C for Scientists and Engineers A

int *max, int *nis, float epsl, int weight, int bp 11 , float save [I , float pax[] , float y [I , float **yp, float **fy, float **fp, int cobsll, float tobs[l, float obscl, float in[], float aux[l, int clean, int (*deriv) (int, int, float [I ,float [I ,float, float [I ) , int (*jacdfdy) (int, int, float 11 ,float [I , float, float * * ) , int ( * j acdfdp) (int, int , float [I , float [I , float, float * * ) , void (*callystart) (int, int, float [I , float 11 , float [I ) , void (*monitor) (int, int, int, float [I, float [I, int, int) ) ;

void inivec (int, int, float [I , float) ; void inimat(int, int, int, int, float ** , float); void mulvec (int, int, int, float [I , float [I , float) ; void mulrow(int, int, int, int, float ** , float **, float); void dupvec (int, int, int, float 11 , float 11 ) ; void dupmat (int, int, int, int, float **, float * * ) ; float vecvec (int, int, int, float [I, float [I ) ; float matvec(int, int, int, float **, float [I ) ; void elmvec (int, int, int, float [I, float [I, float) ; void sol(f1oat ** , int, int [I, float [I); void dec (float ** , int, float [I , int [I ) ; void mulcol(int, int, int, int, float ** , float ** , float); float tamvec (int, int, int, float ** , float [I ) ; float mattam(int, int, int, int, float ** , float * * ) ; int qrisngvaldec (float ** , int, int, float [I , float ** , float [I ) ; int i,j,weight,ncol,nrow,away,max,nfe,nis,*cobs,

first,sec,clean,nbp~ld,maxfe,fe,it,err,emergency; float epsl,resl,in3,in4,fac3,fac4,aux[4l,*obs,*save,*tobs,

**yp,*ymax,*y,**fy,**fp,w,**aid,temp, ~,~~,~2,mu,res2,fpar,fparpres,lambda,lambdamin,p,pw~ reltolres,abstolres,em[8],*val,*b,*bb,*parpres,**jaco;

static float save1[35]=(1.0, 1.0, 9.0, 4.0, 0.0, 2.0/3.0, 1.0, 1.0/3.0, 36.0, 20.25, 1.0, 6.0/11.0, 1.0, 6.0/11.0, 1.0/11.0, 84.028, 53.778, 0.25, 0.48, 1.0, 0.7, 0.2, 0.02, 156.25, 108.51, 0.027778, 120.0/274.0, 1.0, 225.0/274.0, 85.0/274.0, 15.0/274.0, 1.0/274.0, 0.0, 187.69, 0.0047361) ;

nbpold= ( *nbp) ; cobs=allocate~integer~vector(1,nobs); obs=allocate~real~vector(l,nobs); save=allocate-real-vector(-38,6*n); tobs=allocate~real~vector(0,nobs) ; ymax=allocate-real-vector(1,n); y=allocate real vector (l,6*n* (nbpold+m+l) ) ; yp=allocat~reai~matrix(1,nbpold+nobs,l,nbpold+m) ; fy=allocate-real-matrix(l,n,l,n); fp=allocate real matrix (1, n, l,m+nbpold) ; aid=allocat~rea~~matrix(1,m+nbpold,1,m+nbpold);

for (i=O; i<=34; i++) save [-38+il =save1 [il ; (*data) (nobs, tobs, obs, cobs) ; weight=l; first=sec=O; clean= (*nbp > 0) ; aux 121 =FLT-EPSILON; epsl=l.OelO; out 111 =o. 0; bp [Ol =max=O; /* smooth integration without break-points * / if (!peidefunct(nobs,m,par,res,

n,m,nobs,nbp,first,&sec,&max,&nis,epsl,weight,bp, save,ymax,y,yp,fy,fp,cobs,tobs,obs,in,aux,clean,deriv, jacdfdy,jacdfdp,callystart,monitor)) goto Escape;

reslzsqrt (vecvec (1, nobs ,0, res , res) ) ; nfe=l; if (in151 == 1.0) {

out Ell =l.O; goto Escape;

1 if (clean) {

f irst=l; clean=O ; fac3=sqrt (sqrt (in [3l /resl) ) ; fac4=sqrt (sqrt (in [41 /resl) ) ;

Copyright 1995 by CRC Press, Inc

Page 535: Numerical Library in C for Scientists and Engineers A

epsl=resl*fac4; if ( !peidefunct (nobs,m,par, res,

n,m,nobs,nbp,first,&sec,&max,&nis,epsl,weight,bp, save,ymax,y,yp,fy,fp,cobs,tobs,obs,in,aux,clean,deriv, jacdfdy,jacdfdp,callystart,monitor)) goto Escape;

f irst=O; ) else.

nf e=0 ; ncol=m+ (*nbp) ; nrow=nobs+ (*nbp) ; sec=l; in3=in [31 ; in4=in [41 ; in [31 =resl; weight=away=O; out [41 =out [51 =w=0 -0; temp=sqrt (weight) +l. 0; weight=temp*temp; while (weight != 16 && *nbp > 0) (

if (away == 0 && w ! = 0.0) ( / * if no break-points were omitted then one function

function evaluation is saved * / w=weight/w; for (i=nobs+l; ic=nrow; i++) (

for (j=l; jc=ncol; j++) yp[il [jl *= w; res [il *= w;

1

in [31 *= fac3*weight; in [41 =epsl; (*monitor) (2, ncol, nrow,par, res, weight,nis) ; / * marquardt's method */ val=allocate~real~vector(1,ncol); b=allocate-real-vector(1,ncol); bb=allocate-real-vector(1,ncol); parpres=allocate-real-vector(1,ncol); jaco=allocate~real~matrix(l,nrow,l,ncol); w=lO.O ; w2=0.5 ; mu=O. 01; ww = (in[61 c 1.0e-7) ? 1.0e-8 : l.0e-l*in[61; em [Ol =em[21 =em[61 =in 101 ; em[4] =lO*ncol; reltolres=in [31 ; abstolres=in [41 *in [41 ; maxfe=in [51 ; err=O ; fe=it=l; p=fpar=res2=0.0; pw = -log(ww*in[Ol ) /2.30; if ( !peidefunct (nrow, ncol,par, res,

n,m,nobs,nbp, first, &sec, &max, &nis, epsl, weight,bp,save,ymax,y,yp,fy,fp,cobs,tobs,obs, in,aux,clean,deriv,jacdfdy,jacdfdp, callystart,monitor))

err=3 ; else (

fpar=vecvec (l,nrow, 0, res, res) ; out [31 =sqrt (fpar) ; emergency=O; it=l; do (

dupmat (1, nrow, 1, ncol, j aco, yp) ; i=qrisngvaldec(jaco,nrow,ncol,val,aid,em); if (it == 1)

lambdazin [6] *vecvec (l,ncol, O,val,val) ; else

if (p == 0.0) lambda *= w2; for (i=l; ic=ncol; i++)

b [i] =val [il *tamvec (l,nrow, i, jaco, res) ; while (1) {

for (i=l; i<=ncol; i++)

Copyright 1995 by CRC Press, Inc

Page 536: Numerical Library in C for Scientists and Engineers A

bb [i] =b [il / (val [il *val [il +lambda) ; for (i=l; i<=ncol; i++)

parpres [il =par [il -rnatvec (l,ncol, i, aid, bb) ; f e++ ; if (fe >= rnaxfe)

err=l; else

if (!peidefunct(nrow,ncol,parpres,res, n, rn,nobs, nbp, first, &sec, &max, &nis, epsl,weight,bp,save,ymax,y,yp,fy,fp, cobs,tobs,obs,in,aux,clean,deriv, jacdfdy,jacdfdp,callystart,rnonitor))

err=2 ; if (err ! = 0) (

emergency=l; break;

I I fparpres=vecvec (l,nrow, 0, res, res) ; res2zfpar-fparpres; if (res2 c rnu*vecvec (l,ncol, 0, b, bb) ) (

p += 1.0; lambda *= w; if (p == 1.0) {

lambdamin=ww*vecvec(l,ncol,0,val,val) ; if (lambda c lambdamin) lambda=lambdarnin;

1 if (p >= pw) (

err=4 ; ernergency=l; break;

1 ) elke (

dupvec (1, ncol, 0, par, parpres) ; fpar=fparpres; break;

1 if (emergency) break; it++;

) while (fpar>abstolres && res2>reltolres*fpar+abstolres);

for (i=l; i<=ncol; i++) rnulcol(l,ncol, i, i, jaco,aid,l.O/(val [il+in[Ol ) ) ;

for (i=l; i<=ncol; i++) for (j=l; jc=i; j++)

aid[i] [j]=aid[jl [il=mattam(l,ncol,i, j, jaco, jaco); larnbda=lambdarnin=val [ll ; for (i=2; i<=ncol; i++)

if (val [il > lambda) lambda=val [il ;

else if (val [i] c lambdamin) lambdarnin=val [il ;

ternp=lambda/ (lambdarnin+in [Ol ) ; out 171 =ternp*ternp; out 121 =sqrt (fpar) ; out [6] =sqrt (res2+fpar) -out 121 ;

1 out [41 =fe; out [51 =it-1; out [ll =err; free real vector (val , 1) ; free~real~vector (b, 1) ; free real vector(bb,l); f ree-real-vector (parpres , 1) ; freeIrealImatrix (jaco, 1, nrow, 1) ; if (out [ll > 0.0) goto Escape; / * the relative starting value of lambda is adjusted

to the last value of lambda used */ away=out [41 -out 151 -1.0; in [6] *= pow (5.0, away) *pow (2.0, away-out [S] ) ; nfe += out [41 ; w=weight ; temp=sqrt (weight) +l. 0; epsl=temp*temp*in [41 *fac4;

Copyright 1995 by CRC Press, Inc

Page 537: Numerical Library in C for Scientists and Engineers A

away=O ; / * omit useless break-points * / for (j=l; jc=(*nbp); j++)

if (fabs(obs[bp[jll+res[bp[jll-par[j+ml) c epsl) ( (*nbp) --; for (i=j ; ic= (*nbp) ; i++) bp [il =bp [i+l] ; dupvec (j+m, (*nbp) +m, 1, par,par) ; j--; away++; bp [*nbp+ll =O;

I ncol - = away; nrow - = away; temp=sqrt (weight) +l. 0; weight=temp*temp;

1 I

in [31 =in3 ; in 141 =in4; *nbp=O ; weightzl; (*monitor) (2,m, nobs,par, res, weight,nis) ; / * marquardt's method * / val=allocate-real-vector(1,m) ; b=allocate-real-vector(1,m); bb=allocate-real-vector(1,m) ; parpres=allocate-real-vector(1,rn); j aco=allocate-real-matrix (1, nobs, 1, m) ; w=lO. 0 ; w2=0.5; mu=O. 01; ww = (in[6] c 1.0e-7) ? 1.0e-8 : l.0e-l*in[61; em [O] =em [21 =em [61 =in [O] ; em 141 =lO*m; reltolres=in [31 ; abstolres=in [41 *in 141 ; maxfe=in [51 ; err=O ; fe=it=l; p=fpar=res2=0.0; pw = -log(ww*in[O] ) /2.30; if ( !peidefunct (nobs,m, par, res,

n,m, nobs,nbp, first, &sec, &max, &nis, epsl, weight, bp, save,yyax,y,yp,fy,fp,cobs,tobs,obs,in,aux,clean, deriv,~acdfdy,jacdfdp,callystart,monitor))

err=3 ; else (

fpar=vecvec(l,nobs,O,res,res) ; out [31 =sqrt (£par) ; emergency=O; it=l; do I

dupmat (l,nobs,l,m, jaco,yp) ; izqrisngvaldec (jaco,nobs,m,val, j tjinv, em) ; if (it == 1)

lambda=in[6] *vecvec (1,m, O,val,val) ; else

if (p == 0.0) lambda *= w2; for (i=l; ic=m; i++)

b[i] =val [i] *tamvec(l,nobs,i, jaco,res) ; while (1) (

for (i=l; ic=m; i++) bb [i] =b [il / (val [il *val [il +lambda) ;

for (i=l; ic=m; i++) parpres [i] =par [il -matvec(l,m, i, jtjinv,bb) ;

f e++ ; if (fe >= maxfe)

err=l; else

if ( !peidefunct (nobs, m, parpres, res, n,m,nobs,nbp,first,&sec,&max,&nis,epsl, weight,bp,save,ymax,y,~,fy,fp,cobs,tobs, obs, in, aux, clean, derlv, jacdfdy, jacdfdp, callystart,monitor))

err=2 :

Copyright 1995 by CRC Press, Inc

Page 538: Numerical Library in C for Scientists and Engineers A

if (err ! = 0) { emergency=l; break:

1 fparpres=vecvec (l,nobs, 0, res, res) ; res2=fpar-fparpres; if (res2 c mu*vecvec(l,m,0,b,bb) ) {

p += 1.0; lambda *= w; if (p == 1.0) (

lambdamin=ww*vecvec(1,m,O,val,val) ; if (lambda c lambdamin) lambda=lambdamin;

1 if (p >= pw) {

err=4 ; emergency=l; break;

) el$e ( dupvec (l,m, 0, par, parpres) ; fpardparpres; break;

1 1

if (emergency) break; it++;

} while (fpar>abstolres && res2>reltolres*fpar+abstolres); for (i=l; ic=m; i++)

mulcol(l,m,i,i, jaco, jtjinv,l.0/(val[il+in[Ol~~ ; for (i=l; ic=m; i++)

for (j=l; jc=i; j++) jtjinv[i] [jl=jtjinv[jl [il=mattam(l,m,i, j, jaco, jaco);

lambda=lambdamin=val [ 11 : - - ,

for (i=2; ic=m; i++) if (val [il > lambda)

lambda=val [il ; else

if (val [il c lambdamin) lambdamin=val [il ; temp=lambda/ (lambdamin+in [Ol ) ; out [71 =temp*temp; out [21 =sqrt (fpar) ; out [6] =sqrt (res2+fpar) -out 121 ;

out [41 =fe; out [51 =it-1; out [ll =err; f ree-real-vector (val ,1) ; f ree-real-vector (b, 1) ; f ree-real-vector (bb, 1) ; free-real-vector (parpres, 1) ; free-real-matrix (jaco, 1, nobs, 1) ; nfe += out [41 ;

Escape : if (out[ll == 3.0)

out [ll=2.0; else

if (out [l] == 4.0) out 111 =6.O; if (save [-31 ! = 0.0) out [ll =save [-31 ; out [31 =resl; out 141 =nfe; out [51 =max; free-integer-vector(cobs,l); free-real-vector(obs,l); free-real-vector(save,-38); free-real-vector(tobs,O); f ree-real-vector (pax, 1) ; free-real-vector (y, 1) ; free-real-matrix(yp,l,nbpold+nobs,l) ; free-real-matrix (fy, 1, n, 1) ; free-real-matrix(fp, l,n, 1) ; free-real-matrix (aid, l,m+nbpold, 1) ;

1

Copyright 1995 by CRC Press, Inc

Page 539: Numerical Library in C for Scientists and Engineers A

int peidefunct (int nrow, int ncol, float par [I , float res [I , int n, int m, int nobs, int *nbp, int first, int *sec, int *max, int *nis, float epsl, int weight, int bp[l, float save [I, float pax[], float y [I, float **yp, float **fy, float **fp, int cobs[], float tobsfl, float obs [I , float in [I , float aux [I , int clean, int (*deriv) (int, int, float [I , float [I , float, float [I ) , int (*jacdfdy) (int, int, float [I ,float [I, float, float ** ) , int (*]acdfdp) (int,int,float [I, float [I, float, float * * ) , void (*callystart) (int, int, float [I ,float [I ,float [I ) , void (*monitor) (int, int, int, float [I , float [I , int, int) )

I 1

/* this function is internally used by PEIDE * /

void peidereset (int , int , float, float, float, float, f l0at [I , float [ I , float * , float * , float * , int * ) ;

void peideorder (int, int, float, float [I , float [I , float * , float , float * , float *, float * , int * ) ;

void peidestep(int, int, int, float, float, float, float, float [I, float [I, float [I, float [I, int * , float * ) ;

float peideinterpol(int, int, int, float, float [I); int l,k,knew,fails,same,kpold,n6,nnpar,j5n,cobsii,*p,evaluate,

evaluated,decompose,conv,extra,npar,i,j,jj,ii; float xold,hold,aO,tolup,tol,toldwn,tolconv,h,ch,chnew,error,

dfi, tobsdif ,a[6], *delta, *lastdelta, *df, *yo, **jacob,xend, hmax, hmin, eps, s, aa,x, t, c;

if (*set) ( *sec=O ; goto Finish;

xend=tobs [nobsl ; eps=in [21 ; npar=m; extra= (*nis) =O; ii=l; jj = (*nbp== 0) ? 0 : 1; n6=n*6 ; inivec(-3, -l,save,O.O) ; inivec (n6+l, (6+m) *n,y, 0.0) ; inimat(l,nobs+(*nbp) ,l,m+(*nbp) ,yp,O.O) ; t=tobs [ll ; x=tobs [OI ; (*callystart) (n,m,par, y,ymax) ; hmax=tobs [ll -tobs [O] ; hmin=hmax*in [ll ; / * evaluate jacobian * / evaluate=O; decompose=evaluated=1; if ( ! (*jacdfdy) (n,m,par,y,x,fy)) {

save [-31=4.0; goto Finish;

1

Newstart : k=l; kpold=O; same=2 ; peideorder(n,k,eps,a,save,&tol,&tolup,&toldwn,&tolconv,

&a0 , &decompose) ; if ( ! (*deriv) (n,m,par,y,x,df)) {

save[-31 d.0; goto Finish;

1 s=FLT MIN; for (T=1; ic=n; i++) (

Copyright 1995 by CRC Press, Inc

Page 540: Numerical Library in C for Scientists and Engineers A

I h=sqrt (2.0*eps/sqrt (s) ) ; if (h > hmax)

h=hmax; else

if (h c hmin) h=hmin; xold=x; hold=h; ch=l. 0 ; for (i=l; i<=n; i++) {

save [il =y [il ; save [n+i] =y [n+il =df [il *h;

I fails=O; while (x c xend) {

if (x+h c= xend) x += h;

else { h=xend-x; x=xend; ch=h/hold; c=1.0; for (j=n; jc=k*n; j += n) {

c *= ch; for (i=j+l; ic=j+n; i++) y[il *= c;

same = (same c 3) ? 3 : same+l; I )* prediction * / for (1=1; lc=n; 1++) {

for (i=l; ic=(k-1) *n+l; i += n) for (j=(k-l)*n+l; j>=i; j - = n) y[jl += y[j+nl ;

delta [ll =O. 0;

evaluated=~ ; / * correction and estimation local error * / for (1=1; 1<=3; 1++) {

if ( ! (*deriv) (n,m,par, y,x,df) ) { save [-31=3; goto Finish;

I ;or (i=l; ic=n; i++) df [i] =df [il *h-y [n+il ; if (evaluate) (

/ * evaluate jacobian * / evaluate=O; decompose=evaluated=l; if ( ! (*jacdfdy) (n,m,par,y,x,fy)) {

save [-31=4 .O; goto Finish;

I 1

if (decompose) ( /* decompose jacobian * / decompose=O; c = -aO*h: for (j=l;'jc=n; j++) {

for (i=l; ic=n; i++) jacob[il [jl=fy[il [jl*c; jacob[jl [jl += 1.0;

I

.b~l(jacob,n,~,df) ; conv=l ; for (i=l; ic=n; i++) {

dfi=df [il ; y[i] += aO*dfi; y [n+il += dfi; delta[il += dfi; conv= (conv && (fabs (df i) c tolconv*ymax [il ) ) ;

Copyright 1995 by CRC Press, Inc

Page 541: Numerical Library in C for Scientists and Engineers A

for (i=l; i<=n; i++) ( aa=delta [il /wax [il ; s += aa*aa;

1 error=s; break ;

I

1 / * acceptance or rejection * / if (!conv) {

if ( !evaluated) evaluate=l;

else { ch /= 4.0; if (h < 4.0*hmin) (

save[-11 += 10.0; hmin / = 10.0; if (save [-11 > 40.0) goto Finish;

1 1

peidereset (n, k, hmin, hmax, hold,xold, y, save, &ch, &x, &h, &decompose) ;

) else if (error > tol) ( fails++; if (h > l.l*hmin) (

if (fails > 2) { peidereset (n, k, hmin, hmax, hold,xold, y, save, &ch, &x,

&h, &decompose) ; goto Newstart;

) else ( / * calculate step and order * / peidestep (n, k, fails, tolup, toldwn, tol, error, delta,

lastdelta, y,ymax, &knew, &chnew) ; if (knew ! = k) (

k=knew; peideorder(n,k,eps,a,save,&tol,&tolup,

&toldwn, &tolconv, &aO, &decompose) ;

bh *= chnew; peidereset (n, k, hmin, hmax, hold,xold, y, save, &ch, &x,

&h, &decompose) ; 1

) el$e { if (k == 1) {

/ * violate eps criterion * / save[-21 += 1.0; same=4 ; goto Errortestok;

k=1; peidereset (n, k, hmin, hmax, hold,xold, y, save, &ch, &x,

&h, &decompose) ; peideorder (n, k, eps, a, save, &tol, &tolup,

&toldwn, &tolconv, &aO, &decompose) ; same=2 ;

I ) el'se

Errortestok: fails=O; for (i=l; i<=n; i++) {

c=delta [il ; for (1=2; l<=k; I++) y[l*n+il += a111 *c; if (fabs(y[il) > ymax[il) ymax[il=fabs(y[il);

1 same-- ; if (same == 1)

dupvec (l,n, 0, lastdelta, delta) ; else if (same == 0) {

/ * calculate step and order * / peidestep(n,k,fails,tolup,toldwn,tol,error,delta,

lastdelta, y,ymax, &knew, &chew) ; if (chnew > 1.1) (

if (k ! = knew) { if (knew > k)

Copyright 1995 by CRC Press, Inc

Page 542: Numerical Library in C for Scientists and Engineers A

I same=k+l; if (chnew*h > hmax) chnew=hmax/h; h *= chnew; C=1.0 ; for (j=n; jc=k*n; j += n) {

c *= chnew; rnulvec(j+l, j+n, O,y,y,c) ;

decompose=l; ) else

same=lO ; 1 (*nis) ++; / * start of an integration step of yp * / if (clean) {

hold=h; xold=x; kpold=k; ch=l. 0 ; dupyec(l,k*n+n,O,save,y) ;

) else { (h ! = hold) { ch=h/hold; c=1.0 ; for (j =n6+nnpar; j c=kpold*nnpar+n6 ; j += nnpar) {

c *= ch; for (i=j+l; ic=j+nnpar; i++) y[il *= c;

\

xold=x; kpold=k; ch=l. 0 ; dupvec(l,k*n+n,O,save,y) ; /* evaluate jacobian * / evaluate=O; decompose=evaluated=l; if ( ! (*jacdfdy) (n,m,par,y,x,f~)) {

save[-31=4.0; goto Finish;

)* decompose jacobian * / decompose=O ; c = -aO*h; for (j=l; jc=n; j++) {

for (i=l; ic=n; i++) jacob[il [jl=fy[il [jl *c; jacob[jl [jl += 1.0;

1 dec(jacob,n,aux,p) ; if ( ! (*jacdfdp) (n,m,par,y,x,fp)) (

save[-31 =5.0; goto Finish;

1 if (npar > m) inimat (l,n,m+l,npar, fp, 0.0) ; / * prediction * / for (1~0; lc=k-1; 1++)

for (j=k-1; j>=l; j--) elmvec(j*nnpar+n6+l,j*nnpar+n6+nnpar,nnpart

y,y,1.0); / * correction */ for (j=l; js=npar; j++) (

jSn= (j+S) *n; dupvec(l,n, jSn,yO,y); for (i=l; ic=n; i++)

df [i]=h*(fp[il [jl+matvec(l,n,i,fy,yO))- y [nnpar+j 5n+il ;

Copyright 1995 by CRC Press, Inc

Page 543: Numerical Library in C for Scientists and Engineers A

sol(jacob,n,p,df) ; for (1=0; l<=k; I++) {

i=l*nnpar+jSn; elmvec (i+l, i+n, -i, y, d£,a [ll ) ;

1

1 1

while (x >= t) { / * calculate a row of the jacobian matrix and an

element of the residual vector * / tobsdif = (tobs [iil -x) /h; cobsii=cobs [iil ; res [iil =peideinterpol (cobsii, n, k, tobsdif, y) -obs [iil ; if (!clean) (

for (i=l; i<=npar; i++) yp [iil [il =peideinterpol (cobsii+ (i+5) *n,nnpar, k,

tobsdif, y) ; /* introducing break-points * / if (bp[jjl ! = ii) { ) else if (first && fabs(res[iil ) < epsl) {

(*nbp) -- ; for (i=j j ; i<= (*nbp) ; i++) bp [il =bp [i+ll ; bp [*nbp+l] =0 ;

) else ( extra++; if (first) par [m+j jl =obs [iil ; / * introducing a jacobian row and a residual

vector element for continuity requirements * / yp bobs+ j j I [m+ j j I = -weight ; mulrow (1, npar, nobs+ j j , ii , yp, yp, weight) ; res [nobs+j jl =weight* (res [iil +obs [iil -par [m+j jl ) ;

\ 1

if (ii == nobs) goto Finish;

else ( t=tobs [ii+l] ; if (bp[jjl == ii && jj c *nbp) jj++; hmax=t-tobs [iil ; hmin=hmax*in [I] ;

I /* break-points introduce new initial values for y & yp * / if (extra > 0). {

for (id; 1<=n; i++) { y [il =peideinterpol (i,n, k, tobsdif, y) ; for (j=l; j<=npar; j++)

y [i+ (j+5) *nl =peideinterpol (i+ (j+5) *n,nnpar, k, tobsdif, y) ;

1 for (1=1; l<=extra; I++) (

cobsii=cobs [bp [npar-m+lI 1 ; y [cobsii] =par [npar+ll ; for (i=l; i<=npar+extra; i++) y [cobsii+ (5+i) *nl =O. 0; inivec (l+nnpar+ (l+S) *n,nnpar+ (l+6) *n,y, 0 .O) ; y [cobsii+ (S+npar+l) *nl =l. 0;

1 npar += extra; extra=O ; x=tobs [ii-11 ; / * evaluate jacobian */ evaluate=O; decompose=evaluated=l; if ( ! (*jacdfdy) (n,rn,par, y,x, fy) ) (

save [ - 3 1 = 4 . 0 ; goto Finish;

1 nnpar=n*npar; goto Newstart;

1 1

1 Finish:

Copyright 1995 by CRC Press, Inc

Page 544: Numerical Library in C for Scientists and Engineers A

if (save [-21 > *max) *max=save 1-21 ; if (!first) (*monitor) (l,ncol,nrow,par,res,weight,*nis); free-integer-vector(p,l); f ree-real-vector (delta, 1) ; free-real-vector(lastdelta,l); f ree-real-vector (df ,I) ; f ree-real-vector (yo, 1) ; f ree-real-matrix (jacob, 1, n, 1) ; return (saver-11 <= 40.0 && save[-31 == 0.0);

1 voi

I

.d peidereset (int n, int k, float hmin, float hmax, float hold, float xold, float y [I , float save [I , float *ch, float *x, float *h, int *decompose)

1 / * this function is internally used by PEIDEFUNCT of PEIDE */

int i, j; float c;

if (*ch < hmin/hold) *ch = hmin/hold;

else if (*ch > hmax/hold) *ch = hmax/hold;

*x = xold; *h = hold* (*ch) ; C=1.0 ; for (j=O; j<=k*n; j += n) {

for (i=l; i<=n; i++) y[j+i] =save [j+il *c; c *= (*ch);

void peideorder(int n, int k, float eps, float a[], float save[], float *tol, float *tolup, float *toldwn, float *tolconv, float *a0, int *decompose)

/* this function is internally used by PEIDEFUNCT of PEIDE */

int i, j; float c:

c=eps*eps; j=( (k-1) * (k+8) ) /2-38; for (i=O; i<=k; i++) atil =save [i+jl ; j += k+l; *tolup = c*save [ j I ; *to1 = c*save[j+ll ; *toldwn = c*save f j+2] ; *tolconv = eps/ (2*n* (k+2)) ; *a0 = a101 ; *decompose = 1;

void peidestep(int n, int k, int fails, float tolup, float toldwn, float tol, float error, float delta [I , float lastdelta [I , float y [I , float ymax I1 , int *knew, float *chnew)

I / * this function is internally used by PEIDEFUNCT of PEIDE */

int i; float al,aZ,a3,aa,s;

else { s=FLT-MIN; for (i=l; i<=n; i++) {

aa=y [k*n+il /pax [il ; s += aa*aa;

1

Copyright 1995 by CRC Press, Inc

Page 545: Numerical Library in C for Scientists and Engineers A

a2=0.80*pow(tol/error,0.5/(k+l)); if (k >= 5 1 1 fails != 0)

a3=O. 0; else {

s=FLT MIN; for (T=1; ic=n; i++) {

aa= (delta [i] -1astdelta [il ) /wax [il ; s += aa*aa;

1

if (a1 > a2 && a1 > a3) ( *knew = k-1; *chnew = al;

] else if (a2 > a3) { *knew = k; *chnew = a2;

] else { *knew = k+l; *chnew = a3;

I I

float peideinterpol(int startindex, int jump, int k, float tobsdif, float y[l)

/ * this function is internally used by PEIDEFUNCT of PEIDE * /

int i; float s,r;

s=y [startindex] ; r=tobsdif; for (i=l; ic=k; i++) (

startindex += jump; s += y [startindex] *r; r *= tobsdif;

I return s;

Copyright 1995 by CRC Press, Inc

Page 546: Numerical Library in C for Scientists and Engineers A

6. Special Functions

6.1 Elementary functions

6.1.1 Hyperbolic functions

A. arcsinh

Computes the inverse hyperbolic sine of the argument x. If I X I I 10'' then we use the procedure logoneplusx by writing

arcsinh(x) = In(x + d(x*x+l)) = In(l + x + x2/(1+d(1+X'))). If I X I > 10" we use the formula

arcsinh(x) = sign($ * (ln(2) + In(lx I)).

Function Parameters: float arcsinh (x)

arcsinh: delivers the inverse hyperbolic sine of the argument x; X : float;

entry: the real argument of arcsinh(x).

Function used: logoneplusx.

float arcsinh (float x) I

float logoneplusx (f loat) ; float y;

if (fabs (x) > 1.0e10) return ( (x > 0.0) ? 0.69314718055995+1og(fabs (x) ) :

-0.69314718055995+10g(fab~(~))); else {

y=x*x; return ( (x == 0.0) ? 0.0 : ( (x > 0.0) ?

logoneplusx (fabs (x) +y/ (l.O+sqrt (l.O+y) ) ) : -logoneplusx(fabs (x) +y/ (l.O+sqrt (l.O+y) ) ) ) ) ;

I I

B. arccosh

Computes the inverse hyperbolic cosine of the argument x. If x = 1 then the value 0 is delivered. If 1 < x I 10" then we use the formula

arccosh(x) = In(x + d(x*x-I)). If x > 10" we use the formula

arccosh(x) = In(2) + ln(x). If x is close to 1, say x = I + y, then it is advised to use the procedure logoneplusx by writing

arccosh(x) = In(1 + y + d(y*(y+2)) ). For example, if x = exp(t), t > 0, t is small, then y = exp(t) - I is available in good relative

Copyright 1995 by CRC Press, Inc

Page 547: Numerical Library in C for Scientists and Engineers A

accuracy, y = 2 * exp(t/2) * sinh(t/2).

Function Parameters: float arccosh (x)

arccosh: delivers the inverse hyperbolic cosine of the argument x; X : float;

entry: the real argument of arccosh(x), x 2 1 .

float arccosh(f1oat x) 1 I

return ( (x <= 1.0) ? 0.0 : ( (x s 1.0e10) ? 0.69314718O55995+1og (x) : log(x+sqrt((x-l.O)*(x+l.O)))));

1

C. arctanh

Computes the inverse hyperbolic tangent of the argument x. If 1x1 < 1 then we use the procedure logonepIusx by writing

arctanh(x) = 0.5 * In((1 +$/(I-$) = 0.5 * In(1 + 2*x/(I-x)). If 1x1 = 1 then the value is sign($ * FLT-MAX, where FLT-LUX is a large number.

Function Parameters: float arctanh (x)

arctanh: delivers the inverse hyperbolic tangent of the argument x; X : float;

entry: the real argument of arctanh(x).

Function used: logoneplusx.

float arctanh(f1oat x)

' float logoneplusx (float) ; float ax;

if (fabs(x) s= 1.0) return ( (x s 0.0) ? FLT-MAX : -FLT-MAX) ;

else ( ax=£ abs (x) ; return ((x == 0.0) ? 0.0 : ((x > 0.0) ?

0.5*logoneplusx(2.0*ax/(l.0-ax)) : -0.5*logoneplusx(2.0*ax/(l.O-ax))));

1 1

6.1.2 Logarithmic functions

logoneplusx

Computes the function In(1 + x) for x > -1. For values of x near zero, loss of relative accuracy in the computation of ln(1 +x) by use of the formulae z=l +x, ln(1 +x) =ln(z) occurs

Copyright 1995 by CRC Press, Inc

Page 548: Numerical Library in C for Scientists and Engineers A

(since l+x = I for small x); the use of logoneplusx avoids this loss [HaCL68]. For x < -0.2929 or x > 0.4142, In(l+x) is evaluated by use of the standard function In

directly; otherwise, a polynomial expression of the form

is used, and for small x loss of relative accuracy does not take place.

Function Parameters: float logoneplusx (x)

logoneplusx: delivers the value of ln(l+x); X: float;

entry: the real argument of In(1 +x), x > - 1.

float logoneplusx(float x) I

float y,z;

if (X == 0.0) return 0.0;

else if (x < -0.2928 1 1 x > 0.4142) return log (l.O+x) ;

else { z=x/ (x+2.0) ; y=z*z; return ~*(2.0+y*(0.666666666663366+y*(0.400000001206045+y*

(0.285714091590488+y*(0.22223823332791+y* (0.1811136267967+y*0.16948212488))))));

1 I

6.2 Exponential integral

6.2.1 Exponential integral

Calculates the exponential integral

where the integral is to be interpreted as the Cauchy principal value. When x > 0, the related function

may be obtained from that of Ei(x) by use of the relationship E,(x) = -Ei(-x). For x=O the integral is undefined and the procedure will cause overflow.

Copyright 1995 by CRC Press, Inc

Page 549: Numerical Library in C for Scientists and Engineers A

The exponential integral is computed by means of the rational Chebyshev approximations given in [AbS65, CodT68, CodT691. Only ratios of polynomials with equal degree I are considered.

Function Parameters: float ei (x)

ei: delivers the value of the exponential integral; x: float;

entry: the argument of the integral.

Functions used: chepolsum, pol, jfiac.

float ei(f1oat x) 1

float chepolsum (int , float, float [I ) ; float pol (int, float, float [I ) ; float jfrac(int, float [I, float [I ) ; float p t81 ,qt81 ;

if (X > 24.0) { p [O] = 1.00000000000058; q[l] = 1.99999999924131; p [l] =x-3. OOOOOOl6782085; q[21 = -2.99996432944446; p [21 =x-5. 00140345515924; q [31 = -7.90404992298926; p [31 =x-7.49289167792884; q[41 = -4.31325836146628; p t41 =x-3.08336269051763el; q[51 = 2.95999399486831eZ; p[5] =x-1.39381360364405; qt61 = -6.74704580465832; p 161 =x+8. 91263822573708; qt71 = 1.04745362652468e3; p [71 =x-5.31686623494482el; return exp(x) * (1.0+jfrac(7,q,p) /x) /x;

) else if (x > 12.0) { p LO1 = 9.99994296074708e-1; q[ll = 1.00083867402639; p [l] =X-1.95022321289660; q[2] = -3.43942266899870; p [21=~+1.75656315469614; q[31 = 2.89516727925135el; p [31 =x+l. 79601688769252el; q [4] = 7.60761148007735e2; p [4] =x-3.23467330305403el; q[51 = 2.57776384238440el; p [Sl =x-8 .28561994140641; q[61 = 5.72837193837324el; p [61 =x-1.86545454883399el; qt71 = 6.95000655887434el; p [7l =x-3 .48334653602853; return exp(x)*jfrac(7,q,p)/x;

) else if (x > 6.0) { p [O] = 1.00443109228078; q [l] = 5.27468851962908e-1; p 111 =x-4.32531132878l35el; q t21 = 2.73624119889328e3; p [21 =x+6.01217990830080el; q[3] = 1.43256738121938el; p Dl =x-3.31842531997221el; q[4] = 1.00367439516726e3; p 141 =x+2.50762811293561el; q[51 = -6.25041161671876; p [51=~+9.30816385662165; qt61 = 3.00892648372915eZ; P [61 =x-2.19010233854880el: a[71 = 3.93707701852715:

a - - p [71 =x-2 .18086381520724; . return exp(x)*jfrac(7,q,p)/x;

) else if (x > 0.0) { float t,r,xO,xmxO; p [O] = -1.95773036904548e8; q[Ol = -8.26271498626055e7 p 111 = 3.89280421311201e6; q[ll = 8.91925767575612e7 v t21= -2.21744627758845e7; a I21 = -2.49033375740540e7

Copyright 1995 by CRC Press, Inc

Page 550: Numerical Library in C for Scientists and Engineers A

else { float z,z2; p fO] = 0.837207933976075el; p [l] = -0.652268740837103el; p [21 = 0.569955700306720; q[Ol = 0.418603966988037el; q[l] = -0.465669026080814el; q[21 = O.lel; z=xmxo/ (x+x0) ; z2=z*z; t=z*pol(2,z2,p)/pol(2,z2,q);

keturn t+xmxO*r; ) else if (x > -1.0) {

float y; p fO] = -4.41785471728217e4; q[0] =7.65373323337614e4; p [l] = 5.77217247139444e4; q[1] =3.25971881290275e4; p [Z] = 9.93831388962037e3; q[2] =6.10610794245759e3; p[31 = 1.84211088668000e3; q[3]=6.35419418378382e2; p [4] = 1.01093806161906e2; q [4] =3.72298352833327el; p [5l = 5.03416184097568; q [5l =l. 0; y = -x; return log(y)-pol(5,y,p)/po1(5,y,q);

) else if (x > -4.0) ( float y; p [01=8.67745954838444e-8; q[01=1.0; p [I] =9.9999551930139Oe-1; q[1] =1.28481935379157el; p I21 =l. 18483lO5554946el; q [2] =5.64433569561803el; p I31 =4.55930644253390el; q [3] =I. 06645183769914e2; p [4] =6.99279451291003el; q [4] =8.9731109712529Oel; p [51=4.2520203476884lel; q[5] =3.1497184917044lel; p [61=8.83671808803844; sf61 =3.79559003762122; p[71=4.01377664940665e-1; q[7]=9.08804569188869e-2; y = -1.o/x; return -exp(x)*pol(7,y,pl/pol(5,y,q);

) else ( float y; p [Ol = -9.99999999998447e-1; q [OI =1.0; p [ll = -2.66271060431811el; q [11=2.86271060422192el; p [ZI = -2.41055827097015e2; q[21=~.92310039388533e2; p [31 = -8.95927957772937e~; q[31=1.33278537748257e3; p [41 = -1.29885688756484e3; q[41=2.77761949509163e3; p [51 = -5.45374158883133e2; q[51=2.40401713225909e3; p [61 = -5.66575206533869; q[61=6.3165748328080Oe2; y = -1.o/x; return -exp(x) *y* (l.O+y*pol(6,y,p)/pol(5,y,q)) ;

1 1

B. eialpha

Calculates a sequence of integrals [AbS65] of the form

by use of the recursion a&) = X-I, a&) = q(x) + (i/x)a,, (x) ( i= l ,..., n).

Function Parameters: void eialpha (x, n,alpha)

x: float; entry: the real x in the integrand;

n: int;

Copyright 1995 by CRC Press, Inc

Page 551: Numerical Library in C for Scientists and Engineers A

entry: the integer n in the integrand; alpha: float alpha[O:n];

exit: the value of the integral is stored in alpha[i], i=O, ..., n.

void eialpha(f1oat x, int n, float alpha[]) {

int k; float a,b,c;

c=1. o/x; a=exp (-x) ; b=alpha [OI =a*c; for (k=l; k<=n; k++) alpha Ikl =b= (a+k*b) *c;

1

C. enx

Calculates a sequence of integrals of the form

The value of an,(x) where no = x is first computed using (a) a call of ei if no = 1, (b) a Taylor series expansion in powers of x - nO if no I 10, and (c) (calling nonexpenx for this purpose) the relationship an(x) = e"a ',(x), where

with n=nO if no > 10. Thereafter, the recursion a,,,, (x) = n-' fe" - xa,, (x))

is used in a forward direction if no < n2, and in a backward direction if no > n l to compute the required values of the functions (1). The successive convergence Cr(x) of expansion (2) are computed until I I - Cr(x)/Cr+,(x) I 5 6 , where 6 is the value of the machine precision.

Function Parameters: void enx (x,nl,n2,a)

x: float; entry: the real positive x in the integrand;

nl,n2: int; entry: lower and upper bound, respectively, of the integer n in the integrand;

a: float a[nl:n2]; exit: the value of the integral is stored in a[i], i=nl, ..., n2.

Functions used: ei, nonexpenx.

void enx(f1oat x, int nl, int n2, float a[]) 1

if (X <= 1.5) { float ei(f1oat);

int i:

Copyright 1995 by CRC Press, Inc

Page 552: Numerical Library in C for Scientists and Engineers A

float w, e; w = -ei(-x); if (nl == 1) a[l] =w; if (n2 > 1) e=exp (-x) ; for (i=2; i<=n2; i++) {

w= (e-x*w) / (i-1) ; if (i >= nl) a[il =w;

1

1 e L e { int i,n; float w,e,an; n=ceil (x) ; if (n <= 10) {

float f,wl, t,h,p [201 ; p [2] =0.37534261820491e-1; p [Ill =0.135335283236613; p[3] =0.89306465560228e-2; p[12]=0.497870683678639e-1; p[4] =0.24233983686581e-2; p [ l 3 1 = 0 . 1 8 3 1 5 6 3 8 8 8 8 7 3 4 2 e - 1 ; p [5] =0.70576069342458e-3; p [14] =O. 673794699908547e-2; p[6] =0.21480277819013e-3; p[151=0 .247875217666636e -2 ; p[7] =0.67375807781018e-4; p[16]=0.911881965554516e-3; p[8] =0.21600730159975e-4; p[17 ]=0 .335462627902512e -3 ; p [g] =0.70411579854292e-5; p [I81 =O. 12340980408668Oe-3; p[l0]=0.23253026570282e-5; p[19]=0.453999297624848e-4; f =w=p [nl ; e=p [n+91 ; wl=t=l. 0; h=x-n;

:in? f= (e-i*f) /n; t = -h*t/ (n-i) ; wl=t*f; w += wl; i--;

) while (fabs(w1) > 1.0e-15*w) ; ) else {

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void nonexpenx (float, int, int, float [I ) ; float *b; b=allocate-real-vector(n,n); nonexpenx (x, n, n, b) ; w=b [nl *exp ( -x) ; free-real-vector (b, n) ;

1 I

if (nl == n2 && nl == n) a [nl =w;

else { e=exp (-x) ; an=w ; if (n <= n2 && n >= nl) a [nl =w; for (i=n-1; i>=nl; i--1 {

w= (e-i*w) /x; if (i <= n2) a[il =w;

1 w=an; for (i=n+l; ic=n2; i++) {

w= (e-x*w) / (i-1) ; if (i >= nl) a[il =w;

1

D. nonexpenx

Calculates a sequence of integrals of the form The value of ar,,(x) where no = x is first computed using the methods (a) and (b)

described in the documentation to em if no 5 10 (calling e m for this purpose) and the

Copyright 1995 by CRC Press, Inc

Page 553: Numerical Library in C for Scientists and Engineers A

continued fraction expansion (2) of that documentation if no > 10. Thereafter, the recursion ar,,+,(x) = n-'{I - xa,(x)]

is used as described in the documentation to e m to compute the required values of the functions (1). See [AbS65, CodT68, CodT69, G61, G731.

Function Parameters: void nonexpenx (x, nl, n2, a)

x: float; entry: the real positive x in the integrand;

nl,n2: int; entry: lower and upper bound, respectively, of the integer n in the integrand;

a: float a[nl:n2]; exit: the value of the integral is stored in a[i], i=nl, ..., n2.

Function used: enx.

void nonexpenx(f1oat x, int nl, int n2, float a [ I ) I 1

int i,n; float w, an;

n = (X C = 1.5) ? 1 : ceil (x) ; if (n <= 10) {

float *allocate-real-vector(int, int); void free real vector (f loat * , int) ; void enx (?loat, int, int, float [ I ) : float *b: b=allocate-real-vector (n, n) ; enx(x,n,n,b) ; w=b [nl *exp (x) ; free real-vector (b, n) ;

) else r int 'k, kl; float ue, ve, we, wel, uo, vo, wo, wol, r, s ; ue=l . 0 ; ve=we=l. 0/ (x+n) ; wel=O . 0; uo=1.0; vo = -n/ (x* (x+n+l. 0) ) ; wol=l.O/x; w0=v0+w01; w= (we+wo) /2.0; kl=l; k=kl; while (wo-we > 1.0e-15*w && we > we1 && wo < wol) {

wel=we ; w01=wo; r=n+k; s=r+x+k; ue=l.O/ (1.0-k* (r-1.0) *ue/ ( (s-2.0) *s) ) ; uo=l.0/(1.0-k*r*uo/(s*s-1.0)); ve *= (ue-1.0) ; vo *= (uo-1.0) ; we += ve; wo += vo; w= (we+wo) /2.0; kl++;

Copyright 1995 by CRC Press, Inc

Page 554: Numerical Library in C for Scientists and Engineers A

an=w; if (n c= n2 && n >= nl) a[n] =w; for (i=n-1; i>=nl; i--1 {

w=(l.O-i*w) /x; if (i <= n21 a[il=w;

1 w=an; for (i=n+l; ic=n2; i++) {

w= (1.0-x*w)/(i-1); if (i >= nl) a[il =w;

1

6.2.2 Sine and cosine integral

A. sincosint

Calculates the sine integral si(x) and cosine integral ci(x) defined by

If 1x1 I 4 then si(x) is approximated by means of a Chebyshev series of the form

and ci(x) by a similar series of the form

For values of x outside this range, the functions f(x) and g(x) occurring in the formulae si(x) = %?rsign(x) - f(x)cos(x) - g(x)sin(x) ci(x) = f(x)sin(x) - g(x)cos(x)

are evaluated by means of a call of sincosfg, and the values of si(x) and ci(x) are obtained by use of these relationships [AbS65, Bu1671.

When using the procedure sincosint for large values of x, the relative accuracy mainly depends on the accuracy of the functions sin(x) and cos(x).

Function Parameters: void sincosint (x,si,ci)

x: float; entry: the real argument of si(x) and ci(x);

si: float *; exit: the value of si(x);

ci: float *; exit: the value of ci(x).

Copyright 1995 by CRC Press, Inc

Page 555: Numerical Library in C for Scientists and Engineers A

Functions used: sincosfg, chepolsum.

void sincosint(f1oat x, float *si, float *ci) I

void sincosfg(float, float *, float * ) ; float chepolsum (int, float, float [I ) ; float absx, z, f, g;

absx=f abs (x) ; if (absx c= 4.0) {

float a[lll ,z2; a [0] =2.7368706803630eO; a [l] = -1.1106314107894eO; a [2] =1.4176562194666e-1; a [3] = -1.0252652579174e-2; a [4] =4.6494615619880e-4; a [5] = -1.4361730896642e-5; a [6] =3.2093684948229e-7; a (71 = -5.4251990770162e-9; a[8] =7.1776288639895e-11; a[9] = -7.6335493723482e-13; a [lo] =6.6679958346983e-15; z=x/4.O ; z2=z*z; g=z2+z2-1.0; *si = z*chepolsum(lO,g, a) ; a [0] =2.9659610400727eO; a [l] = -9.4297198341830e-1; a [2] =8.6110342738169e-2; a [3] = -4.7776084547139e-3; a [4] =I. 7529161205146e-4; a [S] = -4.5448727803752e-6; a [6] =8.7515839180060e-8; a [7] = -1.2998699938109e-9; a [8] =I. 5338974898831e-11; a [9] = -1.4724256070277e-13; a [lo] =I. l72l420798429e-l5; *ci = 0.577215664901533+1og(absx)-z2*chepolsum~lO,g,a~;

) else ( float cx,sx; sincosfg (x, &f, &g) ; cx=cos (x) ; sx=sin (x) ; *si = 1.570796326794897; if (X c 0.0) *si = - (*si); *si -= f*cx+g*sx; *ci = f*sx-g*cx;

1 1

B, sincosfg

Evaluates the functions f(x), g(x) related to the sine and cosine integrals [AbS65, Bu1671 by means of the formulae

f(x) = ci(x)sin(x) - {si(x) - d2jlcos(x) g(x) = -ci(x)cos(x) - {si(x) - n/2jlsin(x).

When 1x1 2 4 then the functions si(x) and ci(x) are evaluated by means of a call of sincosint, and the values of f(x) and g(x) are obtained by use of the above relationships. When I x 1 > 4 then f(x) is approximated by use of a Chebyshev series of the form

and g(x) by a use of a similar series of the form

Copyright 1995 by CRC Press, Inc

Page 556: Numerical Library in C for Scientists and Engineers A

Function Parameters: void sincosfg (xdg)

x: float; entry: the real argument of f(x) and g(x); float *; exit: the value of f(x);

g: float *; exit: the value of g(x).

Functions used: sincosint, chepolsum.

void sincosfg(f1oat x, float *f, float *g) I

void sincosint(float, float *, float * ) ; float chepolsum (int, float, float [I ) ; float absx,si,ci;

absx=f abs (x) ; if (absx c= 4.0) {

float cx, sx; sincosint (x, &si, &ci) ; cx=cos (x) ; sx=sin (x) ; si -= 1.570796326794897; *f = ci*sx-S~*CX; *g = -ci*cx-si*sx;

) else { float a [241 ; a [0] = 9.6578828035185e-1; a [l] = -4.3060837778597e-2; a [2] = -7.3143711748104e-3; a [31 = 1.4705235789868e-3; a[4] = -9.8657685732702e-5; a[5] = -2.2743202204655e-5; a [6] = 9.8240257322526e-6; a [7] = -1.8973430148713e-6; a [8] = 1.0063435941558e-7; a [9] = 8.0819364822241e-8; a [lo] = -3.8976282875288e-8; a [ll] = 1.0335650325497e-8; a [I21 = -1.4104344875897e-9; a [I31 = -2.5232078399683e-10; a[14]= 2.5699831325961e-10; a[151 = -1.0597889253948e-10; a [16] = 2.8970031570214e-11; a [I71 = -4.1023142563083e-12; a [18] = -1.0437693730018e-12; a [I91 = 1.0994184520547e-12; a[20]= -5.2214239401679e-13; a[21] = 1.7469920787829e-13; a [22] = -3.8470012979279e-14; *f = chepolsum(22, 8.0/absx-1.0, a) /x; a [0] = 2.2801220638241e-1; a [l] = -2.6869727411097e-2; a [2] = -3.5107157280958e-3; a [31 = 1.2398008635186e-3; a[4] = -1.5672945116862e-4; a[5] = -1.0664141798094e-5; a [6] = 1.1170629343574e-5; a [7] = -3.1754011655614e-6; a [a] = 4.4317473520398e-7; a [9] = 5.5108696874463e-8; a[lO]= -5.9243078711743e-8; a[lll = 2.2102573381555e-8; a[12]= -5.0256827540623e-9; a[131 = 3.1519168259424e-10; a [l4]= 3.6306990848979e-10; a [I51 = -2.2974764234591e-10; a[16]= 8.5530309424048e-11; a[17] = -2.1183067724443e-11; a[18]= 1.7133662645092e-12; ?&[I91 = 1.7238877517248e-12; a [20] = -1.2930281366811e-12; a [21] = 5.7472339223731e-13; a[22]= -1.8415468268314e-13; a[23] = 3.5937256571434e-14; *g = 4.0*chepolsurn(23,8.O/absx-l.O,a)/absx/absx;

I I

6.3 Gamma function

A. recipgamma

Copyright 1995 by CRC Press, Inc

Page 557: Numerical Library in C for Scientists and Engineers A

Calculates the reciprocal of the gamma function for arguments in the range [0.5,1.5]; moreover, odd and even parts are delivered.

recipgamma computes the values of the functions r '(x) = p ( 1 - x)} -I

where

and r ',,(x) = (2+~) -*(r '(x) - r y-x)]

r g(x) = I/Z p '(XI + r y-~)} for -0.5 I x I 0.5.

The functions I' ',,(x), r ',(x) are evaluated by use of truncated Chebyshev series, and the function r '(x) recovered from them by use of the formula

r '(XI = r I,(X) + (I + x/2)r ',(x).

Function Parameters: float recipgamma (x, oddmen)

recipgamma: delivers 1/T(1 -x); x: float;

entry: this argument should satisfy -0.5 I x I 0.5; (actually the gamma function r is calculated for I-x, i.e. if one wants to calculate l/r(l), one has to set x to 0);

odd float *; exit: the odd part of llT(1-x) divided by (2x);

i.e. (llT(1-x) - l/T(l+x)) 1 (2x); even: float *;

exit: the even part of 1/T(1-x) divided by 2; i.e. (llT(1-x) + l/T(l+x)) 12.

float recipgamma (float x, float *odd, float *even) {

int i; float alfa,beta,x2,b[l31 ;

b [1] = -0.283876542276024; b [2] = -0.076852840844786; b [3] = 0.001706305071096; b [41 = 0.001271927136655; b [53 = 0.000076309597586; b [6l = -0.000004971736704; b [7] = -0.000000865920800; b [8] = -0.000000033126120; b [9] = 0.000000001745136; b [I01 = 0.000000000242310; b [ll] = 0.000000000009161; b [I21 = -0.000000000000170; x2=x*x*8.0; alfa = -0.000000000000001; beta=O. 0; for (i=12; i>=2; i -= 2) {

beta = - (alfa*2.0+beta) ; alfa = -beta*x2-alfa+b [il ;

:even= (beta/2 .O+alfa) *x2-alfa+O. 921870293650453; alfa = -0.000000000000034; beta=O .0 ; for (i=ll; iz=l; i -= 2) {

beta = - (alfa*2.0+beta) ; alfa = -beta*x2-alfa+b [il ;

1 *odd= (alfa+beta) *2.0; return (*odd) *x+ (*even) ;

Copyright 1995 by CRC Press, Inc

Page 558: Numerical Library in C for Scientists and Engineers A

B. gamma

Computes the value of the gamma function at x

r ( ~ ) = Jmtx - l e -t dt 0

We distinguish between the following cases for the argument x: x < 0.5:

In this case the formula r(x) * r(1-x) = n/sin(n*x) is used. However the sine function is not calculated directly on the argument n*x but on the argument n*(x mod 0.5), in this way a big decrease of precision is avoided. The precision here depends strongly on the precision of the sine function.

0.5 1 x 1 1.5: Here the procedure recipgamma is called; moreover, r(1) = 1.

1.5 < x I 2 2 : The recursion formula F(l+x) = x * r(x) is used. The precision depends on the number of recursions needed. The upper bound of 22 has been chosen because now it is assured that for all integer arguments for which the value of the gamma function is representable (and this is the case for all integer arguments in the range [1,22]), this value is obtained, i.e, r(i) = 1 * 2 * ... * (i-1).

x > 22: Now the procedures loggamma and exp are used. The precision strongly depends on the precision of the exponential function, and no bound for the error can be given.

Function Parameters: float gamma (x)

gamma: delivers the value of the gamma function at x; x: float;

entry: the argument; if one of the following three conditions is fulfilled then overflow will occur:

1. the argument is too large; 2. the argument is a non-positive integer; 3. the argument is too close to a large (in absolute value) non-positive integer.

Functions used: recipgarnma, loggamma.

float gamma (float x) I

float recipgamma (f loat, float *, float * ) ; float loggamma(f1oat); int inv; float y,s,f,g,odd,even;

Copyright 1995 by CRC Press, Inc

Page 559: Numerical Library in C for Scientists and Engineers A

x=l. 0-x; f=s/sin(3.14159265358979*y) ;

\ else inv=O ;

if (X > 22.0) g=exp (loggamma (x) ) ;

else ( s=1.0; while (x > 1.5) (

x=x- 1.0 ; s *= x;

1

1 return (inv ? f/g : g);

1

C. loggamma

Computes the natural logarithm of the gamma function at x: In(r(x)). We distinguish between the following cases for the argument x (in most cases nothing is said about precision, as this highly depends on the precision of the natural logarithm): O < x < l :

Here the recursion formula loggamma(x) = loggamma(l+x) - ln(x) is used. 1 5 x 5 2 :

On the interval the truncated Chebyshev series for the function loggamma(x) / ((x-I) *(x-2)) is used.

2 < x I 13: The recursion formula loggamma(x) = loggamma(1-x) + In(x) is used.

13 < x I 2 2 : As for x < 1 the formula loggamma(x) = loggamma(1 +x) - In(x) is used.

x > 22: In this case loggamma is calculated by use of the asymptotic expansion for loggamma(x) - (x-0.5) * ln(x).

Function Parameters: float loggamma (x)

loggamma: delivers the value of the natural logarithm of the gamma function at x; x: float;

entry: this argument must be positive.

float loggamma(f1oat x) I

int i; float r,x2, y, f ,uO,ul,u, z , b [I91 ;

(x > 13.0) { r=1.0; while (x c= 22.0) (

r /= x; X += 1.0;

1 x2 = -l.O/(x*x); r=log (r) ; return l o g ( x ) * ( x - 0 . 5 ) - x + r + 0 . 9 1 8 9 3 8 5 3 3 2 0 4 6 7 2 +

Copyright 1995 by CRC Press, Inc

Page 560: Numerical Library in C for Scientists and Engineers A

(((0.595238095238095e-3*x2+0.793650793650794e-3)*~2+ 0.277777777777778e-2)*~2+0.833333333333333e-l)/~;

) else ( f=1.0; uO=ul=O.O; b [l] = -0.0761141616704358; b [2] = 0.0084323249659328; b [3] = -0.0010794937263286; b [4] = 0.0001490074800369; b [5] = -0.0000215123998886; b [6] = 0.0000031979329861; b [7] = -0.0000004851693012; b [El = O.OOOOOOO747l48782; b[9] = -0.0000000116382967; b[101 = 0.0000000018294004; b[ll] = -0.0000000002896918; b[12] = 0.0000000000461570; b[13] = -0.0000000000073928; b[l4] = 0.0000000000011894; b[15] = -0.0000000000001921; b[161 = 0.0000000000000311; b[17] = -0.0000000000000051; b[181 = 0.0000000000000008; if (X < 1.0) (

f =l. O/x; x += 1.0;

) else while (x > 2.0) {

X - = 1.0; f *= x;

f=lo'g (f) ; y=x+x-3.0; z=y+y; for (i=18; i>=l; i--) {

u=uo ; uO=z*uO+b [il -ul; u1=u;

1 I return (uO*y+0.491415393029387-ul) * (x-1.0) * (x-2 .O) +f;

1 1

D. incomgam

Computes the incomplete gamma functions based on Pad6 approximations [AbS65, Lu701. incomgam evaluates the functions

to a prescribed relative accuracy E.

If (a) a,x < 3 or (b) x < a and a 2 3, y(a,x) is computed by use of a continued fraction derived from a power series in ascending powers of x for this function, and r(a,x) is determined from the relationship r(a,x) = r(a) - y(a,x). If neither of the above conditions holds, I'(a,x) is computed by use of a continued fraction derived from an asymptotic series in descending powers of x for this function, and the relationship y(a,x) = r(a) - r(a,x) is used.

The relative accuracy of the results depends not only on the quantity e, but also on the accuracy of the functions exp and gamma. Especially for large values of x and a, the desired accuracy cannot be guaranteed.

Function Parameters: void incomgam (x,a, klgam,grgam,gam,eps)

x: float; entry: the independent argument x, x 2 0;

a: float; entry: the independent parameter a, a > 0;

Copyright 1995 by CRC Press, Inc

Page 561: Numerical Library in C for Scientists and Engineers A

klgam: float *; exit: the integral y(a,x) is delivered in klgam;

grgam: float *; exit: the integral I'(a,x) is delivered in grgam;

gum: float; entry: the value of I'(a);

for this expression, the procedure gamma may be used; eps: float;

entry: the desired relative accuracy (value of e above); the value of eps should not be smaller than the machine accuracy.

void incorngarn(f1oat x, float a, float *klgam, float *grgam, float gam, float eps)

{ int n; float cO, cl, c2, do, dl, d2 ,x2, ax,p, q, r, s, rl, r2, scf;

s=exp (-x+a*log (x) ) ; scf=FLT-MAX; if (X C= ((a c 3.0) ? 1.0 : a)) (

x2=x*x; ax=a*x; d0=1.0; p=a; co=s; dl= (a+l. 0) * (a+2.0-x) ; cl=( (a+l.O) * (a+2.0)+x) *s; r2=cl/dl; n=l ; do (

p += 2.0; q= (p+1.0) * (p* (p+2.0) -ax) ; r=n* (n+a) * (p+2.0) *x2; c2= (q*cl+r*cO) /p; d2= (q*dl+r*dO) /p; rl=r2 : r2=c2/d2 ; co=c1; c1=c2; dO=dl; dl=d2 ; if (fabs (cl) > scf

cO /= scf; Cl /= scf; do /= scf; dl /= scf;

1

I I fabs (dl) > scf

} while' (fabs ( (r2-rl) /r2) > eps) ; *klgam = r2/a; *grgam = gam- (*klgarn) ;

} else ( co=a*s; c1= (1. O+X) *co; q=x+2.0-a; dO=x; dl=x*q; rl=cl/dl; n=l; do (

q += 2.0; r=n* (n+l-a) ; c2=q*cl-r*c0; d2=q*dl-r*dO; rl=r2 ;

Copyright 1995 by CRC Press, Inc

Page 562: Numerical Library in C for Scientists and Engineers A

r2=c2/d2; co=c1; c1=c2 ; dO=dl ; dl=d2 ; if (fabs (cl) > scf I I fabs (dl) > scf) {

co /= scf; Cl /= scf; do /= scf; dl /= S C ~ ;

E. incbeta

The incomplete beta function is defined as

p > 0, q > 0, 0 1 x 5 I, and the incomplete beta function ratio is I,(p,q) = B,(p,q) /B,(p,q). incbeta computes I,(p,q) for 0 1 x 1 1, p > 0, q > 0 by use of the continued fraction corresponding to formula 26.5.8 in [AbS65], see also [G64, G671. If x > 0.5 then the relation I,(p,q)=l-I,,(q,p) is used. The value of the continued fraction is approximated by the convergent C,(x), where r is the smallest integer for which 11 - C,,(x)/C,(x) I I e, e being a small positive real number supplied by the user.

It is advised to use in incbeta only small values of p and q, say O<p 15, O<q 15. For other ranges of the parameters p and q, the procedures ibpplusn and ibqplusn can be used. incbeta satisfies incbeta=x if x=O or x=l , whatever p and q. There is no control on the parameters x, p, q for their intended ranges.

Function Parameters: float incbeta (x,p,q,eps)

incbeta: delivers the value of I,(p,q); x: float;

entry: this argument should satisfy: 0 I x 5 1 ; p: float;

entry: the parameter p, p > 0; q: float;

entry: the parameter q, q > 0; eps: float;

entry: the desired relative accuracy (value of e above); the value of eps should not be smaller than the machine accuracy.

Function used: gamma.

;loat incbeta(f1oat x, float p, float q, float eps)

Copyright 1995 by CRC Press, Inc

Page 563: Numerical Library in C for Scientists and Engineers A

float gamma (float) ; int m, n, neven, recur; float g,f,fn,fnl,fnZ,gn,gnl,gn2,dn,pq;

if (X == 0.0 I I x == 1.0) return x;

else { if (X r 0.5) {

f=p; p=q; q=f ; x=1.0-x; recur=l;

) else recur=O;

g=fn2=0.0; m=O ; pq=p+q; f=fnl=gnl=gnZ=l.O; neven=O ; n=l; do (

if (neven) ( m++; dn=m*x* (q-m) / (p+n-1.0) / (p+n) ;

} else dn = -x* (p+m) * (pq+m) / (p+n-1.0) / (p+n) ;

g=f; fn=fnl+dn*fnZ; gn=gnl+dn*gn2; neven= ( ! neven) ; f =fn/gn; fnZ=fnl; fnl=fn; gn2 =gnl ; gnl=gn; n++ ;

} while (fabs((f-g)/f) > eps); POW (~,p) *pow (1.0-x,q) *gamma (p+q) /gamma(p+l. 0) /gamma(q) ; if (recur) f=l.O-f; return f;

1 1

F. ibpplusn

The incomplete beta function is defined as

p > 0, q > 0, 0 5 x I; I , and the incomplete beta function ratio is I,(p,q) = B,(p,q) / B,(p,q). ibpplusn computes I,(p+n,q) for n=O,l, ..., nmax, 0 S x 5 1, p > 0, q > 0 (see [G64, G671). In [G64] the procedure ibpplusn is called "incomplete beta q fixed". There is no control on the parameters x, p, q, nmax for their intended ranges.

Function Parameters: void ibpplusn (x,p,q,nmax,eps, i)

x: float; entry: this argument should satisfy: 0 I x I 1;

p: float; entry: the parameter p, p > 0; it is advised to take 0 < p I 1;

q: float;

Copyright 1995 by CRC Press, Inc

Page 564: Numerical Library in C for Scientists and Engineers A

entry: the parameter q, q > 0; nmax: int;

entry: nmax indicates the maximum number of function values I,(p+n,q) to be generated;

eps: float; entry: the desired relative accuracy (value of E above);

the value of eps should not be smaller than the machine accuracy; i: float i[O:nmax];

exit: i[n]=I&+n,q)forn=O,l, ..., nmax.

Functions used: ixqfix, ixpfix.

void ibpplusn(f1oat x, float p, float q, int nmax, float eps, float i [I )

void ixqf ix (f loat, float, float, int, float, float [I ) ; void ixpf ix (f loat, float, float, int, float, float [I ) ; int n;

if (X == 0.0 I I x == 1.0) for (n=O; n<=nmax; n++) i[nl=x;

else ( if (X <= 0.5)

ixqfix(x,p, q,nmax,eps, i) ; else (

ixpfix(l.0-x,q,p,nmax,eps,i) ; for (n=O; n<=nmax; n++) i [nl =l. 0-i [nl ;

- 1 1

G . ibqplusn

The incomplete beta function is defined as

p > 0, q > 0, 0 5 x 5 1, and the incomplete beta function ratio is I,(p,q) = B,(p,q) /B,(p,q). ibqplusn computes I,(p,q+n) for n=O,l, ..., nmax, 0 5 x 5 I, p > 0, q > 0 (see [G64, G671). In [G64] the procedure ibqplusn is called "incomplete beta p fixed". There is no control on the parameters x, p, q, nmax for their intended ranges.

Function Parameters: void ibqplusn (x,p,q,nmax,eps, i)

x: float; entry: this argument should satisfy: 0 5 x I 1;

p : float; entry: the parameter p, p > 0;

q: float; entry: the parameter q, q > 0; it is advised to take 0 < q I 1;

nmax: int; entry: nmax indicates the maximum number of function values I,(p,q+n) to be

generated;

Copyright 1995 by CRC Press, Inc

Page 565: Numerical Library in C for Scientists and Engineers A

eps: float; entry: the desired relative accuracy (value of E above);

the value of eps should not be smaller than the machine accuracy; i: float i [O:nmd;

exit: i[n] = I,(p,q+n) for n=O,l, ..., nmax.

Functions used: ixqfix, ixpfix.

void ibqplusn(f1oat x, float p, float q, int nmax, float eps, float i[l)

I

if (X == 0.0 1 1 x == 1.0) for (n=O; ns=nmax; n++) i [nl =x;

else { if (X <= 0.5)

ixpfix(x,p, q,nmax,eps, i) ; else {

ixqfix(l.O-x,q,p,nmax,eps,i) ; for (n=O; nc=nmax; n++) i [nl =l. 0-i [nl ;

H. ixqfix

The four auxiliary procedures ixqjix, ixpfix, forward and backward are for procedures incbeta, ibpplusn and ibqplusn.

These auxiliary procedures are not described here. More information can be found in [G64] of ibqplusn, where the procedures forward and backward have the same name, while ixqjix and ixpfix are called "Isubx q fixed and "Isubx p fixed", respectively. In the procedure backward we changed the starting value nu for the backward recurrence algorithm. The new value of nu is more realistic. Its computation is based on some asymptotic estimations. Also the initial value r=O is changed into r=x.

Functions used: incbeta, forward, backward.

void ixqfix(f1oat x, float p, float q, int nmax, float eps, float iIl) I ' float *allocate-real-vector(int, int);

void free-real-vector(f1oat *, int); float incbeta (float, float, float, float) ; void forward(float, float, float, float, float, int, float 11); void backward(float, float, float, float, int, float, float [I); int m,mmax; float s,iqO,iql,qO,*iq;

m=f loor (q) ; s=q-m; qo = (s > 0.0) ? s : s+1.0; mmax = (s > 0.0) ? m : m-1; iqo=incbeta (x,p, q0, eps) ; if (mmax > 0) iql=incbeta (x,p, qO+l. 0, eps) ; iq=allocate~real~vector(0,mmax); forward(x,p,qO,iqO,iql,mmax,iq); backward (x,p, q, iq [mmax] ,nmax, eps, i) ; free-real-vector (iq, 0) ;

Copyright 1995 by CRC Press, Inc

Page 566: Numerical Library in C for Scientists and Engineers A

I. ixpfix

See the documentation of ixqfix.

Functions used: incbeta, forward, backward.

void ixpfix(f1oat x, float p, float q, int nmax, float eps, float i[l) l

float *allocate_real-vector(int, int) ; void free-real-vector(f1oat *, int); float incbeta (float, float, float, float) ; void forward (float, float, float, float, float, int, float [I ) ; void backward (f loat, float, float, float, int, float, float [ I ) ; int m,mmax; float s,pO,iO,il,iqO,iql,+ip;

m=f loor (p) ; s=p-m; PO = (s > 0.0) ? S : s+1.0; mmax = (s > 0.0) ? m : m-1; iO=incbeta (x,pO, q, eps) ; il=incbeta (x,pO, q+l. 0, eps) ; ip=allocate~real~vector(0,mmax); backward(x,pO,q,iO,mmax,eps,ip); iqO=ip [mmaxl ; backward(x,pO,q+l.O,il,mmax,eps,ip); iql=ip [mmaxl ; free-real-vector (ip, 0) ; forward(x,p, q, iqo, iql,nmax, i) ;

1

J. forward

See the documentation of ixqfix.

void forward(f1oat x, float p, float q, float iO, float il, int nmax, float i [I )

1 1

int m,n; float y,r,s;

i [O] =iO; if (nmax > 0) i[ll=il; m=nmax- 1 ; r=p+q-1.0; y=1.0-x; for (n=l; n<=m; n++) {

s= (n+r) *y; i [n+l] = ( (n+q+s) *i [nl -s*i [n-11 ) / (n+q) ;

K. backward

See the documentation of ixqfix.

void backward(f1oat x, float p, float q, float iO, int nmax,

Copyright 1995 by CRC Press, Inc

Page 567: Numerical Library in C for Scientists and Engineers A

float eps, float i [I ) l ' float *allocate-real-vector(int, int) ;

void free-real-vector(f1oat *, int); int m,n, nu, finish; float r, pq, y, logx, *iapprox;

if -(nrnax > 0) { for (n=l; n<=nmax; n++) iapprox [nl =O. 0; pq=p+q-1.0; logx=log (x) ; r=nrnax+ (log (eps) +q*log (nmax) ) /logx; nu=floor (r-q*log (r) /logx) ; while (1) {

n=nu ; r=x; while (1) {

y= (n+pq) *x; r=y/ (y+(n+p) *(1.0-r) ) ; if (n <= nrnax) i [nl =r; n- - ; if (n < 1) break;

1 r=iO; for (n=l; n<=nrnax; n++) r = i [nl *= r; f inish=l; for (n=l; n<=nrnax; n++)

if (fabs ( (i [nl -iapprox[nl ) /i [nl > eps) { for (m=l; rn<=nmax; m++) iapprox [ml =i [ml ; nu += 5; f inish=O; break;

1 I

if (finish) break;

1 1

free-real-vector(iapprox,O); 1

6.4 Error function

A. errorfunction

Computes the error function erf(x) and complementary error function erfc(x) for a real argument, i.e.

2 e ~ x ) = - S X e -"dt and erfc(x) = -1; 2 -"dt J;r O J;r

When x > 26 then erf(x) = 1 and erfc(x) = 0; when x < -5.5 then erf(x) = - 1 and erfc(x) =

2. Over the range 1x1 I O . 5 , erf(x) is approximated by a Chebyshev rational function of the form

and the relationship erfc(x) = I - erf(x) is used. If 0.5 < x or -5.5 I x < 0.5 then the function nonexperfc(x) = exp(9) * erfc(1x I) is evaluated by means of a call of nonexperfc, the value

Copyright 1995 by CRC Press, Inc

Page 568: Numerical Library in C for Scientists and Engineers A

of erfc(1x 1) is recovered by multiplication by exp(xZ), and the relationship erj(lx 1) = I - erfc()x 1) is used.; if x lies in the second of the above ranges the further relationships

erf(x) = -erjc(l x I ) , erfc(x) = 2 - erjc(1 x 1) are used.

Function Parameters: void errorfunction (x,erJTerfc)

x: float; entry: the real argument of erf(x) and erfc(x);

e r j float *; exit: the value of e m ) ;

erfc: float *; exit: the value of erfc(x).

Function used: nonexperfc.

void errorfunction(f1oat x, float *erf, float *erfc)

if (X > 26.0) { *erf = 1.0; *erfc = 0.0; return;

) else if (x c -5.5) ( *erf = -1.0; *erfc = 2.0; return;

} else ( float nonexperfc(f1oat); float absx,c,p,q; absx=f abs (x) ; if (absx c= 0.5) (

c=x*x; p=((-0.356098437018154e-1*c+0.699638348861914e1~*c+

0.219792616182942e2)*~+0.242667955230532e3; q=((c+0.150827976304078e2)*c+0.911649054045149e2)*~+

0.215058875869861e3; *erf = x*p/q; *erfc = 1.0-(*erf);

) else ( *erf c = exp (-x*x) *nonexperf c (absx) ; *erf = 1.0- (*erfc) ; if (X c 0.0) (

*erf = - (*erf ) ; *erfc = 2.0- (*erfc) ;

nonexperfc

The error function erj(x) and complementary error function erfc(x) for a real argument are given by

e c w

nonexperfc computes

2 and erfe(x) = -p -"dt . J;;

Copyright 1995 by CRC Press, Inc

Page 569: Numerical Library in C for Scientists and Engineers A

When 1x1 2 0.5 then the function efc(x) is evaluated by means of a call of errofunction, and the value of nonexpefc(x) is recovered by multiplication by exp(x2). If 0.5< 1 x 1 < 4 then nonexperfc(1 x 1) is approximated by a Chebyshev rational approximation (see [Cod69]) of the form

if, in addition, x is negative, the relationship nonexpefc(x) = 2 * exp(x2) - nonexpefc(1 x 1) (1)

is used. If 1x1 1 4 then nonexperfc(x) is approximated by a Chebyshev rational approximation (see [Cod69]) of the form

and again if x is negative then relationship (1) is used.

Function Parameters: float nonexperfc (x)

nonexpefc: delivers the value of exp(x2) *erfc(x); X: float;

entry: the real argument of nonexperfc.

Function used: errorfunction.

float nonexperfc(f1oat x) I ' void errorfunction(float, float *, float * ) ;

float absx, erf, erfc, c,p, q;

absx=fabs (x) ; if (absx c = 0.5) {

errorfunction (x, &erf, &erfc) ; return exp (x*x) *erfc;

) else if (absx < 4.0) { c=absx; p=((((((-O.136864857382717e-6*~+0.564195517478974eO)*c+

0.721175825088309e1)*~+0.431622272220567e2~*~+ 0.152989285046940e3)*c+0.339320816734344e3~*c+ 0.451918953711873e3)*c+0.300459261020162e3;

q = ( ( ( ( ( ( c + 0 . 1 2 7 8 2 7 2 7 3 1 9 6 2 9 4 e 2 ) * c + 0 , 7 7 0 0 0 1 5 2 9 3 5 2 2 9 5 e 2 ~ * c + 0 . 2 7 7 5 8 5 4 4 4 7 4 3 9 8 8 e 3 ) * ~ + 0 . 6 3 8 9 8 0 2 6 4 4 6 5 6 3 1 e 3 ) * ~ + 0.931354094850610e3)*c+0.790950925327898e3~*~+ 0.300459260956983e3;

return ( (x > 0.0) ? p/q : exp (x*x) *2.0-p/q) ; } else {

c=l.O/x/x;

Copyright 1995 by CRC Press, Inc

Page 570: Numerical Library in C for Scientists and Engineers A

0.299610707703542e-2; q=(((c+0.198733201817135e1)*c+0.105167510706793el~*c+

0.191308926107830e0)*c+0.106209230528468e-1; c= (c* ( - p ) /q+O. 564l89583547756) /absx; return ( (x > 0.0) ? c : exp (x*x) *2.0-c) ;

I 1

C. inverseerrorfunction

Evaluates the inverse error function y(x), where

the values of x and 1-x being supplied (for values of x near 1, loss of accuracy results from the formation of 1-x; this loss is avoided by defining y as a function of 1-x for such values of x, provided the supplied value of 1-x is sufficiently accurate).

When 1x1 2 0.8, a telescoped power series is used to evaluate y(x): y satisfies the equation

so that if

then the {C,) may be extracted from the equation

and from the {C,) a Chebyshev series (see [Str68]) of the form

valid for Ix 1 2 0.8 may be obtained. Over the range 0.8 < 1x1 2 0.9975, an expansion of the form y(x) = J(x)R(x), where

Copyright 1995 by CRC Press, Inc

Page 571: Numerical Library in C for Scientists and Engineers A

with j= l5 is used; over the range 2.5*104 > 1-x 2 0.5*10-'~ a similar expansion with j=23 is used, and over the range OS* > 1-x, yet another similar expansion with j=12 is used.

Function Parameters: void inverseerrorfunction (x, oneminx, inverfl

x: float; entry: the argument of inverseerrorfunction(x); it is necessary that -1 < x < 1;

if I x I > 0.8 then the value of x is not used in the procedure; oneminx: float;

entry: if Ix 1 5 0.8 then the value of oneminx is not used in the procedure; if 1x1 > 0.8 then oneminx has to contain the value of 1-1x1; in the case that

I X I is in the neighborhood of 1, cancellation of digits take place in the calculation of 1 - I x 1 ; if the value 1 - I x 1 is known exactly from another source then oneminx has to contain this value, which will give better results;

inverj float *; exit: the result of the procedure.

Function used: chepolsum.

void inverseerrorfunction(float x, float oneminx, float *inverf) I

float chepolsum (int , float, float [I ) ; float absx,p,betax,a[241 ;

absx=f abs (x) ; if (absx > 0.8 && oneminx > 0.2) oneminx=O.O; if (absx c= 0.8) (

a [O] = 0.992885376618941; a [l] = O.l204675l6l43lO4; a [2] = 0.016078199342100; a [3] = 0.002686704437162; a [4] = 0.000499634730236; a [5] = 0.000098898218599; a [6] = 0.000020391812764; a [7] = 0.000004327271618; a [8] = 0.000000938081413; a [9] = O.OOOOOO2O673472O; a [lo] = 0.000000046159699; a [lll = 0.000000010416680; a [l2] = 0.000000002371501; a [I31 = 0.000000000543928; a [l4] = 0.000000000125549; a [I51 = 0.000000000029138; a [16] = 0.000000000006795; a 1171 = 0.000000000001591; a [l8] = 0.000000000000374; a [I91 = 0.000000000000088; a [20] = 0.000000000000021; a [211 = O.OOOOOOOOOOOOOO5; *inverf = chepolsum(2l,x*x/0.32-l.O,a)*x;

} else if (oneminx >= 25.0e-4) { a [0] = 0.912158803417554; a [I] = -0.016266281867664; a [2] = 0.000433556472949; a [3] = 0.000214438570074; a [4] = 0.000002625751076; a [5] = -0.000003021091050; a [6] = -0.000000012406062; a [7] = O.OOOOOOO624O66O9; a [8] = -0.000000000540125; a [9] = -0.000000001423208; a [lo] = 0.000000000034384; a [ll] = 0 .OOOOOOOOOO33584; a[l2] = -0.000000000001458; a[13] = -0.000000000000810; a [I41 = 0.000000000000053; a [I51 = 0.000000000000020; betax=sqrt (-log ( (l.O+absx) *oneminx) ) ; p = -1.54881304237326*betax+2.56549012314782; p=chepolsum (l5,p, a) ; *inverf = (x c 0.0) ? -betax*p : betax*p;

) else if (oneminx >= 5.0e-16) { a [0] = 0.956679709020493; a [l] = -0.023107004309065; a [2] = -0.004374236097508; a [3] = -0.000576503422651; a[4] = -0.000010961022307; a[51 = 0.000025108547025; a [6] = 0.000010562336068; a [7] = 0.000002754412330; a [8] = 0.000000432484498; a [9] = -0.000000020530337; a[lO] = -0.000000043891537; a[lll = -0.000000017684010; a[l2] = -0.000000003991289; a[131 = -0.000000000186932; a [14] = O.OOOOOOOOO272923; a [15] = O.OOOOOOOOOl328l7;

Copyright 1995 by CRC Press, Inc

Page 572: Numerical Library in C for Scientists and Engineers A

a [16] = O.OOOOOOOOOO3l834; a [17] = 0.000000000001670; a[l8] = -0.000000000002036; a[191 = -0.000000000000965; a[20] = -0.000000000000220; a[2ll = -0.000000000000010; a [22] = 0.000000000000014; a [231 = O.OOOOOOOOOOOOOO6; betax=sqrt(-log((l.O+absx)*oneminx)); p = -0.559457631329832*betax+2.28791571626336; p=chepolsum(23 ,p, a) ; *inverf = (x c 0.0) ? -betax*p : betax*p;

) else if (oneminx >= FLT-MIN) { a [O] = 0.988575064066189; a [l] = 0.010857705184599; a [2] = -0.OOl751165lO2763; a [3l = O.OOOO2ll96993207; a [4] = 0.000015664871404; a [5] = -0.000000519041687; a [6] = -0.000000037135790; a[7] = 0.000000001217431; a [8] = -0.000000000176812; a[91 = -0.000000000011937; a [lo] = 0.000000000000380; a [ll] = -0.000000000000066; a [I21 = -0.000000000000009; betaxzsqrt (-log ( (l.O+absx) *oneminx) ) ; p = -9.19999235883015/sqrt(betax)+2.79499082012460; p=chepolsum(l2 ,p, a) ; *inverf = (x c 0.0) ? -betax*p : betax*p;

} else *inverf = (x > 0.0) ? 26.0 : -26.0;

1

D. fresnel

Evaluates the Fresnel integrals

~ ( x ) = /oX~in('t 2 '1 dt,

If 1x1 I 1.2 then S(x) is approximated by means of a Chebyshev rational function (see [Cod68]) of the form

and C(x) by a similar function of the form

where j=4. When 1.2 < I x 1 I 1.6, similar approximations with j=5 are used. Over the range 1.6< I x I , the functions f(x) and g(x) occurring in the formulae

S(x) = '/i - f(x)cos(ux '/2) - g(x)sin(u2/2) C(x) = '/i + f(x)sin(?rx2/2) - g(x)cos(ux2/2)

are evaluated by means of a call of fg, and the values of S(x) and C(x) are obtained by use of these relationships.

Function Parameters: void fresnel (x,c,s)

x: float; entry: the real argument of C(x) and S(x);

c: float *;

Copyright 1995 by CRC Press, Inc

Page 573: Numerical Library in C for Scientists and Engineers A

exit: the value of C(x); s: float *;

exit: the value of S(x).

Function used: fg.

void f resne l ( f1oa t x , f l o a t *c, f l o a t * s ) I ' void f g ( f l o a t , f l o a t *, f l o a t * ) ;

f l o a t absx, x3, x4, a , p , q, f , g, c l , s l ;

absx=f abs (x) ; i f (absx c= 1 . 2 ) {

a=x*x; x3=a*x; x4=a*a; p = ( ( ( 5 . 4 7 7 1 1 3 8 5 6 8 2 6 8 7 e - 6 * ~ 4 - 5 . 2 8 0 7 9 6 5 1 3 7 2 6 2 3 e - 4 ) * ~ 4 +

1 . 7 6 1 9 3 9 5 2 5 4 3 4 9 1 e - 2 ) * ~ 4 - 1 . 9 9 4 6 0 8 9 8 8 2 6 1 8 4 e - l ) * x 4 + 1 . 0 ; q = ( ( ( 1 . 1 8 9 3 8 9 0 1 4 2 2 8 7 6 e - 7 * ~ 4 + 1 . 5 5 2 3 7 8 8 5 2 7 6 9 9 4 e - 5 ) * ~ 4 +

1 . 0 9 9 5 7 2 1 5 0 2 5 6 4 2 e - 3 ) * x 4 + 4 . 7 2 7 9 2 1 1 2 0 1 0 4 5 3 e - 2 ) * ~ 4 + 1 . 0 ; *C = x*p/q; p = ( ( ( 6 . 7 1 7 4 8 4 6 6 6 2 5 1 4 1 e - 7 * ~ 4 - 8 . 4 5 5 5 7 2 8 4 3 5 2 7 7 7 e - 5 ) * ~ 4 +

3 . 8 7 7 8 2 1 2 3 4 6 3 6 8 3 e - 3 ) * x 4 - 7 . 0 7 4 8 9 9 1 5 1 4 4 5 2 3 e - 2 ) * x 4 + 5.23598775598299e-1;

q = ( ( ( 5 . 9 5 2 8 1 2 2 7 6 7 8 4 1 0 e - 8 * ~ 4 + 9 . 6 2 6 9 0 8 7 5 9 3 9 0 3 4 e - 6 ) * ~ 4 + 8 . 1 7 0 9 1 9 4 2 1 5 2 1 3 4 e - 4 ) * ~ 4 + 4 . 1 1 2 2 3 1 5 1 1 4 2 3 8 4 e - 2 ) * ~ 4 + 1 . 0 ;

*s = x3*p/q; ) e l s e i f (absx c= 1 .6 ) {

a=x*x; x3=a*x; x4=a*a; p = ( ( ( ( - 5 . 6 8 2 9 3 3 1 0 1 2 1 8 7 1 e - 8 * x 4 + 1 . 0 2 3 6 5 4 3 5 0 5 6 1 0 6 e - 5 ) * ~ 4 -

6 . 7 1 3 7 6 0 3 4 6 9 4 9 2 2 e - 4 ) * ~ 4 + 1 . 9 1 8 7 0 2 7 9 4 3 1 7 4 7 e - 2 ) * x 4 - 2.07073360335324e-1) *x4+1.00000000000111eO;

q = ( ( ( ( 4 . 4 1 7 0 1 3 7 4 0 6 5 0 1 0 e - 1 0 * x 4 + 8 . 7 7 9 4 5 3 7 7 8 9 2 3 6 9 e - 8 ~ * ~ 4 + 1 . 0 1 3 4 4 6 3 0 8 6 6 7 4 9 e - 5 ) * ~ 4 + 7 . 8 8 9 0 5 2 4 5 0 5 2 3 6 0 e - 4 ) * x 4 + 3 . 9 6 6 6 7 4 9 6 9 5 2 3 2 3 e - 2 ) * x 4 + 1 . 0 ;

*c = x*p/q; p = ( ( ( ( - 5 . 7 6 7 6 5 8 1 5 5 9 3 0 8 9 e - 9 * ~ 4 + 1 . 2 8 5 3 1 0 4 3 7 4 2 7 2 5 e - 6 ) * ~ 4 -

1 . 0 9 5 4 0 0 2 3 9 1 1 4 3 5 e - 4 ) * x 4 + 4 . 3 0 7 3 0 5 2 6 5 0 4 3 6 7 e - 3 ) * ~ 4 - 7 . 3 7 7 6 6 9 1 4 0 1 0 1 9 1 e - 2 ) * ~ 4 + 5 . 2 3 5 9 8 7 7 5 5 9 8 3 4 4 e - 1 ;

q = ( ( ( ( 2 . 0 5 5 3 9 1 2 4 4 5 8 5 8 0 e - 1 0 * x 4 + 5 . 0 3 0 9 0 5 8 1 2 4 6 6 1 2 e - 8 ) * ~ 4 + 6 . 8 7 0 8 6 2 6 5 7 1 8 6 2 0 e - 6 ) * ~ 4 + 6 . 1 8 2 2 4 6 2 0 1 9 5 4 7 3 e - 4 ) * x 4 + 3 . 5 3 3 9 8 3 4 2 7 6 7 4 7 2 e - 2 ) * x 4 + 1 . 0 ;

*s = x3*p/q; } e l s e i f (absx c 1.0e15) {

f g ( x , & f , & g ) ; a=x*x; a = ( a - f l o o r ( a / 4 . o ) *4 . o ) *1.57079632679490; c l=cos ( a ) ; s l = s i n ( a ) ; a = (X c 0.0) ? -0.5 : 0.5; *C = f*s1-g*cl+a; *s = - f*cl-g*sl+a;

) e l s e *c = *s = ( ( x > 0.0) ? 0.5 : - 0 . 5 ) ;

1

Evaluates the functions f(x), g(x) related to the Fresnel integrals by means of the formulae

f(x) = {W - S(x)}cos(?rx2/2) - {W - C(x)}sin(nx 2/2) g(x) = {W - C(x)}cos(m2/2) + {W - S(x)}sin(d/2).

Copyright 1995 by CRC Press, Inc

Page 574: Numerical Library in C for Scientists and Engineers A

When Ix I 5 1.6 the functions S(x) and C(x) are evaluated by means of a call offresnel, and the values of f(x) and g(x) are obtained by use of the above relationships. When 1.6 < ( x 111.9, f(x) is approximated by use of a Chebyshev rational function (see [Cod68]) of the form

and g(x) by use of a similar function of the form

with i=4 and j=5. When I x 1 2 2.4, similar expansions with i=j=5 are used. When I x 1 > 2.4, the approximating functions are

for f(x) and

for g(x).

Function Parameters: void fg (x,jg)

x: float; entry: the real argument of f(x) and g(x);

$ float *; exit: the value of f(x);

g: float *; exit: the value of g(x).

Function used: fresnel.

void fg(f1oat x, float *f, float *g) 1

void fresnel (float, float * , float * ) ; float absx, c, s, cl, sl, a, xinv, x3inv, c4, p, q;

absx=f abs (x) ; if (absx <= 1.6) (

fresnel (x, &c, &s) ; a=x*x*1.57079632679490; cl=cos (a) ;

Copyright 1995 by CRC Press, Inc

Page 575: Numerical Library in C for Scientists and Engineers A

sl=sin (a) ; a = (X < 0.0) ? -0.5 : 0.5; p=a-c; q=a-s; *f = q*c1-p*s1; *g = p*c1+q*s1;

) else if (absx <= 1.9) { xinv=l.O/x; a=xinv*xinv; x3 inv=a*xinv; c4=a*a; p=(((1.35304235540388e1*c4+6.98534261601021el)*c4+

4.80340655577925e1)*~4+8.03588122803942eO)*c4+ 3.18309268504906e-1;

q=(((6.55630640083916e1*~4+2.49561993805172e2)*~4+ 1.57611005580123e2)*c4+2.55491618435795el~*c4+1.0;

*f = xinv*p/q; p=((((2.05421432498501e1*~4+1.96232037971663e2)*~4+

1.99182818678903e2)*~4+5.31122813480989el)*c4+ 4.44533827550512eO)*c4+1.01320618810275e-1;

q=((((1.01379483396003e3*~4+3.48112147856545e3)*~4+ 2.54473133181822e3)*~4+5.83590575716429e2)*~4+ 4.53925019673689el)*c4+1.0;

*g = x3inv*p/q; } else if (absx <= 2.4) {

xinv=l.O/x; a=xinv*xinv; x3inv=a*xinv; c4=a*a; p=((((7.17703249365140e2*~4+3.0914516157443Oe3)*~4+

1.93007640786716e3)*~4+3.39837134926984e2)*~4+ 1.95883941021969e1)*~4+3.18309881822017e-1;

q=((((3.36121699180551e3*~4+1.09334248988809e4)*~4+ 6.33747155851144e3)*~4+1.08535067500650e3)*~4+ 6.18427138172887el)*c4+1.0;

*f = xinv*p/q; p=((((3.13330163068756e2*~4+1.59268006085354e3)*~4+

9.08311749529594e2)*~4+1.40959617911316e2)*~4+ 7.11205001789783e0)*c4+1.01321161761805e-1;

q=((((1.15149832376261e4*~4+2.4131556721337Oe4)*~4+ 1.06729678030581e4)*~4+1.49051922797329e3)*~4+ 7.17128596939302el)*c4+1.0;

*g = x3inv*p/q; ) else {

xinv=l.O/x; a=xinv*xinv; x3inv=a*xinv; c4=a*a; p=((((2.61294753225142e4*~4+6.135471136147OOe4)*~4+

1.34922028171857e4)*~4+8.16343401784375e2)*~4+ 1.64797712841246e1)*~4+9.67546032967090e-2;

q=((((1.37012364817226e6*c4+1.0010547890079le6~*~4+ 1.65946462621853e5)*~4+9.01827596231524e3)*~4+ 1.73871690673649e2)*~4+1.0;

*f = (c4* (-p) /q+0.318309886183791) *xinv; p=(((((1.72590224654837e6*~4+6.66907061668636e6)*~4+

1.77758950838030e6)*~4+1.35678867813756e5)*~4+ 3.87754141746378e3)*~4+4.31710157823358el)*c4+ 1.53989733819769e-1;

q=(((((1.40622441123580e8*~4+9.38695862531635e7)*~4+ 1.62095600500232e7)*c4+1.02878693056688e6~*~4+ 2.69183180396243e4)*~4+2.86733194975899e2)*~4+1.0;

*g = (c4* (-p) /q+O. lOl32ll83642338) *x3inv;

1 1

6.5 Bessel functions of integer order

6.5.1 Bessel functions J and Y

Copyright 1995 by CRC Press, Inc

Page 576: Numerical Library in C for Scientists and Engineers A

Computes the value of the ordinary Bessel function of the first kind of order zero Jo(x). When Ix 1 < 8, J,(x) is evaluated by use of a Chebyshev polynomial approximation [Cle62] in the variable 2(2/16 - I ) , and 1x1 2 8 by use of the formula

(besspqO being called to evaluate the functions Po and Q,).

Function Parameters: float bessjO (x)

bessj0: delivers the ordinary Bessel function of the first kind of order zero with argument A 9

x: float; entry: the argument of the Bessel function.

Function used: besspq0.

Float bess j 0 (float x) t

if (X == 0.0) return 1.0; if (fabs(x) < 8.0) {

int i; float z,z2,bO,bl,b2; static float ar [IS] =(-0.75885e-15, 0.4125321e-13,

-0.194383469e-11, 0.7848696314e-10, -0.267925353056e-8, 0.7608163592419e-7, -0.176194690776215e-5, 0.324603288210051e-4, -0.46062616620628e-3, 0.48191800694676e-2, -0.34893769411409e-1, 0.158067102332097, -0.37009499367265, 0.265178613203337, -0.872344235285222e-2);

x /= 8.0; z=2.o*x*x-1.0; z2=z+z; bl=b2=0.0; for (i=O; i<=14; i++) (

bO=z2*bl-b2+ar [il ; b2=bl; bl=bO ;

return z*b1-b2+0.15772797147489; ) else (

void besspq0 (float, float * , float * ) ; float c,cosx,sinx,pO,qO; x=f abs (x) ; c=0.797884560802865/sqrt (x) ; cosx=~os (x -o .706858347057703e1) ; sinx=sin(x-0.706858347057703el); besspqo (x, &PO, &qO) ; return c* (pO*cosx-qO*sinx) ;

1 1

B. bessj 1

Copyright 1995 by CRC Press, Inc

Page 577: Numerical Library in C for Scientists and Engineers A

Computes the value of the ordinary Bessel function of the first kind of order one J,(x). When (x ( < 8, J,(x) is evaluated by use of a Chebyshev polynomial approximation [Cle62] in the variable 2(2/16 - I), and 1x1 2 8 by use of the formula

(besspql being called to evaluate the functions P, and Q,).

Function Parameters: float bessj 1 (x)

bessjl: delivers the ordinary Bessel function of the first kind of order one with argument x;

x: float; entry: the argument of the Bessel function.

Function used: besspq

#include <math.hz

float bessjl (float x)

if (X == 0.0) return 1.0; if (fabs(x) c 8.0) (

int i; float z,z2,bO,bl,b2; static float ar[15]={-0.19554e-15, 0.1138572e-13,

-0.57774042e-12, 0.2528123664e-10, -0.94242129816e-9, 0.2949707007278e-7, -0.76175878054003e-6, 0.158870192399321e-4, -0.260444389348581e-3, 0.324027018268386e-2, -0.291755248061542e-1, 0.177709117239728e0, -0.661443934134543e0, 0.128799409885768e1, -0.119180116054122e1);

x /= 8.0; z=2.o*x*x-1.0; z2=z+z; bl=b2=0.0; for (i=O; i<=14; i++) {

bO=z2*bl-b2+ar [il ; b2=bl; bl=bO ;

1 return x*(z*bl-b2+0.648358770605265);

} else ( void besspql (float, float *, float *) ; - - int sgnx; float c,cosx,sinx,pl,ql; sgnx = (x > 0.0) ? 1 : -1; x=f abs (x) ; c=O. 797884560802865/sqrt (x) ; cosx=cos(x-0.706858347057703el) ; sinx=sin(x-0.706858347057703el); besspql (x, &pl, &ql) ; return sgnx*c*(pl*sinx+ql*cosx);

C. bessj

Generates an array of ordinary Bessel functions of the first kind of order k, J,(x),

Copyright 1995 by CRC Press, Inc

Page 578: Numerical Library in C for Scientists and Engineers A

k=O, ..., n. The method used [G67] is suitable for the determination of a sequence of numbers f , f,, ... which satisfy a recursion of the form

h+1+ ' A + bh-I = 0 (1) and decrease in magnitude with k more rapidly than any other solution of this difference equation, and in addition satisfy a relationship of the form

Setting rk = f,,, / h , formally

and with

sk-, = rk-, (Xk+sJ. By definition f, = s/(X,+s,J. For suitably large v, the numbers

are computed by use of the recursions ry(*) = 0, rk-,'"j = -bJ(ak +rk(Yg Sr) = 0, sk-/") = rk-/(') (Xk+sk(Y9

for k=v,v-I, ..., I . Thereafter the required numbers f,S,,...,f, are recovered by use of the relationships

hfVj = s / (X,+s,")), h(") = rk- l fv~-l f") , (&I, ..., n). The functions Ju+,(x) satisfy the recursion

Ja+k+l(x) - {2(a+k)/x)Ja+k(x) + Ju+k-l(x) = O and also the relationship

Copyright 1995 by CRC Press, Inc

Page 579: Numerical Library in C for Scientists and Engineers A

Thus when a = 0, a, = 2Wx, b, = -I and A, = I, A,,, = 0, A,, = 2 (m=1,2 ,... ), s = I may be taken in the above.

Function Parameters: void bessj (x,n,j)

x: float; entry: the argument of the Bessel functions;

n: int; entry: the upper bound of the indices of array j; n 1 0;

j : float j[O:n]; exit: j[k] is the ordinary Bessel function of the first kind of order k and argument

X .

Function used: start.

void bessj (float x, int n, float j [I ) 1

j [OI =1.0; ' for ( ; n>=l; n--) j[n]=O.O;

) else ( int start (float, int, int) ; int 1,m, nu, signx; float x2,r,s; signx= ( x > 0.0) ? 1 : -1; x=fabs (x) ; r=s=O .O ; x2=2. o/x; 1=0; nu=start (x,n, 0) ; for (m=nu; m>=l; m--) (

r=l. 0/ (x2*m-r) ; 1=2-1; s=r* (l+s) ; if (m c= n) j [m] =r;

1 j [ol =r=l.0/ (l.O+s) ; for (m=l; m<=n; m++) r = j [ml *= r; if (signx c 0.0)

for (m=l; m<=n; m += 2) j [ml = -j [ml;

1 1

Computes the ordinary Bessel functions of the second kind of orders zero and one: Y,(x) and Y,(x) for x>O. When x < 8, Yo(x) and Y,(x) are determined from relationships of the form

Ydx) = (2Wn(x)Jo(x) + YO($ Y,(x) = (2/n;)ln(x) J , ( - 2/(nx) + xy,(x)

where y,(x) and y,(x) are approximated by use of Chebyshev polynomials [Cle62]. When x>8, the relationships

Copyright 1995 by CRC Press, Inc

Page 580: Numerical Library in C for Scientists and Engineers A

Yo(x) = (2/(ux))'"{~,(x)sin(x - 9d4) + Q,(x)cos(x - 9d4)) Yl(x) = (2/(?rx))'"{~,(x)sin(x - 9d4) - P,(x)cos(x - 9d4))

are used.

Function Parameters: void bessyO 1 (x,yO,yl)

x: float; entry: the argument of the Bessel function; x > 0;

yo: float *; exit: yo has the value of the ordinary Bessel function of the second kind of order

zero with argument x; y l : float *;

exit: y l has the value of the ordinary Bessel function of the second kind of order one with argument x.

Functions used: bessj0, bessj 1, besspq0, besspql .

void bessyOl(f1oat x, float *yo, float *yl) I

if (X < 8.0) ( int i; float bessjO(f1oat); float bessjl(f1oat); float z,z2,c,lnx,bO,bl,b2; static float ar1[151=(0.164349e-14, -0. J ,

0.402633082e-11, -0.15837552542e-9, 0.524879478733e-8, -0.14407233274019e-6, 0.32065325376548e-5, -0.563207914105699e-4, 0.753113593257774e-3, -0.72879624795521e-2, 0.471966895957634e-1, -0.177302012781143, 0,261567346255047, 0.179034314077182, -0.274474305529745};

static float ar2[151=(0.42773e-15, -0.2440949e-13, 0.121143321e-11, -0.5172121473e-10, 0.187547032473e-8, -0.5688440039919e-7, 0.141662436449235e-5, -0.283046401495148e-4, 0.440478629867099e-3, -0.51316411610611e-2, 0.423191803533369e-1, -0.226624991556755, 0.675615780772188, -0.767296362806646, -0.128697384381350};

C=O.636619772367581; lnx=c*log (x) ; c / = x; x / = 8.0; z=2.o*x*x-1.0; z2=z+z; bl=b2=0.0; for (i=O; i<=14; i++) {

bO=z2*bl-b2+arl [il ; b2=bl; bl=bO ;

1 J *yo = lnx*bessj0(8.0*x)+z*bl-b2-0.33146113203285e-1; bl=b2=0.0; for (i=O; i<=14; i++) {

bO=z2*bl-b2+ar2 [il ; b2=bl; bl=bO ;

1 *yl = lnx*bessjl(8.0*x)-c+x*(z*bl-b2+0.2030410588593425e-l~;

} else ( void besspq0 (float, float * , float * ) ; void besspql (float, float *, float * ) ; float c,cosx,sinx,pO,qO,pl,ql; ~=0.797884560802865/~qrt(~);

Copyright 1995 by CRC Press, Inc

Page 581: Numerical Library in C for Scientists and Engineers A

besspq0 (x, &pot &q0) ; besspql (x, &pl, &ql) ; x -= 0.706858347057703el; cosx=cos (XI ; sinx=sin (x) ; *yo P c* (pO*sin~+qO*~~s~) ; *yl = c* (ql*sinx-pl*cosx) ;

1 1

E. bessy

Generates an array of ordinary Bessel functions of the second kind of order k, Y,(x), k=O ,..., n, for x > 0.

The functions Yo(x) and (if n > 0) Y,(x) are evaluated by means of a call of bessyol, and the recursion

Yk+l (~ ) = (2WY Y k W - Yk-,($

is used.

Function Parameters: void bessy (x,n,y)

x: float; entry: this argument should satisfy x > 0;

n: int; entry: the upper bound of the indices of array y; n 2 0;

y: float y[O:n]; exit: y[k] is the value of the ordinary Bessel function of the second kind of order

k and argument x, k O ,..., n.

Function used: bessy0l.

void bessy (f loat x, int n, float y [I

void bessy0l (float, float *, float *) ; int i; float yO,yl,y2;

bessy0l (x, &YO, &yl) ; y [OI =yo; if (n > 0) yIl1 =yl; x=2. o/x; for (i=2; i<=n; i++) {

y [i] =y2= (i-1) *x*yl-yo; yo=y1; yky2 ;

1 1

This procedure is an auxiliary procedure for the computation of the ordinary Bessel functions of order zero for large values of their argument.

besspqO computes the values of the functions P,(x), Qo(x) occurring in the formulae Jo(x) = (2/(1rx))~'~{P,(x)cos(x - d4) - Q,(x)sin(x - 7r/4)) Yo(x) = (2/(n~))"~{P,(x)sin(x - d4) + Q,(x)cos(x - d4)).

Copyright 1995 by CRC Press, Inc

Page 582: Numerical Library in C for Scientists and Engineers A

When 1x1 < 8, the above equations are used in the form Po&) = (nx/2)'"{~~(x)sin(x - d4) + Jo(x)cos(x - d4)) Qo(x) = (?rx/2)'"{Yo(x)cos(x - id4) - Jo(x)sin(x - d4))

(bessjO and bessyO being used to evaluate the functions Jo and Yo) and when Ix 1 2 8, Po($ and Qo(x) are evaluated by use of Chebyshev polynomial approximations [Cle62] in the variable 2(128/x2 - 1).

Function Parameters: void besspqO (x,pO,qO)

x: float; entry: this argument should satisfy x > 0;

PO: float *; exit: the value of Po($;

qO: float *; exit: the value of Qo(x).

Functions used: bessj0, bessy0l.

void besspq0 (float x, float *PO, float *qO) I

if ( X C 8.0) { float bessj0 (float) ; void bessyOl(float, float * , float * ) ; float b,cosx,sinx,jOx,yO; b=sqrt (x) *1.25331413731550; bessy01 (x, &yo, &jOx) ; j Ox=bess j 0 (x) ; X -= 0.785398163397448; cosx=cos (x) ; sinx=sin (x) ; *pO = b* (yO*sinx+jOx*cosx) ; *qO = b* (yO*cosx- jOx*sinx) ;

) else { int i; float x2,bO,bl,b2,y; static float arl[ll]={-0.10012e-15, 0.67481e-15, -0.506903e-14,

0.4326596e-13, -0.43045789e-12, 0.516826239e-11, -0.7864091377e-10, 0.163064646352e-8, -0.5170594537606e-7, 0.30751847875195e-5, -0.536522046813212e-3);

static float ar2[101={-0.60999e-15, 0.425523e-14, -0.3336328e-13, 0.30061451e-12, -0.320674742e-11, 0.4220121905e-10, -0.72719159369e-9, 0.1797245724797e-7, -0.74144984110606e-6, 0.683851994261165e-4);

y=8. O/X; x=2.0*yry-1.0; x2=x+x; bl=b2=0.0; for (i=O; i<=10; i++) {

bO=x2*bl-b2+arl [il ; b2=bl; bl=bO ;

I I *pO = x*bl-b2+0.99946034934752; bl=b2=0.0; for (i=O; i<=9; i++) {

bO=x2*bl-b2+ar2 [il ; b2=bl; bl=bO ;

\

Copyright 1995 by CRC Press, Inc

Page 583: Numerical Library in C for Scientists and Engineers A

G. besspql

This procedure is an auxiliary procedure for the computation of the ordinary Bessel functions of order one for large values of their argument.

besspql computes the values of the functions PI@), Q,(x) occurring in the formulae J,(x) = (2/(nx))'"{P,(x)cos(x - 3d4) - Q,(x)sin(x - 3d4)) Y,(x) = (2/(~$)'/~{P,(x)sin(x - 3d4) + Q,(x)cos(x - 3d4)).

When Ix 1 < 8, the above equations are used in the form PI($ = (m/2)'"{Y,(x)sin(x - 3d4) + J,(x)cos(x - 31d4)) Q,(x) = (ud2)'"{Y,(x)cos(x - 3d4) - J,(x)sin(x - 3d4))

(bessjl and bessyl being used to evaluate the functions J, and Y,) and when 1x1 2 8, PI@) and Q,(x) are evaluated by use of Chebyshev polynomial approximations [Cle62] in the variable 2(128/x2 - 1).

Function Parameters: void besspql (x,pl,ql)

x: float; entry: this argument should satisfy x > 0;

p l : float *; exit: the value of P,(x);

q l : float *; exit: the value of Q,(x).

Functions used: bessj 1, bessy0l.

void besspql (float x, float *pl, float *ql) I

if ( ~ ~ 8 . 0 ) { float bess j 1 (float) ; void bessyOl(float, float *, float * ) ; float b,cosx,sinx, jlx, yl; b=sqrt (x) *1.25331413731550; bessy0l (x, &jlx, &yl) ; j lx=bess j 1 (x) ; X -= 0.785398163397448; cosx=cos (x) ; sinx=sin (x) ; *pl = b*(jlx*sinx-yl*cosx); *ql = b*(jlx*cosx+yl*sinx);

) else { int i; float x2,bO,bl,b2,y; static float arl[lll={0.10668e-15, -0.72212e-15, 0.545267e-14,

-0.4684224e-13, 0.46991955e-12, -0.570486364e-11, 0.881689866e-10, -0.187189074911e-8, 0.6177633960644e-7, -0.39872843004889e-5, 0.89898983308594e-3);

static float ar2[ll]={-0.10269e-15, 0.65083e-15, -0.456125e-14, 0.3596777e-13, -0.32643157e-12, 0.351521879e-11, -0.4686363688e-10, 0.82291933277e-9, -0.2095978138408e-7, 0.9138615~579555e-6, -0.96277235491571e-4);

y=8. O/X; x=2.o*y*y-1.0; xz=x+x; bl=b2=0.0; for (i=O; ic=10; i++) {

bO=x2*bl-b2+arl [il ; b2=bl; bl=bO ;

Copyright 1995 by CRC Press, Inc

Page 584: Numerical Library in C for Scientists and Engineers A

1 *pl = x*bl-b2+1.0009030408600137; bl=b2=0.0; for (i=O; i<=10; i++) {

bO=x2*bl-b2+ar2 [il ; b2=bl; bl=bO ;

1

6.5.2 Bessel functions I and K

Computes the value of the modified Bessel function of the first kind of order zero Io(x). For Ix 1 I 15, a Chebyshev rational function approximation [Bla74] of the form

is used. When Ix 1 > 15, the function I, '(x) = e"Io(x) is evaluated by means of a call of nonexpbessio, and the relationship Io(x) = e'l,'(x) is used.

Function Parameters: float bessiO (x)

bessi0: delivers the modified Bessel function of the first kind of order zero with argument x;

x: float; entry: the argument of the Bessel function.

Function used: nonexpbessio.

float bessi0 (float x) I

if (X == 0.0) return 1.0; if (fabs(x) c= 15.0) {

float z,denominator,nurnerator; z=x*x; numerator= (z* ( z * (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z*

0.210580722890567e-22+0.380715242345326e-19)+ 0.479440257548300e-16)+0.435125971262668e-13)+ 0.300931127112960e-10)+0.160224679395361e-7)+ 0.654858370096785e-5)+0.202591084143397e-2)+ 0.463076284721000e0)+0.754337328948189e2)+ 0.830792541809429e4)+0.571661130563785e6)+ 0.216415572361227e8)+0.356644482244025e9)+ 0.144048298227235e10);

denominator=(z*(z*(z-0.307646912682801e4)+ 0.347626332405882e7)-0.144048298227235elO);

return -nurnerator/denominator; } else {

float nonexpbessiO(f1oat); return exp (fabs (x) ) *nonexpbessiO (x) ;

I I

Copyright 1995 by CRC Press, Inc

Page 585: Numerical Library in C for Scientists and Engineers A

B. bessil

Computes the value of the modified Bessel function of the first kind of order one I,($. For I x 1 5 15, a Chebyshev rational function approximation [Bla74] of the form

for the function x'"I,(x) is used, and the value of I,(x) is recovered. When 1x1 > 15, the function I,'($ = e"I,(x) is evaluated by means of a call of nonexpbessil, and the relationship I,@) = e"l, '(x) is used.

Function Parameters: float bessil (x)

bessil: delivers the modified Bessel function of the first kind of order one with argument x;

x: float; entry: the argument of the Bessel function.

Function used: nonexpbessil.

£loat bessil (float x) {

if (X == 0.0) return 0.0; if (fabs(x) c= 15.0) {

float z,denominator,numerator; z=x*x; denominator=z*(z-0.222583674000860e4)+0.136293593052499e7; numerator= (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z*

0.207175767232792e-26+0.257091905584414e-23)+ 0.306279283656135e-20)+0.261372772158124e-17)+ 0.178469361410091e-14)+0.963628891518450e-12)+ 0.410068906847159e-9)+0.135455228841096e-6)+ 0.339472890308516e-4)+0.624726195127003e-2)+ 0.806144878821295e0)+0.682100567980207e2~+ 0.341069752284422e4)+0.840705772877836e5)+ 0.681467965262502e6);

return x*(numerator/denominator); } else {

float nonexpbessil(f1oat); return exp (fabs (x) ) *nonexpbessil (x) ;

1 1

C. bessi

Generates an array of modified Bessel functions of the first kind of order one h(x), j=O, ..., n.

The functions h'(x) = e-lxllj(x), j=O, ..., n, are first evaluated by means of a call of nonexpbessi, and the required values of 4(x) are recovered by multiplication by 8.

Copyright 1995 by CRC Press, Inc

Page 586: Numerical Library in C for Scientists and Engineers A

Function Parameters: void bessi (x,n, i)

x: float; entry: the argument of the Bessel functions;

n: int; entry: the upper bound of the indices of the array i;

i: float i[O:n]; exit: ib] contains the value of the modified Bessel function of the first kind of order

j, j=O ,..., n.

Function used: nonexpbessi.

void bessi (float x, int n, float i [ I ) I

if ( x = = 0.0) { i[O]=l.O; for ( ; n>=l; n--) i[nl=O.O;

} else { void nonexpbessi(float, int, float [ I ) ; float expx; expx=exp ( f abs (x) ) ; nonexpbessi (x, n, i) ; for ( ; n>=O; n--) i [nl *= expx;

1 1

Computes the modified Bessel functions of the third kind of orders zero and one: K,(x) and K,(x) for x>O.

For 0 < x < 1.5, K,(x) and K,(x) are computed by use of truncated versions of the Taylor series expansions [AbS65]

For x 2 1.5, the functions K,'(x) = e'K,(x), j=0,1, are evaluated by a call of nonexpbesskOl, and the relationship K,(x) =e"K, '(x) is used.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 587: Numerical Library in C for Scientists and Engineers A

void besskO 1 (x, kO, kl) x: float;

entry: the argument of the Bessel functions; x > 0; kO: float *;

exit: kO has the value of the modified Bessel function of the third kind of order zero with argument x;

kl: float *; exit: kl has the value of the modified Bessel function of the third kind of order one

with argument x.

Function used: nonexpbessko 1 .

void besskOl(f1oat x, float *kO, float *kl) {

if (x c= 1.5) { int k; float c, d,r,sumO, suml, t, term, to, tl; sumO=d=log(2.0/~)-0.5772156649015328606; suml = c = -1.0-2.0*d; r=term=l.O; t=x*x/4.0; k=1; do {

term *= t*r*r; d += r; c -= r; r=l. O/ (k+l) ; c -= r; tO=term*d; tl=term*c*r; sum0 += to; suml += tl; k++ ;

} while (fabs(tO/sumO)+fabs(tl/suml) > 1.0e-15) ; *kO = sumo; *kl = (l.O+t*suml) /x;

} else { void nonexpbesskOl(float, float *, float * ) ; float expx; expx=exp ( -x) ; nonexpbesskol (x, kO , kl) ; *kl *= expx; *kO *= expx;

1 }

E. bessk

Generates an array of modified Bessel functions of the third kind of order j, %(x), j=O ,..., n, for x > 0.

The functions KO($ and K,(x) are first evaluated by means of a call of bessk01, and the

Copyright 1995 by CRC Press, Inc

Page 588: Numerical Library in C for Scientists and Engineers A

recursion [AbS65]

is then used.

Function Parameters: void bessk (x,n,k)

x: float; entry: the argument of the Bessel functions; x > 0;

n: int; entry: the upper bound of the indices of array k; n 2 0;

k: float k[O:n]; exit: kfi] is the value of the modified Bessel function of the third kind of order j

with argument x, j=O ,..., n.

Function used: bessk0l.

#include <math.h>

void bessk(f1oat x, int n, float kt])

void besskOl(float, float *, float * ) ; int i; float kO,kl,k2;

bessk01 (x, &k0, &kl) ; kt01 =k0; if (n s 0) k[ll =kl; x=2. o/x; for (i=2; i<=n; i++) {

k [il =kZ=kO+x* (i-1) *k1; kO=kl; kl=k2 :

F. nonexpbessio

Computes the value of the modified Bessel function of the first kind of order zero multiplied by e-1"'.

nonexpbessio evaluates the function IO1(x) = e-lxllo(x). When Ix 1 2 15, the function I& is evaluated by means of a call of bessi0, and the function I,' is computed by use of its defining relationship. When I x 1 > 15, a Chebyshev rational function approximation [Bla74] of the form

for the function x1"l0 '(x) is used, and the value of I, '(x) is recovered.

Function Parameters: float nonexpbessio (x)

nonexpbessio: delivers the modified Bessel function of the first kind of order zero with argument x, multiplied by e-Ix1;

Copyright 1995 by CRC Press, Inc

Page 589: Numerical Library in C for Scientists and Engineers A

x: float; entry: the argument of the Bessel function.

Function used: bessi0.

float nonexpbessiO(f1oat x) {

if (X == 0.0) return 1.0; if (fabs(x) <= 15.0) {

float bessi0 (float) ; return exp (-fabs (x) ) *bessiO (x) ;

} else ( int i; float sqrtx,br,brl,br2,z,z2,numerator,denominator; static float ar1[4]={0.2439260769778. -0.115591978104435e3,

0.784034249005088e4, -0.143464631313583e6); static float ar2[4]={1.0, -0.325197333369824e3,

0.203128436100794e5, -0.361847779219653e6); x=f abs (x) ; sqrtx=sqrt (x) ; brl=br2=0.0; z=~O.O/X-1.0; z2=z+z; for (i=O; i<=3; i++) {

br=z2*brl-br2+arl [ i l ; br2=brl; brl=br;

I numerator=z*brl-br2+0.346519833357379e6; brl=br2=0.0; for (i=O; i<=3; i++) {

br=zZ*brl-br2+ar2 [il ; br2=brl; brl=br;

1 denominator=z*brl-br2+0.865665274832055e6; return (numerator/denominator)/sqrtx;

1 1

G. nonexpbessil

Computes the value of the modified Bessel function of the first kind of order one multiplied by e-1"'.

nonexpbessil evaluates the function I, '(x) = sign(x)e-lxl~,(x). When Ix 1 r 15, the function I,($ is evaluated by means of a call of bessil, and the function I, ' is computed by use of its defining relationship. When 1x1 > 15, a Chebyshev rational function approximation [Bla74] of the form

for the function ~"~1, '(x) is used, and the value of I, '(x) is recovered.

Function Parameters: float nonexpbessi 1 (x)

nonexpbessil: delivers the modified Bessel function of the first kind of order one with

Copyright 1995 by CRC Press, Inc

Page 590: Numerical Library in C for Scientists and Engineers A

argument x, multiplied by e-1.1; x: float;

entry: the argument of the Bessel function.

Function used: bessil

float nonexpbessil(f1oat x) 1

if (X == 0.0) return 0 .O; if (fabs(x) > 15.0) {

int i,signx; float br,brl,br2,z,z2,sqrtx,numerator,denominator; static float ar1[4]={0.1494052814740el, -0.362026420242263e3,

0.220549722260336e5, -0.408928084944275e6); static float ar2[4]=(1.0, -0.631003200551590e3,

0.496811949533398e5, -0.100425428133695e7); signx = (x > 0.0) ? 1 : -1; x=f abs (x) ; sqrtx=sqrt (x) ; Z=30.0/~-1.0; z2=z+z; brl=br2=0.0; for (i=O; i<=3; i++) (

br=z2*brl-br2+arl [il ; br2=brl; brl=br;

1 numerator=z*brl-br2+0,102776692371524e7; brl=br2=0.0; for (i=O; i<=3; i++) (

br=z2*brl-br2+ar2 [il ; br2=brl; brl=br;

1 denominator=z*brl-br2+0.26028876789105e7; return ((numerator/denominator)/sqrtx)*signx;

} else { float bessil(f1oat); return exp (-fabs (x) ) *bessil (x) ;

H. nonexpbessi

Generates an array of modified Bessel functions of the first kind of order one I,(x), multiplied by e-1.1, j=O ,..., n.

nonexpbessi evaluates the functions I,'(x) = e-lxll,(x), j=O, ..., n. The method used [G67] is that described in the documentation to bessj. The functions Ia+,'(x) satisfy the recursion

Ia+k+,'(x) + ~2(a+k)/xlIa+k'(x) - Ia+k-,(x) = 0 and the relationship

when x=O, ak and b, in formula ( 1 ) of the documentation to bessj are a , = 2Wx, b, = -1 and X,=l, s=l may be taken in the further formulae of that documentation.

Function Parameters:

Copyright 1995 by CRC Press, Inc

Page 591: Numerical Library in C for Scientists and Engineers A

void nonexpbessi (x,n, i) x: float;

entry: the argument of the Bessel functions; n: int;

entry: the upper bound of the indices of the array i, n 2 0; i: float i[O:n];

exit: ifi] contains the value of the modified Bessel fimction of the first kind of order j , multiplied by 6111, j=O ,..., n.

Function used: start.

void nonexpbessi(f1oat x, int n, float i[l) I

if (x== 0.0) { i[Ol=l.O; for ( ; n>=l; n--) i[nl=O.O;

) else ( int start (float, int, int) ; int k,negative; float x2,r,s; negative = (x c 0.0) ; x=f abs (x) ; r=s=O . 0 ; x2=2. o/x; k=start (x,n, 1) ; for ( ; k>=l; k--1 {

r=l. 0/ (r+x2*k) ; s=r* (2.0+s) ; if (k c= n) i[kl=r;

1

i [O] =r=l.O/(l.O+s) ; if (negative)

for (k=l; kc-n; k++) r = i[kl *= (-r); else

for (k=l; kc=n; k++) r = i[kl *= r;

1 I

Computes the modified Bessel functions of the third kind of orders zero and one, K&) and K,(x) for x>O, multiplied by 8.

nonexpbesskO1 evaluates the functions Kjl(x) = exKj(x) for x > 0, j=0,1. For 0-51.5, the functions K&) and Kl(x) are computed by a call of besskOl and the 4' are evaluated by use of their defining relationship. For 1.5-15, the trapezoidal rule (see [Hu64] of bessi0) is used to evaluate the integrals (see [AbS65] of bessi0)

with p = 215. For x > 5, truncated Chebyshev expansions (see [Cle62, Lu691) of the form are used.

Function Parameters: void nonexpbessko 1 (x, k0,kl)

Copyright 1995 by CRC Press, Inc

Page 592: Numerical Library in C for Scientists and Engineers A

x: float; entry: the argument of the Bessel functions; x > 0;

kO: float *; exit: kO has the value of the modified Bessel function of the third kind of order zero

with argument x, multiplied by 8; kl: float *;

exit: kl has the value of the modified Bessel function of the third kind of order one with argument x, multiplied by 8.

Function used: bessk0l.

void nonexpbesskOl(float x, float *kO, float *kl)

if (X c= 1.5) { void bessk0l (float, float *, float *) ; float expx; expx=exp (x) ; bessk01 (x, kO, kl) ; *kO *= expx; *kl *= expx;

) else if (x c= 5.0) { int i,r; float t2,~1,~2,terml,term2,sqrtexpr,exph2,~2; static float fac[201=(0.90483741803596, 0.67032004603564,

0.40656965974060, 0.20189651799466, 0.82084998623899e-1, 0.27323722447293e-1, 0.74465830709243e-2, 0.16615572731739e-2, 0.30353913807887e-3, 0.45399929762485e-4, 0.55595132416500e-5, 0.55739036926944e-6, 0.45753387694459e-7, 0.30748798795865e-8, 0.16918979226151e-9, 0.76218651945127e-11, 0.28111852987891e-12, 0.84890440338729e-14, 0.2098791048793e-15, 0.42483542552916e-17);

s1=0.5 ; s2=0.0; r=O . 0; x2 =x+x; exph2=l. O/sqrt (5.0*x) ; for (i=O; i<=19; i++) {

r += 1.0; t2=r*r/l0.0; sqrtexpr=sqrt (t2/x2+1.0) ; terml=fac [il /sqrtexpr; term2=fac [il *sqrtexpr*t2; sl += terml; s2 += term2:

1 *kO = exph2*sl; *kl = exphZ*s2*2.0;

) else { int r,i; float br,brl,br2,cr,crl,cr2,erminl,erplusl,er,fO,fl,

expx,y,y2; static float dr[14]={0.27545e-15, -0.172697e-14,

0.1136042e-13, -0.7883236e-13, 0.58081063e-12,

Copyright 1995 by CRC Press, Inc

Page 593: Numerical Library in C for Scientists and Engineers A

r=30; brl=br2=crl=cr2=erplusl=er=O.O; for (i=O; i<=13; i++) (

J. nonexpbessk

Generates an array of modified Bessel functions of the third kind of order j , K,(x), multiplied by 8 , j=O ,..., n, for x > 0.

nonexpbessk computes the values of the functions Kj'(x) = exK,(x), j=O, ..., n, where f$(x) is a modified Bessel function of the third kind of order j , for x > 0.

The functions KO '(x) and K, '(x) are first evaluated by means of a call of nonexpbessk01, and the recursion [AbS65]

Kj+l '(x) = Kj., '(x) + (2Jx))K, '(x) is then used.

Function Parameters: void nonexpbessk (x,n, k)

x: float; entry: the argument of the Bessel functions; x > 0;

n: int; entry: the upper bound of the indices of array k; n 2 0;

k: float k[O:n]; exit: kD] is value of the modified Bessel function of the third kind of order j

multiplied by 8 , j=O ,..., n.

Function used: nonexpbessko 1.

void nonexpbessk(f1oat x, int n, float k[l) t

void nonexpbesskOl(float, float *, float * ) ; int i; float k0, kl, k2 ;

nonexpbessk01 (x, hk0, &kl) ; k [01 =k0; if (n > 0) k[ll =kl; x=2. o/x; for (i=2; i<=n; i++) {

Copyright 1995 by CRC Press, Inc

Page 594: Numerical Library in C for Scientists and Engineers A

6.6 Bessel functions of real order

6.6.1 Bessel functions J and Y

A. bessjaplusn

Calculates the Bessel functions of the first kind of order a+k, Ja+,(x), (Olkln, OIa<l). If x=O then Ja(x) equals 0 if a>O and equals 1 if a=O, and J,+,(x)=O for k l , ..., n. If a=%, the functions J,+,(x) are evaluated by means of a call of spherbessj; otherwise the method used is that described in the documentation to bessj. Now a, and bk in formula (1) of that documentation are

a, = 2(a+k)/x, b, = -1, and

A, = I, A ,,, = 0, A,, = (a+2m)r(a+m)/{m!I'(a+m)) (m=1,2 ,... ), s=(~/2)~/I'(a+l) may be taken in the further formulae of that documentation see [G67].

Function Parameters:

a:

x:

n:

ja:

void bessjaplusn (a,x,n Ja) float; entry: the noninteger part of the order; 0 5 a < 1; float; entry: the argument value, x 2 0; int; entry: the upper bound of the indices of the array ja; float ja[O:n]; exit: ja[k] is assigned the value of the Bessel function of the first kind Ja+,(x),

Olkln.

Functions used: bessj, spherbessj, gamma, start.

void bessjaplusn(f1oat a, float x, int n, float ja [ I ) I ' if (X == 0.0) (

ja[O] = (a == 0.0) ? 1.0 : 0.0; for ( ; n>=l; n--) ja[nl=0.0;

) else if (a == 0.0) { void bessj (float, int, float [I ) ; bessj (x,n, ja) ;

) else if (a == 0.5) ( void spherbessj (float, int, float [I ) ; float s; s=sqrt (x) *O. 797884560802865; spherbessj (x, n, ja) ; for ( ; n>=O; n--) ja[nl *= s;

) else { float gamma(f1oat) ; int start (float, int, int) ; int k,m,nu;

Copyright 1995 by CRC Press, Inc

Page 595: Numerical Library in C for Scientists and Engineers A

float a2, x2, r, s, 1, labda; l=l.O; nu=start (x,n, 0) ; for (m=l; m<=nu; m++) l=l* (m+a) / (m+l) ; r=s=O.O; x2=2. o/x; k = -1; a2=a+a; for (m=nu+nu; m>=l; m--) {

r=l. O/ (x2* (a+m) -r) ; if (k == 1)

labda=O.O; else {

1=1* (m+2) / (m+a2) ;

;a [o] =r=l.~/gamma(l.O+a) / (l.o+s) /pow(x2,a) ; for (m=l; mc=n; m++) r = ja[ml *= r;

I

Computes the Bessel functions of the second kind (also called Neumann's functions) of order a and a+l: Y&) and Ya+,(x) for x>O, a20.

For x < 3, the above functions are evaluated by use of truncated Taylor series (see [T76a]). For x23, the functions P,(x), Q,(x) occurring in the formula

Y,(x) = (2/(1rx))"~{~,(x)sin(x - (a+%))?r/2) + Q,(x)cos(x - (a+%)z/2)) are evaluated for a=a. a + l by means of a call of besspqa01; the values of Ya(x), Y,+,(x) are then recovered.

Function Parameters: void bessyaO 1 (a,x,ya,yal)

a: float; entry: the order;

x: float; entry: this argument

ya: float *; exit: the Neumann

yal : float *; exit: the Neumann

should satisfy x > 0;

function of order a and argument x;

function of order a+l.

Functions used: bessy0 1 , recipgamma, besspqa0 1 .

#include <math.h>

void bessyaOl(f1oat a, float x, float *ya, float *yal) I

if ( ~ = = o . o ) { void bessyOl(float, float *, float * ) ; bessy0l (x; ya, yal) ;

} else ( int n, na, rec, rev; float b,c,d.e,f,g,h,p,pi,q,r,s; pi=4.0*atan(l.O); na=floor(a+0.5); rec = (a >= 0.5);

Copyright 1995 by CRC Press, Inc

Page 596: Numerical Library in C for Scientists and Engineers A

rev = (a c -0.5) ; if (rev I I rec) a -= na; if (a == -0.5) {

p=sqrt (2.0/pi/x) ; f =p*sin (x) ; g = -p*cos (x) ;

) else if (x c 3.0) { float recipgamma (float, float * , float * ) ; b=x/2.O ; d = -log(b) ; e=a*d; c = (fabs(a) c 1.0e-8) ? l.O/pi : a/sin(a*pi) ; s = (fabs(e) c 1.0e-8) ? 1.0 : sinh(e)/e; e=exp (e) ; g=recipgamma (a, &p, &q) *e; e=(e+l.O/e) /2 .O; f=2.0*c* (p*e+q*s*d) ; e=a*a; p=g*c; q=l.O/g/pi; c=a*pi/2.0; r = (fabs(c) c 1.0e-8) ? 1.0 : sin(c)/c; r *= pi*c*r; c=1.0; d = -b*b; *ya = f+r*q; *yal = p; n=l; do {

f = (f *n+p+q) / (n*n-e) ; c=c*d/n; p /= (n-a) ; q /= (n+a) ; g=c* (f+r*q) ; h=c*p-n*g; *ya += g; *yal += h; n++ ;

) while (fabs(g/(l.~+fabs(*ya)) )+fabs(h/(l.O+fabs*yal 1 ) > 1.0e-15) ;

f = -(*ya); g = - (*yal)/b;

} else { void besspqaol (float, float, float * , float *, float *, float * ) ; b=x-pi* (a+O. 5) /2.0; c=cos (b) ; s=sin(b) ; d=sqrt (2.0/x/pi) ; besspqaol (a,x, &p, &q, &b, &h) ; f =d* (p*s+q*c) ; g=d* (h*s-b*c) ;

1 if (rev) {

x=2. o/x; na = -na-1; for (n=O; nc=na; n++) {

h=x* (a-n) *f -g; g=f; f =h;

1 ) else if (rec) {

x=2. o/x; for (n=l; nc=na; n++) (

h=x* (a+n) *g-f ; f=g; g=h;

Copyright 1995 by CRC Press, Inc

Page 597: Numerical Library in C for Scientists and Engineers A

C. bessyaplusn

Generates an array of Bessel functions of the second kind of order a+n, Ya+,(x), n=O ,..., nmax, for x > 0, a 2 0.

The values of the functions Ya(x), Ya+,(x) are first obtained by means of a call of bessya01, and the recursion

Ya+n+/(x) = -Ya+n-/(x) + J2(n+a)/x)Ya+n(x) is then used.

Function Parameters: void bessyaplusn (a,x, nmcucjan)

a: float; entry: the order;

x: float; entry: the argument value, x > 0;

nmax: int; entry: the upper bound of the indices of the array yan; nmax 2 0;

yan: float yan[O:nmax]; exit: the values of the Bessel functions of the second kind of order a+n, for

argument x are assigned to yan[n], 0 I n I nmax.

Function used: bessya0l .

void bessyaplusn(f1oat a, float x, int nmax, float yan[l) {

void bessyaOl(float, float, float * , float * ) ; int n; float yl;

bessya0l (a,x, w a n [O] , &yl) ; a - = 1.0; x=2. o/x; if (nmax > 0) yan[ll=yl; for (n=2; nc=nrnax; n++) yan [nl = -yan [n-21+ (a+n) *x*yan [n-11 ;

1

This procedure is an auxiliary procedure for the computation of the Bessel functions for large values of their argument.

besspqaOl evaluates the functions P,(x), Q,(x) occurring in the formulae J, (x) = (2/(7rx)'" JP ,(x) cos (x - (a + %) x/2) - Q,(x) s in (x - (a + %) d2)) Y,(x) = (2/(~x))'"J~,(x)sin(x - (a+%)n/2) + Q,(x)cos(x - (a+%)n/2)}

for a = a, a + l (a 2 0 and x > 0). If x < 3 then the formulae

P,(x) = ( d 2 ) I" J~,(x)sin(x - (a+ %) d2) + J,(x) cos (x - (a+ %) 7d2)) Q,(x) = ( d 2 ) "2J~a(x)cos(~ - (a+ 35) 7d2) - Ja(x)sin(x - (a+ %) d2))

Pa+,(x) = (~x/2)~"{J~+,(x)sin(x - (a+%)d2) - Y,+,(x)cos(x - (a+%)n/2)) Q,+,(x) = (?~~/~)'"JJ~+~(x)cos(x - (a+%)n/2) + Y,+,(x)sin(x - (a+%)lr/2))

are used, bessjaplusn and bessyaOI being called to evaluate the functions J, ..., Ya+,. When x23, Chebyshev expansions are used (see [T76a, W451).

Copyright 1995 by CRC Press, Inc

Page 598: Numerical Library in C for Scientists and Engineers A

Function Parameters: void besspqaO 1 (a,x,pa, qa,paI, gal)

a: float; entry: the order;

x: float; entry: this argument should satisfy x > 0;

pa: float *; exit: the value of P,(x);

qa: float *; exit: the value of Q,(x);

p a l : float *; exit: the value of P,+,(x);

ga l : float *; exit: the value of Q,+,(x).

Functions used: besspq0, besspql, bessjaplusn, bessyaol.

void besspqaOl(f1oat a, float x, float *pa, float *qa, float *pal, float *qal)

( if (a == 0.0) {

void besspq0 (float, float *, float * ) ; void besspql (float, float *, float * ) ; besspq0 (x,pa, qa) ; besspql (x,pal, qal) ;

) else ( int n, na, rec, rev; float b,pi,pO,qO; pi=4.0*atan(l. 0) ; rev = (a < -0.5); if (rev) a = -a-1.0; rec = (a >= 0.5); if (rec) (

na=f loor (a+0.5) ; a - = na;

if ( a == -0.5) ( *pa = *pal = 1.0; *qa ,= *qal = 0.0;

) else if (x >= 3.0) ( float c,d,e,f,g,p,q,r,s, temp; c=0.25-a*a; b=x+x; f=r=l.O; g = -x; s=o . 0 ; temp=x*cos(a*pi)/pi*l.Oe15; e=temp*temp; n=2 ; do (

d= (n-l+c/n) ; p= (2*n*f+b*g-d*r) / (n+1) ; q= (2*n*g-b*f-d*s) / (n+1) ; r=f; f=p ; s=g;

n++ ; } while ( (p*p+q*q) *n*n < e) ; e=f*f+g*g; p= (r*f+s*g) /e; q= (s*f-r*g) /e;

Copyright 1995 by CRC Press, Inc

Page 599: Numerical Library in C for Scientists and Engineers A

g=q; n--; while (n > 0) (

r=(n+l) * (2.0-p) -2 .O; s=b+ (n+l) *q; d= (n-l+c/n) / (r*r+s*s) ; p=d*r; q=d*s; e=f; f=p* (e+l.O) -g*q; g=q* (e+l. 0) +p*g; n--;

1 f += 1.0; d=f*f+g*g; *pa = f/d; *qa = -g/d; d=a+0.5-p; q += x; *pal = ( (*pa) *q- (*qa) *d) /x; *qal = ( (*qa) *q+ (*pa) *d) /x;

) else ( void bessjaplusn (float, float, int, float [I ) ; void bessyaOl(float, float, float * , float * ) ; float c,s,chi,ya,yal,ja[21; b=sqrt (pi*x/2.0) ; chi=x-pi* (a/2.0+0.25) ; c=cos (chi) ; s=sin(chi) ; bessyaol (a,x, &ya, &yal) ; bessjaplusn(a,x, 1, ja) ; *pa = b* (ya*s+c*ja [Ol ) ; *qa = b*(c*ya-s*ja[Ol ) ; *pal = b* (s*ja [ll -c*yal) ; *qal = b* ( c * ja [ll +s*yal) ;

I

if (rec) ( x=2. o/x; b= (a+l.O) *x; for (n=l; nc=na; n++) (

p0= (*pa) - (*qal) *b; q0= (*qa) + (*pal) *b; *pa = *pal; *pal = PO; *qa = *qal; *qal = q0; b += x;

1 if (rev) {

pO = *pal; *pal = *pa; *pa = PO; q0 = *qal; *qal = *qa; *qa = qO;

1 1

1

E. besszeros

Calculates the first n zeros of a Bessel function of the first or the second kind or its derivative.

besszero computes the first n zeros of either 1) J,(z) or 2) Y,(z) or 3) dl,(z)/& or 4 ) dY,(z)/&, (a 2 0). Which of the above set of zeros is derived is determined by the value of the parameter d upon call: thus 1 for the zeros of J,(z), and so on.

Each zero is obtained by use of an initial approximation derived from an asymptotic

Copyright 1995 by CRC Press, Inc

Page 600: Numerical Library in C for Scientists and Engineers A

expansion [AbS65], and subsequent improvement by use of a Newton-Raphson process [T76b, T78].

If a < 3, then with p=4d, the s-th zero of Ja(z) or Ya(z) is given by za,s = P - (~-1)/(8P) - 4(~-~)(7~-31)//3(8P)~} -

32(p-l)(83p '-982p+3 779)/{15(8J)'} ... where J = (s + d 2 - 1/4)u for Ja(z) and J = (s + d 2 - 3/4)7r for Ya(z). Similarly the s-th zero of dJa(z)/dz or dYa(z)/dz is given by

z la,, = J ' - (p+3)/(8) 7 - 4(7p2 +82p-9)/{3(8J y3} - 32(83p3+2075p2-3039c+353 7)/{15(8J 7') ...

where J' = (s + d 2 - 3/4)n for dla(z)/dz and ji" = (s + d 2 - 1/4)r for dYa(z)/dz. If a 2 3, then with w(u) defined by

(2/3)(-~)~" = {w(u) - 1 ) ' I2 - arc cos(w(u)-') i.e. w(u) = llcosgl(u) where

{tangl(u)) - $(u) = (2/3)(-~)~" the s-th zero of Ja(z) or Ya(z) is given by

z,, = aw[-a2'y{3 ~(4s-2k- I)/8}] where

f{x} = 2l3(l + (5/48)f2 - (5/36)x4 + ...) where k=O for Ja(z) and k=1 for Ya(z). Similarly, the s-th zero of dla(z)/dz or dYa(z)/dz is given by

z h,, = a~[-a"'~{3u(4~-2k-1)/8,'] where

g{x) = x'/3(l - (7/48)x" + (35/288)x4 + ...) where now k=l for dla(z)/dz and k=O for dYa(z)/dz.

Function Parameters: void besszeros (a,n,z,d)

a: float; entry: the order of the Bessel function, a 2 0;

n: int; entry: the number of zeros to be evaluated, n 2 1;

z: float z[l:n]; exit: z/j] is the j-th zero of the selected Bessel function;

d int; entry: the choice of d determines the type of the Bessel function of which the zeros

are computed: if d=l then Ja(z); if d=2 then Ya(z); if d=3 then dla(z)/dz; if &= then dYa(')/dz.

Function used: besspqaol .

void besszeros(f1oat a, int n, float z[l , int d) I

void besspqaOl(float, float, float *, float *, float *, float *) ; int j,s; float aa,a2,b,bb,c,chi,co,mu,mu2,mu3,mu4,p,pi,pa,pal,pO,pl,ppl,

q,qa,qal,ql,qql,ro,si,t,tt,u,v,wrx,xx,x4,y,fl,fi;

Copyright 1995 by CRC Press, Inc

Page 601: Numerical Library in C for Scientists and Engineers A

pi=4 .O*atan(l. 0) ; aa=a*a; mu=4.0*aa; mu2=mu*mu; mu3=mu*mu2; mu4=mu2*mu2; if ( d < 3 ) {

p=7.0*mu-31.0; pO=mu-1.0; pl=4.0*(253.0*mu2-3722.0*mu+17869.0)/15.0/p*pO; ql=8.0*(83.0*mu2-982.0*mu+3779.0)/5.0/p;

) else ( p=7.0*mu2+82.0*mu-9.0; pO=mu+3.0; pl=(4048.0*mu4+131264.0*mu3-221984.0*mu2-

417600.0*mu+1012176.0)/60.0/p; ql=1.6*(83.0*mu3+2075.0*mu2-3039.0*mu+3537.O~/p;

\ J t = (d == 1 I / d = = 4) ? 0.25 : 0.75; tt=4.0*t; if ( d c 3 ) {

ppl=5.0/48.0; qql = -5.0/36.0;

) else ( ppl = -7.0/48.0; qql=35.0/288.0;

I

for (s=l; s<=n; s++) { if (a == 0.0 && s == 1 && d == 3) {

x=o .o ; j =O ;

} else ( if (S >= 3.0*a-8.0) {

b= (s+a/2.0-t) *pi; c=l.O/b/b/64.0; x=b-1 .O/b/8.0* (PO-pl*c) / (1.0-ql*c) ;

) else { if (S == 1)

x = ((d == 1) ? -2.33811 : ((d == 2) ? -1.17371 : ((d == 3) ? -1.01879 : -2.29444)));

else ( x=y* (4 .O*s-tt) ; v=l.O/x/x; x = -pow (x, 2.0/3.0) * (1. O+V* (ppl+qql*v) ) ;

1 u=x*bb; yy=2.0/3.0*p0~(-~, 1.5) ; if (yy == 0.0)

fi=O.O; else if (yy > 1.0e5)

fi=1.570796; else {

float ~,P,PP; if (yy ~1.0) {

p=pow(3.0*yy, 1.0/3 .O) ; PP=P*P; p *= (I. o+pp* (-210.0+pp* (27.0-2.0*pp) ) i1575.0) ;

) else {

Copyright 1995 by CRC Press, Inc

Page 602: Numerical Library in C for Scientists and Engineers A

j=O; do {

xx=x*x; x4=xx*xx; a2=aa-xx; besspqaol (a,x, &pa, &qa, &pal, &qal) ; chi=x-pi*(a/2.0+0.25); si=sin(chi) ; co=cos (chi) ; ro = ( (d == 1) ? (pa*co-qa*si) / (pal*si+qal*co) :

( (d == 2) ? (pa*si+qa*co) / (qal*si-pal*co) : ( (d == 3) ? a/x- (pal*si+qal*co) / (pa*co-qa*si) :

a/x- (qal*si-pal*co) / (pa*si+qa*co) ) ) ) ; j++; if (d < 3) {

u=ro ; p= (1.0-4.0*a2) /6.0/x/ (2.0*a+1.0) ; q=(2.O* (xx-mu) -l.0-6.0*a)/3.0/~/(2.O*a+l.O) ;

} else { u = -xx*ro/a2; v=2.0*x*a2/ (aa+xx) /3.0; w=a2*a2*a2; q=v* (1.0+ (rnu2+3Z. O*mu*xx+48.O*x4) /32. O/w) ; p=v*(1.0+(-mu2+4O.O*mu*xx+48.O*x4)/64.O/w);

t , w=u* (l.O+p*ro) / (l.O+q*ro) ; X += w;

} while (fabs(w/x) > 1.0e-13 && j c 5);

F. start

This is an auxiliary procedure which computes a starting value of an algorithm used in several Bessel function procedures.

Certain stable methods for evaluating functions f, f,, ..., J;,which satisfy a three term recurrence relationship of the form f,+, + a& + bS,, = 0 require a value of v to be determined such that the value of the continued fraction

and that of its convergent

should agree. (The theory of such methods [see T76b], which involve backward recursion, is described in outline in the documentation to bessj which concerns the case in which f, =

J,(x); the same methods are also implemented by bessjaplusn (for which f, = Ja+,(x)), by nonexpbessi (for which f, = I,(x)), by nonexpbessiaplusn (for which f, = e"Ia+,(x)), by spherbessj (for which ~,=(X/(~X)) ' /~J,+,(X)) , and by nonexpspherbessi (for which f,=e- x ( 7 m 4 ) 1/21k+ %W.)

Copyright 1995 by CRC Press, Inc

Page 603: Numerical Library in C for Scientists and Engineers A

The above requirement is equivalent to the condition that the tail

of expansion (1) should be negligible. For the special cases considered, t(v) represents the ratio of two Bessel functions of contiguous orders. Estimates of t(v) may be obtained by the use of such formulae as

J,(x) = (2nr tanh(a)}"'2exp[r{tanh(a)-a} ] where r=x cosh(a), and

I,&) = (21rr)-'" (1 +2)-''4d~z) where z=xh and

~(z) = (1 +z2)'" + ln[z/{l+ (1 +z 2)1'23]

Function Parameters: int start (x, n, t)

start: a starting value for the Miller algorithm for computing an array of Bessel functions; x: float;

entry: the argument of the Bessel functions, x > 0; n: int;

entry: the number of Bessel functions to be computed, n 2 0; t: int;

entry: the type of Bessel function in question, f=O corresponds to ordinary Bessel functions; t-1 corresponds to modified Bessel functions.

int start (float x, int n, int t) {

s=2*t-1; p=36.0/~-t; r=n/x; if (r > 1.0 [ I t == 1) (

q=sqrt (r*r+s) ; r=r*log (q+r) -q;

) else r=O.O;

q=la.O/x+r; r = ( p > q ) ? p : q; p=sqrt (2 .O* (t+r) ) ; p=x*((l.o+r)+p)/(l.O+p); y=o . 0 ;

y=p; p /= x; q=sqrt (p*p+s) ; p=x* (r+q) /log (p+q) ; q=y;

) whlle (p > q 1 1 p < q-1.0); return ((t == 1) ? floor(p+l.O) : -floor(-p/2.0)*2);

1

Copyright 1995 by CRC Press, Inc

Page 604: Numerical Library in C for Scientists and Engineers A

6.6.2 Bessel functions I and K

A. bessiaplusn

Generates an array of modified Bessel functions of the first kind of order a+j, Iu+j(x), (Oljln, OIa-4).

When x=O the above functions are evaluated directly; when a=O or a=0.5 the procedures bessi or nonexpspherbessi, as is appropriate, is used. Otherwise the functions

e-lx'~,+,(x) (j=O, ..., n) are evaluated by means of a call of nonexpbessiaplusn, and the values of the functions I,+,(x) (j=O, ..., n) are recovered by multiplication by elX1.

Function Parameters: void bessiaplusn (a,x,n, ia)

a: float; entry: the noninteger part of the order of the Bessel functions; 0 I a < 1 ;

x: float; entry: the argument value of the Bessel functions, x 1 0;

n: int; entry: the upper bound of the indices of the array ia; n 2 0;

ia: float ia[O:n]; exit: ial;] is assigned the value of the modified Bessel function of the first kind of

order a+j and argument x, I,+,(x), Oljln.

Functions used: nonexpbessiaplusn, bessi, nonexpspherbessi.

yoid bessiaplusn(f1oat a, float x, int n, float ia[l) i

if (X == 0.0) { ia[O] = (a == 0.0) ? 1.0 : 0.0; for ( ; n>=l; n--) ia[nl=0.0;

) else if (a == 0.0) { void bessi (float, int, float [I ) ; bessi (x,n, ia) ;

} else if (a == 0.5) { void nonexpspherbessi(float, int, float [I); float c; c=0.797884560802865*sqrt (fabs (x) ) *exp (fabs (x) ) ; nonexpspherbessi (x,n, ia) ; for ( ; n>=O; n--) ia[nl *= c;

} else { void nonexpbessiaplusn(float, float, int, float[] ) ; float expx; expx=exp ( f abs (x) ) ; nonexpbessiaplusn (a, x,n, ia) ; for ( ; n>=O; n--) ia[nl *= expx;

Computes the modified Bessel functions of the third kind of order a and a+]: K,(x) and K,+,(x) for x>O, a20.

For 0 < x < 1, K,(x) and K,+,(x) are computed by using Taylor series (see [T75]). For

Copyright 1995 by CRC Press, Inc

Page 605: Numerical Library in C for Scientists and Engineers A

x2 1 the procedure calls

Function Parameters:

a: float; entry: the order;

x: float;

for nonexpbesska01.

void besskaO 1

entry: this argument should satisfy x > 0; ka: float *;

exit: the value of the modified Bessel function of the third kind of order a and argument x;

kal: float *; exit: the value of the modified Bessel function of the third kind of order a+l and

argument x.

Functions used: bessk0 1, recipgamma, nonexpbesskao 1.

yoid besskaOl(f1oat a, float x, float *ka, float *kal)

if (a == 0.0) { void bessk0l (float, float *, float * ) ; bessk0l (x, ka, kal) ;

) else ( int n, na, rec, rev; float f,g,h,pi; pi=4 .O*atan(l.O) ; rev = (a < -0.5) ; if (rev) a = -a-1.0; rec = (a >= 0.5) ; if (rec) {

na=floor (a+0.5) ; a - = na;

I

if (a == 0.5) f =g=sqrt (pi/x/Z.O) *exp (-x) ;

else if (x < 1.0) { float recipgamma (float, float *, float * ) ; float al,b,c,d,e,p,q,s; b=x/2.0 ; d = -log(b); e=a*d; c=a*pi; c = (fabs(c) < 1.0e-15) ? 1.0 : c/sin(c); s = (fabs(e) < 1.0e-15) ? 1.0 : sinh(e)/e; e=exp (e) ; al= (e+l. 0/e) /2 .O; g=recipgarnma (a, &p, &q) *e; *ka = f = c* (p*al+q*s*d) ; e=a*a; p=o.s*g*c; q=o. 5/g; c=1.0;

Copyright 1995 by CRC Press, Inc

Page 606: Numerical Library in C for Scientists and Engineers A

n++; ) while (h/ (*ka)+fabs(g)/(*kal) > 1.0e-15) ; f= (*ka) ; g= (*kalj /b;

} else { void nonexpbesskaOl(float, float, float *, float * ) ; float expon; expon=exp ( -x) ; nonexpbesskaol (a,x, ka, kal) ; f =expon* (*ka) ; g=expon* (*kal) ;

I

if (rec) ( x=2. o/x; for (n=l; n<=na; n++) {

h=f + (a+n) *x*g; f=g;

*kal = f; *ka = g;

) else ( *ka = f; *kal = g;

} 1

1

C . besskaplusn

Generates an array of modified Bessel functions of the third kind of order a+n, Ka+,(x), n=O ,..., nmax, for x > 0, a 2 0.

The values of the functions Ka(x), Ka+,(x) are first obtained by means of a call of besskaol, and the recursion

Ka+n+,(x) = Ka+n-I&) + J2(n+a)/xIKa+n(x) is then used.

Function Parameters: void besskaplusn (a,x,nmax,kan)

a: float; entry: the order; a 2 0;

x: float; entry: the argument value, x > 0;

nmax: int; entry: the upper bound of the indices of the array kan; nmax 2 0;

kan: float kan[O:nmax]; exit: the values of the modified Bessel functions of the third kind of order a+n, for

argument x are assigned to kan[n], 0 5 n n nmax.

Function used: besska0l .

void besskaplusn(f1oat a, float x, int nmax, float kan[l) (

void besskaOl(float, float, float *, float * ) ; int n; float kl;

Copyright 1995 by CRC Press, Inc

Page 607: Numerical Library in C for Scientists and Engineers A

besska01 (a,x, &kan [OI , &kl) ; a -= 1.0; x=2. o/x; if (nmax > 0) kan[ll =kl; for (n=2; n<=nmax; n++) kan [nl =kan 111-21 + (a+n) *x*kan [n-11 ;

I

D. nonexpbessiaplusn

Generates an array of modified Bessel functions of the first kind of order a+j, (O<j<n, OIa<l), multiplied by the factor e". Thus, apart from the exponential factor the array entries are the same as those computed by bessiaplusn.

nonexpbessiaplusn computes the values of the functions e"Ia+j(x) o=O, ..., n). When x=O, the above functions are evaluated directly; when a=O or a=OS the procedure nonexpbessi or nonexpspherbessi, as is appropriate, is used. Otherwise the above functions are evaluated by the methods described in the documentation to nonexpbessi, where now ak=2(a+k)/x, bk=-I, X,=l, Xk=2(a+k)I'(a+2k)/{k!I'(2a+I)} and s=(x/2) "A'(a+l). See [G67].

Function Parameters: void nonexpbessiaplusn (a,x,n, ia)

a: float; entry: the noninteger part of the order a+n; 0 I a < 1;

x: float; entry: the argument of the Bessel functions, x 2 0;

n: int; entry: the upper bound of the indices of the array ia; n 2 0;

ia: float ia[O:n]; exit: iab] is assigned the value of the modified Bessel function of the first kind of

order a+ j and argument x, multiplied by e", Oyln.

Functions used: nonexpbessi, nonexpspherbessi, gamma, start.

void nonexpbessiaplusn(float a, float x, int n, float ia[l) {

if (x == 0.0) { ia[O] = (a == 0.0) ? 1.0 : 0.0; for ( ; n>=l; n--) ia[nl=0.0;

) else if (a == 0.0) { void nonexpbessi(float, int, float [I ) ; nonexpbessi (x, n, ia) ;

} else if (a == 0.5) { void nonexpspherbessi(float, int, float [I); float c; c=0.797884560802865*sqrt(x); nonexpspherbessi (x, n, ia) ; for ( ; n>=O; n--) ia[nl *= c;

} else ( float garnma(f1oat) ; int start (float, int, int) ; int m,nu; float r,s,labda,l,a2,x2; a2=a+a; x2=2. o/x; 1=1.0; nuzstart (x,n, 1) ; r=s=O. 0; for (rn=l; mc=nu; m++) l=l* (m+a2) / (m+l) ; for (m=nu; m>=l; m--1 (

Copyright 1995 by CRC Press, Inc

Page 608: Numerical Library in C for Scientists and Engineers A

la [o] =r=l. O/ (l.O+s) /gamma(l. 0+a) /pow (x2, a) ; for (m=l; mc=n; m++) r = ia[ml *= r;

1 1

Computes the modified Bessel functions of the third kind of order a and a+l, Ka(x) and Ka+,(x), multiplied by the factor 8, for x>O, a2O. Thus, apart from the exponential factor, the functions are the same as those computed by besska0l.

nonexpbessku01 evaluates the functions K,'(x) = e'K,(x) (a=a,a+l). For O<x<l, the procedure besska01 is called. For x 2 1 the Bessel functions are computed by a Miller algorithm for confluent hypergeometric functions (see [T75]).

Function Parameters: void nonexpbesskao 1 (a,x,ka,kal)

a: float; entry: the order;

x: float; entry: this argument should satisfy x > 0;

ka: float *; exit: the value of the modified Bessel function of the third kind of order a and

argument x; kal: float *;

exit: the value of the modified Bessel function of the third kind of order a+l and argument x.

Functions used: besskaol, nonexpbesskol.

void nonexpbesskaOl(f1oat a, float x, float *ka, float *kal) {

if (a == 0.0) { void nonexpbesskOl(float, float *, float * ) ; nonexpbessk01 (x, ka, kal) ;

) else { int n,na,rec,rev; float f,g,h,pi; pi=4.0*atan(l.O) ; rev = (a c -0.5); if (rev) a = -a-1.0; rec = (a >= 0.5) ; if (rec) {

na=f loor (a+O. 5) ; a -= na;

1 if (a == -0.5)

f =g=sqrt (pi/x/2.0) ; else if (x c 1.0) {

void besskaOl(float, float, float *, float * ) ; float expon; expomexp (x) ; besska0l (a,x,ka, kal) ;

Copyright 1995 by CRC Press, Inc

Page 609: Numerical Library in C for Scientists and Engineers A

f=expon* (*ka) ; g=expon* (*kal) ;

} else { float b,c,e,p,q; c=O.25-a*a; b=x+x; g=l.O; f=O.O; e=cos (a*pi) /pi*x*l. 0e15; n=l; do I

h= (2. O* (n+x) *g- (n-l+c/n) *f) / (n+l) ; f=g; g=h; n++ ;

} while (h*n < el; p=q=f/g; e=b-2.0:

q=p* (1.0+q) ; n--;

} while (n > 0); f =sqrt (pi/b) / (l.O+q) ; g=f* (a+x+O .5-p) /x;

1 if (rec) {

x=2. o/x; for (n=l; n<=na; n++) {

h=f+ (a+n) *x*g; f =g; g=h;

1 1

if (rev) { *kal = f; *ka = g;

} else { *ka = f;

F. nonexpbesskaplusn

Generates an array of modified Bessel functions of the third kind of order a+n, Ka+,l(x), n=0, ..., nmax, multiplied by the factor e', for x > 0, a 2 0. Thus, apart from the exponential factor, the functions are the same as those computed by besskaplusn

nonexpbesskaplusn computes the values of the functions K,+,'(x) = d;K,+,(x) (n=O, ..., nmax). The values of the functions Ka'(x), Ka+,'(x) are first obtained by means of a call of nonexpbesskaOl, and the recursion

Ka+n+, '(XI = Ka+n-1 '(XI + {2(n+a)/~)Ka+n '(x) is then used.

Function Parameters: void nonexpbesskaplusn (a,x, nmax, kan)

a: float; entry: the order; a > 0;

x: float; entry: the argument value, x > 0;

nmax: int; entry: the upper bound of the indices of the array kan; nmax 2 0;

Copyright 1995 by CRC Press, Inc

Page 610: Numerical Library in C for Scientists and Engineers A

kan: float kan[O:nmm]; exit: the values of the modified Bessel functions of the third kind of order a+n, for

argument x multiplied by 8 are assigned to kan[n], 0 2 n 2 nmax.

Function used: nonexpbesskaol

void nonexpbesskaplusn(float a, float x, int nmax, float kan[l) I

void nonexpbesskaOl(float, float, float *, float * ) ; int n; float kl;

nonexpbesskaOl(a,x, &kan [Ol , &kl) ; a - = 1.0; x=2. o/x; if (nmax > 0) kan[ll =kl; for (n=2; nc=nmax; n++) kan [nl =kan 11-1-21 + (a+n) *x*kan [n-11 ;

1

6.6.3 Spherical Bessel functions

A. spherbessj

Calculates the spherical Bessel functions J,+,, '(x) = (x/(~x))~'~J~+~,,(x), k=O, ..., n, where J,+,,(x) denotes the Bessel function of the f ~ s t kind of order k+0.5, for x 2 0. The method used [G67] is that described in the documentation to bessj, with a = 0.5 in formula (1). Since

J,,, '(x) = x"sin(x), A, = I, A, = 0 (k=1,2 ,... ), s = x-'sin(x) may be taken in the further formulae of that documentation, which in consequence become a little simpler.

Function Parameters: void spherbessj (x,n,j)

x: float; entry: the value of the argument; x 2 0;

n: int; entry: the upper bound of the indices of array j ; n 2 0;

j : float j[O:n]; exit: j[k] is the value of the spherical Bessel hnction J,,,'(x), k=O, ..., n.

Function used: start.

void spherbessj(f1oat x, int n, float j[]) I

if (x== 0.0) { j [Ol=l.O; for ( ; n>=l; n--) j [nl=O.O;

} else if (n == 0) { float x2; if (fabs(x) c 0.015) {

xZ=x*x/6.0; j [O]=l.O+x2* (x2*0.3-1.0) ;

} else

Copyright 1995 by CRC Press, Inc

Page 611: Numerical Library in C for Scientists and Engineers A

else [ol =sin (x) /x;

int start (float, int, int) ; int m; float r,s; r=O . 0 ; m=start (x,n, 0) ; for ( ; m>=l; m--1 {

r=l. O/ ( (m+m+l) /x-r) ; if (m <= n) j [ml =r;

1 if (X < 0.015) {

s=x*x/6.0; j [Ol =r=s* (s*0.3-1.0) +1.0;

) else j [Ol =r=sin (x) /x;

for (m=l; m<=n; m++) r = j [m] *= r;

1 1

B. spherbessy

Calculates the spherical Bessel functions Y,+,,'(x) = (7r/(2x))1'2~+0,5(x), j=O, ..., n, where Y,+,,(x) denotes the Bessel function of the third kind of order j+0.5, for x > 0. The recursion [AbS65]

Yo,5'(x) = -x-'cos(x), Y,,, '(x) = -~-~cos(x) - x"sin(x)

Y,+O., '(Y = ((2j-I)/x) Yj-0.5 '(x) + Y,-,., '(x) ~ = 2 , ..., n) is used.

Function Parameters: void spherbessy (x,n,y)

x: float; entry: the argument of the Bessel fknctions; x > 0;

n: int; entry: the upper bound of the indices of array y; n 2 0;

y: float y[O:n]; exit: yo] is the value of the spherical Bessel function Y,+0,5'(~), j=O, ..., n.

void spherbessy(f1oat x, int n, float y[] ) I

if (n == 0) y [O] = -cos(x) /x;

else { int i; float yi,yil,yi2; yi2 = y[Ol = -COS(X) /x; yil=y [I] = (yi2-sin(x) ) /x; for (i=2; i<=n; i++) (

y[i] = yi = -yi2+(i+i-1) *yil/x; yi2zyil; yil=yi;

I

C. spherbessi

Copyright 1995 by CRC Press, Inc

Page 612: Numerical Library in C for Scientists and Engineers A

Calculates the modified spherical Bessel functions J+0.5 '(x) = (?~/(~X))"~I~+~,~(X), j=O ,..., n, where J+,,(x) denotes the modified Bessel function of the first kind of order j+0.5, for x 1 0.

The functions J+o,5'1(x) = e"J+o,5'(x), j=O, ..., n, are first evaluated by means of a call of nonexpspherbessi; the values of the functions J+,, '(x) are then recovered by multiplication by 8.

Function Parameters: void spherbessi (x, n, i)

x: float; entry: the argument of the Bessel functions; x 1 0;

n: int; entry: the upper bound of the indices of array i; n 2 0;

i: float i[O:n]; exit: ib] is the value of the modified spherical Bessel function J+0,5'(~), j=O, ..., n.

Function used: nonexpspherbessi.

void spherbessi(f1oat x, int n, float i[l) I

) else { void nonexpspherbessi(float, int, float [ I ) ; float expx; expx=exp (xl ; nonexpspherbessi (x, n, i) ; for (; n>=O; n--) i[nl *= expx;

I 1

D. spherbessk

Calculates the modified spherical Bessel functions K,+,,'(x) = (~/(2x))'~2~+o,,(x), j=O, ... ,n, where Kj+,,(x) denotes the modified Bessel function of the third kind of order j+0.5, for x > 0.

The functions Z$+o,511(x) = ex~+o,5'(x), j=O, ..., n, are first evaluated by means of a call of nonexpspherbessk; the functions Kj+o,,'(x) are then recovered by multiplication by e".

Function Parameters: void spherbessk (x,n, k)

x: float; entry: the argument value; x > 0;

n: int; entry: the upper bound of the indices of array k; n 2 0;

k: float k[O:n]; exit: kb] is the value of the modified spherical Bessel function l$+0.5'(~), j=O, ..., n.

Function used: nonexpspherbessk.

Copyright 1995 by CRC Press, Inc

Page 613: Numerical Library in C for Scientists and Engineers A

void spherbessk(f1oat x, int n, float k[] ) I

void nonexpspherbessk (float, int, float [I ) ; float expx; expx=exp ( -x) ; nonexpspherbessk (x,n, k) ; for ( ; n>=O; n--) k[nl *= expx;

1

E. nonexpspherbessi

Calculates the modified spherical Bessel functions multiplied by e". nonexpspherbessi evaluates J+O.Jrl(X) = e~*(~/(2~))''~I/+~,~(x), j=O, ..., n, where I/+o,5(x) denotes the modified Bessel function of the first kind of order j+0.5, for x 2 0.

The ratio of two subsequent elements is computed using a backward recurrence formula according to Miller's method (see [G67]). Since the zeroth element is known to be (1-e- '")(2x), the other elements follow immediately. The starting value is computed by start.

Function Parameters: void nonexpspherbessi (x, n, i)

x: float; entry: the argument of the Bessel functions; x 2 0;

n: int; entry: the upper bound of the indices of array i; n 2 0;

i: float i[O:n]; exit: ib] is the value of the modified spherical Bessel function I/+o,,"(x), j=O, ..., n.

Function used: start.

void nonexpspherbessi(f1oat x, int n, float i[l) (

if (X == 0.0) ( i [Ol =l.O; for ( ; n>=l; n--) i[nl=O.O;

) else ( int start (float, int, int) ; int m; float x2,r; x2=x+x; i[O] = x2 = ((x == 0.0) ? 1.0 : ((x2 < 0.7) ?

sinh(x)/(x*exp(x)) : (1.0-exp(-x2))/~2)); if (n ! = 0) {

r=O. 0; m=start (x, n, 1) ; for ( ; m>=l; m--) (

r=l. O/ ( (m+m+l) /x+r) ; if (m <= n) i [ml =r;

1 for (m=l; mc=n; m++) x2 = i[ml *= x2;

1 1

1

F. nonexpspherbessk

Copyright 1995 by CRC Press, Inc

Page 614: Numerical Library in C for Scientists and Engineers A

Calculates the modified spherical Bessel functions multiplied by e'. nonexpspherbessk evaluates the functions K,+o,5"(x) = e ' (d (2x) ) '"~~+~.~(x) , j=O, ..., n, where Kj+o,,(x) denotes the modified Bessel function of the third kind of order j+0.5, for x > 0.

The recursion Ko.5"(x) = 7r/(2x),

K,,,"(X) = (I + I / X ) K ~ , , ~ ~ X ) "(x) = ( ( 2 j - ~ ) ~ j - 0 , 5 ' ( + 4.1.5 "(x) 0=2, ..., n)

is used.

Function Parameters: void nonexpspherbessk (x,n, k)

x: float; entry: the argument of the Bessel functions; x > 0;

n: int; entry: the upper bound of the indices of array k; n 2 0;

k: float k[O:n]; exit: k/j] is the value of the modified spherical Bessel function K,+o,5't(x), j=O, ..., n.

void nonexpspherbessk(f1oat x, int n, float k[l) l

int i; float ki,kil,kiZ; X=l. o/x; k [O] =ki2=~*1.5707963267949; if (n ! = 0) (

k [l] =kil=ki2* (l.O+x) ; for (i=2; i<=n; i++) {

k [il =ki=ki2+ (i+i-1) *x*kil; kiZ=kil; kil=ki;

1

6.6.4 Airy functions

A. airy

Evaluates the functions e"xPO"fz)~i(z) and eeXPonfd~i(z), where the Airy functions Ai and Bi (see [AbS65, Gor691) may be defined by the formulae

Ai(z) = cf(z) - c2g(z), Bi(z) = 3'"{cf(z) + c2g(z)) where

and expon(z) = 0 for z < 9, expon(z) = (2/3)z3" for z 2 9. airy also evaluates the derivatives

Copyright 1995 by CRC Press, Inc

Page 615: Numerical Library in C for Scientists and Engineers A

of these functions: e*xpOn(z)dAi(z)/dz and eexpn(z)d~i(z)/dz.

When -5 I z I 8, the above defining formulae, and those obtained by differentiation are used to compute the Airy functions and their derivatives.

When z 2 8, approximate versions of the formulae

where

are used. These versions have the form

Copyright 1995 by CRC Press, Inc

Page 616: Numerical Library in C for Scientists and Engineers A

where

When z < 0, similar use is made of the formulae

where J = 2z3I2/3. In both of the above cases the derivatives of Ai and Bi are obtained by differentiation of their approximation formulae.

Function Parameters:

z: float; entry: the

ai: float *; exit: the

aid: float *; exit: the

bi: float *; exit: the

bid float *; exit: the

expon: float *;

void airy (z, ai, aid, bi, bid, exponfzrst)

real argument of the Airy functions;

value of the Airy function given by e"xPOn(z)Ai(z);

value of the derivative of the Airy function given by e""POnfz)Ai(z);

value of the Airy function given by eeXPonf*)Bi(z);

value of the derivative of the Airy function given by e'"Pon(*)~i(z);

exit: if z < 9 then 0 else (2/3)z3"; first: int;

entry: the value of first should be zero unless the procedure is called for the first time; iffirst is nonzero then two internal static arrays are built up.

void airy(f1oat z, float *ai, float *aid, float *bi, float *bid, float *expon, int first)

I 1

int n.1; float. s; t,u,v, sc, tc,uc,vc,x, kl, k2, k3, k4, c, zt, si, co, expzt, sqrtz, wwl,

pl,pll,pl2,p13; static float cl, c2, sqrt3, sqrtlopi,pio4,xx[lll ,ww ill1 ;

if (first) ( sqrt3=1.73205080756887729; sqrtlopi=0.56418958354775629;

Copyright 1995 by CRC Press, Inc

Page 617: Numerical Library in C for Scientists and Engineers A

*expon=O.O; if (Z >= -5.0 && z c= 8.0) {

u=v=t=uc=vc=tc=1.0; s=sc=o. 5; n=3 ; x=z*z*z; while (fabs(u) +fabs (v)+fabs (s)+fabs (t) > 1.0e-18) {

u=u*x/ (n* (n-1) ) ; v=v*x/ (n* (n+l) ) ; s=s*x/ (n* (n+2) ; t=t*x/ (n* (n-2) ) ; UC += u; VC += v; SC += s; tc += t;

*bi=sqrt3* (cl*uc+c2*z*vc) ; *bid=sqrt3* (cl*z*z*sc+c2*tc) ; if ( ~ ~ 2 . 5 ) {

*ai=cl*uc-c2*z*vc; *aid=cl*sc*z*z-c2*tc; return;

1 I

kl=k2=k3=k4=0.0; sqrtz=sqrt (fabs (2) ) ; zt=0.666666666666667*fab~(Z)*sqrtZ; c=sqrtlopi/sqrt(sqrtz); if (Z c 0.0) {

Z = -2; co=cos (zt-pio4) ; si=sin (zt-pio4) ; for (1=1; 1c=10; I++) (

wwl=ww [ll ; pl=xx [ll /zt; pl2=pl*pl; pl1=1.O+p12; pl3=pll*pll; kl += wwl/pll; k2 += wl*pl/pll; k3 += wl*pl* (1.0+pl* (2.O/zt+pl) ) /pl3; k4 += wwl* (-1.0-pl*(l.~+pl*(zt-pl) ) /zt)/pl3;

1 1

*ai=c* (co*kl+si*k2) ; *aid=0.25*(*ai)/z-c*sqrtz*(co*k3+si*k4); *bi=c* (co*k2-si*kl) ; *bid=O.25*(*bi)/z-c*sqrtz*(co*k4-si*k3);

} else { if (z c 9.0)

Copyright 1995 by CRC Press, Inc

Page 618: Numerical Library in C for Scientists and Engineers A

expzt=exp (zt) ; else {

expzt=l. 0; *expon=zt;

I

B. airyzeros

Computes the zeros and associated values of the Airy functions Ai(x) and Bi(x), and their derivatives.

Denoting by a,, a, ', b,, b, ' the s-th zero of Ai(x), &i(x)/dx, Bi(x), dBi(x)/dx respectively (see [AbS65]):

a, = -f{3*(4s-1)/8}, a,' = -g{3*(4s-3)/8} b, = #3~(4~-3)/8), b,' = -g{3*(4s-1)/8}

where the functions f and g are defined in the documentation of airy. The appropriate member of the above set of approximations is used as the first iterate in a quadratic interpolation process for determining the zeros in question. The values of the Airy functions (and the associated values delivered in the array vai) are calculated by means of the procedure airy.

Function Parameters: float airyzeros (n, d,zai,vai)

airyzeros: delivers the n-th zero of the selected Airy hnction; d int;

entry: an integer which selects the required Airy function, d = 0, 1, 2 or 3; zai: float zai[l :n];

exit: zailj] contains the j-th zero of the selected Airy function: if d=O then Ai(x), if d=l then (d&)Ai(x), if d=2 then Bi(x), if d=3 then (ddx)Bi(x);

vai: float vai[l :n]; exit: vailj] contains the value at x = zailj] of the following function:

if d=O then (d/d)Ai(x), if d=l then Ai(x), if d=2 then (ddx)Bi(x), if d=3 then Bi(x).

Copyright 1995 by CRC Press, Inc

Page 619: Numerical Library in C for Scientists and Engineers A

Function used: airy.

float airyzeros(int n, int d, float zaill, float vai[l) I ' void airy(float,float *,float *,float *,float *,float *,int);

int a, found, i; float c,e,r,zaj.zak.vaj,daj.kaj,zz;

a=((d == 0) 1 1 (d == 2)); r = (d == 0 1 1 d == 3) ? -1.17809724509617 : -3.53429173528852; airy(O.O,&zaj,&vaj,&daj,&kaj, &zz,l) ; for (i=l; i<=n; i++) {

r += 4.71238898038469; zz=r*r; zaj = (i == 1 && d == 1) ? -1.01879297 :

((i == 1 && d == 2) ? -1.17371322 : pow(r,0.666666666666667)* (a ? -(1.0+(5.0/48.0-(5.0/36.0-(77125.0/82944.0- (108056875.0/6967296.0-(162375596875.0/334430208.0)/ zz) /zz) /zz)/zz) /zz) : - (1.0- (7.0/48 .O- (35.0/288.0- (181223.0/207360.0-(18683371.0/1244160.0- (91145884361 .O/l9llO2976.O) /zz) /zz) /zz) /zz) /zz) ) ) ;

if (d c= 1.0) airy(zaj ,&vaj ,&daj,&c,&e,&zz, 0) ;

else airy(zaj,&c,&e,&vaj,&daj,&zz,O) ;

found=(fabs(a ? vaj : daj) c 1.0e-12); while (!found) {

if (a) { kaj=vaj/daj; zak=zaj-kaj* (l.O+zaj*kaj*kaj) ;

} else { kaj=daj/ (zaj*vaj) ; zak=zaj-kaj* (l.O+kaj*(kaj*zaj+l.O/zaj));

1 if (d <= 1)

airy(zak,&vaj,&daj,&c,&e,&zz,O); else

airy(zak, &c,&e,&vaj,&daj,&zz, 0) ; found=(fabs(zak-zaj) c l.0e-14*fabs(zak) I I

fabs(a ? vaj : daj) c 1.0e-12); zaj=zak;

1 I vai[il=(a ? daj : vaj); zai [il =zaj ;

\ keturn zai [n] ;

Copyright 1995 by CRC Press, Inc

Page 620: Numerical Library in C for Scientists and Engineers A

7. Interpolation and Approximation

7.1 Real data in one dimension

7.1.1 Interpolation with general polynomials

newton

Calculates the coefficients of the Newton polynomial through given interpolation points and corresponding function values.

newton computes the divided differences Gf(xJ, j=O, ..., n, derived from the function values and their associated arguments xi, i=O, ..., n, (the xi being assumed distinct). The {6if(xJ} are computed by use of the defining recursion

6: = I ; (i=O, ..., n) 6,"' = (&+/ - 6,') / (xi+,+' - XJ (j=O ,..., n-1 ; i=O ,..., n-j-1)

when Gif(x,J = 660j.

Function Parameters: void newton (n,x,j)

n: int; entry: the degree of the polynomial;

x: float x[O:n]; entry: the interpolation points;

f: float f[O:n]; entry: the function values at the interpolation points; exit: the coefficients of the Newton polynomial.

yoid newton (int n, float x [I , float f [I ) 1

int k,i,iml; float xim1,fiml;

iml=O ; for (i=l; i<=n; i++) (

f iml=f [imll ; ximl=x [imll ; for (k=i; kc=n; k++) f [kl = (f Ikl -f iml) / (x [kl -ximl) ; iml=i;

7.1.2 Approximation in infinity norm

A. ini

Selects a set of integers out of a given set of integers. With integers m,n (m > n), ini determines a sequence of integer approximations s(j), j=O, ..., n; s(j) > s(j-1), to the points in the range [ O n ] at which Tn((2x-m)lm), where T,(y) = cos{n arc cos(y)} being a Chebyshev polynomial and (2x-m)lm maps XE[-1,1] onto [O,m], assumes its maximal absolute values.

Copyright 1995 by CRC Press, Inc

Page 621: Numerical Library in C for Scientists and Engineers A

ini is an auxiliary procedure used in minmaxpol.

Function Parameters: void ini (n,m,s)

n,m: int; entry: the number of points to be selected equals n+l; the reference set contains the

numbers O,l, ..., m, (m 2 n); s: int s[O:n];

exit: the selected integers are delivered in s.

yoid ini(int n, int m, int s [ l ) i

int i,j,k,l; float pin2,temp;

pin2=atan(l.O) *2.0/n; k=l; l=n-1; j=s [Ol =O; s [nl =m; while (k c 1) {

temp=sin (k*pin2) ; i=temp*temp*m; j =s[k] = ( ( i c = j) ? j + l : i); s [ll =m- j ; I--;

B. sndremez

Exchanges at most n+l numbers with numbers out of a reference set (see [Me64]). Given a sequence of real numbers g,, i=O, ..., m, which contains a subsequence gfC), j=O,l, ..., n<m; so) > @I), for which a)

sign gs(ii = -sign gsO+ j=l, ..., n, a sequence of integers So), j=O,l, ..., n;

Sfj) > So-I); S(0) 2 0, S(n) I m, is determined such that A)

1 gsC) 1 2 G, j=O,...,n, and B)

sign gso) = -sign gso+ j=l, ..., n, and C) IgsC) 1 > G for at least one j in the range 0 I j I n if Igi 1 > G for at least one i in the range 0 I i I n.

The process used is as follows: let H(1) = max 1 g, 1 for s(0) < i < s(1)

and (gwl = H(1) (H(1) is zero if s(0) = s(1) and I(1) is then undefined; a similar convention is adopted below). If H(1) 5 G then

S(0) = s(O), S(1) = s(1); otherwise if

Copyright 1995 by CRC Press, Inc

Page 622: Numerical Library in C for Scientists and Engineers A

sign gI0 = sign ~ S ( O )

then S(0) = I(]), S(1) =s(l),

whereas if sign g,,, * sign ~ S ( O ) ,

then S(0) = s(O), S(1) = I(1).

Let H(2) = maxlg,l for s(l) < i < s(2) and lgI(2)1 = H(2).

If H(2) I G then S(2) = 4 2 ) ; otherwise if sign g,,, = sign gsm then S(1) is replaced by I(2) and S(2) = s(2), whereas if sign g,(2) # sign gS(,) then S(2) = I(2). The numbers g, s(2)<i<s(3), are inspected, S(2) is possibly replaced, and S(3) is determined as before. In this way S(O), ..., S(n) are determined. Let

H' = max I g , I for 0 I i < s(0) with I g,, 1 =H', and

H" = max lg , 1 for s(n) < i 5 m, with Igp 1 = HI1. If H', H" < G, the numbers SQ) are left as they stand. If not, then if H' > H" then a) if sign g,, = sign gs(o) then a') if H y Ig,, I , S(0) is replaced by I' and a") if sign g,. = gS(, and H" > Jg,(,, 1 , S(n) is replaced by I"; b) if sign g,. # sign gs(o) then b') if H' > Ig,(,,) 1 , S(k) is replaced by S(k-I), k=n, ..., 1 , and S(0) is replaced by I' and b") (with the new value of S(n)) if sign g,. = sign gs(n) and H" > I g,(,,) 1 , S(n) is replaced by I". If H" 1 H' then similar modifications take place.

sndremez is an auxiliary procedure used in minmaxpol.

Function Parameters: void sndremez (n,m,s,g,em)

n,m: int; entry: the number of points to be exchanged is smaller than or equal to n+l;

the reference set contains the numbers O,l, ..., m, (m 2 n); s: int s[O:n];

entry: in s one must give n+l (strictly) monotone increasing numbers out of O,l, ..., m; exit: n+l (strictly) monotone increasing numbers out of the numbers O,l, ..., m;

g: float g[O:m]; entry: in array g[O:m] one must give the function values;

em: float em[O:I]; entry: 0 < em[O] I g[i], i=O, ..., m; exit: em[1] = infinity norm of array g[O:m].

Function used: i n h v e c .

float infnrmvec(int, int, int *, float [I) ; int sO,sn,sjpl,i,j,k,up,low,nml; float max,msjpl, hi,hj ,he, abse, h, templ, temp2;

sO=sjpl=s [Ol ; he=em [O] ; low=sO+l; max=msjpl=abse=fabs (he) ; nml=n-1;

Copyright 1995 by CRC Press, Inc

Page 623: Numerical Library in C for Scientists and Engineers A

for (j=O; j<=nml; j++) { up=s [j+ll-1; h=infnrmvec (low, up, &i, g) ; if (h > max) max=h; if (h > abse)

if (he*g[il > 0.0) ( s[jl = (msjpl < h) ? i : sjpl; sjpl=s [j+ll ; msjpl=abse;

) else { s[jl=sjpl; sjpl=i; msjpl=h;

I else (

s [jl =sjpl; sjpl-s j+ll ; msjpl=abse;

J

sn=s [nl ; s [nl =sjpl; hi=infnrmvec(O,sO-1, &i,g) ; hj=infnrmvec (sn+l,m, &j ,g) ; if (j > m) ,j=m; if (hi > h)) {

if (hi > max) max=hi; templ = (g[il == 0.0) ? 0.0 : ((g[i] > 0.0) ? 1.0 : -1.0); temp2 = (g[s[Oll==O.O) ? 0.0 : ((g[s[Oll>O.O) ? 1.0 : -1.0); if (templ == temp2) (

if (hi > fabs(g[s [OI 1)) (

L ~ s e { if (hi > fabs(g[s[nll ) ) {

s[n] = (g[jl/g[s[nmlll > 1.0) ? j : s[nmll; for (k=nml; k>=l; k--) s [kl =s [k-11 ; s [Ol =i;

\

I ) else {

if (hj > max) max=hj; templ = (g[jl == 0.0) ? 0.0 : ((g[j] > 0.0) ? 1.0 : -1.0); temp2 = (g[s[nll==O.O) ? 0.0 : ((g[s[nll>O.O) ? 1.0 : -1.0); if (templ == temp2) {

if (hj > fabs(g[s [nll ) ) { s [nl =j; if (g[il/g[s[Oll > 1.0) s[Ol=i;

I ) else

if (hj > fabs (g[s [OI 1 ) ) { s[Ol = (g[il/g[s[ll] > 1.0) ? i : s[ll; for (k=l; k<=nml; k++) s [kl =s [k+ll ; s[nl=j;

1

C. minmaxpol

Calculates the coefficients of the polynomial (as a sum of powers) which approximates a function, given for discrete arguments, in such a way that the infinity norm of the error vector is minimized.

With y, (j=O, ..., m) being a sequence of real arguments Oj-, < yj; j=l, ..., m) and f(yl)

Copyright 1995 by CRC Press, Inc

Page 624: Numerical Library in C for Scientists and Engineers A

corresponding function values, minmaxpol determines the coefficients {ci) of that polynomial

for which

max

is a minimum as j ranges over the vah :s 0, ..., m (m > n). The method used [Me641 involves the iterative construction of polynomials

for which

where s(k,j), j=O, ..., n, is a strictly increasing sequence selected from O,l, ..., m. The discrepancies

' . at all points j=0 ,..., m are then inspected, and from these a sequence gk+lj = gk,sF+lj,, j=O ,..., n, is constructed which a) possesses the alternating property sign gk+lj = -sign gk+lj-l, j=l, ..., n, and b) for which Igk+,jl 2 Igkjl, j=O, ..., n, with (unless the process is to be terminated) Igk+Ij (> (gkj ( for at least one j (for the details of this construction, see the documentation to sndremez). The coefficients {c~+, ,~) in the succeeding polynomial are determined (by use of Newton's interpolation formula, and subsequent reduction to the given polynomial form) from condition (2) with k replaced by k+l .

Initially s(O,j), j=O, ..., n, is a sequence of integer approximations to the points at which Tn((2x-m)/m), where T,,(y) = cos{n arc cosb)} being a Chebyshev polynomial (see the documentation of ini) assumes its maximal absolute values in the range 0 I x I m. The procedure ini is used to set the s(0,j).

Function Parameters: void minrnaxpol (n, m,yfy,co,em)

n: int; entry: the degree of the approximating polynomial; n 2 0;

Copyright 1995 by CRC Press, Inc

Page 625: Numerical Library in C for Scientists and Engineers A

m: int; entry: the number of reference function values is m+l;

y : float y[O:m], fy[0:m]; entry: JL[i] is the function values at y[i], i=O, ..., m;

co: float co[O:n]; exit: the coefficients of the approximating polynomial (co[i] is the coefficient ofy');

em: float em[0:3]; entry: em[2]: maximum allowed number of iterations, say 10*n+5; exit: em[O]: the difference of the given function and the polynomial in the first

approximation point; em[l]: the infinity norm of the error of approximation over the discrete interval; em[3]: the number of iterations performed.

Functions used: elmvec, dupvec, newton, pol, newgrn, ini, sndremez.

void minmaxpol (int n, int m, float y [I , float fy [I , float co [I , float em [I )

{ int *allocate-integer-vector(int, int) ; float *allocate-real-vector(int, int); void free-integer-vector (int *, int) ; void free-real-vector(f1oat * , int); void elmvec(int, int, int, float [I, float [I, float) ; void dupvec(int, int, int, float [I , float [I ) ; float pol (int, float, float [I ) ; void newton (int, float [I , float [I ) ; void newgrn (int, float [I , float [I ) ; void ini (int, int, int 11 ) ; void sndremez(int, int, int [I, float [I, float [I); int np~,k,pomk,count,cnt,j,mi,*s,sjml,sj,sO,up; float e, abse, abseh, *x, *b, *coef,*g;

npl=n+l; ini (npl,m, s) ; mi=em [21 ; abse=O .0 ;

T t = l ; pomk=l ; for (k=O; k<=npl; k++) (

x [kl =y [s [kl I ; coef [kl =fy [s [kl 1 ; b [kl =pomk; pomk = -pomk;

newton(npl,x, coef) ; newton(npl,x, b) ; em 101 =e=coef [npll /b [npll ; elmvec(O,n,O,coef ,b, -e) ; newgrn (n,x, coef) ; sO=sjml=s [OI ; g [sol =e; for (j=l; j<=npl; j++) {

sj=s[jl ; up=sj-1;

Copyright 1995 by CRC Press, Inc

Page 626: Numerical Library in C for Scientists and Engineers A

for (k=sjml+l; k<=up; k++) g [kl =fy[kl -pol (n, y [k] , coef) ; g[sjl = e = -e; s jml=sj ;

1 I for (k=sO-1; k>=O; k--1 g[kl =fy [kl -pol (n, y[kl, coef) ; for (k=sj+l; k<=m; k++) g[kl =fy[kl -pol (n,y[kl, coef) ; sndremez (npl,m, s, g, em) ; abseh=abse; abse=fabs (e) ; cnt=count; count++ ;

} while (count <= mi && abse > abseh) ; em [21 =mi; em [31 =cnt; dupvec(O,n, O,co,coef) ; free-integer-vector(s,O); free-real-vector (x , 0) ; free-real-vector (b, 0) ; free-real-vector(coef,O); free-real-vector (g, 0) ;

1

Copyright 1995 by CRC Press, Inc

Page 627: Numerical Library in C for Scientists and Engineers A

Worked Examples

Examples for chapter 1 procedures

Functions tested: hshcomcol, hshcomprd

Example: The matrix

is reduced to upper triangular form by successive calls of hshcomcol and hshcomprd.

void main 0 1

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); int hshcomcol(int, int, int, float **, float ** , float,

float * , float * , float *, float * ) ; void hshcomprd(int, int, int, int, int, float ** ,

float **, float ** , float ** , float); float k,c,s,t; float **ar,**ai;

ar=allocate-real-matrix(1,2,1,2) ; ai=allocate-real_matrix(l,2,1,2); ar[ll [11=3.0; ar [ll [21 =ar [21 [I1 =O.O; ar [21 [21=5.0; ai [ll [ll =0 .O; ai [ll [21 =ai [21 [ll =4 .O; ai [21 121 =0.0; if (hshcomcol (1,2,l,ar,ai,25.0e-28, &kt &c,&s, &t) )

hshcomprd (1,2,2,2,1, ar, ai, ar, ai, t) ; printf("After using hshcomcol and hshcomprd:\nU

%-3.lf+%-3.if*1 %-3.lf+%-3.1.f*I\n~ %-3.lf+%-3.lf*I %-3.lf+%-3.lf*I\nW

"k, c, s, t\n %6.lf %6.lf %6.lf %6.1f1', ar [I] [ll , ai 111 [ll ,ar [ll [21 , ai [ll 121 , ar [21 [ll ,ai [21 [ll ,ar[21 [21 ,ai [21 121 ,k,c,s,t) ;

free-real-matrix(ar, 1,2,1) ; free-real-matrix (ai, 1,2,1) ;

1 Output:

After using hshcomcol and hshcomprd: 8.0+0.0*1 0.0+1.6*1 0.0+4.0*1 6.2+0.0*1

k, c, s, t 5.0 -1.0 -0.0 40.0

Function tested: elmcomcol

Example:

Copyright 1995 by CRC Press, Inc

Page 628: Numerical Library in C for Scientists and Engineers A

With the matrix

this example sets A , , = A,,, + (I-4i)A, , , for k1,2 .

void main 0 (

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); void elmcomcol(int, int, int, int, float ** , float **,

float ** , float **, float, float) ; float **ar,**ai;

ar=allocate-real-matrix(1,2,1,2) ; ai=allocate-real_matrix(1,2,1,2); ar[l][1]=1.0; ar[l1[21 = -9.0; ar[2l[lI=ar[21[21 = -1.0; ai [I] [ll =ai [I] [2] =ai [21 [11=2.0; ai [21 [21 = -2.0; elmcomcol(l,2,2,l, ar, ai, ar, ai, 1, -4) ; printf("Matrix after elimination:\nU

" %-3.lf+%-3.lf*I %-3.lf+%-3.1f*1\nH %-3.lf+%-3.lf*I %-3.lf+%-3.1f*1\n1',

ar [I] [I] , ai 111 111 , ar [ll [21 , ai 111 [21 , ar [2] [ll ,ai [21 [ll ,ar 0 1 [21 ,ai [21 [21 ) ;

free real matrix(ar, l,2,l) ; free~real~matrix(ai, 1,2,1) ;

I

Output:

Matrix after elimination: 1.0+2.0*1 O.O+O.O*I -1.0+2.0*1 6.0+4.0*1

Function tested: rotcomcol

Example: The matrix

is post multiplied by the rotation matrix

#include cstdio.h>

void main 0 (

float **allocate-real-matrix(int, int, int, int) ;

Copyright 1995 by CRC Press, Inc

Page 629: Numerical Library in C for Scientists and Engineers A

void free-real-matrix(f1oat **, int, int, int) ; void rotcomcol(int, int, int, int, float **, float **,

float, float, float) ; int i, j; float **ar,**ai;

ar=allocate~real~matrix(1,2,1,2); ai=allocate-real_matrix(l,2,1,2); ar[l] [I] =4.0; ar[l] [2]=5.0; ar[2] [l] = -5.0; ar[2] [21=4.0; ai [I] [I] =3 .O; ai [ll [21 =ai 121 [11=0.0; ai [21 [21 = -3 .O; rotcomco1(1,2,1,2,ar,ai,0.08,0.06,-0.1); printf ("Af ter postmultiplication: \n"

%+3.1£%+3.lf*I %+3.1f%+3.1f*I\nn %+3.1f%+3.1£*1 %+3.if%+3.1f*1\nn,

ar [l] [ll , ai [l] [I] , ar [ll [2] , ai [ll [21 , ar [2] [I] , ai [2] [I] ,ar [21 [2] ,ai [21 [21 ) ;

f ree-real-matrix (ar, 1,2,1) ; f ree-real-matrix (ai, 1,2,1) ;

1 Output:

After postmultiplication: +1.0+0.0*1 -0.0-O.O*I +o.o-O.O*I +l.O+O.O*I

Function tested: comabs

Example: Compute / 0.3+0.4i I.

void main 0 {

float comabs (float, float) ;

printf("The modulus of .3+.4*i equals %-4.2f",comabs(0.3,0.4)); 1

Output:

The modulus of .3+.4*i equals 0.50

Function tested: comsqrt

Example: Compute the value of (-3+4i)'I2 with positive real part.

void main 0 {

void comsqrt (float, float, float *, float *) ; float r,i;

comsqrt (-3.0,4.0,&r,&i) ; printf ("The square root of -3+4*i is %-4 .2f+%-4.2f*it',r, i) ;

1 Output:

The square root of -3+4*i is 1.00+2.00*i

Copyright 1995 by CRC Press, Inc

Page 630: Numerical Library in C for Scientists and Engineers A

Function tested: carpol

Example: Compute the value of r, cos+ and sin+, where rei" 00.3+0.4i.

void main 0 1

void carpol (float, float, float *, float *, float * ) ; float r,c,s;

carpol(0.3,0.4,&r,&c,&s) ; printf("The polar coordinates of 0.3+0.4*i are \nu

" modulus: %-4.2f\n cosine of argument: %-4.2f\nU sine of argument: %-4.2fu,r,c,s) ;

1

Output:

The polar coordinates of 0.3+0.4*i are modulus: 0.50 cosine of argument: 0.60 sine of argument: 0.80

Function tested: commul

Example: Compute the value of (0.1+0.2i)(0.3+0.4i).

void main 0 {

void commul(float, float, float, float, float * , float * ) ; float r,i;

commul(O.l,O.2,0.3,0.4,&r,&i); printf ( " (.l+.2i) * (.3+.4*i) = %-5.2f+%-4.2f*i1',r, i) ;

1 Output:

Function tested: comdiv

Example: Compute the value of (-0.05+0.l i)/(O. 1+0.2i).

void main 0 1

void comdiv(float, float, float, float, float * , float * ) ; float r,i;

comdiv(-0.05,0.1,0.1,0.2,&r,&i); printf ( " ( - .05+.1*i) / (.1+.2*i) = %-4.2f+%-4 .2f*in,r,i) ;

1

Copyright 1995 by CRC Press, Inc

Page 631: Numerical Library in C for Scientists and Engineers A

Output:

Functions tested: lngintadd, lngintsubtract, lngintmult, lngintdivide, lngintpower

Example: Compute the sum, difference, product, and quotient and remainder of u = 3370707070

and v = 444, and also compute v4.

void main 0 I

void lngintadd(int [I, int [I, int [I); void lngintsubtract(int [I, int [I, int [I); void lngintmult (int [I, int [I, int [I ) ; void lngintdivide (int [I , int [I, int [I, int [I ) ; void lngintpower (int [I , int, int [I ) ; int i,u [lo01 ,v[lOOl ,rl [loo] ,r2 [loo] ;

u [O] =5; u[ll=33; u[2] =u[31 =u[~I =~[51 =70; v[01=2; v [ll=4; v[21=44; printf ("\nInput numbers: \n") ; for (i=l; ic=u [o] ; i++) printf ("%4dH, u [il ) ; printf ("\nu) ; for (i=l; ic=v[~] ; i++) printf (n%4d",v[il ) ; printf (lt\n\nadd: " 1 ;

lngintadd (u,v, rl) ; for (i=l; ic=rl[Ol ; i++) printf ("%4d1',rl[il

("\nsubtract: " ) ; lngintsubtract (u,v, r1) ; for (i=l; ic=rl [O] ; i++) printf ("%4d1', rl [il

("\nmultiple: " ) ; lngintmult (u,v, rl) ; for (i=l; ic=rl [Ol ; i++) printf ("%4dn, rl [il printf ("\ndivide: Quotient: 'I) ; lngintdivide (u, v, rl, r2) ; for (i=l; ic=rl [O] ; i++) printf ("%4d", rl [il printf ( " Remainder: " ) ; for (i=l; ic=r2 [01 ; i++) printf ("%4d1',r2 [il ) printf ( I1\npower: " ) ; lngintpower (v, 4, rl) ; for (i=l; ic=rl [Ol ; i++) printf ("%4dH,rl [il ;

I Output:

Input numbers: 33 70 70 70 70 4 44

add: 33 70 70 75 14 subtract: 33 70 70 66 26 multiple: 1 49 65 93 93 90 80 divide: Quotient: 7 59 16 82 Remainder: 2 62 power: 3 88 62 60 24 96

Examples for chapter 2 procedures

Copyright 1995 by CRC Press, Inc

Page 632: Numerical Library in C for Scientists and Engineers A

Function tested: derpol

Example: Compute the derivatives dp(x)/&, for j=0, ..., 3, of

p(x) = -1 + x - 2 2 + 3x3 at the point x = 1.

void main 0 I

void derpol (int, int, float, float [I ) ; float a[41 = (-1.0, 1.0, -2.0, 3.0);

derpol(3,3,1.0,a); printf("The 0-th until and including the 3rd derivatives:"

%-4. of%-4. of%-4. of%-4. Of I t , a [Ol ,a [I] ,a [21 ,a Dl ) ;

1 Output:

The 0-th until and including the 3rd derivatives: 1 6 14 18

Function tested: allortpol

Example: Compute the Laguerre polynomials Li(x), for i=0, ..., 5, which satis@ the recursion

L,(x) = I , L,(x) = x - I &+I($ = (x-2k-I)L k ( ~ ) - pLk-,(x) ( k 1 , 2 , ...)

when x = 0 .

void main 0 I

b[Ol=l.O; for (i=l; i<=4; i++) {

b [il=2*i+l; c [il =i*i;

1 allortpol (5,0.0,b,c,p) ; printf("ALL0RTPOL delivers: %-6.lf%-6.lf%-6.lf%-6.lf%-6.lf%-6.1f",

p101 ,p 111 ,p Dl .pDI ,p[41 .p[51 ; 1 Output:

ALLORTPOL delivers: 1.0 -1.0 2.0 -6.0 24.0 -120.0

Function tested: chepolsum

Example: Compute the polynomial

1 + (1/2)T,(x) + (1/4)T2(x)

Copyright 1995 by CRC Press, Inc

Page 633: Numerical Library in C for Scientists and Engineers A

for i=-1,0,1, where 'T,(x) and T,(x) are the Chebyshev polynomials of first and second degree, respectively.

#include <stdio.h>

yoid main 0 '

float chepolsum (int, float, float [I ) ; float a[31 = I1.0, 0.5, 0.25);

printf ("CHEPOLSUM delivers: %-6.2f%-6.2f%-6 .2ft', chepolsum(2, -1.0,a) ,chepolsum(2,0.0,a) ,chepo~su~(2,~.0,a)) ;

1 Output:

CHEPOLSUM delivers: 0.75 0.75 1.75

Function tested: oddchepolsum

Example: Compute the polynomial

1 + (1/2)T,(x) + (1/5)T3(x) for i=-1,0,1, where T,(x) and T3(x) are the Chebyshev polynomials of first and third degree, respectively.

void main 0 {

float oddchepolsum(int, float, float [I ) ; float a[21 = (0.5, 0.2);

printf("0DDCHEPOLSUM delivers: %-7.2f%-7.2f%-7.2f1', oddchepolsum(1,-1.0,a),oddchepolsum(l,O.O,a~, oddchepolsum(l,l.O,a)) ;

1

Output:

ODDCHEPOLSUM delivers: -0.70 -0.00 0.70

Functions tested: chepol, allchepol

Example: The Chebyshev polynomials of the first kind of degrees 0,1,2 are evaluated at -1,0,1.

void main 0 (

void allchepol (int, float, float [I ) ; float chepol (int, float) ; float t [31 ;

allchepol(2, -1.0, t) ; printf("Delivers:\n %4.0f%4.0f%4.0f",t[01,t[l1,t[21); allchepol(2,0.0,t); printf ("\n %4.0£%4 .Of%4 .Of1', t [O] , t [ll , t [21 ) ; allchepo1(2,1.0, t) ; printf("\n %4.0f%4.0f%4.0f",t[0],t[l],t[21); printf ("\n\n %-6.Of%-6.0f%-6.0f",

Copyright 1995 by CRC Press, Inc

Page 634: Numerical Library in C for Scientists and Engineers A

)

Output:

Delivers : 1 -1 1 1 0 -1 1 1 1

Function tested: fouser

Example: Evaluate 0.5 + cose + sine for 8 = 0, 7112 and n.

void main 0 I

float f ouser (int, float, float [I ) ; float pi, a121 = I0.5, 1.0);

pi=atan(l.O) * 4 .O; printf ("FOUSER delivers: %-7.2£%-7.2f%-7.2f1',

fouser(l,O.O,a), fouser(l,pi/2.0,a) ,fouser(l,pi,a) ; 1

Output:

FOUSER delivers: 1.50 1.50 -0.50

Function tested: jfrac

Example: Compute the value of the n-th convergent of the continued fraction

for n = 7, ..., 10.

void main 0 I

float fouser(int, float, float [I); int i; float p [lll , q 1111 ;

for (i=l; i<=10; i++) { p[il=l.O; q[i1=2.0;

1 q[01=1.0; printf("JFRAC delivers: %11.7f%11.7f%11.7f%11.7f",

jfrac(7,p,q), jfrac(8,p,q), jfrac(g,p,q) ,jfrac(lO,p,q)) ; 1

Copyright 1995 by CRC Press, Inc

Page 635: Numerical Library in C for Scientists and Engineers A

JFRAC delivers: ' 1.4142157 1.4142132 1.4142136 1.4142135

Functions tested: chspol, polchs

Example: Convert the power sum 1+2x+3x2 into a sum of Chebyshev polynomials

bo+blTl(x)+b2T2(x) (by means of a call of polchs) and, as a check, transform the latter representation back into the original power sum (by means of a call of chspol).

void main 0 t

void polchs (int, float [I ) ; void chspol (int, float [I ) ; float a[31 = (1.0, 2.0, 3.0);

printf ( " a [o] a [ll a [21 \ninput : " " %-6.2f%-6.~f%-6.2fH,a[o1 ,a[ll ,a[21) ;

polchs (2, a) ; printf ("\npolchs: %-6 .2f%-6.2f%-6.2fw,a[01 ,a [ll ,a [2] chspol(2, a) ; printf (I1\nchspol: %-6.2f%-6.2f%-6.2f1',a[O1 ,a[ll ,a[21

1

Output:

a[Ol a[ll a[21 input: 1.00 2.00 3.00 polchs: 2.50 2.00 1.50 chspol: 1.00 2.00 3.00

Functions tested: polshtchs, shtchspol

Example: convert the power sum 1+2x+3x2 into a sum of shifted Chebyshev polynomials

bo+blT, '(x)+b2T2 '(x) (by means of a call of polshtchs) and, as a check, transform the latter representation back into the original power sum (by means of a call of shtchspol).

void main 0 \

void polshtchs (int, float 11 ) ; void shtchspol (int, float [I ) ; float a[31;

a[O]=l.O; a[ll=2.O; a[21=3.0; printf ( I 1 a [ol a [ll a [21 \ninput : "

It %-6.2f%-6.2£%-6.2f",a[o] ,a[ll ,a[21); polshtchs (2, a) ; printf ("\npolshtchs: %-6.2f%-6.2f%-6 .2f1',a [OI ,a[ll ,a[21 shtchspol(2, a) ; printf ("\nshtchspol: %-6 .2f%-6.2f%-6.2fn,a [O] ,a[ll ,a [21

1

Output:

a[Ol a[ll a [21 input : 1.00 2.00 3.00 polshtchs: 3.12 2.50 0.38 shtchspol: 1.00 2.00 3.00

Copyright 1995 by CRC Press, Inc

Page 636: Numerical Library in C for Scientists and Engineers A

Functions tested: newgrn, grnnew

Example: Convert the power sum 1+2x+3x2 into its Newton sum of the form

S,"+ (x-x,)S,'+ (x-x,) (x-x JS: (by means of a call of newgrn) and, as a check, transform the latter representation back into the original power sum (by means of a call of grnnew).

void main 0 {

void grnnew (int, float [I , float [I ) ; void newgrn (int, f l0at [I , float [I ) ; float x[2] = (1.0, 2.01, a131 = (1.0, 2.0, 3.0);

printf ( " a [0] a [ll a [21 \ninput: " %7.2f%7.2f%7.2ffl,a[01,a[11,a[21);

grnnew(2,x,a) ; printf (~\ngrnnew: %7.2f%7.2f%7.2fM,a [Ol ,a[ll ,a[21) ; newgrn (2, x, a) ; printf ("\nnewgrn: %7.2f%7.2f%7.2fM,a[01 ,a[ll ,a[21 ) ;

1 Output:

a [Ol a [ll a[21 input : 1.00 2.00 3.00 grnnew: 6.00 11.00 3.00 newgrn: 1.00 2.00 3.00

Function tested: lintfmpol

Example: Convert the power sum 1+2x+3x2 into its power sum in y with x = 2y + 3, and, as a

check, transform the latter representation back into the original power sum (both transformations are carried out by means of a call of lintfmpol).

void main 0 I

void lintfmpol (float, float, int, float [I ) ; float a[31 = (1.0, 2.0, 3.0);

printf ( " a [O] a [ll a [21 \ninput : " %7.2f%7.2f%7.2f'r,a[Ol ,a[ll ,a[21);

lintfmpol(2.0,3.0,2,a); printf("\nlintfmpol: %7.2£%7.2£%7.2£ (power sum in y ) " ,

a[Ol ,a[ll ,a[2l) ; lintfmpol(0.5, -1.5,2,a) ; printf("\nlintfmpol: %7.2f%7.2f%7.2f (power sum in x)",

a[Ol ,a[ll ,a[2l);

Output:

a input : 1. lintfmpol: 34. lintfmpol: 1.

01 a[ll a[21 00 2.00 3.00 00 40.00 12.00 (power sum in y ) 00 2.00 3.00 (power sum inx)

Copyright 1995 by CRC Press, Inc

Page 637: Numerical Library in C for Scientists and Engineers A

Function tested: . intchs

Example: Determine the coefficients {b,} in the expansion

where {T,(x)} are Chebyshev polynomials.

void main 0 1

void intchs (int, float [I , float [I ; float b[51, a[41 = (1.0, 0.5, 0.2, 0.1);

intchs (3,a,b) ; printf ("INTCHS delivers:%8.4£%8.4£%8.4f%8 .4f1',b [I] ,b [21 ,b [31 ,b [41) ;

1 Output:

INTCHS delivers: 0.9000 0.1000 0.0333 0.0125

Examples for chapter 3 procedures

Functions tested: determ, gsselm

Example: Compute the determinant of the 4x4 Hilbert matrix A for which Aij = ll(i+j-1),

i,j=l, ..., 4.

void main 0 l '

float **allocate-real-matrix (int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void gsselm(f1oat **, int, float [I, int [ I , int [I); float determ(f1oat **, int, int) ; int i, j,ri[Sl ,ci[51; float d, **a,aux[81 ;

a=allocate~real~matrix(1,4,1,4); for (i=l; ic=4; i++)

for (j=l; j<=4; j++) a[il [jl=l.O/(i+j-1) ; aux[2] =l.Oe-5; aux[4] =8; gsselm(a, 4, aw,ri, ci) ; d = (aux[3] == 4) ? determ(a,4,aux[ll) : 0.0; printf ("Determinant = %el1, d) ; free-real-matrix(a, l,4,1) ;

I Output:

Determinant = 1.65344e-07

Copyright 1995 by CRC Press, Inc

Page 638: Numerical Library in C for Scientists and Engineers A

Function tested: decsoll

Example: Solve the 4x4 linear system of equations Ax=b, where A is the Hilbert matrix, for which

A,,=ll(i+j-l), i,j=l, ..., 4, and b, = 1/(2+i), i=I ,..., 4, (so that the solution is the third unit vector: (0,0,1 ,O)T).

void main 0

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat * * , int, int, int) ; void decsol (float ** , int, float [I, float [I ) ; int i, j; float **a,b[51 ,aux!41 ;

aux[2] =l.Oe-5; decsol (a,4,aux,b) ; printf ("Solution: %e %e %e %e\nn, b Ill , b [21 , b [3l , b [4l ) ; printf("Sign(Det) =%3.0f\nNumber of eliminations =%3.0f\nU,

aux [ll , auxL31 ) ; free-real-.matrix(a, 1,4,1) ;

1

Output:

Solution: 0.00000e+00 0.00000e+00 1.90000e+00 -0.00000e+00 Sign(Det) = 1 Number of eliminations = 4

Function tested: gsssol

Example: Solve the 4x4 linear system of equations Ax=b, where A is the Hilbert matrix, for which

Alj=ll(i+j-I), i,j=l, ..., 4, and b, = 11(2+i), i=1, ..., 4, (so that the solution is the third unit vector: (0,0,1 ,O)T).

void main 0 I

float **allocate-realmatrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int); void gsssol (float ** , int, float [I, float [I ) ; int i, j; float **a,b [5I ,aux[8I ;

a=allocate-real_matrix(l,4,1,4); for (i=l; ic=4; i++) {

for (j=l; j<=4; j;+) a[il [jl=l.~/(i+j-1); b [il =a [il [31 ;

1 aux[2] =l.Oe-5; aux [41 =8; gsssol (a, 4, aux, b) ; printf ("Solution: %e %e %e %e\nU , b [ll , b [21 , b [31 , b [4l ) ; printf("Sign(Det) =%3.0f\nNumber of eliminations =%3.0f\nn

"~ax(abs(a[i,jl)) = %e\nUpper bound growth = %e\nV,

Copyright 1995 by CRC Press, Inc

Page 639: Numerical Library in C for Scientists and Engineers A

aux[ll,,aux[31 ,aux[51 ,aux[71 ) ; free-real-matrix (a, l,4,1) ;

1 Output:

Solution: 0.00000e+00 1.78814e-07 1.000000e+00 -0.00000e+00 Sign(Det) = 1 Number of eliminations = 4 Max(abs(a[i, jl ) ) = l.OOOCOe+OO Upper bound growth = 1.59619e+00

Function tested: gsssslerb

Example: Solve the 4x4 linear system of equations Ax=b, where A is the Hilbert matrix, for which

Aij=ll(i+j-I), i,j=1, ..., 4, and bi = 1/(2+i), i=1, ..., 4, (so that the solution is the third unit vector: (O,O,l,O)T), and provide an upper bound for the relative error in x.

void main 0 I

float **allocate-real-matrix(int, int, int, int) void free-real-matrix(f1oat **, int, int, int); void gsssolerb(f1oat * * , int, float [I, float [I int i, j; float **a,b[51 ,aux[lZI ;

a=allocate-real_matrix(1,4,1,4) ; for (i=l; ic=4; i++) {

for (j=l; j<=4; j++) a[il [jl=l.O/(i+j-1) ; b [il =a [il [31 ;

1

gsssolerb(a,4, aux, b) ; printf (tlSolution: %e %e %e %e\nU,b [ll ,b [21 ,b [31, b [41 ) ; printf("Sign(Det) =%3.0f\nNurnber of eliminations =%3.0f\nU

"Max(abs(a[i,j])) = %e\nUpper bound growth = %e\nW "1-norm of the inverse matrix = %e\nU "Upper bound rel. error in the calc. solution = %e", aux[ll ,aux[31 ,aux[51 ,aux[71 ,aux[9l ,aux[lll);

free-real-matrix (a, l,4,1) ; 1 Output:

Solution: 0.00000e+00 1.78814e-07 1.000000e+00 -0.00000e+00 Sign(Det) = 1 Number of eliminations = 4 Max (abs (a [i, j I ) ) = 1.00000e+00 Upper bound growth = 1.59619e+00 1-norm of the inverse matrix = 1.36200e+04 Upper bound rel. error in the calc. solution = 2.77896e-08

Function tested: dercinv

Example: Compute the inverse of the 4x4 matrix

void main 0

Copyright 1995 by CRC Press, Inc

Page 640: Numerical Library in C for Scientists and Engineers A

1 float * * a l l o c a t e - r e a l m a t r i x ( i n t , int, int, int); void free-real-matrix(f1oat ** , int, int, int) ; void decinv(f1oat ** , int, float 11 ) ; int i; float **a,aux[41 ;

a=allocate-real_matrix(1,4,1,4) ; a [I] [I] =4.0; a [l] [2] =2.0; a[ll [3l =4.O; a111 141 =1.0; a[2] [I] =3O.O; a [2] [2] =20.0; a[2] [3] =4S.O; a[21 [41 =12 .c; a[3] [I] =20.0; a[31 [2]=15.0; a[31 [31=36.0; a[31 [41=10.0; a [4] [I] =35.0; a [41 [21 =28.O; a [41 [3l =7O. 0; a 141 [41 =20.C; aux[2] =l.Oe-5; decinv(a, 4, aux) ; printf("Calcu1ated inverse:\nU); for (i=l; i<=4; i++)

printf ( I 1 %4.Of%4.Of%4.Of%4.Of\n",a[il [I1 ,a[il [21 ,a[il [31 ,a[il 141); printf ("\naux[ll =%3.0f\naux[31 =%3.0f\n",aux[ll ,aux[31 ) ; free-real-matrix(a, l,4,l) ;

1 Output:

Calculated inverse: 4 -2 4 -1

-30 20 -45 12 20 -15 36 -10 -35 28 -70 20

Function tested: gssinv

Example: Compute the inverse of the 4x4 matrix

void main 0 I

float **allocate-real-matrix(int, int, int, int); void free-realmatrix(f1oat ** , int, int, int) ; void gssinv(f1oat ** , int, float [I ) ; int i; float **a,aux[lOI ;

Copyright 1995 by CRC Press, Inc

Page 641: Numerical Library in C for Scientists and Engineers A

a[i] [1]=4.0; . a[1] [21=2.0; a[11 [31=4.0; a[11 [41=1.0; a[2] [l1=30.0; a[21 [21=20.0; a[21 [31=45.0; a[21 [41=12.0; a[3] [l1=20.0; a131 [21=15.0; a[31 [31=36.0; a[31 [4l=lO.O; a[4] [1]=35.0; a[4] [21=28.0; a[41 [31=70.0; a[41 141 =20.0; aux[21 =l.Oe-5; aux [41=8; gssinv(a, 4, aux) ; printf('Calcu1ated inverse:\nn); for (i=l; ic=4; i++)

printf ( " %4.0f%4.0f%4.0£%4 .0f\nt1,a[i1 [ll ,a[il [21 ,a [il 131 ,a [il [41 ) ; printf("\nAUX elements:\n%e %e %e %e %e\nr',

aux[ll ,aux[3] ,aux[5l ,aux[7] ,aux[91 ) ; free-real-matrix(a, l,4,l) ;

1 Output:

Calculated inverse: 4 -2 4 -1

-30 20 -45 12 20 -15 36 -10 -35 28 -70 20

AUX elements: 1.00000e+00 4.00000e+00 7.00000e+01 1.12529e+02 1.54996e+02

Function tested: gssinvex-b

Example: Compute the inverse of the 4x4 matrix

and obtain an error bound for the computed inverse.

void main 0 r 1

float **a l loca te - rea lmat r ix ( in t , int, int, int); void free-real-matrix(f1oat **, int, int, int); void gssinverb(f1oat **, int, float [I ) ; int i; float **a, aux [l21 ;

a=allocate-real-matrix(1,4,1,4); a[l] [1]=4.0; a[11 [21=2.0; a[ll [31=4.0; a[11 [41=1.0; a [2] [I] -30.0; a [21 (21 =20 .O; a[21 131 =45.O; a [21 [41=12.0; a[3] [1]=20.0; a[31 121 =l5.O; a[31 [33=36.0; a[31 141 =10.0; a[4] [1]=35.0; a[41 [2]=28.0; a[41 [31=70.0; a[41 [41=20.0; aux[O] =aux[2] =aux[6] =l.Oe-14; aux [41=8 ; gssinverb (a, 4, aux) ; printf ("Calculated inverse : \nl') ; for (i=l; ic=4; i++)

printf ( " %4 .Of%4 .Of%4.0£%4 .Of\nrl,a [i] [I] ,a[il [21 ,a [il [31 ,a [il 141 ) ; printf("\nAUX elements:\n%e\n%e\n%e\n%e\n%e\n%e\nl',

aux [I] , aux [3l , aux El , aux [7l , aux [91 , aux [Ill ) ; f ree-real-matrix (a, l,4,1) ;

1

Copyright 1995 by CRC Press, Inc

Page 642: Numerical Library in C for Scientists and Engineers A

Output:

Calculated inverse: 4 -2 4 -1

-30 20 -45 12 20 -15 36 -10 -35 28 -70 20

AUX elements: 1.00000e+00 4.00000e+00 7.00000e+01 1.12529e+02 1.54996ec02 2.22941e-08

Function tested: gssitisol

Example: Solve the 4x4 linear system of equations Ax=b, where A,,=840/(i+j-I), i,j=l, ..., 4, and

b is the third column of A (so that the solution is the third unit vector: (O,O,l,O)T).

void main 0 r 1

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int); void gssitisol (float ** , int, float [I , float 11 ) ; int i, j; float **a, b [5l , aux [I41 ;

a=allocate-real-matrix(1,4,1,4) ; for (i=l: i<=4: i++) {

aux[2] =aux[101 =l.Oe-5; aux[4] =8; aux[121 =S.O; gssitisol (a,4, aux,b) ; printf ("Solution: %e %e %e %e\nll,b [ll , b [21 , b 131 ,b [4l) ; printf("Sign(Det) =%3.0f\nNumber of eliminations =%3.0f\nU

ax (abs (a [i, j 1 ) ) = %e\nUpper bound growth = %e\n" "Norm last correction vector = %e\nn "Norm residual vector = %e\nn, aux[l] ,aux[31 ,aux[51 ,aux[71 ,aux[lll ,aux[131 ) ;

free-real-matrix (a, 1,4,1) ; 1

Output:

Solution: -5.68989e-16 6.71685e-15 1.00000e+00 1.08316e-14 Sign(Det) = 1 Number of eliminations = 4 Max(abs (a [i, j I ) ) = 8.40000e+02 Upper bound growth = 1.34080e+03 Norm last correction vector = 3.57885e-10 Norm residual vector = 1.32202e-11

Function tested: gssitisslerb

Example: Solve the 4x4 linear system of equations Ax=b, where A,=84Ol(i+j-l), i,j=l, ..., 4, and

Copyright 1995 by CRC Press, Inc

Page 643: Numerical Library in C for Scientists and Engineers A

b is the third column of A (so that the solution is the third unit vector: (O,O,l,O)T), and provide a realistic upper bound for the relative error in it

void main 0 {

float **allocate real matrix(int, int, int, int) ; void free-real-matrixTfloat **, int, int, int); void gssitisolerb(f1oat ** , int, float [I , float 11 ) ; int i, j; float **a,b[5] ,aux[141 ;

a=allocate-real_matrix(1,4,1,4) ; for (i=l; ic=4; i++) {

for (j=l; jc=4; j++) a[il [jl=840/(i+j-I.); b [il =a [il [31 ;

1 1

aux[O] =aux[21 =aux[lOI =l.Oe-14; aux [41 =8; aux[6] =aux[81=0.0; aux [121=5.0; gssitisolerb(a,4,aux, b) ; printf ("Solution: %e %e %e %e\nM,b [ll , b [21 ,b [3l , b [41 ) ; printf("Sign(Det) =%3.0f\nNumber of eliminations =%3.0f\nn

"Max(abs(a[i,j])) = %e\n~pper bound growth = %e\nn "Norm calculated inverse matrix : = %e\n" "Upper bound for the relative error : = 9e'\nT7 "Norm residual vector = %e\nM, aux[l] ,aux[3] ,aux[51 ,aux[7] ,aux[9] ,sw:lll ,aux[1.31 1 ;

free-real-matrix (a, l,4,1) ; 1 Output:

Solution: 2.67937e-15 -3.38878e-14 1.00000e+00 -5.68474e-14 Sign(Det) = 1 Number of eliminations = 4 Max(abs (a [i, jl ) ) = 8.40000e+02 Upper bound growth = 1.34080e+03 Norm calculated inverse matrix : = 1,62142e+01 Upper bound for the relative error : = 1.10328e-09 Norm residual vector = 6.80441e-11

Functions tested: chldec2, chlsol2, chlinv2

Example: Solve the 4x4 linear system of equations h = b , where A is the symmetric positive

definite coefficient matrix (the Pascal matrix of order 4) for which

and bi = 2', i=1, ..., 4, and obtain the inverse of A.

void main 0 {

float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free real vector(f1oat *, int) ; void freeIreal--atrix(f1oat **, int, int, int); void chldec2 (float ** , int, float [I ) ;

Copyright 1995 by CRC Press, Inc

Page 644: Numerical Library in C for Scientists and Engineers A

void chlsol2(float ** , ant, float [I ) ; void chlinv2 (float ** , int) ; int i, j ; float **pascal2,*b,*aux;

pascal2=allocate-real-matrix(l,4,1,4); b=allocate-real_vector(1,4); aux=allocate-real_vector(2,3); for (j=l; j<=4; j + + ) (

pascal2 [ll [jl =l. 0; for (i=2; i<=j; is+)

pascal2 [il [j I = (i == j) ? pascal2 [i-11 [jl *2.O : pascal2 [i] [j-11 +pascal2 [i-11 [jl ;

b[jl=pow(2.0, j); I I aux [21 =l. 0e-11; chldec2 (pascal2,4, aux) ; if (aux[3] == 4) (

chlsol2 (pascal2,4, b) ; chlinv2 (pascal2,4) ;

) else printf("Matrix not positive definite");

printf("So1ution with CHLDEC2 and CHLSOL~:\~ %e %e %e %e\nn, b[ll ,b[2l ,b[31 ,b[41);

printf("\nInverse matrix with CHLIW2:\nU); for (i=l; i<=4; i++) {

for (j=l; j < = 4 ; j++) if ( j < i)

printf ( " " ) ;

I f ree-real-matrix (pa-2, l7 4 .a 1) ; f ree-real-vector (b, 1) ; free-real-vector(aux,2);

1

Output:

Solution with CHLDEC2 and CHLSOL2: 0.00000e+00 4.00000e+00 -4.00000e+00 2.00000e+00

Inverse matrix with CHLINV2: 4.00000 -6.00000 4.00000 -1.00000

Functions tested:

Example: Solve the 4x4

definite coefficient

chldecf, chlsoll, chlinvl

linear system of equations Ax=b, where A is the symmetric positive matrix (the Pascal matrix of order 4) for which

and b , = 2', i=1, ..., 4, and obtain the inverse of A.

void main 0 (

float *allocate-real-vector(int, int);

Copyright 1995 by CRC Press, Inc

Page 645: Numerical Library in C for Scientists and Engineers A

void free-real-vector(f1oat * , int); void chlsoll (float [I, int, float [I ) ; void chlinvl (float [I , int) ; int i,j,jj; float *pascall,*b,*aux;

j j=l; for (j=l; j<=4; j++) (

pascall[jjl=l.O; for (i=2: ic=i: i++)

iux[21 =l.Oe-ll; chldecl (pascall, 4, aux) ; if (auxL31 == 4) {

chlsoll (pascall, 4, b) ; chlinvl (pascall, 4) ;

) else Drintf("Matr1~ not ~ositive definiteN):

pri&f ("solution with CHLDECI and CHLSOL~:\~ %e %e %e %e\nn, b[11 ,b121 ,b[31 ,bI41);

printf (tl\nInverse matrix with CHLIW~: \nu) ; for (i=l; i<=4; i++) {

for (j=l; j<=4; j++) if (j c i)

printf ( " " ) ; else

printf (1~%ll.5f'',pascall [ ( (j-1) *j) /2+il) ; printf ("\nm) ;

Output:

Solution with CHLDECl and CHLSOLl: 0.00000e+00 4.00000e+00 -4.00000e+00 2.00000e+00

Inverse matrix with CHLINV1: 4.00000 -6.00000 4.00000 -1.00000

14.00000 -11.00000 3.00000 10.00000 -3.00000

1.00000

Functions tested: chldecsol2, chldeterm2, chldecinv2

Example: Solve the 4x4 linear system of equations Ax=b, where A is the symmetric positive

definite coefficient matrix (the Pascal matrix of order 4) for which

and b , = 2', i=1, ..., 4, and obtain the determinant and the inverse of A.

Copyright 1995 by CRC Press, Inc

Page 646: Numerical Library in C for Scientists and Engineers A

void main 0 I

float *allocate-real-vector(int, int); float **allocate-real-matrix(int, int, int, int); void free-real-vector(f1oat * , int); void free-real-matrix(f1oat **, int, int, int); void chldecsol2(float **, int, float [I, float 11); float chldeterm2 (float **, int) ; void chldecinv2(float ** , int, float [I); int i,j; float determinant,**pascal2,*b,*au;

for (j=l; j<=4; j++) { pascal2 [ll [ j I =1.0; for (i=2; i<=j; i++)

pascal2 [il [jl = (i == j) ? pascal2 [i-11 [jl*2 .O : pascal2 [il [j-11 +pascal2 [i-11 [jl ;

b[j1=pow(2.Orj); ) aux[2] =1.0e-11; chldecsol2 (pascall, 4, a n , b) ; if (aux[31 == 4)

determinant=chldeterm2(pasca12,4); else

printf("Matrix not positive definitew); printf (uSolution with CHLDECSOL~ : \n %e %e %e %e\n" ,

b[11 ,b[21,b[31 ,b[41); printf ( "\nDeterminant with CHLDETERM2 : %e\ntl, determinant) ; for (j=l; j<=4; j++) {

pascal2fll [il=1.0; for (i=2; i<=j; i++)

pascal2[i] [j] = (i == j) ? pascal2 [i-11 [ jl*2.O : pas

1 bhldecinv2 (pascal2,4, aux) ; printf(lt\nInverse matrix with CHLDECINV2 for (i=l; i<=4; i++) (

for (j-1; j<=4; j++) if (j 5 i)

printf ( " " ) ; else

printf ("%11.5fW ,pascal2 [il [jl ) printf ('\nn) ;

1

Output:

Solution with CHLDECSOL2:

Determinant with CHLDETERMI: 1.00000e+00

Inverse matrix with CHLDECINVZ: 4.00000 -6.00000 4.00000 -1.00000

14.00000 -11.00000 3.00000 10.00000 -3.00000

1.00000

Functions tested: chldecsoll, chlldeteml, chldecinvl

Example:

Copyright 1995 by CRC Press, Inc

Page 647: Numerical Library in C for Scientists and Engineers A

Solve the 4x4 linear system of equations Ax=b, where A is the symmetric positive definite coefficient matrix (the Pascal matrix of order 4) for which

and bi = 2', i=1, ..., 4, and obtain the determinant and the inverse of A.

yoid main 0 t

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat * , int); void chldecsoll(float [I, int, float [ I , float [ I ) ; float chldeterml (float [I , int) ; void chldecinvl (float [I , int, float [I ) ; int i,j,jj; float determinant,*pascall,*b,*aux;

j ]=I; for (j=l; j<=4; j++) {

pascall [j jl =l.O; for (i=2; i<=j; i++)

pascall[jj+i-11 = (i == j) ? pascall[jj+i-21*2.0 : pascall[jj+i-2l+pascall[jj+i-jl;

b[j]=pow(2.0, j); jj += j;

1 aux[2] =l.Oe-11; chldecsoll(pascall,4,aux,b); if (auxL31 == 4)

determinant=chldeterml(pascall,4); else

printf("Matrix not positive definite") ; printf("So1ution with CHLDECSOL~:\~ %e %e %e %e\nW,

b[11 ,b[21 ,b[31 ,b[41 1 ; printf(lt\nDeterminant with CHLDETERMI: Be\r.",determinant); j j=l; for (j=l; j<=4; j++) (

pascall [ j j I =l .O; for (i=2; i<=j; i++)

pascall[jj+i-11 = (i == j) ? pascall[jj+i-21*2.0 : pascallijjti-2l+pascall[jj+i-jl ;

jj += j;

chldecinvl (pascall, 4, ~ U X ) ; printf("\nInverse matrix with CHLDECINV~:\~"); for (i=l; i<=4; i++) (

for (j=l; jc=4; j++) if (j < i)

print£ ( " " ) ; else

printf("%ll.5f",pascall[ ( (j-1) *j) /2+il ) ; printf ("\nN) ;

1 free-real-vector(pascal1,l); f ree-real-vector (b, 1) ; free-real_vector(aux,2);

1

Output:

Copyright 1995 by CRC Press, Inc

Page 648: Numerical Library in C for Scientists and Engineers A

Solution with CHLDECSOLI: 0.00000e+00 4.00000e+00 -4.00000e+00 2.00000e+00

Determinant with CHLDETERMI: 1.00000e+00

Inverse matrix with CHLDECINVI: 4.00000 -6.00000 4.00000 -1.00000

14.00000 -11.00000 3.00000 10.00000 -3.00000

1.00000

Function tested: determsym2

Example: Evaluate the deterrri~ant of the matrix

#include cstdio.h> void main ( )

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); void decsym2 (float * * , int, float, int [I , int [I, float I1 ) ; float detmsym2 (float [ I , int, int [ I ) ; int i, j,aux[6] ,p[61; float tol,determinant, **a,detaux[6] ;

a=allocate.-real-matrix (1,5,1,5) ; a[l] [l]=a[ll [2] = -3.0; all] 131 = -18.0; a[l] [41 = -30.0; at11 [51=18.0; a[2] [2] = -1.0; a[2] [31 = -4.0; a[2] [41 = -48.0; a[21 [51=8.0; a[3] [31 = -6.0; a [31 141 - -274.0; a[3] [51=6.0; a[4] [4] =1lg.O; a[41 [5I =19.0; a151 151 =2l6.0; for (i=l; i<=5; i++)

for (j=i+l; j < = 5 ; j++) a[jl [il =a[il [ j l ; tol=l.Oe-6; decsym2 (a,5, tol,aux,p,detaux! ; if (aux[21 == 1)

printf("\nThe rtatrlx is symmetric."); else

printf("The matrix is asymmetric, results are meaningless."); determinant=determsym2(detaux,5,aux); printf("\nThe determinant of the matrix :%8.2f\nM,determinant); free-real-matrix(a, l,5,1) ;

1

Output:

The matrix is symmetric. The determinant of the matrix : 168.00

Function tested: deesolsym2

Example: Solve the system of equations

Copyright 1995 by CRC Press, Inc

Page 649: Numerical Library in C for Scientists and Engineers A

void main 0 I

float **allocate-real-matrix (int, int, int, int) ; void free-real-matrix(f1oat ** , int, int, int) ; void decsolsym2 (float ** , int, float [I , float, int 11 ) ; int i, j,aux[61 ; float tol, **a,b 161 ;

a=allocate-real_rnatrix(1,5,1,5) ; a[l][ll=a[1][21 =-3.0; a[l1[31 = -18.0; a[l] 141 = -30.0; a[ll [51=18.0; a[Zl [21 = -1.0; a[21 [31 = -4.0; ai21 [41 = -48.0; a[3] [31 = -6.0; a[3] [4] = -274.0; a131 [51=6.0; a [4] [41 =119.0; a[41 [51=19.0; a151 151 =216.0; b[1] =327.O; b[21 =29l.O; b[31 =l29O.O; b[41=275.0; for (i=l; ic=5; i++)

for (j=i+l; jc=5; j + + ) a[jl [il=aiil [jl ; tol=l.Oe-6; decsolsym2 (a, 5, b, tol, aux) ; if (aux[2] == 1)

(I1\nThe matrix is symmetric. 'I) ; else

printf("The matrix is asymmetric, results are meaningless."); printf ("\nInertia : %2d, %2d, $2d\nU,aux[3l ,aux[41 ,aux[51 ) ; printf("\nThe computed ~olution:\n%10.5f%10.5f%10.5f%10.5f%10.5f\~"~

b[11 ,b[21 ,b[31 ,b[41 ,b[51); free-real-matrix (a, l,5,1) ;

1

Output:

The matrix is symmetric Inertia : 3, 2, 0

The computed solution: -7.00000 -2.00000 -1.00000 -4.00000 9.00000

Functions tested: lsqortdec, lsqsol, lsqdglinv

Example: Derive the least squares solution of the system of equations

-2x, + x, = 0 - X I + x 2 = 1

X I + x, = 2 2x, + x2 = 2 x, + 2x2 = 3

void main 0

Copyright 1995 by CRC Press, Inc

Page 650: Numerical Library in C for Scientists and Engineers A

I float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); void lsqortdec(f1oat **, int, int, float [I, float [I, int [I); void lsqsol(f1oat **, int, int, float [I, int [I, float [I ) ; void lsqdglinv(f1oat **, int, float [ I , int [I, float 11 ) ; float vecvec (int, int, int, float [I , float [I ) ; int i,piv[31 ; float sum, temp, **a, **c,b[61 ,x[6l ,diag[3] ,aid[31 ,aux[61 ;

a=allocate-real_matrix(l,5,1,2); c=allocate-real_matrix(1,5,1,2); auxL21 =l.Oe-6; ail] [11 =C 111 [11 = -2.0; a[21 [I1 =c221 [I1 = -1.0; a 131 [ll =c [31 111 =l.O; a [41 Ell =c [41 [I] =2.0; a [5l [ll =c [SI [I] =I. 0; a [I] [21 =a [2] [2] =a [31 121 =a [ 4 ] [21 -C ill (23 =c [21 /21 =c 131 (21 =c [41 121 =I. 0; a[51 [21=c[51 [21=2.0; b [l] =xi11 =O.O; b[2]=~[21=1.0; b[3] =x[31=b[41 =~[41=2.0; b[5]=~[51=3.0; lsqortdec (a, 5,2, aux, aid,piv) ; if (aux131 == 2) {

~sqsol (a, 5,2,aid,piv,x) ; lsqdglinv(a, 2, aid,piv,diagl ; sum=O. 0 ; for (i=l; i<=5; i++) {

temp=b [il -c [il [ll *x [ll -c 1 1 1 121 *x [21 ; sum += temp*temp;

1 1

printf ("Aux [2, 3, 51 = %e %e %e\nM "LSQ solution : %e %e\nU "Residue (delivered) : %e\nfl "Residue (checked) : %e\nw ''~iagonal of inverse M'M : %e %e\nN, aux[2] ,aux[3l ,aux[5] ,x[ll ,xDI ,sqrt(vecvec(3,5,O,x,x~~, sqrt (sum) , diag [I1 , diag [21 ) ;

Aux[2, 3, 51 = 1.000000e-06 2.00000e+00 3.31662e+00 LSQ solution : 5.00000e-01 1.25000e+00 Residue (delivered) : 5.00000e-01 Residue (checked) : 5.00000e-01 Diagonal of inverse M'M : 9.52381e-02 1.30952e-01.

Function tested: Ilsqsntdecsd

Example: Derive the least squares solution of the system of equations

-2x, + x, = 0 -x,+ x , = l x, + x, = 2 2x, + x, - 2 x, + 2x, = 3

void main 0 {

Copyright 1995 by CRC Press, Inc

Page 651: Numerical Library in C for Scientists and Engineers A

Copyright 1995 by CRC Press, Inc

Page 652: Numerical Library in C for Scientists and Engineers A

float matmat (int, int, int, int, float ** , float * * ) ; int i, j,piv[31 ; float **a, **c, **t,aid[3] ,aux[6] ;

lsqinv(a, 2, aid,piv) ; t ill [ll =a [ll [ll ; t [z] 121 =a[21 [21 ; t [zl [I] =t [ll [21 =a [ll 121 ; for (j=l; jc=2; j++)

for (i=l; ic=5; i++) a[il [jl=matmat(l,2,i, j,c,t) ; printf ("Aux[2, 3, 51 = %e %e %e\nl'

"\n~nverse:\n %e %e\n %e %e\nm "\nCheck: St * (S * T) :\n %e %e\n %e %e\n", aux[2] ,aux[3] ,aux[51 ,t [I] [ll ,t [I] 121 ,t [21 111 ,t [21 121, tammat(1,5,1,1,c,a) ,tammat(1,5,1,2,c,a), tammat(l,5,2,l,c,a),tammat(l,5,2,2,c,a));

1

Output:

Inverse : 9.52381e-02 -2.38095e-02 -2.38095e-02 1.30952e-01

Check: S' * (S * T) : 1.00000e+00 2.98023e-08 -7.45058e-09 1.000000e+00

Functions tested: lsqdecomp, lsqrefsol

Example: Minimize 11 b-Ax 11 ,, where xsR3 and

subject to the constraint

#include <stdio.h>

void main 0 {

Copyright 1995 by CRC Press, Inc

Page 653: Numerical Library in C for Scientists and Engineers A

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(fl0at ** , int, int, int); void lsqdecomp(f1oat **, int, int, int, float [I, float [I, int [I ) ; void Isqrefsol(float **, float **, int, int, int, float [I, float [I,

int [I, float [ I , float * , float [I, float [I); int n,m,nl,i,j,ci[ll; float ldx, **a, **qr,aux[81 ,b[61 ,res[61 ,aid[41 ,x[41 ;

Output:

The solution vector: 1.00000e+00 2.00000e+00 3.00000e+00

The residual vector: -2.25629e-09 9.10484e-09 2.28816e-09 1.00000e+00

Number of iterations: 2 Norm last correction of x: 3.87508e-08

Function tested: solovr

Example: Determine that xcRS with minimum 11 x (1 , which minimizes 11 Ax-b 11 ,, where

Copyright 1995 by CRC Press, Inc

Page 654: Numerical Library in C for Scientists and Engineers A

void main 0

float **allocate-real-matr~x (int, int . int, int) ; void free-realmatrix(f1oat ** , int, int, int); int solovr (float * * , int, int, float [I , fioat [I ) ; int i; float **a, b [91 ,em 181 ;

a=allocate-real_matri~(1,8~1,5) ; a [I] [I] =22; a [ll [2] =a [21 131 =lo. 0; a [l] [3] =a 171 [I] =a [81 [51 =2.0; a [l] [4] =a [3] [5] =3.0; a [l] [5] =a [2] [2] =7.0; a [21 111 =l4.O; a 121 [51 =8. 0; a[2] [4] =a[8] [3]=0.0; a[3] [1l=a[31 [31=al61 151 = -1.0; a131 [2]=13.0; a[3] [41 = -11.0; a[41 [I] = -3.0; a[4] [21 =a[41 [41 =a[5l [41 =a[81 [41 = -2.0; a [4] [31 =l3.O; a [41 [5l =a [5l 151 =a [ 8 1 [I] =4.0; a [51 [I] =a [61 111 =9.0; a[5] [2] =8 .O; a[51 131 =a[61 [21 =a[71 151 =1.0; a[61 [31 = -7.0; a[6] [4] =a[7] [4]=a[8] [2] =5.O; a[7] [2] = -6.0; a[71 [31=6.0; b[l] = -1.0; b[2]=2.0; b[3]=b[7]=1.0; b[41=4.0; b[51=b[81=0.0; b[6] = -3.0; em[01 =l.Oe-14; em[2] =l.Oe-12; em[4] =80.0; em[6] =l.Oe-10; i=solovr (a, 8,5, b, em) ; printf("Number of singular values not found : %2d\nU

"Norm : %e\nMaximal neglected subdiagonal element : %e\nn "Number of iterations : %3.0f\nRank : %3.0f\n\n~olution vector" "\n %13.6e\n %13.6e\n %13.6e\n %13.6e\n %13.6e\nH, i,em[ll ,em[3l ,em[5l ,em[71 ,b[ll ,b[21 ,b[31 ,b[41 ,bl51) ;

free-real-matrix(a, l,8,1) ; 1

Output:

Number of singular values not found : 0 Norm : 4.40000e+01 Maximal neglected subdiagonal element : 2.75552e-16 Number of iterations : 5 Rank : 3

Solution vector -8.33333e-02 -1.25858e-17 2.50000e-01 -8.33333e-02 8.33333e-02

Function tested: solund

Example: Determine that XER' with minimum 11 x 11 , which minimizes 11 ~ ~ x - b 11 ,, where

Copyright 1995 by CRC Press, Inc

Page 655: Numerical Library in C for Scientists and Engineers A

yoid main 0 t

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); int solund(f1oat **, int, int, float [I, float [I ) ; int i; float **a,b [91 ,em181 ;

a=allocate-real-matrix(1,8,1,5) ; a [l] [I] =22; a [l] [2] =a [2] [3] =10.0; a [ll [3l =a [7] [l] =a [81 [51 =2 .o; a[l] [4] =a[3] [51 =3 .O; a [l] [51 =a[21 [21 ~ 7 . 0 ; a[21 111 =l4.0; a121 [51 =8.0; a[2] [4] =are] [31=0.0; a[3] [l] =a[3] [3]=a[6] [5] = -1.0; a[3] [21 =l3.0; a[31 [41 = -11.0; a[41 111 = -3.0; a [41 121 =a141 [41 =a[Sl [41 =a[81 [41 = -2.0; a [4] [3] =13.0; a [4] [51 =a 151 151 =a 181 [I] =4.0; a [51 [ll =a [61 [I] =9.0; a[5] [2]=8.0; a151 [3l=a[61 [21=a[71 [5]=1.0; a[61 [31 = -7.0; a [6] [41 =a[7] [41 =a[8] [2] =s.o; a[71 [2] = -6.0; a[71 131 =6.O; b[ll = -1.0; b[21=2.0; b[31=1.0; b[41=4.0; b[51=0.0; em[O] =l.Oe-14; em[2] =l.Oe-12; em141 =8O.O; emf61 =l.Oe-10; i=solund(a, 8,5,b, em) ; printf(ItNumber of singular values not found : %2d\n11

"Norm : %e\n~aximal neglected subdiagonal element : %e\nu "Number of iterations : %3.0f\nRank : %3.0f\n\n~olution vector" "\n %13.6e\n %13.6e\n %13.6e\n %13.6e\n %13.6e\n %13.6eM "\n %13.6e\n %l3. 6e\nU, i, em [l] ,em 131 ,em [s] ,em 171 , b[l] ,b[21 ,b[31 ,b[41 ,b[51 ,b[61 ,b[71 ,b[81);

f ree-real-matrix (a, l,8,1) ;

Output:

Number of singular values not found : 0 Norm : 4.40000e+01 Maximal neglected subdiagonal element : 2.75552e-16 Number of iterations : 5 Rank : 3

Solution vector 1.64103e-02 1.48077e-02 -4.83974e-02 1.00000e-02 -6.79487e-03 1.16026e-02 3.00000e-02 -8.39744e-03

Function tested: hornsol

Copyright 1995 by CRC Press, Inc

Page 656: Numerical Library in C for Scientists and Engineers A

Example: With the 8x5 matrix A of rank 3 given by

the vectors v,&R5 (j=4,5) defining the complementary column subspace in which xeR5 must lie for the condition Ax=O to hold, and the vectors u , ~ (j=4,5) defining the complementary row subspace in which uT&R8 must lie for the condition xTA=O to hold are determined.

void main 0 {

float **allocate-real-matrix(int, int, int, int); void f ree-real-matrix (f loat ** , int, int, int) ; int homsol(f1oat ** , int, int, float ** , float [I ) ; int i, j; float **a, **v,em[8] ;

a=allocate-real-matrix (1,8,1,5) ; v=allocate-real-matrix (1,5,1,5) ; a [I] [I] =22; a [I] 121 =a[2] [3] =10.0; a111 [31 =a[71 [I] =are1 [51 =2.0; a[l] [41 =a[3] 151 =3 .O; a[l] 151 =a[21 [2] =7.0; a[21 111 =14.0; a[21 [51=8.0; a[2] 141 =a[8] [3]=0.0; a[3] [1]=a[31 [3]=a[6] [5] = -1.0; a131 [2]=13.0; a131 141 = -11.0; a[41 [I] = -3.0; a[41 121 =a141 141 =a151 [41 =a[81 [41 = -2.0; a[41 [31 =13.0; a[4] [51 =a[51 [51 =a181 [11=4.0; a[51 [11=a[61 [11=9.0; a [5] [2] =8.0; a [51 [31 =a[61 [21 =a[7] [5] =1.0; a[61 [31 = -7.0; a[61 [4l=a[7] [41 =a[81 [2]=5.0; a171 [2] = -6.0; a[71 [31 =6.0; em[O] =l.Oe-14; em[2] =l.Oe-12; em[4] =80.0; em[6] =l.Oe-10; i=homsol (a, 8,5,v,em) ; printf("Number of singular values not found : %2d\nM

"Norm : %e\nMaximal neglected subdiagonal element : %e\nU "Number of iterations : %3.0f\nRank : %3.0f\nn, i,em[ll ,em[3l ,em[51 ,em[71);

for (j=em[71+1; j<=5; j++) { printf("\nColumn number : %2d\nU,j); for (i=l; i<=5; i++)

printf(" %13.6e %13.6e\nv,a[iI [jl ,v[il [jl); print£(" %13.6e\n %13.6e\n %13.6e\nU.

Output:

Number of singular values not found : 0 Norm : 4.40000e+01 Maximal neglected subdiagonal element : 2.75552e-16 Number of iterations : 5 Rank : 3

Copyright 1995 by CRC Press, Inc

Page 657: Numerical Library in C for Scientists and Engineers A

Column number : 4 3.47086e-01 4.19095e-01 -6.07234e-01 -4.40509e-01 1.22075e-01 5.20045e-02 6.18826e-01 -6.76059e-01 -4.63444e-03 -4.12977e-01 3.34099e-01 -3.35284e-02 -1.35472e-02

Column number : 5 -2.55331e-01 -0.00000e+00 -1.73598e-01 4.18548e-01 -2.20812e-01 3.48790e-01 4.11655e-02 2.44153e-01 9.20442e-01 -8.02217e-01 -2.88960e-02 6.13276e-02 -4.9058l.e-02

Function tested: psdinv

Example: Compute the generalized inverse of the 8x5 matrix given by

void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix (f laat ** , int, k t , int) ; int psdinv(f1oat **, inc, int, float [I ) ; int i, j; float **a, em [El ;

a=allocate-real_matrix(l,8,1,5) ; a [I] [I] =22; a [l] [2] =a [2] [3] =lo. 0; a [l] 131 =a [71 [I] =a [El [5l =2.0; a [I] [4] =a 131 [51 =3.0; a 111 [51 =a [21 [21 =7.0; a I21 [ll =l4.O; a 121 [51 =8.0; a[2] [4]=a[8] [3]=0.0; a131 [l]=a[3] [3l=a[6l 151 = -1.0; a[31 [21 A3.O; a[3] [4] = -11.0; a[41 [I] = -3.0; a [4] [21 =a [41 141 =a 151 L41 =a 181 [41 = -2.0; a [4] [3] =13.0; a [4] [5] =a [5] [5] =a [El [l] =4.0; a 151 [ll =a [61 111 =9.0; a[5] [2] ~ 8 . 0 ; a[5] [3] =a[6] [2] =a[7] [5] =1.0; a[61 [31 = -7.0; a[6] [4] =a[7] [4]=a[8] [2]=5.0; a[7] [a] = -6.0; a[71 [3l =6.O; em[O] =l.Oe-14; em121 =l.Oe-12; em[4] =8O.O; em[6] =l.Oe-10; i=psdinv(a, 8,5, em) ; printf("Number of singular values not found : %2d\nu

"Norm : %e\nMaximal neglected subdiagonal element : %e\nn "Number of iterations : %3.0f\n~ank : %3.0f\n1', i,em[ll ,em[31 ,em[51 ,em[71 ) ;

Copyright 1995 by CRC Press, Inc

Page 658: Numerical Library in C for Scientists and Engineers A

printf("\nTranspose of pseudo-inverse, first three columns:\n"); for (i=l; i<=8; i++)

printf ( " %13.6e %13.6e %13.6e\nt',a[il [I] ,a[il 121 ,a[il [31 ) ; printf("\nLast two columns:\n") ; for (i=l; i<=8; i++)

printf (I1 %13.6e %13. 6e\n1', a [il [41 ,a [il 151 ) ; free-real-matrix(a, 1,8,1) ;

1

Output:

Number of singular values not found : 0 Norm : 4.40000e+01 Maximal neglected subdiagonal element : 2.75552e-16 Number of iterations : 5 Rank : 3

Transpose of pseudo-inverse, 2.11298e-02 4.61538e-03 9.31090e-03 2.21154e-03 -1.10978e-02 2.74038e-02 -7.91667e-03 -5.00000e-03 5.51282e-03 9.80769e-03 1.43189e-02 -2.59615e-03 4.89583e-03 -1.50000e-02 1.50641e-03 7.40385e-03

first three columns: -2.10737e-03 2.05288e-02 -3.88622e-03 3.37500e-02 -8.97436e-04 -2.01362e-02 1.53125e-02 -1.69872e-03

Last two columns: 7.60417e-03 -2.08333e-04 -2.76042e-02 -5.41667e-03 -5.00000e-03 1.28125e-02 1.23958e-02 -5.00000e-03

Functions tested: solbnd, decbnd, determbnd

Example: Solve the system of equations

2x, - x, = 1 -x, + 2x2 - X3 = 0

- x, + 2x3 - x, = 0 - x3 + 2x, - x, = 0

- x, + 2x5 = I and evaluate the determinant of the coefficient matrix.

void main 0

void decbnd (f loat [I , int, int, int, float [I , float [I , int [I ) ; void solbnd(f1oat [I, int, int, int, float [I, int [I, float [I ) ; float determbnd(f1oat [I, int, int, int, int); int i,rowind[61 ; float band [l41 ,mult [51 ,right [61 , aux [61 ;

for (i=l; i<=13; i++) band[il = (((i+1)/3)*3 < i) ? 2.0 : -1.0;

right [ll =right [5l =l. 0; right [2] =right [31 =right [41 =O. 0; aux[2] =l.Oe-12; decbnd (band, 5,l, 1, aux, mult, rowind) ; if (auxl31 == 5 ) {

solbnd (band, 5,l, 1, mult,rowind, right) ;

Copyright 1995 by CRC Press, Inc

Page 659: Numerical Library in C for Scientists and Engineers A

printf("De1ivers: %8.4f %8.4f %8.4f %8.4f %8.4f\nm "~eterminant is %e\nl', right [I] ,right [21 ,right [31 , right [4], right [5] ,determbnd(band,S, l,l,aux[ll ) ) ;

1 1

Output:

Delivers: 1.0000 1.0000 1.0000 1.0000 1.0000 Determinant is 6.00000e+00

Function tested: decsolbnd

Example: Solve the system of equations

- - 2x / - x , -x, + 2x, - x, = 0

- x, + 2x, - x, = 0 - x, + 2x, - x, = 0

- x, + 2x5 = 1 and evaluate the determinant of the coefficient matrix.

void main 0

void decsolbnd(f1oat [ j , int, int, knt, float [ I , float [I ) ; float determbnd (f loat [I , int, int, int, int) ; int i; float band [14] , right [6l , aux [61 ;

for (i=l; i<=13; i++) band[i] = (((i+1)/3)*3 : i) ? 2,0 : -1.0;

right [ll =right [51 =I. 0; right [2] =right [31 =right [4] =O. 0; aux [21 =l. 0e-12; decsolbnd (band, 5,i, 1, aux, r i g h t ) ; if !aux[31 == 5)

printf("De1ivers: %8.4f %8.4f %8.4£ %8.4f %8.4f\nU "~eterminant is %e\,nU, right [ll ,right [2] ,right [31 , right [4] ,right [5] ,determbnd(band,5,1,l,aux[ll ) ;

Output:

Delivers: 1.0000 1.0000 1.0000 1.0000 1.0000 Determinant is 6.00000e+00

Function tested: decsoltri

Example: Solve the system of equations Ax=h, where A is a 3 0 x 3 0 tridiagonal matrix for which

A,+/ , , = 2*6, Ai,, = i+10, = i, and h is the second column of A (the solution is given by the second unit vector).

#include cmath.h> #include cstdio.h>

void main 0 (

void decsoltri (float I1 , float [ I , float [I , int,

Copyright 1995 by CRC Press, Inc

Page 660: Numerical Library in C for Scientists and Engineers A

float [I, float [I) ; float vecvec (int, int, int, float [I , float [I ) ;

for (i=l; ic=30; i++) { sub [il =i*2; super [il =i; d [il =i+lO; b[il =O.O;

1 b[l]=1.0; b[2]=12.0; b[3]=4.0: aux[2] =l.Oe-6; decsoltri (sub,d, super, 30,aux,b) ; b[21 -- ; printf ("AUX[3] and AUX [51 : %e %e\nU

"Error in the solution: %e\nv, aux[3] ,aux[Sl ,sqrt(vecve~(l~30,0,b,h)) ) ;

1

Output:

AUX [31 and AUX [Sl : 3.00000e+01 1.24000e+02 Error in the solution: 0.00000e+00

Function tested: soltripiv

Example: Solve the two systems of equations Ax-hl, Ax=bZ, where A is a 30x30 tridiagonal

matrix for which = 2*i, A,,, = i+10, A,,,, - i, and b l , b2 are the second and third column of A, respectively, (the solutions of the systems are given by the second and third unit vector, respectively).

void main 0 I 1

void dectripiv(f1oat [I , float [I, float [ I , lnt, float [I, float [ I , lnt [ J ) ;

void soltripiv(f1oat [I, float [I, float [ I , lnt, float [I , int [ I , float [I ;

float vecvec (int, int, int, float [ I , float 11 ) ; ~ n t i,piv[301 ; float d [31] ,sub [31] ,super [3l] . aad 1311 , b1 [311 , b2 [311 , aux 161 ;

for (i=l; i<=30; i++) { sub [il =i*2; super [il =i; d [il =i+lO; bl [i] =b2 [il =O. 0;

1 b1[1]=1.0; b1[21=12.0; b1[31=4.0; b2[2]=2.0; b2[31=13.0; b2[41=6.0; aux[2] =l.Oe-6; dectripiv(sub, d, super, 30, aid, aux,piv) ; soltripiv(sub,d, super, 30,aid,piv,bl) ; soltripiv(sub, d, super, 30, aid,piv, b2) ; b1[21--; b2[31--; printf ("AUX [3] and AUX [5] : %e %e\nw

"Error in bl: %e\n~rror in b2: %e\nfl,aux[3j,aux[5], sqrt(vecvec(l,30,0,bl,bl)) , ~ q r t i v e c ~ v e c ( 1 , 3 ~ ~ O , b 2 , b 2 ) ) ) ;

1

Output:

AUX [31 and AUX [SI : 3.00000e+01 1.24000e+02 Error in bl: 0.00000e+00

Copyright 1995 by CRC Press, Inc

Page 661: Numerical Library in C for Scientists and Engineers A

Error in b2: 0.00000e+00

Function tested: decsoltripiv

Example: Solve the system of equations Ax=b, where A is a 30x30 tridiagonal matrix for which

A,+,,, = 2*i, A,,, = i+lO, = i , and b is the second column of A (the solution is given by the second unit vector).

#include cmath.h> #include cstdio.h>

void main 0

void decsoltripiv(f1oat [I, float [I, float 1 1 , int, float [I, float [I);

float vecvec(int, int, int, float [ I , float [I ) ; int i; float d[311 ,sub[311 ,super[311 ,b[311 ,aux[61 ;

for (i=l; ic=30; i++) { sub [il =i*2; super [il =i; d [ i l =i+lO; b[il=O.O;

b[1]=1.0; b[21=12.0; b[31=4.0; aux[2] =l.Oe-6; decsoltripiv(sub,d,super,30,aux,b); b[21 --; print£ ("AUX [31 and AUX [S] : %e %e\;,I1

"Error in the solution: %e\n , aux[3] ,aux[S] ,sqrt(vecvec(l,30,0,b,b)));

1 Output:

AUX [3l and AUX [51 : 3.00000e+01 1.24000e+02 Error in the solution: 0.00000e+00

Functions tested: chlsolbnd, chldecbnd, chldetermbnd

Example: Solve the system of equations

Zx, - x , = 1 -XI + 2x, - x, = 0

- x, + 2x3 - x, = 0 - x, + 2x, - x, = 0

- x, + 2x, = 1 and evaluate the determinant of the coefficient matrix.

void main 0 {

float *allocate-real-vector(int, int) ; void free-real-vector(f1oat *, int); void chldecbnd (float [I , int, int, float [I ) ; void chlsolbnd(f1oat [I, int, int, float [I); float chldeterrnbnd(f1oat [I, int, int); int i;

Copyright 1995 by CRC Press, Inc

Page 662: Numerical Library in C for Scientists and Engineers A

float *symband,*right,*aux;

for (i=l; i<=9; i++) symband[i] = ((i/2)*2 < i) ? 2.0 : -1.0;

right [ll =right [51 =l. 0; right [21 =right [3] =right [41 =O. 0; aux[2] =l.Oe-12; chldecbnd(symband, 5,1, aux) ; if (aux[31 == 5) {

chlsolbnd(symband, 5,1, right) ; printf("De1ivers: %8.4f %8.4f %8.4f %8.4f %8.4f\nn

"Determinant is %e\nU, right [ll ,right [21 ,right [3l , right [41 , right [51 , chldeterrnbnd (symband, 5,l) ) ;

1 free-real-vector(symband,l); free-real-vector(right,l) ; free-real-vector (aux, 2) ;

1

Output:

Delivers: 1.0000 1.0000 1.0000 1.0000 1.0000 Determinant is 6.00000e+00

Functions tested: chldecsolbnd, chldetermbnd

Example: Solve the system of equations

2x, - x, = I -x, + 2x, - x, = 0

- x, + 2x, - x, = 0 - x, + 2x, - x, = 0

- x, + 2x, = I and evaluate the determinant of the coefficient matrix.

void main 0 (

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void chldecsolbnd(f1oat [I, int, int, float [I, float [I); float chldetermbnd(f1oat [I, int, int); int i; float *symband,*right,*aux;

for (i=l; i<=9; i++) symband[il = ((i/2)*2 < i) ? 2.0 : -1.0;

right [l] =right [51 =l. 0; right [2] =right [3] =right [41 =O. 0; aux[2] =l.Oe-12; chldecsolbnd(symband,S,l,aux,right); if (aux[3l == 5) (

printf("De1ivers: %8.4f %8.4f %8.4f %8.4f %8.4f\nU "Determinant is %e\nW , right [ll , right [21 , right [31 , right [4] ,right [51 , chldeterrnbnd (symband, 5,l) ) ;

kree-real-vector (symband, 1) ;

Copyright 1995 by CRC Press, Inc

Page 663: Numerical Library in C for Scientists and Engineers A

free-real-vector(rignt,l); free-real-vector (aux, 2) ;

1 Output:

Delivers: 1.0000 1.0000 1.0000 1.0000 1.0000 Determinant is 6.00000e+00

Function tested: decsolsymtri

Example: Solve the system of equations Ax=b, where A is a lOOxlOO symmetric tridiagonal

matrix for which A,+,,i = = 2*1, = i, and b is the second column of A (the solution is given by the second unit vector).

void main 0 I

void decsolsymtri(f1oat [I, float [I, int, float [I, float [ I ) ; float vecvec (int, int, int, float [I , float [I ) ; int i; float d [loll , co [loll , b [lo11 , aux[Sl ;

for (i=l; i<=100; i++) { d [il =i; co [il =i*2; b[il=O.O;

b[l]=b[2]=2.0; b[31=4.0; aux[2] =l.Oe-6; decsolsymtri (d, co, 100, aux, b) ; b[2] --; printf ("AUX [31 and AUX[5] : %e %e\nM

"Error in the solution: %e\nn, aux[3] ,aux[5] ,sqrt (vecvec(1,100,0,b,b) ) ) ;

1 Output:

AUX [3] and AUX [51 : 1.00000e+02 4.93000e+02 Error in the solution: 0.00000e+00

Function tested: conjgrad

Example: Solve the system of equations Ax=b, b&RI3, where

= A , . = 2 , A i j = Ofor l i - j l> l , Ai+l,i , , ,+I

and b , = I, bi = 0 (i=2 ,..., 12), b,, = 4, using x=(O,O ,..., 0) as an initial approximation to the solution.

void a(f1oat x[], float b[l) I

int i; b [O] =2. O*X [Ol -X [ll ; for (i=l; ic=ll; i++) b [i] = -x [i-11+2.0*x [il -x [i+l] ; b [121=2.0*~[121 -X [ill ;

1

Copyright 1995 by CRC Press, Inc

Page 664: Numerical Library in C for Scientists and Engineers A

fnt moveon(int iter, float norm) t

return (iterc20 && norm>l.Oe-10); 1 void main 0 I

for (i=O; i<=12; i++) x [il =b[il =O. 0; b[0]=1.0; b[121=4.0; conjgrad(a,x,b, 0,l2,moveon, &it, &no) ; printf("Delivers:\nIT = %3d, NO = %e\nM

"\n X ~\n\n" , it, no) ; for (i=O; i<=12; i++) printf ( " %+e %+e\nU,x [il , b Cil ) ;

1 Output:

Delivers : IT = 13, NO = 1.83603e-14

Function tested: eqilbrcom

Example: Equilibrate the 3x3 matrix

void main 0

float **allocate-real-matrix (int, int, int, intj ; void free-real-matrix(f1oat ** , int, int, int); void inimat(int, int, int, int, float * * float); void eqilbrcom(float ** , float ** , int, kloat [I , float 11 , int I j ) ; int inter [41 ; float **al, **a2,em[81 ,d[41 ;

Copyright 1995 by CRC Press, Inc

Page 665: Numerical Library in C for Scientists and Engineers A

em[01=5.0e-7; em[61=10.0; inimat(l,3,1,3,al,O.O); inimat(1,3,1,3,a2,0.0); a1 [ll [11 =a1 l21 [21 =I. 0; all31 [31=2.0; a2f11 [31=pow(2.0,10.0) ; a2131 [l]=pow(2.0,-10.0); eqilbrcom(a1, a2,3, em, d, inter) ; printf("Equi1ibrated matrix:\n %2.0f %2.0f %2.0f\nW - %?..of %2.0f I\n %2.0f I %2.0f\nU

"\nEM [71 : %2.0f\nD[1:31 : %2. Of %5. Of %5. Of \nl' "INTER[1:3] : %2d %5d %5d\nW,al fll 111 ,a1111 121, a1 [I] [31 ,a1 121 [l] ,a1 [21 [21 ,a1 [31 111 ,a1 [31 [31 ,em[71, d [I] , d [2] , d [3l , inter [l] , inter [21 ,inter [31 ;

free-real-matrix (al, 1,3,1) ; free-real-matrix (a2,1,3,1) ;

1

Output:

Equilibrated matrix: 1 0 0 0 1 1 0 1 2

Function tested: hshhrmtri

Example: Reduce the 4x4 complex matrix

to real tridiagonal form, and estimate the value of 11 A 11 .

void main 0

float **allocate-real-matrix (int , int , int , int) ; void free-real-matrix(f1oat **, int, int, int); void hshhrmtri (float **, int, float [I, float [I , float [ I ,

float [I, float [I, float [I); void inimat(int, int, int, int, float **, float); float **a, d [Sl , b [51 , bb [51 , tr [4] ,ti [41 ,em [21 ;

a=allocate-real_matrix(1,4,1,4) ; inimat(l,4,1,4,a,O.O) ; a [ll 111 =a 121 121 =3.0; a [I] 121 =a [31 [31 =a [31 [41 =a [41 [41=1.0; a[31 I21=2.0; a[41 [I1 = -2.0; em[01 =l. 0e-6; hshhrmtri (a.4.d.b.bb.em. tr, ti) : printf ( l l ~ s ~ ~ ~ ~ ~ . delivkrs(n\ki) [l:41 : %7.3f %7.3f %7.3f %7 .3f\ngs

"B[1:31 : %7.3f %7.3f %7.3f\nw "BB[1:3] : %7.3f %7.3f %7.3f\nv

Copyright 1995 by CRC Press, Inc

Page 666: Numerical Library in C for Scientists and Engineers A

Output:

HSHHRMTRI delivers

Functions tested: valsyrntsi, vecsymtri

Example: Compute the largest and second largest eigenvalues, and their corresponding

eigenvectors, of the 4x4 matrix A for which A,,=2 (i=1,2,3,4), A ,,-, 1 (i=2,3,4), A,=O ( I i-j 122).

void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void valsymtri(f1oat [I, float [I, int, int, int,

float [I, float [I) ; void vecsymtri (float [I , float [ I , int, int, int,

float [I , float **, float [I ; float b[51 ,d[51 ,bb[4] ,val[31 ,em[lOl ,**vet;

vec=allocate-realmatrix(l,4,1,2) ; em [Ol =l. 0e-6; em [ll=4.0; em [21 =l.Oe-5; em[4] =l.Oe-3; em[6] =l.Oe-6; em[8]=5.0; d[l] =d[21 =d[31 =d[41 =2 .O; b[4]=0.O; b[l]=b[2I=b[31 = -1.0; bb[l] =bb[21 =bb[31=1.0; valsymtri (d,bb,4,1,2,valrem) ; vecsymtri(d,b,4,1,2,val,vec,em); printf(I1The eigenvalues:\n %12.5e %12.5e\n\n~he eigenvectors:\nl'

" %12.5e %12.5e\n %12.5% %12.5e\n %12.5e %12.5e\nN %12.5e %12.5e\nV

I1\nEM [7] = %e\nEM [3] =%3. Of \nEM [5] =%3.0f E EM [9] =%3.0f \n" , val [I] ,va1[21 ,vec [ll 111 ,vec [ll [21 ,vec 121 [I1 ,vet [21 [21 , vec [31 [l] ,vec 131 [21 ,vec [41 [ll ,vec 141 [21 , em[7] ,em[3l ,em[51 ,em[91 ) ;

free-real-matrix (vec, 1,4,1) ; I Output:

The eigenvalues: 3.6180e+00 2.6180e+00

The eigenvectors: -3.7175e-01 6.0150e-01 6.0150e-01 -3.7175e-01 -6.0150e-01 -3.7175e-01 3.7175e-01 6.0150e-01

Copyright 1995 by CRC Press, Inc

Page 667: Numerical Library in C for Scientists and Engineers A

Function tested: eigsyml

Example: Compute the two largest eigenvalues and corresponding eigenvectors of the 4x4 matrix

A for which Ai j = ll(i+j-I), ij=1,2,3,4.

void main 0

float *allocate-real-vector (int, int) ; float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat *, int) ; void free-real-matrix(f1oat **, int, int, int); void eigsyml(f1oat [I, int, int, float [I, float ** , float [I ) ; int i, j; float a1111 ,val[3l ,em[lOl, **vet;

vec=allocate-real_matrix(1,4,1,2); em[0] =l.Oe-6; em[2]=1.0e-5; em[4] =l.Oe-3; em[6] =l.Oe-5; em181 =5.0; for (i=l; i<=4; i++)

for (j=i; j<=4; j++) a[ (j*j-j) /2+il =l.O/(i+j-1) ; eigsyml(a,4,2,val,veC,em); printf("The eigenvalues:\n %12.5e %12.5e\n\n~he eigenvectors:\nn

l1 %12.5e %12.5e\n %12.5e %12.5e\n %12.5e %12.5e\nu %12.5e %12.5e\n\nEM [I] = %e\nl1

"EM [7] = %e\nEM [3] =%3. Of \nEM [5] =%3.0f E EM [9] =%3. of \n" , val [I] ,va1 [2] ,vec [I] [I] ,vec [l] [21 , vec 121 111 ,vec [21 121 , vec [31 [ll ,vec [31 121 ,vec [41 [ll ,vet [41 [21 , em[l] ,ern[7] ,em[31 ,em[51 ,ern[91 ) ;

free-real-rnatrix(vec,1,4,1); 1 Output:

The eigenvalues: 1.5002e+00 1.6914e-01

The eigenvectors: -7.9261e-01 5.8208e-01 -4.5192e-01 -3.7050e-01 -3.2242e-01 -5.0958e-01 -2.5216e-01 -5.1405e-01

Function tested: symeigimp

Example: Determine approximations to the eigenvalues and eigenvectors of the matrix

Copyright 1995 by CRC Press, Inc

Page 668: Numerical Library in C for Scientists and Engineers A

#include <stdio.h>

void main 0

float **allocate-real-matrix (int, int, int, int) ; void free-real-matrix (float * * , int, int, int) ; void symeigimp(int, float ** , float * * , float [I,

float [I, float [I, float [I); int qrisym(f1oat ** , int, float [I, float [I ) ;

a=allocate-real_rnatrix(1,4,1,4) ; x=allocate-real_matrix(1,4,1,4) ; a[l] 111 =at21 [21 =a[31 [31 =a[41 141 =6.0; a [I] [21 =a [21 [I1 =a [31 [ll =a [ll 131 =4 .O; a [4] [21 =a 121 [4] =a [31 141 =a [4l [3l =4 .O; a[l] [4] =a[41 [I] =a[31 [21 =a[21 [31 =1.0; for (i=l; i<=4; i++)

for (j=i; j<=4; j++) x[il [jl=x[jl [il=a[il [jl ; em[O] =l.Oe-6; em[4]=100.0; emr21 =l.Oe-5; qrisym(x, 4,val, em) ; aux [o] =0.0; aux [41 =lo. 0; aux[2] =l.Oe-6; symeigimp (4, a, x, val, lbound, ubound, aux) ; printf("\nThe exact eigenvalues are: -1, 5, 5, 15\n\nM

"The computed eigenvalues:\n %12.6e\n %12.6e\n %12.6e\nU " %12.6e\n\n Lowerbounds ~pperbounds\n %e %e\nn %e %e\n %e %e\n %e %e\nl'

"\nNumber of iterations =%3.0f\nU "Infinity norm of A =%3.0f\nU "Maximum absolute element of residu = %e", val [ll ,val [21 ,val[31 ,va1[4] , lbound[ll ,ubound[ll ,lbound[21 ,ubound[21, lbound [31 , ubound [3l , lbound [41 , ubound [41 , aux [5l , aux [ll , aux 131 ) ;

free-realmatrix(a, 1,4,1) ; free-real-matrix (x, l,4,1) ;

I Output:

The exact eigenvalues are: -1, 5, 5, 15

The computed eigenvalues: -1.00000e+00 5.00000e+00 5.00000e+00 1.50000e+01

Lowerbounds Upperbounds 1.54543e-13 1.54543e-13 1.13840e-06 1.13840e-06 6.67992e-07 6.67992e-07 4.05009e-14 4.05009e-14

Number of iterations = 1 Infinity norm of A = 15 Maximum absolute element of residu = 3.57628e-07

Copyright 1995 by CRC Press, Inc

Page 669: Numerical Library in C for Scientists and Engineers A

Functions tested: comvalqri, csmveches

Example: Determine all eigenvalues and corresponding eigenvectors of the 4x4 matrix

#include <stdio.h>

void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); int comvalqri (float **, int, float [I, float [I, float [I ) ; void comveches(f1oat **, int, float, float,

float [I, float [I, float [ I ) ; int i,j,m,k; float **a,re[Sl ,im[51 ,u[51 .v[51 ,em[lOl ;

a=allocate-real_matrix(1,4,1,4); em[O] =l.Oe-6; em[2] =l.Oe-6; em111 =4.0; em141 =4O.O; em[6] =l.Oe-5; em[81=5.0; for (i=l; ic=4; i++)

for (j=l; j<=4; j++) a[i][j] = (i == 1) ? -1.0 : ((i-j == 1) ? 1.0 : 0.0);

m=comvalqri (a, 4, em, re, im) ; printf(I1The number of not calculated eigenvalues: %2d\n9'

"\nThe eigenvalues and eigenvectors:\n",m); for (j=m+l; jc=4; j++) {

for (i=l; ic=4; i++) for (k=l; kc=4; k++)

a[i] [k] = (i == 1) ? -1.0 : ((i-k == 1) ? 1.0 : 0.0); comveches(a,4,re[jl ,im[jl ,em,u,v) ; ~rintf ("\n %e %e\n\nW

%12.6e %12.6e\n %12.6e %12. 6e\n1' %12.6e %12.6e\n %12,6e %12.6e\nU,

re[jl ,im[jl ,u[ll ,v[ll ,u[21 ,v[21 ,u[31 ,v[31 ,u[41 ,v[41) ; 1 EM [3] = %e\nEM [7] = %e\nEM [S] = %3.0f\nEM [9l = %3.0f \nu,

em [31 ,em [71 ,em [51 ,em [9l ) ; f ree-real-matrix (a, 1,4,1) ;

1 Output:

The number of not calculated eigenvalues: 0

The eigenvalues and eigenvectors:

Copyright 1995 by CRC Press, Inc

Page 670: Numerical Library in C for Scientists and Engineers A

Function tested: reaeig3

Example: Compute all eigenvalues and corresponding eigenvectors of the 4x4 matrix

void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); int reaeig3 (float **, int, float [I , float [I , float * * ) ; int i, j ,m; float **a, **vec,val[5] ,em[6] ;

a=allocate-real_matrix(l,4,1,4) ; vec=allocate-realmatrix(1,4,1,4) ; for (i=l; i<=4; i++)

for (j=l; jc=4; j++) a[i] [j] = (i == 1) ? 1.0 : l.O/(i+j-1);

em [O] =l. 0e-6; em [21=1.0e-5; em[41=40.0; m=reaeig3 (a, 4, em,val,vec) ; printf("The number of not calculated eigenvalues: %3.0f\n\nT'

"The eigenvalues and corresponding eigenvectors:\nn,m); for (i=m+l; i<=4; i++)

printf ("\n %12.6e %12.6e\n %12.6eVt "\n %12.6e\n %12. 6e\n1', val [i] ,vec [l] [i] ,vec 121 [il ,vec [31 [il ,vec [41 [il ) ;

printf ("\nEM[l] = %e\nEM[3] = %e\n~~[51 = %3 .Of\nu, emf11 ,em[31 ,em[5l ;

free-realmatrix(a, 1,4,1) ; free-real-matrix(vec, l,4,l) ;

1

Output:

The number of not calculated eigenvalues: 0

Copyright 1995 by CRC Press, Inc

Page 671: Numerical Library in C for Scientists and Engineers A

The eigenvalues and corresponding eigenvectors:

Function tested: eighrm

Example: Compute the largest eigenvalue and corresponding eigenvector of the 4x4 matrix

void main 0 l

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int); void sclcom(float ** , float **, int, int, int) ; void inimat (int, int, int, int, float **, float) ; void eighrm(f1oat **, int, int, float [I, float **, float ** ,

float [I) ; int i; float **a, **vecr, **veci,va1[2] ,em[10] ;

a=allocate-real_matrix(l,4,1,4) ; vecr=allocate real matrix (1,4,1,1) ; veci=allocate~real~matrix(1,4,1,1) ;

em[O] =5.0e-6; em[2] =l.Oe-5; em[4]=0.01; em[6l =l.Oe-5; em[8] -5.0; eighrm(a, 4,l,val,vecr,veci, em) ; s~1~0m(ve~r,ve~i, 4,1,1) ;

Copyright 1995 by CRC Press, Inc

Page 672: Numerical Library in C for Scientists and Engineers A

printf("Largest eigenvalue: %e\nW "\nCorresponding eigenvector:\n",val[ll);

for (i=l; i<=4; i++) printf ( " %5.2f %6 .3f*I\nW,vecr [i] [I] ,veci [i] [l] ) ;

printf ("\nEM [I] : %e\nEM [3] : %e\nEM [5] : %e\nEM [7] : %el1

free-real-rnatrix(a, l,4,1) ; f ree-real-matrix (vecr, 1,4,1) ; f ree-real-matrix (veci, 1,4,1) ;

1

Output:

Largest eigenvalue: 4.82843e+00

Corresponding eigenvector: 1.00 O.OOO*I 1.00 O.OOO*I 0.00 0.414*1 0.00 -0.414*1

Function tested: qrihrm

Example: Compute all eigenvalues and corresponding eigenvectors of the 4x4 matrix

void main 0 I

float **allocate-realmatrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void sclcorn(f1oat **, float **, int, int, int) ; void inirnat (int, int, int, int, float **, float) ; int qrihrm(f1oat **, int, float [I, float **, float **, float [I ) ; int i; float **a, **vr, **vi,val[51 ,em[61 ;

inimat (1,4,1,4,a,0.0) ; a [ll [ll =a [21 I21 =3.0; a[3][21=2.0; a[4][11 = -2.0; a[l] [21 =a[3l [31 =a[31 141 =a[41 [41 =1.0; ern[O] =ern121 =5.0e-5; ern[41=20.0; printf ("QRIHRM: %2d\n1I, qrihrrn(a, 4,val,vr,vi, em) ) ; sclcom(vr,vi,4,2,3) ; printf ("\nEigenvalues: \n VAL [I] : %7.3f\n VAL 121 : %7 .3f\n1'

VAL [3] : %7.3f\n VAL [I1 : %7. 3f\n1' w\nEigenvectors corresponding to\n VAL[21 VAL

Copyright 1995 by CRC Press, Inc

Page 673: Numerical Library in C for Scientists and Engineers A

val [I] ,val[21 ,val[31 ,va1[41) ; for (i=l; ic=4; it+)

print£(" %3.0£%3.0f*I , %3.0f%3.0f*1\nW, vr [i] [2] ,vi [il 121 ,vr [il [31 ,vi [il [31 ) ;

printf ("\nEM [I] : %e\nEM : %e\nEM [51 : %e\nl', em [ll ,em [31 ,em [5l ) ;

f ree-real-matrix (a, l,4,1) ; free-real-matrix (vr, 1,4,1) ; f ree-real-matrix (vi, 1,4,1) ;

1 Output:

QRIHRM: 0

Eigenvalues: VAL[lI : 4.828 VAL[2] : 4.000 VAL[3] : 0.000 VAL [4] : -0.828

Eigenvectors corresponding to VAL[21 , VAL [3l 1 O*I , 0 -l*I -1 -O*I , 0 1*1 0 -1*I , 1 -Of1 0 -1*I , 1 O*I

Function tested: valqricom

Example: Determine the roots of the polynomial

x4 + (4+2i)x3 + (5+6i)2 + (2+6i)x + 2i by computing the eigenvalues of the companion matrix

#include cstdio.h> void main 0 1

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat **, int, int, int) ; void inimat (int, int, int, int, float **, float) ; int valqricom(f1oat **, float **, float [I, int, float [I,

float [I, float [I);

al=allocate-real_matrix(1,4,1,4); a2=allocate-real_matrix(l,4,1,4); inimat(l,4,1,4,al,O.O); inimat(1,4,1,4,a2,0.0); al[l] [I] = -4.0; al[ll I21 = -5.0; a1 [I] [31 = a2 [I] [I] = a2 [I] [41 = -2.0; a2 [I] [21 = a2 [11 131 = -6.0; b [1] =b [2] =b [31=1.0;

Copyright 1995 by CRC Press, Inc

Page 674: Numerical Library in C for Scientists and Engineers A

em[O] =5.0e-6; em[l] =27.O; em[2] =l.Oe-6; em[41 =l5.O; printf ("VALQRICOM: %2d\n",valqricom(al,a2, b, 4,em,vall,va12) ) ; printf("\n Eigenvalues:\n Real part Imaginary part\nn); for (i=l; i<=4; i++)

printf ( " %12.4e %12 .4e\nM,vall [il ,va12 [il ) ; printf("\nEM[3] : %e\nEM[51 : %3 .0f\nu,em[3I ,em[5]) ; free-real-matrix (a1,1,4,1) ; f ree-real-matrix (a2,1,4,1) ;

1 Output:

VALQRICOM: 0

Eigenvalues: Real part Imaginary part -9.989e-01 -1.001e+00 -1.001e+00 -9.994e-01 -1.005e+00 -3.410e-03 -9.953e-01 3.406e-03

Function tested: qricom

Example: Compute the eigenvalues and eigenvectors of the matrix

void main 0 (

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat ** , int, int, int) ; void sclcom(f1oat ** , float ** , int, int, int); int qricom(f1oat **, float **, float [ I , int, float [ I ,

float [I, float [I, float ** , float * * ) ; void inimat (int, int, int, int, float ** , float) ; int i; float **al, **a2, **vecl, **vec2,b[41 ,va11[51 ,va12 [51 ,em[61 ;

al=allocate-real_rnatrix(1,4,1,4) ; a2=allocate-real_matrix(1,4,1,4) ; vecl=allocate-real_matrix(l,4,1,4); vec2=allocate-real_rnatrix(1,4,1,4) ; inimat(l,4,1,4,al,0.0); inimat(1,4,1,4,a2,0.0); al[l] [I] = -4.0; a1111 [21 = -5.0; a1 [I] [31 = a2 [ll [I] = a2 [ll [41 = -2.0; a2 [I] [21 = a2 [ll [31 = -6.0; b [l] =b [21 =b [31 =l. 0; em[0] =5.0e-6; em[l] =27.O; em[21 =l.Oe-6; em[4] =l5.0; printf("QR1COM: %2d\nw,qricom(al,a2,b,4,em,vall,val2,vec1,vec2)); printf("\n Eigenvalues:\n Real part Imaginary part\nU); for (i=l; i<=4; i++)

printf ( " %12.4e %12.4e\nn,vall [i] ,va12 [i] ) ; sclcom(vecl,vec2,4,1,4) ; printf("\nFirst eigenvector:\n Real part Imaginary part\nl');

Copyright 1995 by CRC Press, Inc

Page 675: Numerical Library in C for Scientists and Engineers A

for (i=l; ic=4; i++) printf ( " %12.4e %12 .4e\nu,vecl [i] [I] ,vec2 [il [ll ) ;

printf("\nEM[3! : %e\nEM[51 : %3.Of\n",em[31 ,em[5] ) ; free-real-matrlx (al, 1,4,1) ; free-real-matrix (a2,1,4,1) ; f ree-real-matrix(vecl,l, 4,l) ; free-real-matrix(vec2,1,4,1) ;

1 Output:

QRICOM: 0

Eigenvalues: Real part Imaginary part -1.001e+00 -9.994e-01 -9.989e-01 -1.001e+00 -1.005e+00 -3.410e-03 -9.953e-01 3.406e-03

First eigenvector: Real part Imaginary part 1.000e+00 -3.585e-08 -5.003e-01 4.994e-01 8.288e-04 -4.997e-01 2.492e-01 2.504e-01

Function tested: eigcom

Example: Compute the eigenvalues and eigenvectors of the matrix

yoid main 0 i

float *allocate-real-vector(int, int) ; float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat *, int); void f ree-real-matrix (float **, int, int, int) ; int eigcom(f1oat **, float **, int, float [I, float [I,

float [I, float **, float * * ) ; int i; float **ar, **ai, **vr, **vi, *valr, *vali,em[EI ;

Copyright 1995 by CRC Press, Inc

Page 676: Numerical Library in C for Scientists and Engineers A

ai [I] [I] =ai [21 [41 =ai [31 [I] =ai [41 [41=3 .O; ar [2] [41 =ai 121 [I] =ai [41 [31 =4 .O; ar [3] [41 =ar [41 [41 =ai [31 [21=5.0; em[0] =5.0e-6; em[21=1.0e-5; em141 =10.0; em[61=10.0; print£ ("EIGCOM: %2d\n11, eigcom (ar, ai, 4, em,valr,vali,vr,vi) ) ; printf ("\n ~igenvalues : \n") ; for (i=l; i<=4; i++)

printf ( " %12.5e%12.5e * I\n0 ,valr [i] , vali [il) ; printf("\nFirst eigenvector:\nn); for (i=l; i<=4; i++)

printf ( " %12.5e%12. 5e\nW,vr [i] [I] ,vi [i] [I] ) ; printf ("\nEM [I] : %6.2f\nEM [3] : %e\nEM[51 : %3 . o ~ \ ~ E M [7] : %3 .Of\nM,

em[ll ,em[31 ,em[51 ,em[71 ) ; free-real-vector (valr, 1) ; free-real-vector(vali,l) ; free-real-matrix (ar, 1,4,1) ; free real matrix (ai, l,4,1) ; freeIrealImatrix (vr, 1,4,1) ; free-real-matrix (vi, 1,4,1) ;

1 Output:

EIGCOM: 0

Eigenvalues: -3.3710e+00 -7.7045e-01 * I 9.7837e+00 9.3225e+00 * I 1.3657e+00 -1.4011e+00 I 2.2217e+00 1.8490e+00 * I

First eigenvector: -5.0610e-01 5.8345e-01 1.0000e+00 -3.5252e-11 5.1832e-01 -7.1466e-01 -5.5348e-01 1.8756e-02

Function tested: qzival

Example: With

determine complex numbers ao) and real numbers So) such that Jo)A-aO)B is singular (j=1, ..., 4) and evaluate the quotients AO)=~O)@O)".

void main 0

' float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int); void qzival (int, float **, float ** , float [I, float 11,

float [I, int [I, float [I); int k, iter [51 ;

Copyright 1995 by CRC Press, Inc

Page 677: Numerical Library in C for Scientists and Engineers A

a=allocate-real_matrix(1,4,1,4); b=allocate-real-matrix (1,4,1,4) ; a[1] [I] =2.0; a[ll [21=3.0; a[ll [31 = -3.0; a[2] [1]=1.0; a[21 [21 = -1.0; a[21 [31=5.0; a[3] [1]=0.0; a[31 [21=2.0; a[3] [3] =6.0; a[4] [1]=1.O; a[41 [2]=1.0; a[4] [31=0.0; b[1] [1]=1.0; b[11 [21=5.0; b [I] [31=9.0; b[2] [I] =2.0; b[21 [2]=6.0; b[21 [31=10.0; b[3] [I] =3 .O; b [31 [21=7.0; b[3] [3] =11.0; b[4] [1]=4.0; b[41 [21=8.0; b[4] [31=12.0; em[O] =l.Oe-35; em[ll =l.Oe-6; qzival(4,a,b, alfr,alfi,beta, iter,em) ; for (k=l: k<=4: k++)

printf (MITER [%Id] =%3d\n'. k, iter Ikl ) ; ("\n~~FA(real part) ALFA(imaginary part) BETA\nf1 ) ;

for (k=l; k<=4; k++) printf ( I 1 %12.6e %l6.6e %21. 6e\ntt, alfr [kl , alfi [kl ,beta [kl ) ;

printf ("\nLAMBDA (real part) LAMBDA (imaginary art) \nw ) ; for (k=l; k<=4; k++)

if (beta[kl == 0.0) printf ( I1 INFINITE INDEFINITE\nnt ) ;

else printf ( " %12.6e %l6. 6e\ns', alfr [kl /beta [kl , alfi [kl /beta I'., ;

f ree-real-matrix (a, l,4,1) ; free-real-matrix (b, l,4,1) ;

1

Output:

ITER[l] = 0 ITER[2]= 0 ITER[3]= 0 ITER [4] = 9

ALFA(rea1 part) -4.43471e+00 2.96138e-01 -1.67632e-01 -1.33137e-04

LAMBDA (real part ) INFINITE -2.01418e+00 -9.88182e-02 -9.88182e-02

Function tested:

ALFA (imaginary part) BETA 0.00000e+00 0.00000e+00 0.00000e+00 -1.47027e-01 5.34577e-01 1.69637e+00 -4.24572e-04 1.34729e-03

LAMBDA (imaginary part) INDEFINITE -0.00000e+00 3.15130e-01 -3.15130e-01

qzi

Example: With

determine complex numbers a@ and real numbers JG) such that ,@A-OI~)B is singular (j=l, ..., 4), and evaluate the quotients X@=aa)/@), and also determine the components of normalized eigenvectors xo) such that J@&)=QI@BX@.

Copyright 1995 by CRC Press, Inc

Page 678: Numerical Library in C for Scientists and Engineers A

void main ( ) 1

float **allocate-real-matrix(int, int, int, int); void free real-matrix(f1oat **, int, int, int); void qzi (Tnt, float **, float **, float **, float (1 ,

float [I . float [I . int [ I . float [I ) ; - - . - - . - - . ~ ~

int k, 1, iter [5l ; float **a, **b, **x,alfr [s] ,alfilSI ,beta [5l ,em[21 ;

a=allocate real matrix(l,4,1,4); b=allocate~real~matrix(1,4,1,4); x=allocate-real_matrix(1,4,1,4); a [I] [I] =2 .0; a [I] [21=3.0; a[ll [31 = -3.0; a[2] [1]=1.0; a[21 [2] = -1.0; a[21 [31=5.0; a[3l [11=0.0; a131 [21=2.0; a [3] [31=6.0; a[4][1]=1.0; a[41[21=1.0; a[41 [31=0.0; b[l] [l]=l.O; b[ll [21=5.0; b111 [31=9.0; b [2] [I] ~2.0; b [21 [21=6 .O; b i21 131 =lo. 0; b[3][1]=3.0; b[31[21=7.0; b[3] [31=11.0; b [4] [I] =4 .O; b [41 [21=8.0; b[41 [31=12.0; for (k=l; k<=4; k++)

for (1=1; 1<=4; I++) x[kf [l] = (k == 1) ? em[O] =l.Oe-35; em [ll =l. 0e-6; qzi (4, a,b,x,alfr, alf i, beta, iter,em) ; for (k=l; k<=4; k++)

printf ("ITER [%ldl =%3d\n1', k, iter [kl ) ; printf ("\n~igenvectors: \n") ; for (k=l: k<=4: k++)

print£ ( " %i2.6e %12.6e %12.6e %12. 6e\n1', x[kl [I] ,x[kl [21 ,x[kl [31 ,x[k] 141 ) ;

print£ ( U\~ALFA (real part) ALFA (imaginary part) BETA\^" ) ; for (k=l; k<=4; k++)-

printf ( I 1 %12.6e %l6.6e %21. 6e\nv, alfr [k] , alf i [kl ,beta [kl ) ; printf LAMBDA (real part) LAMBDA (imaginary part) \n" ) ; for (k=l; k<=4; k++)

if (beta[kl == 0.0) printf ( " INFINITE INDEFINITE\^");

else- printf(" %12.6e %16.6e\nN,

alfr [kl /beta [kl , alf i [kl /beta [kl ) ; free-real-matrix(a, l,4,1) ; free real matrix (b, l,4,1) ; free~real~matrix(x,l.4,1);

1 Output:

Eigenvectors: -5.00000e-01 1.00000e+00 -6.29479e-01 6.51869e-01 1.00000e+00 -3.82291e-02 1.00000e+00 6.19239e-09

ALFA(rea1 part) ALFA(imaginary part) BETA -4.43471e+00 0.00000e+00 0.00000e+00 2.96138e-01 0.00000e+00 -1.47027e-01 -1.67632e-01 5.34577e-01 1.69637e+00 -1.33137e-04 -4.24572e-04 1.34729e-03

LAMBDA (real part) LAMBDA (imaginary part) INFINITE INDEFINITE -2.01418e+00 -0.00000e+00 -9.88182e-02 3.15130e-01 -9.88182e-02 -3.15130e-01

Copyright 1995 by CRC Press, Inc

Page 679: Numerical Library in C for Scientists and Engineers A

Function tested: qrisngvaldec

Example: Compute the singular value decomposition of the 6x5 matrix A for which

Aij = l/(i+j-I).

void main 0 I

float **allocate-real-matrix(int, int, int, int); void f ree-real-matrix (f loat **, int, int , int) ; int qrisngvaldec (float **, int, int, float [I , float **, float [I ) ; int i,j; float **a, **v,val[5] ,em[8] ;

a=allocate-real-matrix (1,6,1,5) ; v=allocate-real-matrix (1,5,1,5) ; for (i=l; ic=6; i++)

for (j=l; jc=5; j++) a[i] [jl=l.O/(i+j-1); em[O] =l.Oe-6; emf21 =l.Oe-5; em[41 =Z5.O; emf61 =l.Oe-5; i=qrisngvaldec(a,6,5,val,v,em); printf("Number of singular values not found : %2d\nu

"Infinity norm : %e\nMax neglected subdiagonal element : %e\nU1 "Number of iterations : %3.0f\nNumerical rank : %3.0f\ntt I1\nSingular values : \nl', i,em[ll ,em[31 ,em[sI ,em[71) ;

for (i=l; ic=5; i++) printf ( Ig $12. 6e\nSt ,val [ill ;

printf ("\matrix U, first 3 columns : \ntl) ; for (i=l; ic=6; i++)

printf ( " %12.6e %12.6e %12. 6e\n1I, a [il (11 ,a [il [21 ,a [il [31 ) ; printf ("\n Last 2 columns :\nti); for (i=l; i<=6; i++)

printf ( " %12.6e %12. 6e\ntt, a [il [41 ,a [il [51 ; free-real-matrix(a, 1,6,1) ; free-real-matrix(v, 1,5,1) ;

1 Output:

Number of singular values not found : 0 Infinity norm : 2.28333e+00 Max neglected subdiagonal element : 2.11744e-05 Number of iterations : 3 Numerical rank : 5

Singular values : 1.59212e+00 2.24496e-01 1.36102e-02 1.25732e-04 1.41708e-05

Matrix U, first 3 columns : -7.54979e-01 6.10111e-01 -2.33268e-01 -4.39093e-01 -2.26021e-01 7.05900e-01 -3.17031e-01 -3.73070e-01 2.11268e-01 -2.49995e-01 -3.95578e-01 -1.47776e-01 -2.07050e-01 -3.84833e-01 -3.68053e-01 -1.76997e-01 -3.64582e-01 -4.95334e-01

Last 2 columns : 9.87459e-03 -2.57538e-02 -6.88724e-03 2.67619e-01 -3.89435e-01 -5.02005e-01 8.52031e-01 -1.34877e-01 -2.25330e-01 7.40444e-01 -2.67327e-01 -3.30543e-01

Copyright 1995 by CRC Press, Inc

Page 680: Numerical Library in C for Scientists and Engineers A

Functions tested: zerpol, bounds

Example: Determine the zeros of the polynomial

z7 - 3z6 - 3 2 + 25z4 - 462 + 38z2 - 122 by means of a call of zerpol, and derive the real and imaginary parts of the centers and corresponding radii of discs containing the true zeros of the above polynomial.

void main 0 l

int zerpol(int, float [I, float [ I , float [I, float [I 8 float [I); void bounds (int, float [I, float [I , float [I, float*

float, float [I, float [I, float [I) ; int i,j; float a [a] , d [a] ,re [a] , im ,em ~51, recentre [8I . imcentre [El ,bound[8] ; a[7]=1.0; a[6]=a[S] = -3.0; a[41=25.0; a[31 = -46.0; a[2]=38.0; a[ll = -12.0; a[Ol=O.O; em[0] =l.Oe-6; em[ll=40.0; iZzerpol(7, a, em, re, im, d) ; printf ("Coefficients of polynomial : \n " ) ; for ( j = 7 ; j>=O; j--) printf ("%5.0f",a[jl); printf("\n\nNumber of not found zeros: %2d\nU

"Fail indication: $3. Of\n" "Number of new starts: %3. 0f\nU "Number of iterations: %3.0f\n\nZeros:\n", i,em[2] ,em[31 ,em[41 ) ;

for (j=i+l; j<=7; j++) if (im[jl == 0.0)

printf ( " %12. 6e\nt', re [ j 1 1 ; else

printf(" %12.6e %12.6e\nm,re[jl,im[j1); if (i == 0) {

bounds(7,a,re,im,0.0,O.O,recentre,imcent~e,b0~nd~; printf("\nReal and imaginary part of centre + radius\nM); for (j=l; j<=7; j++)

print£(" %12.6e %12.6e %12.6e\n1', recentre [j I , imcentre [ j I ,bound [ j I ) ;

I 1

Output:

Coefficients of polynomial: 1 -3 -3 25 -46 38 -12 0

Number of not found zeros: 0 Fail indication: 0 Number of new starts: 0 Number of iterations: 11

Zeros : 1.99994e+00 -3.00000e+00 9.99974e-01 -9.99995e-01 9.99974e-01 9.99995e-01 9.93030e-01 1.00708e+00 0.00000e+00

Real and imaginary part of centre + radius 1.99994e+00 0.00000e+00 7.00949e-05 -3.00000e+OO 0.00000e+00 1.07083e-06 9.99974e-01 -9.99995e-01 3.35562e-05 9.99974e-01 9.99995e-01 3.35562e-05 1.00005e+00 0.00000e+00 1.49372e-02 1.00005e+00 0.00000e+00 1.49372e-02

Copyright 1995 by CRC Press, Inc

Page 681: Numerical Library in C for Scientists and Engineers A

Function tested: allzerortpol

Example: Determine the roots of the Chebyshev polynomial T,(x) for which

To($ = 1, TI (x) =x,

void main 0 I

void allzerortpol (int, float [ float b[41 ,c[41 ,zer[41 ,em[61 ;

1, float [I, float [I, float

0;

allzerortpol(3,b, c, zer,em) ; printf("The three zeros:\n %13.6e\n %13.6e\n %13.6e\n\n1'

I1EM[1] : %5.2f\nEM[31 : %9.3e\n~~[5] : %2.0f\n1', zer [ll , zer [21 , zer [31 ,em [ll ,em [3l ,em 151 ) ;

1 Output:

The three zeros: -8.66026e-01 8.66025e-01

-1.000000e-06

Function tested: lupzerortpol

Example: Determine the two smaller and two larger roots of the Laguerre polynomial L,(x) for

which Lo($=], LI(x)=x-1, Lk+l(x)=(x-2k-l)L ,(x)-kZLk-,(x), k=1,2.

#include cstdio.h>

void main 0 {

em[O] =em [2] =l.Oe-6; em[4] =45.0; em[61=1.0; for (i=O; i<=2; i++) {

b [il=2*i+l; c [il =i*i;

\ iupzerortpol (3,2, b, c, zer, em) ; printf("The two lower zeros:\n %13.6e\n %13.6e\n\n1'

"EM[l] : %5.2f\nEM[3] : %9.3e\nEM[5] : %3 .0f\nV, zer [I] , zer [21 ,em [ll ,em [3l ,em [Sl ;

em[6]=0.0; for (i=O; i<=2; i++) {

bfi] = -2*i-1; c [il =i*i;

1

Copyright 1995 by CRC Press, Inc

Page 682: Numerical Library in C for Scientists and Engineers A

lupzerortpol(3,2,b,c, zer,em) ; printf("\nThe two upper zeros:\n %13.6e\n %13.6e\n\nW

"EM [I] : %5.2f\nEM [31 : %9.3e\nEM 151 : %3 .0f\n8', -zer[ll, -zer[21 ,em[ll ,em[31 ,em[51) ;

1 Output:

The two lower zeros: 4.15775e-01 2.29428e+00

The two upper zeros: 6.28995e+00 2.29428e+00

Function tested: selzerortpol

Example: Determine the third root of the Legendre polynomial P,(x) for which

po(x)=l, p1(x)=x, Pk+,(x)=xPk(x)-{k2/(4k2 -I))Pk-,(x), k=1,2,3

void main 0 I

void selzerortpol(int, int, int, float [I, float [I, float [I, float [I);

int i; float b [5l , c [Sl , zer [41 ,em [GI ;

em[0] =em[2] =l.Oe-6; for (i=O; i<=3; i++) {

b[il=O.O; c [i] =i*i/ (4.O*i*i-1.0) ;

\ selzerortpol (4,3,3, b, c, zer, em) ; printf("The third zero:\n %13.6e\n\nEM[1] : %5.2f\nEM[Sl : %3.0f\nn,

zer 131 ,em[ll ,em151 ) ; 1 Output:

The third zero: -3.39981e-01

Function tested: alljaczer

Example: Compute the roots of the Jacobi polynomial P,(-'"~-'/*)(X).

Copyright 1995 by CRC Press, Inc

Page 683: Numerical Library in C for Scientists and Engineers A

void main 0 I

void alljaczer (int, float, float, float [I ) ; float x 141 ;

alljaczer(3,-0.5,-0.5,~); printf ("Delivers : \n %l3.6e %l3.6e %l3. 6e\nS' ,x 111 ,X 121 ,X [31) ;

1 Output:

Delivers : -8.66025e-01 0.00000e+00 8.66025e-01

Function tested: alllagzer

Example: Compute the roots of the Laguerre polynomial L,(-"2i(~).

void main 0 I

void alllagzer(int, float, float 11); float x [41 ;

alllagzer (3, -0.5,~) ; printf ("Delivers: \n %l3.6e %l3.6e %l3.6e\n",x[l] ,x[2] ,x [31) ;

1 Output:

Delivers : 5.52534e+00 1.78449e+00 1.90164e-01

Function tested: comkwd

Example: Compute the roots of 2 - 2(-0.1+0.3i)x - (0.11 +0.02i).

void main 0 1

void comkwd(float, float, float, float, float *, float *, float *, float * ) ;

float gr,gi,kr,ki;

comkwd ( - 0.1,O. 3,O. 11,O. 02, &gr, &gi , &kr, &ki ; printf ("x**2-2 (-0.1+0.3*i) *x- (0.11+0.02* has roots\nw

%6 .Zf+%e.Zf*i\n %6.3£+%4 .2f*i\nt',gr,gi,kr,ki) ;

1 Output:

x**2-2 (-0.1+0.3*i) *x- (0.11+0.02*i) has roots -0.30+0.40*i 0.100+0.20*i

Examples for chapter 4 procedures

Copyright 1995 by CRC Press, Inc

Page 684: Numerical Library in C for Scientists and Engineers A

Function tested: euler

Example: Apply the Euler transformation to the series

#include cstdio.h>

float a(int i) I

return (pow(-1, i) / ( (i+l) * (i+1) ) ) ; 1 void main 0 {

float euler (float ( * ) (int) , float, int) ;

printf ("Delivers: %l3 .6e\n8' ,euler(a, l.Oe-6,100) ) ; 1 Output:

Delivers: 8.22467e-01

Function tested: sumposseries

Example: Evaluate the sum

#include <stdio.h>

float ai (float i) {

return l.O/ (i*i) ; 1 void main 0 I

float sumposseries (float ( * ) (float) , int, float, int, int, int) ;

printf("SUMP0SSERIES delivers: %e\ni', sumposseries(ai,100,1.Oe-6,8,100,10));

1 Output:

SUMPOSSERIES delivers: 1.64493e+00

Function tested: qadrat

Copyright 1995 by CRC Press, Inc

Page 685: Numerical Library in C for Scientists and Engineers A

Example: Evaluate the integral

#include cmath.h> #include cstdio.h>

float a(f1oat x) I

return (sin (x) ) ; 1 void main 0 t

float qadrat(f1oat * , float, float, float ( * ) (float), float 1 1 ) ; float t,q,e[41 ;

e [ll =e [21 =l.Oe-6; q=qadrat(&t,0.0,3.141592653589,a,e); printf ("Delivers: %l3.6e $3. Of \nu, q, e [3] ) ;

1 Output:

Delivers: 2.00000e+00 0

Function tested: integral

Example: Evaluate the integral

with, in succession, a = -1 and I3 = -2, -4, -20, -100.

float fx(f1oat x) {

return 10.O/ (x*x) ; 1 void main 0 I

float integral (float, float, float ( * ) (float) , float [I , int, int) ;

int ua,ub, i; float e [71 ,a; static float b[41=(2.0, 4.0, 20.0, 100.0);

printf ("INTEGRAL delivers: \n") ; ua=l; e [ll =e [21 =l.Oe-6; for (i=O; ic=3; i++) (

ub= (b [il c 50.0) ; a=integral(-1.0, -b [il ,fx,e,ua,ub) ; printf ( " %e %3. Of %e $3. Of %3. Of\nl',

a,e[31 ,e[41 ,e[51 ,e[61 ) ; ua=o ;

Copyright 1995 by CRC Press, Inc

Page 686: Numerical Library in C for Scientists and Engineers A

Output:

INTEGRAL delivers: -5.00000e+00 0 -5.00000e+00 -2 2 -7.50000e+00 0 -7.50000e+00 -4 1 -9.50000e+00 0 -9.50000e+00 -20 0 -9.99999e+00 1 -9.99999e+00 0 0

Function tested: tricub

Example: Evaluate the double integral

over the triangle R in the x-y plane with vertices (0,0), (0,n/2), (n/2,d2).

float e(f1oat x, float y ) {

return cos (x) *cos ( y ) ; 1 void main 0 1

float tricub(float, float, float, float, float, float, float ( * ) (float,float), float, float);

int i; float pi, acc;

printf ("TRICUB delivers: \no#) ; pi=3.14159265359; acc=l .0 ; for (i=O; i<=5; i++) {

acc *= 1.0e-1; printf ( " %9. le %e\nl', acc,

tricub(0.0,0.0,0.0,pi/2.0,pi/2.0,pi/2.0,~,~CC,a~~~~;

1 1

Output:

TRICUB delivers: le-01 5.00640e-01

1.0e-02 5.00640e-01 1.0e-03 5.00640e-01 1.0e-04 4.99991e-01 1.0e-05 4.99999e-01 1.0e-06 4.99999e-01

Function tested: reccof

Example: Evaluate the coefficients c,, c, in the recursion

Ck+,f$ = xckfx) - c,Ck-,fx) (k=1,2) for the Chebyshev polynomials of the second kind which are orthogonal over [ - 1 , 1 ] with

Copyright 1995 by CRC Press, Inc

Page 687: Numerical Library in C for Scientists and Engineers A

respect to the weight function w(x)=(l-x2)'".

#include <stdio.h>

float a(f1oat x) {

return sqrt (1.0-x*x) ; I void main 0 {

void reccof (int, int, float *, float ( * ) (float) , float [I 1

float [I, float [I, int) ; float x,b[31 ,C [31 ,1131 ;

reccof (2,2OO,&x,a,b,c,l,l); printf ("Delivers: %7.3f %7.3f\nM,c[11 ,c[21) ;

1

Output:

Delivers: 0.250 0.250

Function tested: gsswtssym

Example: Compute the weights wi which render the formula

where

exact for all polynomials of degree < 10 by means of a call c,=1/4 (k=2,3, ...).

void main 0

' void gsswtssym(int, float [I, float [ I , float [ I ) ; float pi,zer[31 ,w[41 ,c [51 ;

pi=4.0*atan (1.0) ; c[1]=0.5; c[21=0.25; ~[31=0.25; ~[41=0.25; zer [ll =cos (0.9*pi) ; zer [21 =cos (0.7*pi) ; gsswtssym(5, zer, c,w) ; printf("Results:\n %7.3f %7.3f %7.3f %7.3f %7.3f1',

w[l] *pi,w[2] *pi,w[3l*pi,w[2l*pi,w[ll *pi) 1

n=5

of gsswtssym with c,=1/2,

Output:

Results :

Copyright 1995 by CRC Press, Inc

Page 688: Numerical Library in C for Scientists and Engineers A

Function tested: gssjacwghts

Example: Evaluate the integral

by use of a fifth order Gauss-Jacobi quadrature formula. The exact value is 2e - IO/e. (The error is printed out.)

void main 0 I ' void gssjacwghts (int, float, float, float [I , float [I ) ;

int n; float alfa,beta, ind,x[6l ,w[61 ;

alfa=l.O; beta=2.0 ; n=5 ; ind=O. 0 ; gssjacwghts (n,alfa,beta,x,w) ; for (n=l; n<=5; n++) ind += w [nl *exp(x[nl ) ; printf ("Delivers: %l3. 6e\nu, ind-2.O*exp(1.0) +10.0/exp (1.0) ) ;

1 Output:

Delivers: 1.01034e-07

Function tested: gsslagwghts

Example: Evaluate the integral

by use of a ten point Gauss-Laguerre quadrature formula. The exact value is 0.5. (The error is printed out.)

void main 0 I

void gsslagwghts (int, float, float [I , float [I ) ; int n; float ind,x [lll , w [lll ;

gsslagwghts(lO,O.O,x,w); ind=O. 0 ; for (n=10; n>=l; n--) ind += w [nl *sin (x [nl ) ; printf("De1iver.s: %13.6e\nV,ind-0.5);

1

Output:

Copyright 1995 by CRC Press, Inc

Page 689: Numerical Library in C for Scientists and Engineers A

Delivers: 1.78814e-07

Function tested: jacobnnf

Example: Compute approximations to the partial derivatives af/ax, (i,j=1,2) of the components of

the function f(x) given by fi = x,j + X2 f2 = l o x ,

at the point x = (2 , l ) .

void f 1 (int n, float x [I , float f [I ) I

float di(int i) (

return ((i == 1) ? 1.0e-5 : 1.0); I void main 0 I

float **allocate real matrix(int, int, int, int) ; void free-real-mstrixTfloat **, int, int, int); void jacobnnf (int, float [I, float [I, float **,

float ( * ) (int), void ( * ) (int, float[], float[])); int i; float **jac,x[31 ,f [31 ;

jac=allocate-real-matrix(1,2,1,2); x[1]=2.0; x[21=1.0; £1(2,x,f); jacobnnf (Z,x,f, jac,di,fl) ; printf("The calculated jacobian is:\n %6.lf %6.lf\n %6.lf %6.1f\nlt,

jac [ll [il , jac Ell [ZI , jac [ZI 111 , jac [zl 121 ; f ree-real-matrix ( j ac, 1,2,1) ;

1 Output:

The calculated jacobian is: 12.0 1.0 0.0 10.0

Function tested: jacobnmf

Example: Compute approximations to the partial derivatives af/axj (i=1,2,3; j=1,2) of the

components of the fimction f(x) given by fi = xi3 + X2, f2 = l o x 2 + x,x2, = XlX2

at the point x = (2,l).

void fl(int n, int m, float x[l, float f [I) I

Copyright 1995 by CRC Press, Inc

Page 690: Numerical Library in C for Scientists and Engineers A

float di(int i) {

return ((i == 2) ? 1.0 : 1.0e-5); 1 yoid main 0

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int) ; void jacobnmf(int, int, float [I, float [I, float ** ,

float ( * ) (int), void ( * ) (int, int, float[], float[])); int i; float **jac,x[31 ,f [41 ;

jac=allocate-real_rnatrix(1,3,1,2); x[11=2.0; x[21=1.0; f1(3,2,x,f); jacobnmf (3,2,x,f, jac,di,fl) ; printf("The calculated jacobian is:\nn

%7.1f %7.1f\n %7.1f %7.1f\n %7.lf %7.1f\nH, jac [I] [I] , jac [I] [2] , jac [21 [ll , jac [21 [2] , jac 131 111 , jac 131 [21 ) ;

free-real-matrix(jac,1,3,1) ; 1

Output:

The calculated j acobian is : 12.0 1.0 4.0 14.0 1.0 2.0

Function tested: jacobnbndf

Example: Compute approximations to the partial derivatives

afJax,, i=l ,..., 5; j-ax(1 ,i- 1) ,,.., min(5,i+l) of the components of the function f(x) given by

f/ = ( 3 - 2 x 3 ~ ~ - 2x, + I f; = (3-2xJxj - 2 ~ , + ~ - x,, + I (i=2,3,4) fs = 4 - x, - 2x,

at the point x = (-I,-],- 1,-1,-1).

int func(int n, int 1, int u, float x[l, float f[l) {

int i;

for (i=l; ic=((u == 5) ? 4 : u); if+) { f [i] =(3.0-2.0*x[il )*x[il +l.O-2 .O*x[i+l] ; if (i ! = 1) f[il - = x[i-11;

float di(int i) I

return ((i == 5) ? 1.0 : 1.0e-6) ; 1 yoid main 0 {

void j acobnbndf (int, int, int, float [I , float [I , float [ I , float ( * ) (int),

Copyright 1995 by CRC Press, Inc

Page 691: Numerical Library in C for Scientists and Engineers A

for (i=l; i<=5; i++) x[i] = -1.0; func(5,1,5,x,f) ; jacobnbndf (5,l, l,x, f, jac, di, func) ; printf(ttThe calculated tridiagonal jacobian is:\nU

" %4.0f %4.0f\n %4.0f %4.0f %4.0f\n1' It %4. of %4. of %4. Of \n" , %4. of %4. of $4. Of \n1I

%4.of %4.0f\nu, jac [1] ,jac [2], jac [3], jac [4], jac [51 , jac [6 , jac [71, jac [81, jac [g] , ~ a c [lo] , jac [lll , jac [I21 , jac [l3l ) ;

1

Output:

The calculated tridiagonal jacobian is: 7 -2

- 1 7 -2 - 1 7 -2

- 1 7 -2 -1 -2

Examples for chapter 5 procedures

Function tested: zeroin

Example: Determine a zero of d3"(x-l)+x3 in the interval [0,1].

#include <math.h> #include <stdio.h>

float fx(f1oat x) {

return exp (-x*3.0) * (x-1.0) +x*x*x; 1 float tolx(f1oat x) {

return fabs(x) *l.Oe-6+1.0e-6; 1 void main 0 I

int zeroin(f1oat *, float *, float (*)(float), float (*)(float)); float x,y;

y=1.0; if (zeroin(&x, &y, fx, tolx) )

~rintf ( "Calculated zero: %e\nl1, x) ; else-

printf ("No zero found. " ) ; 1 Output:

Calculated zero: 4.89703e-01

Function tested: zeroinrat

Copyright 1995 by CRC Press, Inc

Page 692: Numerical Library in C for Scientists and Engineers A

Example: Determine a zero of e- jX(x- l )+2 in the interval [0,1].

float fx(f1oat x) I L

return exp (-x*3.0) * (x-1.0) +x*x*x; I float tolx(f1oat x) I

return fabs (x) *l. 0e-6+1.0e-6; I void main 0 I

int zeroinrat (float * , float , float ( * ) (float) , float ( * ) (float) ) ; float x, y;

x=o.o; y=1.0; if (zeroinrat (&x, &y, fx, tolx) )

printf ("Calculated zero: %e\nl' ,x) ; else

printf("No zero found."); I Output:

Calculated zero: 4.89703e-01

Function tested: zeroinder

Example: Determine a zero of e-3x(x-l)+x3 in the interval [O,l].

#include <math.h> #include <stdio.h>

float f (float x) I

return exp (-x*3.0) (x-1.0) +x*x*x; I float df(f1oat x) I

return exp (-x*3.0) * (-3.0*x+4.0) +3.0*x*x; I float tolx(f1oat x) I

return fabs (x) *l.Oe-6+1.0e-6; I void main 0 {

int zeroinder(f1oat *, float *, float ( * ) (float), float ( * ) (float), float ( * ) (float)) ;

float x, y;

x=o . 0 ; y=1.0; if (zeroinder (&x, &y, f, df, tolx) )

printf("Ca1culated zero and function value:\n %e %el8 "\nother straddling approximation and function value:" "\n %e %e\nv,x, f (x) , y, f (y) ) ;

Copyright 1995 by CRC Press, Inc

Page 693: Numerical Library in C for Scientists and Engineers A

else printf ("No zero found. " ) ;

1 Output:

Calculated zero and function value: 4.89703e-01 1.64360e-08

Other straddling approximation and function value: 4.89701e-01 -1.92349e-06

Function tested: quanewbndl

Example: Solve the system of equations f(x) = 0 OxsRn) where

p'' = (3 - 2x'0)x'" - zx'*) + 1 j@) = (3 - 2xF))xF) - 2xF+') - xF+ + 1 ( k 2 , ..., n- 1) y) = (3 - 2x'"')x'"' - x'"-4 + 1

with initial approximation xOF) = -1 ( k l , ..., n), for n = 600.

int fun(int n, int 1, int u, float x[l, float f [I) I

int i; float xl,x2,x3;

xl = (1 == 1) ? 0.0 : x[l-11; x2=x [l] ; x3 = (1 == n) ? 0.0 : x [l+ll ; for (i=l; i<=u; i++) (

f [i1=(3.0-2.0*~2) *x2+1.0-XI-x3*2.0; x1=x2 ; x2 =x3 ; x3 = (i <= n-2) ? x[i+2] : 0.0;

1

void main 0

' float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void quanewbndl(int, int, int, float [I, float [I,

int ( * ) (int, int, int, float [I , float [I ) , float [I , float [I ) ;

int i; float *x, *f, in [61 ,out [61 ;

x=allocate~real~vector(1,600) ; f=allocate-real-vector(1,600); for (i=l; i<=600; i++) x[il = -1.0; in [O] =l. 0e-6; in[ll =in[2] =in[31 =l.Oe-5; in[4] =20000.0; in [5] =0.001; quanewbnd1(600,1,1,x, f,fun,in,out) ; printf ("Norm Residual vector: %e\nI1

"Length of last step: %e\nl' "Number of function component evaluations: %6.0f\nI1 ItNumber of iterations: %3.0f\n~eport: %3.0f\nf', out [2] ,out [ll ,out [31 ,out [41 ,out [51 ) ;

free-real-vector (x, 1) ; free-real-vector (f, 1) ;

1 Output:

Norm Residual vector: 2.39722e-06

Copyright 1995 by CRC Press, Inc

Page 694: Numerical Library in C for Scientists and Engineers A

Length of last step: 2.70116e-05 Number of function component evaluations: 5998 Number of iterations: 6 Report: 0

Function tested: minin

Example: Determine an approximation to the point in the interval [1,4] at which the function

assumes a minimum value.

float f (float x) [

int i; float s,temp;

s=o.o; for (i=l; i<=20; i++) {

temp= (i*2-5) / (x-i*i) ; s += temp*temp;

return s; I float to1 (float x) {

return (fabs (x) *l.Oe-6+1.0e-6) ; I void main ( )

float minin(f1oat *, float * , float * , float ( * ) (float), float ( * ) (float)) ;

float m,x,a,b;

a=l.O+tol(l.O) ; b=4.0-tol(4.0); m=minin(&x, &a, &b, f, tol) ; printf("Minimum is %e\nFor x is %e\nin the interval with "

"endpoints %e %eV,m,x,a,b); I Output:

Minimum is 3.67670e+00 For x is 3.02290e+00 in the interval with endpoints 3.02290e+00 3.02291e+00

Function tested: mininder

Example: Determine an approximation to the point in the interval [1.01,3.99] at which the

function assumes a minimum value. The derivative of this hnction is

Copyright 1995 by CRC Press, Inc

Page 695: Numerical Library in C for Scientists and Engineers A

float f (float x) I

int i; float s, temp;

s=o.o; for (i=l; ic=20; i++) {

temp= (i*2-5) / (x-i*i) ; s += temp*temp;

1 return s;

1 float df (float x) I

int i; float s,templ,tempZ;

s=o.o; for (i=l; i<=20; i++) {

templ=i*2-5; tempZ=x-i*i; s += (templ*templ) / (temp2*tempZ*tempZ) ;

return -s*2.0; 1 float to1 (float x) (

return (fabs(x)*l.Oe-6+1.0e-6); 1 void main ( ) ' float mininder(f1oat *, float *, float (*)(float),

float (*) (float), float ( * ) (float)); float m,x.y;

x=1.01; y=3.99; mxmininder (&x, &y, f , df , to1 ; printf("Minimum is %e\nFor x is %e and y is %e\n",m,x,y);

1

Output:

Minimum is 3.67670e+00 For x is 3.02291e+00 and y is 3.02292e+00

Function tested: praxis

Copyright 1995 by CRC Press, Inc

Page 696: Numerical Library in C for Scientists and Engineers A

Example: Calculate the minimum of the function

f(x) = 100(x2-x12)2 + (I-xJ2 using ( - 1 . 2 , l ) as an initial estimate.

float f (int n, float x[l) l

float temp;

temp=x [2] -x [ll *x [ll ; return temp*temp*100 .O+ (1.0-x[ll ) * (1.0-x[ll ) ;

1 void main 0 I I

void praxis (int, float [I , float ( * ) (int, float [I ) , float [I, float [I);

float x 131 ,in [lo1 ,out [71 ;

in[O] =l.Oe-6; in[l] =in121 =l.Oe-6; in[51=2SO.O; in [6] =in [7] =in [8l =in [9] =1.0; X[l] = -1.2; x[21=1.0; praxis(2,x, f,in,out) ; if (out [l] == 0.0) printf ("Normal ~ermination\n\n") ; printf("Minimum is %e\nFor x is %e %e\nn

"The initial function value was %e\nl' "The number of function evaluations needed was %4.0f\nU "The number of line searches was %4.0f\nn "The step size in the last iteration step was %e\nH, out [21 ,x[ll ,x[21 ,out [3l ,out[41 ,out [51 ,out [GI ;

Output:

Normal Termination

Minimum is 0.00000e+00 For x is 1.00000e+00 1.00000e+00 The initial function value was 2.42000e+01 The number of function evaluations needed was 180 The number of line searches was 68 The step size in the last iteration step was 4.28428e

Functions tested: rnklmin, flemin

Example: Determine the value of x = (x,,x2) yielding a minimum of the hnction

f ( ~ ) = roo(^,-^,')^ + ( I - x j 2 twice: firstly by use of rnklmin, and secondly by Jlemin. In both cases the initial approximation is taken to be ( -1 .2 , l ) .

float rosenbrock(int n, float x[l, float g[l) {

float temp;

temp=x [21 -x [ll *x [ll ; g[l] =(-temp*400.0+2.0) *xi11 -2.0; g[21 =temp*200.0; return temp*temp*100.0+ (1.0-x[ll ) (1.0-x[ll ) ;

1

Copyright 1995 by CRC Press, Inc

Page 697: Numerical Library in C for Scientists and Engineers A

void main ( ) I

float rnklmin(int, float [I, float [I , float 11 , float ( * ) (int, float[], float[]), float [I , float [I ) ;

float flemin (int, float [I , float [I , float [I ,

while (1) { printf(I1\nLeast value: %e\nx: %e %e\nI1 - "Gradient: %e %e\nM

"Metric : %e %e\n %e\n" "OUT: %e\n %e\n %e\n %e\n %e\nl', f,x[l] ,x[2] ,g[l] ,g[21 ,h[ll ,h[21 ,h[31 ,out LO] ,out [I] lout [21 out [31 ,out[41);

if (again) { X[l] = -1.2; x[21=1.0; again=O ; f=flemin(2,x, g, h, rosenbrock, in, out) ;

) else break;

I I

Output:

Least value: 5.68434e-14 x: 1.00000e+00 1.00000e+00 Gradient: 4.76860e-07 -1.13687e-11 Metric: 4.89787e-01 9.77621e-01

1.95649e+00 OUT: 5.21398e-07

4.76860e-07 5.60000e+01 1.10000e+01 6.00000e+00

Least value: 1.42109e-14 x: 1.000000e+00 1.000000e+00 Gradient: -2.38413e-07 -2.84217e-12 Metric: 4.90739e-01 9.80828e-01

1.96534e+00 OUT: 2.61484e-07

2.38413e-07 4.30OOOe+Ol 6.00000e+00 0.00000e+00

Function tested: marquardt

Example: Determine the parameters p,, p2 and p, of best fit of the function

g(x1p) = PI + P2 * a p b + ) when x=x, to data readings yi (i=l, ..., b), where x ,, . . . , x, are -5, -3, -1, 1, 3, 5 and y, ,..., y, are 127.0, 151.0, 379.0, 421.0, 460.0, 426.0.

The components of the residual vector are P I + ~2 * ~ P ( P + J - ~i (i=l, ..., 6) .

The elements of the Jacobian matrix are ag/ap, = 1, ag/ap2 = ~ X P ( P , X J , ag/ap, = P,*x,*~xP(P+J, (j=l,...,6).

Copyright 1995 by CRC Press, Inc

Page 698: Numerical Library in C for Scientists and Engineers A

float x [71 , y [71 ;

int expfunct(int m, int n,float par[], float rv[l)

int i;

for (i=l; i<=m; i++) { if (par [3] *x[i] > 680.0) return 0; rv [il =par [ll +par [21 *exp (par [31 *x [il ) -Y [il ;

) return 1;

1 void jacobian(int m, int n, float par [I , float rv[l , float * * jac) {

int i; float ex;

for (i=l; i<=m; i++) { jac [il [I] =1.0; jac [il [2] =ex=exp (par [31 *x [il ) ; jac [i] [31 =x [il *par [21 *ex;

void main 0

float **allocate-real-matrix(int, int, int, int); void free-real-matrix(f1oat ** , int, int, int) ; void marquardt (int, int, float 11 , float [I , float **,

int ( * ) (int, int, float [I , float [I ) , void ( * ) (int, int, float[], float[], float * * I , float [I, float [I ) ;

float in[7],out[8l,rv[7],par[4],**jjinv;

jjinv=allocate-real-matrix(1,3,1,3); in[0] =l.Oe-6; in[3] =l.Oe-4; in[4]=l.Oe-1; in[5] =7S.O; in [61=1.0e-2; X[l] = -5.0; x[2] = -3.0; x[3] = -1.0; x[41=1.0; x[51=3.0; ~[61=5.0; y[l]=127.0; y[2]=151.0; y[3]=379.0; y[4]=421.0; y[51=460.0; y[61=426.0; par[l]=580.0; par[2] = -180.0; par[3] = -0.160; marquardt(6,3,par,rv,jjinv,expfunct,jacobian,in,out~; printf("Parameters:\n %9.4e %9.4e %9.4e\n\nOUT:\n1'

%14.6e\n %14.6e\n %14.6e\n %14.6e\n %14.6e\n %14.6e\n11 %14.6e\n\nLast residual vector:\nU %6.lf %6.lf %6.lf %6.lf %6.lf %6.lf\nW,

par [ll ,par [21 ,par [31 ,out [71 ,out [21 ,out [ 6 out I ,out 141 , out [Sl ,out [ll ,rv[ll ,rv[21 ,rv[31 ,rv[41 ,rv[51 ,rv[61 ) ;

free-real-matrix( j jinv, 1,3,1) ; 1 Output:

Parameters: 5.232e+02 -1.568e+02 -1.998e-01

OUT : 7.22150e+07 1.15716e+02 1.72813e-03 1.65459e+02 2.30000e+01 2.20000e+01 0.00000e+00

Last residual vector: -29.6 86.6 -47.3 -26.2 -22.9 39.5

Copyright 1995 by CRC Press, Inc

Page 699: Numerical Library in C for Scientists and Engineers A

Function tested: gssnewton

Example: Determine the parameters p,, p2 and p, of best fit of the function

~CGP) = PI + P ~ * ~ P @ G ) when x=xi, to data readings y; (i=l, ..., b), where x ,,..., x, are -5 , -3, -1, 1, 3, 5 and y, ,..., y, are 127.0, 151.0, 379.0, 421.0, 460.0, 426.0.

The components of the residual vector are PI + P ~ * ~ P @ $ S - Yi (i=l, ..., 6).

The elements of the Jacobian matrix are ag/ap, = 1, ag/ap, = exp@,x~, a g ~ a p , = p , * x , * a p ( p ~ ~ G=L...,~).

float x 171 . y [71 ; int expfunct(int m, int n, float par[], float g[l) I

int i;

for (i=l; ic=m; i++) ( if (par[3] *x[i] z 680.0) return 0; g [i] =par [ll +par [21 *exp (par [31 *x [il ) -y [il ;

1 return 1;

I void jacobian(int m, int n, float par [I, float g[l , float **jac) I

int i; float ex;

for (i=l; ic=m; i++) ( jac [il [ll =l. 0; jac [i] [21 =ex=exp (par 131 *x [il ) ; jac [i] [31 =x [il *par [21 *ex;

1 1

void main 0 I

float **allocate-real-matrix (int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void gssnewton(int, int, float [I, float [I, float **,

int ( * ) (int, int, float[], float[]), void ( * ) (int, int, float [I , float [I , float * * ) , float [I, float [I);

float in[81 ,out 1101 .g[71 ,par[4] , **v;

v=allocate-real_matrix(l,3,1,3); in [O] =l. 0e-6; in [1] =in [2] =l.Oe-6; in [5] =75.0; in [4] =I. 0e-6; in[6]=14.0; in[7]=1.0; X[I] = -5.0; x[21 = -3.0; x[31 = -1.0; ~[41=1.0; x[5]=3.0; x[61=5.0; y[l]=127.0; y[2]=151.0; y[31=379.0; y[4]=421.0; y [5] =460.O; y[61=426.O; par[l]=580.0; par[2] = -180.0; par[3] = -0.160; gssnewton(6,3,par,g,v,expfun~t,ja~0bian,in,out) ;

("~arameters:\n %9.4e %9.4e %9.4e\n\n0~~: \nl' " %14.6e\n %14.6e\n %14.6e\n %14.6e\n %14.6e\n %14.6e\nit %14.6e\n %14.6e\n %14.6e\n\nLast residual vector:\ntl

" %6.lf %6.lf %6.lf %6.lf %6.lf %6.lf\nt1, par[l] ,par [21 ,par [31 ,out 161 ,out [2l ,out [3l ,out [4l ,0ut[51r out [I] ,out [TI ,out [El ,out [9l ,g[ll ,g[21 ,g[31 ,g[4l ,g[51 ,g[61 ;

f ree-real-matrix (v, l,3,1) ; I

Copyright 1995 by CRC Press, Inc

Page 700: Numerical Library in C for Scientists and Engineers A

Output:

Parameters: 5.233e+02 -1.570e+02 -1.996e-01

Last residual vector: -29.6 86.6 -47.3 -26.2 -22.9 39.5

Function tested: rkl

Example: Compute the solution at x = I of the differential equation

dy/& = -y with initial condition y(0) = I .

float fxy(f1oat x, float y)

return -y; 1 yoid main 0 (

void rkl(f1oat * , float, float, float *, float, float ( * ) (float, float), float 11, float 11, int);

int first; float x,y,d[51 ,e[31 ;

e [ll =e [21=1.0e-4; first=l; rkl(&x,O.O,l.O,&y,l.O,fxy,e,d,first) ; printf("RK1 delivers:\n x = %e\n y = %e yexact = %e",

x,y,exp(-XI); 1

Output:

RK1 delivers: x = 1.00000e+00 y = 3.67877e-01 yexact = 3.67879e-01

Function tested: rke

Example: Compute the solution at t = I and t = -I of the system

d d t = y - z dy/dt = 2 + 2y + 4t &/dt = 2 + 5x + 2 + 4t,

with x = y = 0 and z = 2 at t = 0.

Copyright 1995 by CRC Press, Inc

Page 701: Numerical Library in C for Scientists and Engineers A

void rhs (int n, float t, float y [I ) I

float xx,yy,zz;

void info(int n, float t, float te, float y[l , float data[] ) I 1

float et,t2,aex,aey,aez,rex,rey,rez;

(t == te) { et=exp(t) ; t2=2.0*t; rex = -et*sin(t2) ; aex=rex-y [ll ; rex=fabs (aex/rex) ; rey=et*et*(8.0+2.0*t2-sin(2.0*t2))/8.0-t2-1.0; rez=et* (sin(t2) +2.0*cos (t2) ) +rey; aey=rey-y [21 ; rey=fabs (aey/rey) ; aez=rez-y [31 ; rez=fabs (aez/rez) ; printf("\nT = %2.0f\nW

"Relative and absolute errors in x, y and z:\nl' Ig RE(X) RE(Y) RE(Z) AE(X) AE(Y) AE(Z) \n" " %7.2e %7.2e %7.2e %7.2e %7.2e %7.2e\nV' "Number of integration steps performed : %3.0f\n1' "Number of integration steps skipped : %3.0f\nW "Number of integration steps rejected : %3.0f\nW, t,rex,rey,rez,fabs(aex) ,£abs(aey) ,£abs(aez), data [41 ,data [61 ,data [51 ) ;

void main 0 1

void rke(f1oat *, float *, int, float [I, void ( * ) (int, float, float [I ) , float [I, int, void ( * ) (int, float, float, float [I, float [I));

float t, te, y [41 ,data[71 ;

te=l. 0 ; while (1) {

y [ll =y [21 =o. 0; y[31=2.0; t=O.O; data [ll =data [21 =l .Oe-5; rke (&t, &te, 3, y, rhs, data, 1, info) ; if (te != 1.0) break;

Output:

T = 1 Relative and absolute errors in x, y and z: RE(X) RE(Y) RE(Z) AE(X) AE(Y) AE(Z) 4.8e-07 1.5e-06 1.4e-06 1.2e-06 1.3e-05 1.2e-05 Number of integration steps performed : 9 Number of integration steps skipped : 0 Number of integration steps rejected : 5

Copyright 1995 by CRC Press, Inc

Page 702: Numerical Library in C for Scientists and Engineers A

Relative and absolute errors in x, y and z: RE(X) RE(Y) RE(Z) AE(X) AE(Y) AE(Z) 4.5e-07 0.0e+00 2.2e-07 1.5e-07 0.0e+00 8.9e-08 Number of integration steps performed : 10 Number of integration steps skipped : 0 Number of integration steps rejected : 7

Function tested: rk4a

Example: The solution of the differential equation

&/& = I - 2(2+y), x 1 0, y = O a t x = O ,

is represented by the parabola y = x(1-x). Find the value of x for which the curve of the solution intersects the line y+x=O.

#include cmath.h> #include <stdio.h>

float b(f1oat x, float y) {

return x+y; 1 float fxy(f1oat x, float y) I

return 1.0-2.0*(x*x+y); 1 void main 0 I

void rk4a (float *, float, float ( * ) (float, float) , float *, float, float ( * ) (float, float), float [I , float [I , int, int, int) ;

float x,y,d[5l8eI61;

e [o] =e [l] =e [21 =e 131 =e [41 =e [51 =l. 0e-4; rk4a(&x,O.O,b,&y,O.O,fxy,e,d,1,1,1); printf ("x = %e Exactly : 2.00000\ny = %e\nn

"y-x* (1-x) = %e\nU,x, y, y-x* (1-x) ) ; 1 Output:

x = 1.99995e+00 Exactly : 2.00000 y = -2.00006e+00 y-x* (1-x) = -2.10879e-04

Function tested: rk4na

Example: Obtain the period of the solution of the van der Pol equation

&,/dt = x2 &Jdt = I O(1-x,Z)x2-x,, t 2 0 .

#include <stdio.h>

float b(int n, float x[l )

{ return x 121 ;

1

Copyright 1995 by CRC Press, Inc

Page 703: Numerical Library in C for Scientists and Engineers A

float fxj(int n, int k, float x[l) (

return ( (k == 1) ? x [21 : 10.O* (1.0-x[l] *x [ll ) *X 121 -X Ell ;

1 void main 0 {

void rk4na (f loat [I , float [I , float (*) (int, float [I ) . float (*) (int, int, float [I), float [I, float [I, int, int, int, int) ;

int j,first; float xO,e[81 ,xa[31 ,x[31 ,dt61 ;

for (j=O; jc=5; j++) e[jI=O.le-4; e [6] =e [7] =l. 0e-4; printf("VAN DER POL\~\~EPS = %e\n\nt1

"The values of x[01 ,xtlI ,xi21 ,p:\n7',e [01) ; xO=xa [O] =xa 121 =O. 0; xa[ll=2.0; printf ( " %8.5f %8.5f %8.5f %8.5f\nn,xat01 ,xa[ll first=l; for (j=l; jc=4; j++) {

rk4na(x,xa,b, fxj ,e,d, first,^, 0,l) ; xo=x [OI -xO; printf ( " %8. Sf %8.5f %8. Sf %8. Sf \n" ,x [01 ,x [ : f irst=O; xo=x 101 ;

Output:

VAN DER POL

EPS = 1.000000e-05

The values of x[O],x[l],x[21,p: 0.00000 2.00000 0.00000 0.00000 9.32386 -2.01429 0.00000 9.32386 18.86305 2.01429 0.00000 9.53919 28.40223 -2.01429 -0.00000 9.53918 37.94142 2.01429 0.00000 9.53919

Function tested: rWna

Example: The van der Pol equation in the phase plane

&,/&, = ( I o ( I - x o ~ ~ j - ~ J / x j can be integrated by rk5na. The starting values are xo = 2, x, = 0. The integration proceeds until the next zero of x,, then it continues until the next zero and so on until the fourth zero is encountered.

float b (int n, float x[l) I

return x[ll ; I float fxj (int n, int k, float xi]) {

return ( (k == 0) ? x[ll : 10.O* (1.0-x[Ol *x[Ol ) *x[ll -x[Ol ) ; 1 void main 0 {

Copyright 1995 by CRC Press, Inc

Page 704: Numerical Library in C for Scientists and Engineers A

Output:

Results : x [OI x [ll S

2.00000 0 .ooooo 0.00000 -2.01429 0.00000 29.38738 2.01429 0.00000 58.78843 -2.01429 -0.00000 88.18951 2.01429 -0.00000 117.59058

Function tested: multistep

Example: Compute the solution at x = 1 and at x = 10 of the differential equations

dy,/ak = 0.04(1 - y, - yJ - y l ( l 04y2 + 3* I 07y J dyJak = 3*107y12

with the initial conditions y, = 0 and y2 = 0 at x = 0.

void der (float f [I , int n, float x, float y [I )

float r;

;nt avail(int n, float x, float y[l , float **jac) i

float r;

jac [2] [l] =r=6.Oe7*y [I] ; jac[ll [ll = -0.04-1.Oe4*y[ZI -r; jac[ll [21 = -0.04-l.Oe4*y[l] ; jac[21 [21=0.0; return 1;

1 void out(f1oat h, int k, int n, float x, float y[l) (

return; 1 void main 0 (

float *allocate-real-vector(int, int) ;

Copyright 1995 by CRC Press, Inc

Page 705: Numerical Library in C for Scientists and Engineers A

float **allocate-real-matrix(int, int, int, int) ; void free-real-vector(f1oat *, int); void free-real-matrix(f1oat **, int, int, int) ; int multistep(f1oat * , float, float [I, float, float,

float [I , float, int *, float [I , void ( * ) (float [I, int, float, float [I ) , int ( * ) (int, float, float [I, float * * I , float ** , int, int, void ( * ) (float, int, int, float, float [ I ) ;

int i,first; float x,xend,hmin,eps,y[131 ,ymax[31 ,*d,**jac;

d=allocate-real-vector(-40,12); jac=allocate-real_rnatrix(1,2,1,2); hmin=l.Oe-6; eps=l.Oe-6; first=l; x=o . 0 ; y [ll =y [21 =o. 0; ymax[l]=O .0001; p a x [21 =l. 0; printf(ltDelivers with hmin = %5.le and eps = %5.1e\nn,hmin,eps); for (i=l; i<=10; i+=9) {

xend=i ; multistep (&x,xend, y, hmin, 5,pax, eps, &first, d,

der,avail, jac,l,Z,out); printf ( " %e %e\nn, y [ll , y [21 ) ;

1 free-real-vector (d, -40) ; free-real-matrix(jac, 1,2,1) ;

1

Output:

Delivers with hmin = 1.0e-06 and eps = 1.0e-06 3.07463e-05 3.35095e-02 1.62340e-05 1.58613e-01

Function tested: diffsys

Example: Solve the system of differential equations

Yl ' = Y2 Y2' = Yl + 2 ~ 4 - CCI(YI+CL)/~I - CC(YI-CLLYS~ Y3 = Y4 Y4' = Y3 + 2 ~ 2 - P I Y J ~ I - PYJ~Z

where s1 = {(Y1+d2 + ~ 3 ~ 1 , S2 = i(Y1-pJ2 + ~ 3 ~ 1 , PI

This problem arises from the restricted problem of three bodies. solution is a closed orbit with period t = 6.192169331396.

int passes,k;

void der(int n, float x, float y[l, float dy[l) I \

float mu, mul, yl, y2, y3, y4, sl, s2 ;

= l - p . When p = 1/82.45, the

Copyright 1995 by CRC Press, Inc

Page 706: Numerical Library in C for Scientists and Engineers A

y4=dy [31 =y[41 ; sl= (yl+mu) * (yl+mu) +y3*y3; s2= (yl-mul) * (yl-mul) +y3*y3; sl *= sqrt(s1); s2 *= sqrt (s2) ; dy[2] =y1+2.0*~4-mul* (~l+mu) /sl-mu* (yl-mull /s2; dy[4]=y3-2.0*y2-mul*y3/sl-mu*y3/s2;

I void out (int n, float x, float xe, float y[l , float s[l )

{ k++ ; if (X >= xe)

printf ( ' %3d %4d %e %e\nl',k,passes, y [ll ,y [3l) ; I void main ( )

1 int i; float x,xe,tol,hO,y[~l ,s[5l;

printf("Resu1ts with DIFFSYS are :\nu " K DER.EV. y [I] Y [31 \n") ;

tol=l.Oe-2; for (i=1; ic=2; i++) {

to1 *= 1.0e-2; passes=k=O; x=O . 0 ; xe=6.192169331396; y[11=1.2; y[21 =y [31 =o.o; y[4] = -1.04935750983; s 111 =S [21 =S [31 =S I41 =O. 0; h0=0.2 ; diffsys (&x,xe, 4, y, der, tol, tol, s, h0, out) ;

1 I

Output:

Results with DIFFSYS are : K DER.EV. Y [I] Y [31 30 2585 l.32403e+OO -3.19608e-02

Function tested: ark

Example: Compute the values of: (1) y(1) and y(2) of the initial value problem

dy/& = y - 2dy, y(0) = I and

(2) u(0.6,0) of the Cauchy problem dddt = 0.5*dd&, u(0,x) = exp(-2).

void derl(int *mO, int *m, float *t, float v[l)

void der2 (int *mO, int *m, float *t, float v [ I ) {

int j; float vl,v2,v3;

Copyright 1995 by CRC Press, Inc

Page 707: Numerical Library in C for Scientists and Engineers A

v2=v[*mOl ; (*mO) ++; (*m) --; v3=v [*mOI ; for (j=(*mO); j<=(*m); I++) {

v1=v2 ; v2 =v3 ; v3=v[j+ll ; v[j]=250.0*(~3-v1)/3.0;

1 1

void outl(int *mO, int *m, float *t, float *te, float y[l, float data [I )

I

' if (*t == *te) if (*t == 1.0)

printf ("\nProblem l\n\nU " x integration steps y (computed) y (exact) \nl' ) ;

printf ( "%2. Of $3 .Of %e %e\ntt, *t, data [8l , y [ll , sqrt (2. O* (*t) +I) ) ;

*te = 2.0;

1 1

void out2 (int *mO, int *m, float *t, float *te, float u [ I , float data [I )

I if (fabs ( (*t)-0.6) < 1.0e-5)

printf ( \n\nProblem 2\n\nt1 " derivative calls u ( .6,0) (computed) u ( .6,0) exact\no' I' %4.0f %e %e\n" , data[l] *data[8] ,u[Ol ,exp(-0.09) ;

1 void main 0 (

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void ark (f loat *, float *, int *, int *, float [I ,

void ( * ) (int * , int * , float * , float [I ) , float [I , void ( * ) (int *, int *, float *, float *,

float [I, float [I)); int mO,m,i; static float dat1[131={3.0, 3.0, 1.0, 1.0, 1.0e-3, 1.0e-6,

1.0e-6, 0.0, 0.0, 0.0, 1.0, 0.5, 1.0/6.0}; static float dat2[14]={4.0, 3.0, 0.0, 500.0/3.0, 0.0,

-1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.5, 1.0/6.0, 1.0/24.0]; float t, te, y [21, *u,data[lSI ;

u=allocate~real~vector(-150,150); for (i=l; ic=13; i++) data [i] =datl [i-11 ; t=O.O; y[11=1.0; te=l . 0 ; mO=m=l; ark(&t,&te, &mO,&m,y,derl,data,outl) ; for (i=l; i<=14; i++) data [il =dat2 [i-11 ; data [31 =sqrt (8.0) ; data [S] =data [3l /data [41 ; mO = -150; m=lSO ; t=O. 0; u[01=1.0; for (i=l; i<=m; i++) u[il =u[-il =exp(- (O.OO3*i) * (O.OO3*i)) ; te=0.6; ark(&t, &te, &mO, &m,u, der2, data,out2) ; free-real-vector(u,-150);

I Output:

Problem 1

Copyright 1995 by CRC Press, Inc

Page 708: Numerical Library in C for Scientists and Engineers A

x integration steps y (computed) y(exact) 1 3 8 1.73205e+00 1.73205e+00 2 55 2.23610e+00 2.23607e+00

Problem 2

derivative calls u ( .6,0) (computed) u( .6,0) exact 144 9.13933e-01 9.13931e-01

Function tested: efrk

Example: Consider the system of differential equations:

= -YI + YIYZ + 0 % ~ ~ &Jh = -100O*t-~1 + YlY2 + Y3

with the initial conditions y, = I and y2 = 0 at x = 0. The solution at x = 50 is approximately y, = 0.7658783202487 and y2 = 0,4337103535768. The following program shows some different calls of the procedure e@k.

Note that the computations are carried out in double precision by using the macro statement: #define float double.

From these results it appears that calls with thirdorder equals nonzero in efrk are less advisable.

#define float double

unsigned int passes;

void der(int mO, int m, float x, float y[l) 1

float yl, y2 ;

void out (int mO, int m, float x, float xe, float y [I, float *sigma, float *phi, float *diameter, int k, float *step, int r, int 1)

{ float s;

s= (-1000. o*y [ll -1001. o+y 121 ) /2 .o; *sigma=fabs(s-sqrt (s*s+lO .O* (y 121 -1.0))) ; *diameter=2.O*(*step)*fabs(lOOO.O*

(l.99*~[2] -2.O*y[l] * (1.0-y[2] ) ) ) ; if (X == 50.0)

printf (la %2d %2d %4d %Su %e %e\nu, r,l,k,passes,y[ll .y[2l);

1 void main 0 !

void ef rk (float *, float, int, int, float [I , float *, float *, float *, void ( * ) (int, int, float, float [ I ) , int *, float *, float, float, float [I, int, float, void ( * ) (int, int, float, float, float [I, float *,

float *, float *, int, float *, int, int)); int k,r,l,i;

Copyright 1995 by CRC Press, Inc

Page 709: Numerical Library in C for Scientists and Engineers A

float x,xe, sigma,phi, step,diameter, y [31 ,beta [71 ;

printf("The results with EFRK are:\n\nU " R L K DER.EV. y [I] Y[21 \n") ;

phi=4.0*atan (1.0) ; beta [O] =beta [ll =l. 0; for (r=l; rc=3; r++)

for (1=1; 1c=3; I++) { for (k=2; kc=r; k++) beta [kl =beta [k-11 /k; for (i=l; ic=2; i++) (

step = ((i == 1) ? 1.0 : 0.1); passes=k=O; x=y [21 =o. 0; y[l]=l.O; out (I, 2,x,xe, y, &sigma, &phi, &diameter, k, &step, r, 1) ; efrk(&x, 5O.O,1,2, y, &sigma, &phi, &diameter, der, &k,

&step, r, l,beta, r>=3,l. 0e-3,out) ;

1 Output:

The results with EFRK are:

Function tested: efsirk

Example: Solve the differential equation:

dy1d.x. = -exJy - In($) + I/x with the initial value y(0.01) = In(O.01) over the two ranges [0.01,0.4] and [0.4,8]. The analytic solution is y(x) = In(x).

The above equation is written in autonomous form (taking P(x) = x) as crrl)//d. = - - 1 ~ ( / ~ 9 ) + 1 /y0

= 1. The Jacobian matrix J, for this set of equations has elements

J,",') = -exp(y(2.'), J,('.~) = -JY(') - In('')) - l/yO)exp(y(2i) - 1/('2))2

Copyright 1995 by CRC Press, Inc

Page 710: Numerical Library in C for Scientists and Engineers A

J,",') = J,".') = 0, and its eigenvalue with largest absolute value is 6, = -e~p(y'~.').

float lnx;

void der (int m, float y [I , float *delta) I 1

float y2 ;

void jac(int m, float **j, float y[l, float *delta) I

float y2;

void outp (float x, float xe, int m, float y [I , float delta, float **j, int n)

I 1

float yl ;

if (X == xe) ( y1=y [ll ; lnX=log (x) ; printf ("\n N =%3d X =%4. lf Y (X) = %7. Sf"

DELTA = %4.2f\n ABS.ERR. = %7.2e1' REL . ERR. = %7. 2e\n1',

n,x,yl,delta, fabs (yl-lnx) ,fabs( (yl-1m) /lnx) ;

void main 0 I

void efsirk (float *, float, int, float [I , float *, void ( * ) (int, float[], float * ) , void ( * ) (int, float ** , float [I, float * I , float **, int *, float, float, float, float, int, void ( * ) (float, float, int, float [I,

float, float ** , int)) ; int n; float x,xe,delta,y[31 ,**I;

jzallocate real matrix(l,2,1,2); p r i n t f ( " ~ ~ s ~ ~ ~ ;ielivers:\nU); xe=O. 4 ; x=o. 01; y [ll =log (0.01) ; y 121 =x; efsirk(&x,xe,2,y,&delta,der,jac,j,&n,1.Oe-2,1.Oe-2,0.005,1.5,

0, outp) ; xe=8.0 ; efsirk(&x,xe,Z,y,&delta,der, jac, j ,&n, 1.Oe-2,l.Oe-2,0.005,1.5,

0, OU~D) ;

free-real-mat'rix ( j , l,2,1) ; 1 Output:

EFSIRK delivers:

Copyright 1995 by CRC Press, Inc

Page 711: Numerical Library in C for Scientists and Engineers A

N = 10 X = 0.4 Y (XI = -0.91093 DELTA = -1.44 ABS.ERR. = 5.4e-03 REL.ERR. = 5.8e-03

N = 92 X = 8.0 Y(X) = 2.07639 DELTA = -2962.96 ABS.ERR. = 3.le-03 REL.ERR. = 1.5e-03

Function tested: eferk

Example: Consider the system of differential equations:

dY/h = -Y, + YlY2 + 0.9%

dYJA = -~OOO*(-Y~ + YIY~ + YJ with the initial conditions y, = I and y2 = 0 at x = 0. The solution at x = 50 is approximately y, = 0.7658783202487 and y, = 0.433 71035.35768. The following program shows some different calls of the procedure eferk.

int passes, pas j ac;

void der (int m, float y [I ) {

float yl , y2 ;

void jacobian(int m, float **j, float y[l , float *sigma) I L

j I11 [ll =y [21 -1.0; j [ll [21 =O. 99+y [I] ; j [21 [11=1000.0* (1.0-y [21 1 ; j[21 [21 = -1000.0*(1.O+y[l]); *sigma=fabs (j 121 [21 +j [I1 [I1 -sqrt ( (j [2] Dl- j [I] [I] ) *

(j [21 [21 -j [ll [ll )+4.O*j [21 [ll *j [I] [21 ) ) /2 .O; pas j ac++;

1 void out(float x, float xe, int m, float yil, float **I, int k) I

void main 0 I '

float **allocate-real-matrix (int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void eferk(f1oat *, float, int, float [I, float *, float,

void ( * ) (int, float [I ) , float **, void ( * ) (int, float **, float [I, float * ) , int *, int, int, float, float, float, float, int, void ( * ) (float, float, int, float [I, float **, int));

int i,k; float x,xe,sigma,phi,tol,y[31 ,**I;

j=allocate-real_matrix(1,2,1,2); printf("The results with EFERK are:\n\ntl

" K DER.EV. JAC.EV. y (11 Y[21 \n") ; phi=4.0*atan (1.0) ; tol=l.O;

Copyright 1995 by CRC Press, Inc

Page 712: Numerical Library in C for Scientists and Engineers A

for

~ e ~ 5 0 . 0 ; eferk (&x,xe, 2, y, &sigma,phi, der, j, jacobian, &k, 1,1, tol, tol,

1.0e-6.50.0.0,out) :

1 free-real-matrix (j , l,2,1) ;

1

Output:

The results with EFERK are:

Function tested: linigerlvs

Example: ~bnsider the system of differential equations:

= -Y, + YIY, + 0 % ~ ~ duJd = -1OOO*~-Y, + YlY2 + YJ

with the initial conditions y, = I and y, = 0 at x = 0. The solution at x = 50 is approximately y, = 0.7658783202487 and y, = 0.433 7103535768. The following program shows some integration of this problem with variable and constant stepsizes.

void f (int m, float a[], float *sigma) I 1

float al,a2;

void jacobian (int m, float **j , float y [I , float *sigma)

void out (float x, float xe, int m, float y [I , float sigma, float **j, float info[])

I

void main 0 (

float **allocate-real-matrix(int, int, int, int);

Copyright 1995 by CRC Press, Inc

Page 713: Numerical Library in C for Scientists and Engineers A

void free-real-matrix(f1oat **, int, int, int) ; void linigerlvs(f1oat *, float, int, float [I, float *,

void ( * ) (int, float[], float * ) , float **, void ( * ) (int, float **, float [I, float * ) , int, float, float, float, float, float [I , void ( * ) (float, float, int, float [I , float,

float **, float [ I ) ) ; int i,itmax; float x, sigma, reta, y [31, **j, info [lo1 ;

j=allocate real matrix(l,2,1,2); printf("~hZ results with LINIGERlVS are:\n\ntt); reta=l. 0; for (i=l; ic=3; i++) {

reta *= 1.0e-2; x=y[2]=0.0;

printf ("\nn) ; reta = -1.0; for (i=l; i<=3; i++) {

reta *= 1.0e-2; x=y 121 =o. 0; y[11=1.0; liniger~vs(&x,50.0,2,y,&sigma,f,j,jacobian,lO,O.l,l.O,

reta, reta, info, out) ; l

Output:

The results with LINIGERlVS are:

Function tested: liniger2

Example: Consider the system of differential equations:

@I/& = -YI + YIYZ + 0.99~2 @J& = -1000*(-~1 + YIYZ + Y J

with the initial conditions y, = 1 and y2 = 0 at x = 0. The solution at x = 50 is approximately y, = 0.7658783202487 and y2 = 0.4337103535768. The following program shows some different calls of liniger2.

int passes,pasjac;

;loat f (int m, float y[l , int i, float *sigmal, float *sigma2)

if (i == 1) return (y [I1 +O.99) * (y[21 -1.0) +0.99;

else ( passes++; return 1000.0*( (l.O+y[ll )*(1.0-y[21) -1.0) ;

1

Copyright 1995 by CRC Press, Inc

Page 714: Numerical Library in C for Scientists and Engineers A

void jacobian (int m, float * * j , float y [I , float *sigmal, float *sigma2)

l j [I] 111 =y [21 -1.0; j 111 [21 =o. 99+y [XI ; j [21 [11=1000.0* (1.0-y[2] ) ; j [21 [21 = -1OOO.O* (l.o+y[ll); *sigmal=fabs (j [21 121 +j [ll 111 -sqrt ( (j [21 [21 - j [I] [i] ) *

(j 121 [21 - j [ll 111 +4.0* j [21 Ill *j [11 [21) ) /2.0; pas j ac++ ;

1 int evaluate1 (int i) (

return (i == 1); 1 int evaluate2 (int i) (

return 1; 1 void out (float x, float xe, int m, float y [I,

float sigmal, float sigma2, float **j, int k) 1 I

if (X == 50.0) printf ("%3d %4d %4d %e %e\nm,

k,passes,pasjac,y[ll ,y[21) ; 1 void main 0 I

float **allocate real matrix(int, int, int, int) ; void free-real-m~trix~float ** , int, int, int) ; void liniger2 (float *, float, int, float [ I , float *, float *,

float ( * ) (int, float [I, int, float *, float *) , int ( * ) (int), float **, void ( * ) (int, float **, float [I , float *, float * ) , int *, int, float, float, float, void ( * ) (float, float, int, float [I , float, float,

float **, int)); int i, k, itmax; float x,sigmal,sigma2,step,y[3] ,**j;

j=allocate-real_matrix(1,2,1,2) ; printf ("The results with LINIGER2 (second order) are:\nnl

" K DER.EV. JAC. EV. y I11 Y [21 \n") ; for (i=l; ic=2; i++) (

step = (i == 1) ? 10.0 : 1.0; for (itmax=l; itmax<=3; itmax += 2) {

passes=pasjac=O; x=y 121 -0.0; y[ll=l.O; sigma2=0.0; liniger2(&x,50.0,2,y,&sigmal,&sigma2,f,evaluatel,j,

jacobian,&k,itmax,step,1.0e-4,1.0e-4,out~;

\ I

print£ ("\nThe results with LINIGER2 (third order) are : \nu " K DER.EV. JAC.EV. Y[1] Y Dl \n") ;

for (i=l; i<=2; i++) ( step = (i == 1) ? 10.0 : 1.0; for (itmax=l; itmax<=3; itmax += 2) (

passes=pasjac=O; x=y[21 =o.o; y[11=1.0; sigma2=0.0; liniger2(&x,50.0,2,y,&sigmal,&sigma2,f,evaluate2,j,

jacobian,&k,itmax,step,1.0e-4,1.0e-4,out);

1 I

Copyright 1995 by CRC Press, Inc

Page 715: Numerical Library in C for Scientists and Engineers A

1 Output:

The results with LINIGER2 (second order) are: K DER.EV. JAC.EV. y [I] Y [21 5 5 5 7.65612e-01 4.33970e-01 5 15 5 7.65755e-01 4.33671e-01

50 50 50 7.65865e-01 4.33710e-01 50 101 50 7.65877e-01 4.33710e-01

The results with LINIGERZ (third order) are: K DER.EV. JAC.EV. Y [I] Y [21 5 5 5 7.65612e-01 4.33970e-01 5 15 15 7.65882e-01 4.33712e-01

50 50 50 7.65865e-01 4.33710e-01 50 101 101 7.65879e-01 4.33711e-01

Function tested: gms

Example: Solve the system of differential equations:

@I/& = -1 OOOy("(y"'+y f2)-I.999987) w)/& = -2500y(2)(yl"+y(2)-2) with the initial value y"'(0) = f12)(0) = I over the range [0,50]. The The Jacobian matrix J, for this set of equations has elements

J,".') = 1999.987 - 1 000(2y(')+y"9, JnfV) = -1000y(~) ~ ~ ( 2 . ' ) = - 2 5 0 ~ ) J,"~) = 2500(2-~(I)-y(9

#include cmath.h> #include cstdio.h>

void der (int r, float y [I , float *delta) I

float yl,y2;

void jac(int r, float **j, float y[l , float *delta) (

float yl,y2;

void outp (float x, float xe, int r, float y [I , float delta, int n, int jev, int lu)

float ye1,yeZ;

)e1=0 :5976546988; ye2=1.4023434075; printf ( " X = %2.0£ N = %4d JEV = %3d LU = %4d\n1*

Copyright 1995 by CRC Press, Inc

Page 716: Numerical Library in C for Scientists and Engineers A

void main 0 l

void gms (float * , float, int, float [I, float, float, float, float *, void ( * ) (int, float [I, float *) , void ( * ) (int, float **, float [ I , float * ) , float, float, int *, int *, int * , int, int, void ( * ) (float, float, int, float [I , float,

int, int, int)); int n, jev, lu; float x, y [31 ,delta;

printf ("The results with GMS are: \nM) ; y[ll=yt21=1.0; x=o . 0 ; delta=O.O; gms(&x,50.0,2, y, 0.01,0.001,0.5,&delta,der, lac, 1.Oe-5,l.Oe-5,

&n,&jev, &lu, O,O,outp) ; 1

Output:

The results with GMS are: X = 50 N = 1851 JEV = 608 LU = 1742 Y1 = 5.97714e-01 REL.ERR. = 1.00e-04 Y2 = 1.40228e+00 REL.ERR. = 4.2e-05

Function tested: impex

Example: Consider the autonomous system of differential equations:

& / / A = 0.265 - Y J 4 J k = - (60 - Y J ~ ) Y ~ + Y J ~ &/A = I

with initial conditions y,=y,=y,=O at x=O. The solution at several points in the interval [0,400] may be obtained by the following program. (The solution at ~ 4 0 0 is y,=22.24222Oll, y2=27.11071335)

int nfe,nje,point; float print I61 ;

void f (float t, float y[] , float £1 [I, int n) {

int available (float t, float y [I , float **a, int n) I

a[21 [11=10.0; a[21 [21=0.125*y [31-60.0; a [2] [3] =O.l25* (l.O+y [21 ) ; return 1;

1

Copyright 1995 by CRC Press, Inc

Page 717: Numerical Library in C for Scientists and Engineers A

void update (float sw [I, float rl [I, int n) (

int i; float sl, s2;

for (i=l; ic=n; i++) ( sl=l. O/sw [il ; s2=fabs (rl [il ) ; if (sl c s2) sw[iI=l.O/s2;

I I

void control(f1oat *tp, float t, float h, float hnew, float **y, float err[], int n, float tend)

1 L

int i; float c[61 ,*x,s,s2,s3,s4;

x=allocate real-vector (1, n) ; while (1) T

s= (t- (*tp) ) /h; S2=S*S; S3=S2*S; s4=s3*s; c 131 = (~2-S) /2 .O; c [4] = -~3/6.0+~2/2 .O-~/3.0; ~[5]=~4/24.0-~3/4.0+11.0*~2/24.0-~/4.0; for (i=l; ic=n; i++)

x [il =y[ll [il -s*y [21 [il +c [3l *y [3l [il+ c [41 *y[41 [il +c [51 *y 151 [il ;

printf ( I1 %6.2f %7.2e %e %e %4d %3d\nn, *tp,err [31 ,x[ll ,x[21 ,nfe,nje) ;

if (*tp >= tend) break; point++; *tp = print [point] ; if (*tp > t) break;

1 kree-real-vector (x, 1) ;

1 void main 0 {

void impex (int, float, float, float [I , void ( * ) (float, float [I, float [I, int), int ( * ) (float, float [I, float ** , int) , float, float, int, float, float [ I , void ( * ) (float [I , float [I , int) , int *fail, void ( * ) (float * , float, float, float, float * * ,

float [I, int, float)); void dupvec (int, int, int, float [I, float [I ) ; float vecvec(int, int, int, float [I, float [I ; void elmvec (int, int, int, float [I , float [I , float) ; int n,fail,i,it; float t,tend,eps,hmax,l,h2,y[41 ,sw[4] ,f1[41 ,f2[4] ,z[4] tx[4],

nl,n2;

printf("The results with IMPEX are:\n\nl'); n=3 ; nje=nfe=O; t=O. 0; tend=400.0; eps=l.Oe-5; hmax=400.0; y[ll =y[21 =y[31 =o.o; sw [I] =sw [21 =SW [3l =I. 0; print [l] =0.1; print [21 =l. 0; print 131 =lo. 0; print [41 =loo. 0; print [51=400.0; dupvec(l,n,O,z,y); for (i=l; ic=n; i++)

x[i] = (y [il == 0.0) ? eps : (l.O+eps) *y [il ; nl=sqrt (vecvec (l,n, O,x,x) ) *eps; f(t,x,fl,n) ; for (it=l; itc=5; it++) (

f(t,z,f2,n) ;

Copyright 1995 by CRC Press, Inc

Page 718: Numerical Library in C for Scientists and Engineers A

£(t,z,fl,n) ; elmvec(l,n,O,f2,fl, -1.0) ; l=sqrt(vecvec(l,n,O,f2,f2) )/nl; h2=pow(eps*320.0,1.0/5.0) / (4.0*1) ; printf("EPS = %e\nInterval of integration = (%1.0f,%3.0f)\nU

"Maximally allowed stepsize = %e\n\nLipschconst = %e\n" "Starting stepsize = %e\nFunctional eval = %2d\n\nu " X ERROR Y [I] Y [21 NFE NJE\nN, eps, t, tend,hmax, l,h2,nfe) ;

impex (n, t, tend, y, f, available, h2, hmax, 0, eps, sw, update, &fail, control) ;

printf("\nNumber of functional evaluations =%4d\nl1 "Number of Jacobian evaluations = %3d\nl1 ,nfe, nje) ;

1 Output:

The results with IMPEX are:

EPS = 1.000000e-05 Interval of integration = (0,400) Maximally allowed stepsize = 4.00000e+02

Lipschconst = 6.01554e+01 Starting stepsize = 1.31733e-03 Functional eval = 7

X ERROR y [I] Y [21 0.00 O.Oe+OO 0.00000e+00 0.00000e+00 0.10 1.4e-06 1.49652e-06 1.73902e-04 1.00 1.8e-06 1.91084e-04 2.08362e-03 10.00 3.5e-06 1.30151e-02 2.34488e-02 100.00 3.8e-06 3.06299e-01 3.27548e-01 400.00 1.7e-05 2.22389e+01 2.71076e+01

NFE NJE 7 0 57 4 98 9 142 11 253 14 581 34

Number of functional evaluations = 581 Number of Jacobian evaluations = 34

Function tested: modifiedtaylor

Example: Solve the differential equation:

Du(t) = -el{u(t) - In(t)} + l / t (1) where D=d/dt, with initial condition ~ ( 0 . 0 1 ) = ln(O.O1) (the analytic solution is u(t) = In(t)) over the ranges [O.Ol,e] and [e,e2], using a fourth order modified Taylor series method with third order exact stability polynomial with coefficients J, = lI/j! (j=0, ..., 3) J , = 0.018455702 (whose range constant is J(4) = 6.025). The required derivatives of u(t) are given by

Pu( t ) = e'{ln(t) + I/t - u(t) - Du(t)) - l / t2 D3u(t) = d{ln(t) + 2/t - u(t) - 2Du(t) - D2u(t) - I/t2} + 2/t3 DJu(t) = D3u(t) - 2(1 + 3/t)/T' + d[ { l - (2 - 2/t)/t}/t - Du(t) - 2D2u(t) - D3u(t)].

The spectral radius with respect to the eigenvalues lying in the left half-plane of the Jacobian matrix derived from equation (1) is simply el.

float expt,lnt,c0,cl,c2,c3;

void der(f1oat t, int mO, int m, int i, float a[])

Copyright 1995 by CRC Press, Inc

Page 719: Numerical Library in C for Scientists and Engineers A

float sigma (float t, int mO, int m) (

return exp (t) ; 1 float aeta(f1oat t, int mO, int m) I

return 1.0e-5; I float reta(f1oat t, int mO, int m) I

return 1.0e-4; I void op(f1oat t, float te, int mO, int m, float u[l,

int k, float eta, float rho) f I

if (t == te) printf (I1\nNumber of steps: %3d\n1I

solution: T = %8.6f U(T) = %8.6f\nn, k, t,u[01 ) ;

I void main 0 {

float *allocate-real-vector(int, int); void free-real-vector(f1oat *, int); void modif iedtaylor (f loat , float, int, int, float [I ,

float ( * ) (float, int, int) , float, void ( * ) (float, int, int, int, float [I ) , int *, float [I , float, int, float ( * ) (float, int, int) , float ( * I (float, int, int) , float *, float *, void (*) (float, float, int, int, float [I,

int, float, float) ; int j,k; float t, te,eta,rho,u[ll ,*data;

data=allocate real-vector(-2,4); printf("The results with MODIFIEDTAYLOR are:\nl'); data[-21 =4.0; data[-l]=3 .O; data[01=6.025; data[ll =l.O; data [2] ~0.5; data [3] =l.O/6.O; data 141 =O. 018455702; t=u [O] =l. 0e-2 ; k=O; for (j=l; jc=2; j++) {

te = (j == 1) ? exp(l.0) : te*te; modifiedtaylor(&t,te,O,0,u,sigma,1.Oe-4,der,&k,data,1.5,

l,aeta, reta, &eta, &rhotop) ; 1 I

free-real-vector(data,-2); 1 Output:

The results with MODIFIEDTAYLOR

Number of steps: 46 Solution: T = 2.718282 U(T)

are :

= 1.000028

Copyright 1995 by CRC Press, Inc

Page 720: Numerical Library in C for Scientists and Engineers A

Number of steps: 424 Solution: T = 7.389056 U(T) = 1.999989

Function tested: eft

Example: Solve the differential equation:

Du(@ = -ef{u(t) - In(@} + l/t (1) where D=d/dt, with initial condition ~(0.01) = ln(O.O1) (the analytic solution is u(t) = In(t)) over the ranges [O.Ol,e] and [e,e2], using a third order, first order consistent, exponentially fitted Taylor series method. The equation is solved eight times with different absolute and relative tolerances. The derivatives of (1) are as described in the test program of m odifiedtaylor .

float expt,lnt,uO,ul,u2,accuracy;

void derivative(f1oat t, int mO, int m, int i, float u[l) 1 ' if (i == 1) (

expt=exp (t) ; lnt=log (t) ; uo=u [O] ; ul=u[O] =expt*(lnt-uO)+l.O/t;

} else if (i == 2) u2=u[0] =expt* (lnt-u0-ul+l.O/t) -l.O/t/t;

else u[0]=expt*(lnt-u0-2.0*ul-u2+2.O/t-l.O/t/t)+2.O/t/t/t;

1 float sigma (float t, int mO, int m) (

return exp (t) ; I float diameter(f1oat t, int mO, int m) (

return 2.0*exp (2.0*t/3.0) ; I float aetal(f1oat t, int mO, int m) (

return accuracy/lO.O; I float aeta2(float t, int mO, int m) (

return accuracy/lO.O*((t c 3.0) ? 1.0 : exp(2.0*(t-3.0) 1 ) ; I float retal(f1oat t, int mO, int m) (

return accuracy; I float reta2 (float t, int mO, int m) (

return accuracy*((t c 3.0) ? 1.0 : exp(2.0*(t-3.0))); I void out(f1oat t, float te, int mO, int m, float u[l,

int k, float eta, float rho) (

if (t == te) printf ( " %3d %e ",k,u[Ol); I

Copyright 1995 by CRC Press, Inc

Page 721: Numerical Library in C for Scientists and Engineers A

void main 0 1

void eft (float * , float, int, int, float [I, float ( * ) (float, int, int), float, float ( * ) (float, int, int), void ( * ) (float, int, int, int, float [I), int * , float, int, float ( * ) (float, int, int), float ( * I (float, int, int), float *, float *, float, float *, void ( * ) (float, float, int, int, float [I,

int, float, float)); int j,k,l; float t, te, tel, te2, eta, rho,pi,hs,u 111 ;

printf ("The results with EFT are: \n" It K U(TE1) K U (TE2) RETA\nl1 ) ;

pi=4 .O*atan(l. 0) ; tel=exp (1.0) ; te2=exp(2.0) ; accuracy=l.O; for (j=l; j<=4; j++) (

accuracy *= 1.0e-1; t=0.01; u[Ol =log(t) ; k=O ; hs=O . 0 ; for (1=1; 1<=2; I++) {

te = (1 == 1) ? tel : te2; eft(&t,te,O,O,u,sigma,pi,diameter,derivative,&k,

1.5,2, aetal, retal, &eta, &rho, l.0e-4, &hs,out) ; 1 brintf ( " %6. le\nu , accuracy) ;

\ irintf("\n~ith relaxed accuracy conditions for t > 3 :\nn

" K U(TE1) K U (TE2 ) RETA\nl1 ) ; accuracy=l.O; for (j=l; j<=4; j++) {

accuracy *= 1.0e-1; t=0.01; u[O] =log(t) ; k=O ; hs=O. 0; for (1=1; 1<=2; 1++) (

te = (1 == 1) ? tel : te2; eft(&t,te,~,O,u,sigma,pi,diameter,derivative,&k,

1.5,2,aeta2,reta2,&eta,&rho,l.Oe-4,&hs,out; I brintf ( " $6. le\nl', accuracy) ;

I I

Output:

The results with EFT are: K U(TE1) K U (TE2) RETA 15 1.00156e+00 42 2.00008e+00 le-01 22 1.00141e+00 52 2.00007e+00 1.0e-02 37 1.00024e+00 94 2.00001e+00 1.0e-03 60 1.00003e+00 174 2.00000e+00 1.0e-04

With relaxed accuracy conditions for t > 3 : K U(TE1) K U (TE2) RETA 15 1.00156e+00 42 2.00008e+00 le-01 22 1.00141e+00 50 2.00005e+00 1.0e-02 37 1.00024e+00 69 2.00002e+00 1.0e-03 60 1.00003e+00 103 2.00000e+00 1.0e-04

Function tested: rk2

Example:

Copyright 1995 by CRC Press, Inc

Page 722: Numerical Library in C for Scientists and Engineers A

The van del Pol equation dty/'ik2 = IO(1-y=)(&/&) - y , x 2 0,

y = 2, &/& = 0, x = 0, can be integrated by rk2. At the points x=9.32386578, 18.86305405, 28.40224162, 37.94142918 the derivative d y / h vanishes.

Note that the computations are carried out in double precision by using the macro statement: #define float double.

#define float double

float fxyz(f1oat x, float y, float z) I L

return l0.0* (1.0-y*y) *z-y; 1 void main 0

void rk2(float *, float, float, float *, float, float * , float, float ( * ) (float, float, float), float [I, float [I, int);

int i,fi; float x,y,z,e[SI ,d[61,

b[4]=(9.32386578, 18.86305405, 28.40224162, 37.94142918);

e [I] =e [21 =e [31 =e [41 =e [51 =l.Oe-8; printf (ItRK2 delivers : \nW ) ; for (i=O; i<=3; i++) (

fi=(b[i] < 10.0); rk2 (&x, 0.0, b [i] , &y, 2.0, &z, 0.0, fxyz, e, d, f i) ; printf(" X = %+e Y = %+e DY/DX = %+e\n1I,x,y,z);

. I

Output:

RK2 delivers : X = +9.32387e+00 Y = -2.01429e+00 X = +1.88631e+01 Y = +2.01429e+00 X = +2.84022e+01 Y = -2.01429e+00 X = +3.79414e+01 Y = +2.01429e+00

Function tested: rk2n

Example: The second order differential equation

d y / & = -5b2 &I/&) + YI, x 2 0, yI = &J& = I , y, = d y , / h = 0, x = 0

with analytic solution yl = (5/6)ea + e-'" - (l/2)e-" - (1/3)e4", y2 = (5/6)ea - e-'" + (1/2)e4" - (1/3)e4"

can be integrated by rk2n from 0 to 5 with 1,2,3,4 as reference points.

float fxyzj (int n, int j, float x, float y[l , float z[l )

( return -5.O*(y[jl+z[jl)+((j == 1) ? y[21 : y[ll);

1

Copyright 1995 by CRC Press, Inc

Page 723: Numerical Library in C for Scientists and Engineers A

void main 0 ( void rk2n (float , float, float, float [I , float [I 1 float [I

float [I , float ( * ) (int, int, float, float [I t float 11 ) 1

float [I, float [I, int, int); int k,fi; float b,x, expx, y [3l , ya [3l ,z [3l ,za[31 ,e [9] ~d[8] ;

printf ("Results from RK2N :\nu) ; for (k=l; kc=8; k++) e[kl=l.Oe-5; ya [l] =za [2] =l. 0; ya [2] =za Ill =O. 0; b=1.0; do {

fi=(b == 1.0); rk2n(&x,O.O,b,y,ya,z,za,fxyzj,e,d,fi,2); expx=exp ( -x) ; ya[l] = -expx* (expx*(expx*(expx/3.0+0.5)-1.0) -5.0/6.O) ; ya[2] = -expx*(expx*(expx*(expx/3.0-0.5)+1.0) -5.0/6.0) ; za[l] =expx* (expx* (expx* (expx/O.75+1.5) -2.0) -5.0/6.0) ; za[2]=expx*(expx*(expx*(expx/O.75-1.5)+2.0) -5.0/6.0) ; printf ("\n X = %6.4f\nY [l] -YEXACT [I] = %+6.2e "

"Y [2] -YEXACT [2] = %+6.2e\nZ [I] -ZEXACT [I] = %+6.2e "

"Z [2] -ZEXACT[2] = %+6.2e\nw,x,y [I] -ya[ll ,y [21 -ya[21 , z [ll -za [ll , z [21 -za [2I ) ;

b += 1.0; ) while (b c 5.0) ;

1 Output:

Results from RK2N :

Function tested: rk3

Example: Compute the solution of

y" = xy, y(0) = 0, y'(0) = 1 at interval [0,1].

float fxy(f1oat x, float y) (

return x*y; 1 void main 0

Copyright 1995 by CRC Press, Inc

Page 724: Numerical Library in C for Scientists and Engineers A

int n,i,fi; float x, y, z, e [6] , d [61 , x3, s, term,

b[4]={0.25, 0.50, 0.75, 1.00);

e [ll =e [31 =l.Oe-6; e[2] =e 141 =l.Oe-6; printf ( "RK3 delivers : \n" ) ; for (i=O; ic=3; i++) {

fi=(b[il < 0.3); rk3 (&x, 0.0, b [il , &y, 0.0, &z, 1.0, fxy, e, dt fi) ; x3 =x*x*x; term=x; s=o .o ; n=3 ; do (

s += term; term=term*x3/n/ (n+l) ; n += 3;

} while (fabs(term) > 1.0e-14); printf ("Y-YEXACT= %+e X= 24.2f Y= $8 .6f\n1', y-s,x, y) ;

) 1

Output:

RK3 delivers : Y-YEXACTs +0.00000e+00 X= 0.25 Y= 0.250326 Y-YEXACT= +5.96046e-08 X= 0.50 Y= 0.505224 Y-YEXACTs +0.00000e+00 X= 0.75 Y= 0.776633 Y-YEXACT= -1.19209e-07 X= 1.00 Y= 1.085340

Function tested: rk3n

Example: Solve the second order differential equation

Y," = YE y2" = -Y, with y,(O) = y2(0) = 1, y, '(0) = y2 '(0) = 0, the exact solutions of which are

y,(x) = c o s h ( d 2 ) * c o s ( d 2 ) + s i n h ( d 2 ) * s i n ( d 2 ) y2(x) = c o s h ( d 2 ) * c o s ( d 2 ) - s i n h ( d 2 ) * s i n ( d 2 ) .

These equations can be integrated by rk3n because first derivatives are absent from them. Integration is carried out over the intervals [v ,v+ l ] , v=0,1, ..., 4 .

float fxyj (int n, int j, float x, float y [I ) 1 1

return ((j == 1) ? y [21 : -y[ll) ; 1 void main 0

' void rk3n(float * , float, float, float [ I , float [ I , float [I, float [I , float ( * ) (int, int, float, float [I ) , float [I , float [I , int, int) ;

int k,fi,i,n, j; float b,x,y[31 ,ya[31 ,z[31 ,e[91 ,d[81 ,xZ,term;

printf("Resu1ts from RK3N :\nM for (k=l; kc=8; k++) e[kl=l.Oe

Copyright 1995 by CRC Press, Inc

Page 725: Numerical Library in C for Scientists and Engineers A

rk3n(&x,0.0,b,y,y,z,z,fxyj,e,d,fit2) ; ya [ll =ya [21 =O. 0; term=l. 0; x2=x*x*o.5; n=l; do I

for (i=l; i<=2; i++) { j=(i+n-2) /2; ya[i] += term* ((j%2 == 0) ? 1 : -1) ;

I

n++ ; ) while (fabs (term) > 1.0e-14) ; printf ( " ABS (YEXACT [11 -Y [ll +ABS (YEXACT 121 -Y [21 ) = %e\nl',

fabs (y [l] -ya [ll ) +fabs (ya [21 -y [21 ) ) ; fi=O ;

) while (b c 5.0); 1

Output:

Results from RK3N : ABS (YEXACT [I] -Y [l] ) +ABS (YEXACT [2] -Y [2] ) = 2.98023e-07 ABS (YEXACT [I] -Y [l] ) +ABS (YEXACT [2] -Y [2] ) = 3.57628e-07 ABS (YEXACT [l] -Y [l] ) +ABS (YEXACT [2] -Y 121 ) = 1.43051e-06 ABS (YEXACT [I] -Y [l] ) +ABS (YEXACT [2] -Y [2] ) = 4.29153e-06 ABS (YEXACT [I] -Y [I] ) +ABS (YEXACT [2] -Y [2] ) = 1.33514e-05

Function tested: arkmat

Example: Solve the initial boundary value problem

on the domain Olt11, Olx171, OSyll, with initial conditions u(O,x,y) = sin($ *cos(ny/2), (a/at)u(t,x,y) ,,,=O (Olxlx, Osyll)

and boundary values u(t,x, 0) = sin@) *cos{(l +n2/4)t), u(t,x, I) = 0 (0917~)

u(t,O,y) = u(t,n,y) = 0 (01yll) over the range OIt11. The analytic solution of the above initial boundary value problem is

u(t,x, y) = cos{(l + n 2/4) t) *sin@) *cos(ny/2) ).

Equation (1) may be reduced to a form of the first order in t by setting v(t,ay) = Du(t,x,y)

where D=a/at, when

The above first order form is solved by discretizing the variables x,y, and including the construction of the boundary values in the integration of the resulting set of first order differential equations in t, making use of the conditions

D2u(t,x,l) = 0 (Olxlx) D2u(t,0,y) = D u ( t , ~ , ~ ) = 0 (Ol,y11)

and further use of the symmetry property (easily deduced from the form of the original equation and the initial and boundary conditions) that u(t,x,-y) = u(t,x,y), to assist in the

Copyright 1995 by CRC Press, Inc

Page 726: Numerical Library in C for Scientists and Engineers A

determination of D2u(t,x, 0) (OeSx). Taking AX = u/(m-I), ~y = l/(n-I) and for i=l, ..., n; j=l, ..., rn

rf'J'(5) = u(t, G;-l)a, (i-I) by) u'"+'J)(t) = v(t, 0-1) AX, (i-1) AY)

the equations DPJ = I fn+i j ) (i=l, ..., n; j=l, ..., m) ~ p i j ) = {P j+J) - 2 f l j ) + Q J - O } / ( ~ ) ~ +

{ p l ~ ) - 2rf'j) + @ - I J ) } / ( ~ ~ ) ~ (i=2 ,..., n-1; j=2 ,..., m-1) ~ v . 1 ) = ~ c f ' " + ' , m ) = 0 (i=l, ..., n) DU2"j) = 0 (j=2; ..., m-1) D ~ + J J ) = {@j+l) - 2UlJ) + Ulj-1)

+

2{rf2') - u1J)}/(~y)2 G=2, ..., m-1) for the components of the 2nxm matrix U are derived. The initial values for this set of equations are

VJ) = sin{G;-1) AX} *cos{u(i-I) ~y/2) , Ifn+'J) = O (i=l, ..., n; j=l, ..., m). The above set of equations with m=n=lO are solved by use of arkmat with parameters type = 3, order = 2 and constant step length in t equal to 0.1.

int tel; float hlk, h2k,hpi,hl, h2;

void der(int m, int n, float t, float **u, float **du) I

int i, j;

n=n/2 ; for (i=2: i<=n-1; i++)

for (i=2: i<=m-1: i++)

for '(j=l; j<=rn; j += m-1) ( inimat (n+l,n+n, j, j,du,O.O) ; for (i=l; i<=n; i++) du[il [jl =u[n+ll [jl ;

1 for (i=l; i<=n; i += n-1)

for (j=2; j<=rn-1; j++) ( du[il [jl=u[i+nl [jl ; if (i == 1)

du[n+ll [jl =(u[lI [j+ll -2.O*u[lI [jl+u[ll [j-11 ) /hlk+ (2.0*u[21 [jl-2.O*u[ll [jl ) /h2k;

else du[2*nl [jl=O.O;

1

void out (float t, float te, int m, int n, float **u, int type, int order, float *spr)

I

int i;

tel++; if (t == te) (

for (i=l; i<=10; i++) printf (I1%6.3f %6.3f %9.6f %9.6f\n1',

(i-1) *hl, (i-1) *h2,u[il [il , sin(hl* (i-1) ) *cos (hpi*h2* (i-1) ) *cos (t*sqrt (l.O+hpi*hpi) ) ) ;

printf("\nThe number of integration steps: %2d\ntt Type is %Id Order is %1d\ne8, tel, type, order) ;

1

Copyright 1995 by CRC Press, Inc

Page 727: Numerical Library in C for Scientists and Engineers A

void main 0 I

float **allocate-real-matrix (int, int, int, int) ; void f ree-real-matrix (f loat **, int, int, int) ; void arkmat(f1oat *, float, int, int, float **,

void ( * ) (int, int, float, float **, float **) , int, int *, float *, void (*)(float, float, int, int, float **, int, int, float * ) ) ;

int i,j,n,m,typ,orde; float **u,t,te,cosl,spr;

u=allocate~real~matrix(1,20,1,10) ; hpi=2.O*atan(l. 0) ; h2=1.0/9.0; hi= (2.O*hpi) /9.O; n=m=lO ; hlk=hl*hl; h2k=h2*h2; tel=O; t=O.O; te=l . 0 ; for (j=l; jc=m; j++) u[nl [jl=sin(hl*(j-1)); for (i=l; i<=n; i++) {

cosl=cos (h2*hpi* (i-1) ) ; for (j=l; j<=m; j++) u[il [jl=u[nl [jl*cosl;

1 inimat(n+l,n+n, l,m,u,O.O); typ=3 ; orde=2 ; spr=80.0; arkmat (&t, te, m, n+n, u, der, typ, &orde, &spr, out) ; f ree-real-matrix (u, l,20,1) ;

1 Output:

The number of integration steps: 10 Type is 3 Order is 2

Function tested: femlagsym

Example: Compute approximations to the solution of the boundary value problem

- D { W ( x ) } + cos(x)y(x) = ex{sin(x) - cos{x]} + sin(2x)/2 ~ ( 0 ) = Y(T) = 0

where D=ddx, at the points xi = i d n , i=O, ..., n, (approximating the solution on a uniform grid) for the six cases in which n = 10, 20 and the order of the method used is 2, 4, 6. The analytical solution to the above problem is y(x) = sin(x).

float r (float x)

Copyright 1995 by CRC Press, Inc

Page 728: Numerical Library in C for Scientists and Engineers A

{ return cos (x) ;

1 float p (float x) I

return exp (x) ; 1 !loat f (float x)

return exp (x) * (sin (x) -cos (x) ) +sin(2.0*x) /2.0; 1 void main 0 I '

void f emlagsym (f loat t 1 , float [I , int, float ( * ) (float) , float ( * ) (float), float ( * ) (float), int, float [I);

int n,i,order; float pi,x[211,y[211 ,e[71 ,rho,d;

printf ("FEMLAGSYM delivers : \n") ; for (n=10; n<=20; n += 10) (

e[l]=e[41=1.0; e [2] =e t31 =e [51 =e [61 =O.O; pi=3.14159265358979; for (i=O; i<=n; i++) x[il=pi*i/n; printf ( "N=%2d\ngS, n) ; for (order=2; order<&; order += 2) {

femlagsym(x, y,n,p, r, f, order, e) ; rho=O .0 ; for (i=O; i<=n; i++) {

d=fabs (y[i] -sin(x [il ) ) ; if (rho c d) rho=d;

1 printf ( " ORDER=%ld MAX. ERROR= %7. 3e\n1', order, rho) ;

1 1

1 Output:

FEMLAGSYM delivers : N=10

ORDER=2 MAX.ERROR= 1.36e-02 ORDER=4 MAX.ERROR= 7.56e-05 ORDER=6 MAX.ERROR= 8.74e-08

N=20 ORDER=2 MAX.ERROR=3.41e-03 ORDER=4 MAX.ERROR= 4.91e-06 ORDER=6 MAX.ERROR=1.77e-07

Function tested: fernlag

Example: Compute approximations to the solution of the boundary value problem

-D2y(x) + e'y(x) = sin(x)fl+d'] ~ ( 0 ) = Y(T) = 0

where D=d/dr, at the points xi = i d n , i=O, ..., n, (approximating the solution on a uniform grid) for the six cases in which n = 10, 20 and the order of the method used is 2, 4, 6. The analytical solution to the above problem is y(x) = sin($.

float r(f1oat x) (

Copyright 1995 by CRC Press, Inc

Page 729: Numerical Library in C for Scientists and Engineers A

return exp (x) ; 1 float f (float x) I

return sin (x) (l.O+exp (x) ) ; 1 void main 0 I '

void femlag(f1oat [I, float [I, int, float (*)(float), float ( * ) (float), int, float [I);

int n,i,order; float pi,x[211, y[211 ,e [71 ,rho,d;

printf ("FEMLAG delivers :\nu') ; for (n=10; nc=20; n += 10) (

e[ll=e[41=1.0; e [2] =e [31 =e [51 =e [61 =O .O; pi=3.14159265358979; for (i=O; lc=n; i++) x[il=pi*i/n; printf ("N=%2d\nU, n) ; for (order=2; orderc=6; order += 2 ) (

femlag(x, y,n,r, f ,order,e) ; rho=O. 0 ; for (i=O; icsn; i++) (

d=fabs (y[il -sin(x[il ) ) ; if (rho c d) rho=d;

1 brintf (I1 ORDER=%^^ MAX.ERROR= $7. 3e\n1I, order, rho) ;

Output:

FEMLAG delivers: N=10

ORDER=2 MAX.ERROR=1.60e-03 ORDER=4 MAX.ERROR= 1.54e-05 ORDER=6 MAX.ERROR= 1.19e-07

N=20 ORDER=2 MAX.ERROR= 4.01e-04 ORDER=4 MAX.ERROR= 9.93e-07 ORDER=6 MAX.ERROR= 8.74e-08

Function tested: femlagspher

Example: Solve the boundary value problem

-(y'xn') '/P + y = I - x4 + (12 + 4*nc)$ 0 < x < 1; y'(0) = y(1) = 0.

The analytical solution is y(x) = 1 - x4. We approximate the solution on a uniform grid, i.e. xi=i/n, i=O, ..., n, with n = 10, 20 and the order of the method used is 2 and 4.

#include cmath.h> #include cstdio.h>

int nc;

float r(f1oat x) I

return 1.0; 1 float f (float x) (

Copyright 1995 by CRC Press, Inc

Page 730: Numerical Library in C for Scientists and Engineers A

return (12+4*nc)*x*x+1.0-x*x*x*x; I void main 0 I

void femlagspher (float [I , float [ I , int, int, float ( * ) (float) 1

float ( * ) (float), int, float [I); int n, i , order; float x [211, y [211 , e [71 ,rho, d;

printf ("FEMLAGSPHER delivers : \nu) ; for (n=10; n<=20; n += 10)

for (nc=O; ncc=2; nc++) { e[21 =e[41=1.0; e [ll =e [31 =e [5l =e [61 =O. 0; for (i=O; ic=n; i++) x[il =(float) (i)/(float) (n) ; printf ("N= %2d NC=%2d\nu, n,nc) ; for (order=2; order<=4; order += 2) {

femlagspher(x,y,n,nc,r,f,order,e) ; rho=O. 0 ; for (i=O; i<=n; i++) {

d=fabs (y [il -l.O+x [i] *x [il *x [i] *x [il ) ; if (rho c d) rho=d;

1 brintf ( " ORDER=%ld MAX.ERROR= % 7 . 3e\n1', order, rho) ;

1

1 I

Output:

FEMLAGSPHER delivers: N=10 NC=O

ORDER=2 MAX.ERROR= ORDER=4 MAX. ERROR=

N= 10 NC= 1 ORDER=2 MAX. ERROR= ORDER=4 MAX.ERROR=

N=10 NC=2 ORDER=:! MAX.ERROR= ORDER=4 MAX. ERROR=

N= 20 NC= 0 ORDER=2 MAX.ERROR= ORDER=4 MAX. ERROR=

N= 20 NC= 1 ORDER=2 MAX.ERROR= ORDER=4 MAX. ERROR=

N= 20 NC= 2 ORDER=2 MAX.ERROR= ORDER=4 MAX. ERROR=

Function tested: fernlagskew

Example: Compute approximations to the solution of the boundary value problem

- y l + cos(x)yJ + d y = sin(x)fl + d;\ + {cos(x)}~ 0 < x < u; y(0) = y(u) = 0.

The analytical solution is y(x) = sin(x). We approximate the solution on a uniform grid, i.e. xi=iu/n, i=O, ..., n, with n = 10, 20 and the order of the method used is 2, 4 and 6 .

float q(f1oat x) i

return cos (x) ; 1

Copyright 1995 by CRC Press, Inc

Page 731: Numerical Library in C for Scientists and Engineers A

float r(f1oat x) I

return exp (x) ; 1 float f (float x) {

return sin (x) * (1 . O+exp (x) ) +cos (x) *cos (x) ; 1 void main 0 I ' void fernlagskew (float [I , float 11 , int, float ( * ) (float) ,

float ( * ) (float), float ( * ) (float), int, float [ I ) ; int n, i, order; float pi,x[211, y [211 .e[71 ,rho,&

~rintf ("FEMLAGSKEW delivers : \ntl) :

for (i=O; i<=n; i++) x[il=pi*i/n; printf ("N=%2d\nn, n) ; for (order=2; order<=6; order += 2) {

fernlagskew (x, y,n. q, r, f, order, e) ; rho=O. 0 ; for (i=O; i<=n; i++) {

d=fabs (y [il -sin(x[il ) ) ; if (rho < d) rho=d;

1 I printf ( I 1 ORDER=%ld MAX.ERROR= $7. 3e\n1', order, rho) ;

1 1

1 Output:

FEMLAGSKEW delivers: N=10

ORDER=2 MAX.ERROR= 2.95e-03 ORDER=4 MAX.ERROR= 2.56e-05 ORDER=6 MAX.ERROR= 1.42e-07

N=20 ORDER=2 MAX.ERROR= 7.55e-04 ORDER=4 MAX.ERROR= 1.65e-06 ORDER=6 MAX.ERROR= 9.41e-08

Function tested: femhermsym

Example: Compute approximations to the solution of the boundary value problem

y "" - (cos(x)y ') ' + e'y = sin(x){l + e' + 2cos(x)) 0 < x < r; y(0) = y(r) = 0; y'(0) = I ; y '(u) = -1.

The analytical solution is y(x) = sin($. We approximate the solution on a uniform grid, i.e. xi=iu/n, i=O, ..., n, with n = 5, 10 and the order of the method used is 4, 6 and 8.

float p(f1oat x) {

return 1.0; 1 float q(f1oat x) I

Copyright 1995 by CRC Press, Inc

Page 732: Numerical Library in C for Scientists and Engineers A

return cos (x) ; 1 float r(f1oat x) I

return exp (x) ; 1 float f (float x) I

return sin (x) * (l.O+exp (x) +2.O*cos (x) ) ; 1 void main 0 I ' void femhermsym (f loat [I , f l0at [I , int, float ( * ) (float) ,

float ( * ) (float), float ( * ) (float), float ( * ) (float), int, float [I);

int n,i,order; float pi,x[llI ,y [19l ,e [5l ,rhol,rho2,dltd2;

printf ("FEMHERMSYM delivers: \ntt) ; for (11x5; nc=10; n += 5) (

e[l]=e[3]=0.0; e[21=1.0; e[41 = -1.0; pi=3.14159265358979; for (i=O; ic=n; i++) x[il=pi*i/n; printf ("~=%2d\n", n) ; for (order=4; orderc=8; order += 2) {

f emhermsym (x, y, n, p, q, r, f, order, e) ; rhol=rho2=0.0; for (i=l; i<=n-1; i++) {

dl=fabs (y [2*i-11 -sin(x [il ) ) ; if (rhol c dl) rhokdl; d2=fabs (y [2*il -cos (x[il ) ) ; if (rho2 c d2) rho2=d2;

1 I printf ( ' I 0RD~~=%ld\n"

,, MAX. AB~(Y[~*I-11 -Y(x[I])) = %7.3e\ntt ,, MAX. ABS(Y[Z*II -Y' (x[I])) = %7.3e\n1', order, rhol, rho2 ) ;

Output:

FEMHERMSYM delivers: N= 5

ORDER=4 MAX. ABS (Y [2*I-I] -Y (X[Il ) ) = 4.82e-04 MAX. ABS(Y[~*II -Y' (x[I] 1 ) = 4.54e-04

ORDER=6 MAX. ABS(Y[~*I-11 -Y(X[Il)) = 7.55e-06 MAX. ABS(Y[Z*II -Y' (x[I])) = 2.82e-06

ORDER=8 MAX. ABS(Y[2*1-11 -Y(X[Il)) = 4.81e-06 MAX. ABS(Y[~*II-Y'(X[II)) = 4.74e-06

N=10 ORDER=4

MAX. ABS(Y[2*1-11 -Y(X[Il)) = 3.00e-05 MAX. ABS(Y[2*I] -Y' (X[I])) = 3.67e-05

ORDER=6 MAX. ABS (Y [2*I-11 -Y (X [I] ) ) = 2.89e-05 MAX. ABS(Y [2*11 -Y' (X[Il) = 3.25e-05

ORDER= 8 MAX. ABS(Y [2*I-11 -Y(X[Il ) ) = 2.21e-05 MAX. flss (Y [2*11 -Y' (X [I] ) ) = 2.46e-05

Function tested: nonlinfemlagskew

Copyright 1995 by CRC Press, Inc

Page 733: Numerical Library in C for Scientists and Engineers A

Example: Compute approximations to the solution of the boundary value problem

(y'xz) ;k2 = exp(y) + exp(y') - exp(1-2) - exp(2x) - 6 0 < x < I ; y'(0) = y(1) = 0;

The analytical solution is y(x) = 1 - 2. We approximate the solution on a uniform grid, i.e. xi=i/n, i=O ,..., n.

int nc;

float f (float x, float y, float z) {

return exp (y) +exp(z) -exp(l. 0-x*x) -exp(-2.0*x) -2.0-2*nc; I float fy(f1oat x, float y, float z) t

return exp(y) ; I float fz(f1oat x, float y, float z)

return exp (2) ; I void main 0 I

void nonlinfemlagskew(f1oat float ( * ) (float, float ( * ) (float, float ( * ) (float,

int n.i:

[I, float [ I , int, float, float), float, float) , float, float), int, float [I ) ;

float'xi5ll ,y [5ll ,e [71 ,rho,d;

printf ( "NONLINFEMLAGSKEW delivers : \n" ) ; for (nc=O; nc<=2; nc++)

for (n=25; n<=50; n += 25) ( e [21 =e[41=1.0; e [ll =e [31 =e [51 =e [61 =O. 0; for (i=O; ic=n; i++) {

x[il =(float) (i) /(float) (n) ; y[il=O.O;

1 printf ( " N=%2d NC=%ldH , n, nc) ; nonlinfemlagskew(x,y,n,f,fy,fz,nc,e); rho=O. 0; for (i=O; i<=n; i++) {

d=fabs (y [il -l.O+x [il *x [il ) ; if (rho c d) rho=d; I

printf ( " MAX. ERROR= %7. 3e\n1', rho) ; I

Output:

NONLINFEMLAGSKEW delivers: N=25 NC=O MAX.ERROR=2.47e-04 N=50 NC=O MAX.ERROR= 6.19e-05 N=25 NC=1 MAX.ERROR= 1.41e-03 N=50 NC=1 MAX.ERROR= 3.99e-04 N=25 NC=2 MAX.ERROR= 2.44e-03 N=50 NC=2 =.ERROR= 7.02e-04

Function tested: richardson

Copyright 1995 by CRC Press, Inc

Page 734: Numerical Library in C for Scientists and Engineers A

Example: Solve the system of equations in the 144 unknowns q,, (i, I=1, ..., 12)

Ulj = 0, UIzj = $O-I)ZhZ (i=l, ..., 12) U, , ,=O, U,~12=r2(1-1)2h2 (1=1,...,12)

~ , L I + ~ - I , I + ~ + I , I + u,~+, - 4u.1 = 2h2(x:+y;) (i,1=2,...,11) where x, = (I-l)h, yi = &l)h and h = d l l , by use of richardson with parameters a=0.163, b=7.83 and n=50. The q,, are clearly approximations to the solution of the partial differential equation

+ (a/ay)2} = 2(x2+fi with boundary values ti(x,O) = 0, ti(x,,?r) = 782 (0 I x I 'IT.), G(0,y) = 0, ti(n,y) = 7(J (O<y%) which has the analytical solution ti(x,y) = 2y2 (approximately q,, = t{(l-l)h,fi- W I ) .

float h, h2 ;

void residual(int lj, int uj, int 11, int ul, float **u) I

int ujminl,ulminl,ljplusl,j,l; float u2, u1 [I21 ;

ujminl=uj-1; ulminl=ul-1; ljplusl=lj+l; for (j=lj; jc=uj; j++) {

ul[jl=u[jl Ell]; u[j] [lll=O.O;

1 ;or (1=11+1; l<=ulminl; 1++) {

ul[ljl=u[ljl [I]; u[ljl [11=0.0; for (j=ljplusl; j<=ujminl; j++) {

u2=u [ jl 111 ; u[jl [11=(4.0*~2-ul [j-11 -ul [jl -u[j+ll [ll -u[jl [1+11 ) +

2 .O* ( (j*h) (j*h) + (l*h) * (1*h) ) *h2; ul [jl =u2;

I

void outl(f1oat **u, int lj, int uj, int 11, int ul, int *n, float discr[l, int k, float rateconv, float domeigval)

1 1

if (k == *n) printf ( " K DISCR (11 DISCR [21 RATECONV\~"

%2d %e %e %e\nM , k, discr [ll , discr [21 , rateconv) ; 1 void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void richardson(f1oat **, int, int, int, int,

int, void ( * ) (int, int, int, int, float **) , float, float, int *, float [ I , int *, float *, float *, void ( * ) (float **, int, int, int, int, int *, float [I,

int, float, float)); int j,l,lj,uj,ll,ul,n,k; float pi, domeigval, rateconv, a, b,discr [31 , **u;

u=allocate-real-matrix(O,ll,O,ll); printf ("RICHARDSON delivers : \n\nl' ) ; pi=3.14159265358979; lj=O; uj=11; ll=O; ul=ll; n=50;

Copyright 1995 by CRC Press, Inc

Page 735: Numerical Library in C for Scientists and Engineers A

a=0.163; b=7.83; h=pi/ (uj-lj) ; h2=h*h; for (j=lj; jc=uj; j++)

for (1=11; lc=ul; I++) u[j] [l] = (j==lj I 1 j==uj 1 1 1==11 1 1 l==ul) ?

(j*h)*(j*h)*(l*h)*(l*h) : 1.0; richardson(u,lj ,uj, ll,ul, l,residual,a,b, &n,discr, &k,&rateconv,

&domeigval, outl) ; free-real-matrix (u, 0,11,0) ;

I Output:

RICHARDSON delivers:

K DISCR[l] DISCR 121 RATECONV 50 1.40216e-04 4.62895e-05 2.92251e-01

Function tested: elimination

Example: Solve the system of equations described in the documentation of the test program for

richardson. richardson is first called precisely as in that documentation but with the value allocated to a being 0.326. elimination is then called. Note that the computations are carried out in double precision by using the macro statement: #define float double.

#define float double

int nn; float h, h2, dl, d2;

void residual(int lj, int uj, int 11, int ul, float **u)

int ujminl,ulminl,ljplusl,j,l; float u2,u1[12] ;

ujminl=uj -1; ulminl=ul-1; 1 jplusl=l j+l; for (j=lj; jc=uj; j++) (

ul[jl =u[jl [Ill ; u[jl [lll=O.O;

I for (1=11+1; lc=ulminl; 1++) {

ul [l j I =u [l j I Ell ; u[ljl [11=0.0; for (j=ljplusl; jc=ujminl; j++) (

u2=u[jl [ll ; u [j] [ll = (4 .O*u2-ul [j-11 -ul [jl -u [j+ll [ll -u [jl [1+11 ) +

2.0* ( (j*h) * (j*h)+ (l*h) * (1*h) ) *h2; ul[jl =u2;

I u[ujl [11=0.0;

1 J

for (j=lj; j<=uj; j++) u[jl [ull=0.0; 1 void out2(float **u, int lj, int uj, int 11, int ul, int *p,

float discr[l, int k, float rateconv, float domeigval) 1 t

if (k == *p) printf ( " %2d %e %e %e\nN , k, discr [ll , discr [21 , rateconv) ;

I void outl(f1oat **u, int lj, int uj, int 11, int ul, int *n,

Copyright 1995 by CRC Press, Inc

Page 736: Numerical Library in C for Scientists and Engineers A

float discr [I , int k, float

if (k == 0) dl=d2=1.0;

else { d2=dl; dkdomeigval ; *n = (fabs((d1-d2)/d2) < 1.0e-4) if (k == *n)

rateconv, float domeigval)

? k : nn; - -

printf ( I 1 K DISCR [I] DISCR 121 RATECONV\~" %2d %e %e %e\nN, k, discr [ll , discr [2] , rateconv) ;

void main 0 I 1

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat ** , int, int, int); void richardson(f1oat **, int, int, int, int,

int, void ( * ) (int, int, int, int, float * * I , float, float, int * , float [I, int *, float *, float *, void ( * ) (float ** , int, int, int, int, int *, float [I,

int, float, float) ) ; void elimination(f1oat **, int, int, int, int,

void ( * ) (int, int, int, int, float * * ) , float, float, int *, float [I , int *, float * , float *, void ( * ) (float **, int, int, int, int, int *, float [ I ,

int, float, float) ) ; int j,l,lj,uj,ll,ul,n,p,k; float pi, domeigval, rateconvr, rateconve, rateconv, a, b, discr [31 , **u;

u=allocate real matrix(O,ll, 0,ll) ; ( t t ~ ~ C ~ ~ ~ ~ B ~ ~ and ELIMINATION deliver: \n\nl') ;

pi=3.14159265358979; lj=O; uj=ll; ll=O; ul=ll; n=50; a=0.326; b=7.83; h=pi/ (uj-lj) ; h2=h*h; for (j=lj; j<=uj; j++)

for (1=11; lc=ul; 1++) u[j] [l] = (j==lj 1 I j==uj 1 1 1==11 1 1 l==ul) ?

(j*h) * (j*h) * (l*h) * (l*h) : 1.0; nn=n; richardson(u,lj,uj,ll,ul,l,residual,a,b,&n,discr,&k,&rateconv,

&domeigval, outl) ; rateconvr=rateconv; printf ("\n dominant eigenvalue : %e\n\nl', domeigval) ; elimination(u,lj,uj,11,ul,residual,a,b,&p,discr,&k,&rateconv,

&domeigval , out2) ; rateconve=rateconv; nn=n+p; printf (I1\nTotal number of iterations: %2d\n1'

"Rate of convergence with respect to\n1I the zeroth iterand of RICHARDSON: %e\nM,

nn, (n*rateconvr+p*rateconve)/nn); free-real-matrix(u, 0,11,0) ;

1

Output:

RICHARDSON and ELIMINATION deliver:

K DISCRtlI DISCR [2] RATECONV 38 1.15236e-01 2.05237e-02 2.16041e-01

dominant eigenvalue: 1.62087e-01

Total number of iterations: 45 Rate of convergence with respect to

the zeroth iterand of RICHARDSON: 3.46320e-01

Copyright 1995 by CRC Press, Inc

Page 737: Numerical Library in C for Scientists and Engineers A

Function tested: peide

Example: The following initial value problem arises from biochemistry

y,(O) = 1.0, y2(0) = 0.0 ( 1 ) dYl/dt = -(I-YJY, + q92 (2)

dY21dt = ~ , { ( ~ - Y J Y , - (q2+qJy21 is obtained. Setting qi = exp(pJ, i=1,2,3, equations (2) become

dY,/dt = - ( 1 - ~ 2 l ~ , + ap(PJy2 =f,(t,y,p) (3) dWdt = ~ P ( P J{(~-YJY, - (exp(P3 + ex~(P3))~21 = f,(tly1p).

Data have been obtained from formulae (1,2) with q,=1000, q,=0.99, q3=0.01 (i.e. p, =6.907755, p2 =-0.01005034, p3=-4. 6051 702) by tabulating the values of the function y2(t) obtained for f)=0.0002i (i-1, ..., lo), f)=0.02(i-10) (i=11, ..., l5), t'16)=l.0, t(")=L'.O, f)=5.0(i- 17) (i=l8, ..., 23). The initial guess for the determination of the vector q with the above numerical components {q,} is taken to be q(O), where q,(0)=1600, q2'0)=0.8, q3(0)=1.2 (so that p(O) has the components p,~O)=ln(l 600) z 7.377759, h(0)=ln(0.8) = -0.2231 436, p,(O'=O. 182321 6). The superscripts i=17, 19 and 2 1 specify the selected break-points.

From equation (3), we have a?/ayl =y2-1, afJay2 = Y I + ~ P ( P J (4)

afJay1 = ~ P @ J ( ~ - Y J , afJy2 = - ~ P ( P J { Y , + ~ ~ P @ J + ~ P ( P J ~ a m p 1 = a m p , = 0, a m p 2 = ap(P2ly2 ( 5 )

afJap1 = ~ P ( P J {(l-Y2)~1 - (ap(P3 +exp(PdyJ afJa~2 = - ~ ~ P ( P ~ + P J Y ~ , a f J a ~ 3 = - ~ P ( P , + P J Y ~ .

The initial values ( 1 ) are not functions of p. ymax = ( I , ] ) (6 )

is taken to be an estimate of (maxly,(t,p) I, max ly2(t,p) I ) over the range 0 I t I 30. The central terms in formulae (3) are evaluated by use of the procedure deriv, the

elements of the Jacobian matrix given by formulae (4) are evaluated by use of the procedure jacdf4, those of the Jacobian matrix given by formulae (5) by use of the procedure jacdfdp, the initial values (1) and estimates (6) are inserted by use of the procedure callystart, the required data for the computations are inserted by use of the procedure data, and the procedure monitor has been used to monitor the computations.

void communication(int post, float fa, int n, int m, int nobs, int nbp, float par[], float res [ I , int bp [ I , float **jtjinv, float in[], float out[], int weight, int nis)

I float vecvec (int, int, int, float [I , float [ I ) ; int i,j; float c,*conf;

- if (post == 57 {

printf("\nThe first residual vector\n I RES [I] \nu) ; for (i=l; i<=nobs; i++) print£ ( " %2d %+e\n1'.i,res[il);

) else if (post == 3 ) { printf("\nThe Euclidean norm of the residual vector : %e\nN

"Calculated parameters:\nn, sqrt (vecvec (l,nobs, 0, res, res) ) ;

for (i=l; i<=m; i++) printf (I ' %+e\nl1,par [il ) ; printf ("Number of integration steps performed: %d\ntt,nis) ;

) else if (post == 4 ) { if (nbp == 0)

Copyright 1995 by CRC Press, Inc

Page 738: Numerical Library in C for Scientists and Engineers A

printf("Minimization is started without break-points\nW); else {

printf("Minimization is started with weight =%3d\n1' "The extra parameters are the observations:\nn,

weight) ; for (i=l; i<=nbp; i++) printf ( " %5d\n1',bp[il ) ;

1 printf("Starting values of the parameters:\nn); for (i=l; i<=m; i++) printf ( " %+e\nU,par [il ) ; printf("Re1. tol. for the Eucl. norm of the res. vector:"

%e\nAbs. tol. for the Eucl. norm of the res. vector:" ' %e\nRelative starting value of lambda: %e\nn, in [3l , in [41 ,in [6l ) ;

) else if (post == 1) ( printf("\nStarting values of the parameters:\nn); for (i=l; i<=m; i++) printf ( " %+e\nW,parlil ) ; printf ("Numer of euuations : %2d\nM

"Number of obsekations: %2d\n\nM "Machine precision "Relative local error bound for integration: "Relative tolerance for residual "Absolute tolerance for residual "Maximum number of integrations to perform : "Relative starting value of lambda "Relative minimal steplength n,nobs, in [OI ,in [2l ,in 131 , in[4] ,in [51 ,in [6l , ir (nbp == 0) printf("There are no break-points\nW);

else- { printf ("Break-points are the observations: " 1 ; for (i=l; i<=nbp; i++) print£(" %3du,bp[il);

I I printf("\nThe alpha-point of the £-distribution: %5.2f\nn,

fa) ; ) else if (post == 2 ) {

if (out [ll == 0.0) printf("\nNormal termination of the process\nU);

else if (out [ll == 1.0) printf("Number of integrations allowed was exceeded\nn);

else if (out [ll == 2.0) printf (ttMinimal steplength was decreased four times\nl') ;

else if (out [ll == 3.0) printf ("A call of deriv delivered false\nfl) ;

else if (out [ll == 4.0) printf ("A call of jacdfdy delivered false\n") ;

else if (out [ll == 5.0) printf ( " A call of jacdfdp delivered false\n") ;

else if (out [ll == 6.0) printf("Precision asked for may not be attained\nn);

if (nbp == 0) printf("Last integration was performed "

"without break-points\nW); else {

printf("The process stopped with Break-points:"); for (i=l; i<=nbp; i++) printf ( " %3d1I,bp[il) ;

1 printf("\nEucl. norm of the last residual vector : %e\n"

"Eucl. norm of the first residual vector: %e\nw "Number of integrations performed : %2.0f\n1' "Last improvement of the euclidean norm : %e\nU "Condition number of J1*J : %e\nU "Local error bound was exceeded (maxim.): %2.0f\nW, out[2] ,out[3l ,out[4] ,out[61 ,out[71 ,out[51);

printf("\n. Parameters Confidence 1nterval\nW); for (i=l; i<=m; i++) {

conf [i] =sqrt (m*fa* j tj inv [il [il / (nobs-m) ) *out [21 ; printf ( " %+e %+e\nqt ,par [il ,con£ [ill ;

1 & = (nobs == m) ? 0.0 : out [21 *out [21/ (nobs-m) ; printf("\nCorrelation matrix Covariance matrix\nH) ; for (i=l; i<=m; i++) {

for (j=l; j<=m; j++) { if (i == j)

printf ( " " 1 ;

Copyright 1995 by CRC Press, Inc

Page 739: Numerical Library in C for Scientists and Engineers A

if (i > j) printf ("%9.3e " ,

jtjinv[i] [j] /sqrt (jtjinv[i] [i] *jtjinv[jl [jl)) ; else

printf ("%9.3e ", jtjinvril [jl *c) ; 1 printf ("\n") ;

1 irintf("\n~he last residual vector\n I RES [I] \nu) ; for (i=l; i<=nobs; i++) printf ( " %2d %+e\nU, i, res [il ) ;

1

int jacdfdp (int n, int m, float par [I , float y [I , float x, float **fp)

I float y2 ;

yz=y [ZI ; £pill [ll =fp[ll [31=0.0; fp [l] [21 =y2*exp (par [21 ) ; fp I21 [ll =exp(par [ll ) * (y[11 * (1.0-y2) -

(exp (par [21 ) +exp (par [31 ) *y2) ; fp [21 [21 = -exp (par 111 +par [21 ) *y2; fp [2] [31 = -exp (par [ll +par[31 ) *y2; return 1;

1 yoid data (int nobs, float tobs [I , float obs [I , int cobs [ I )

L

int i; static float a 1231 ={0.0002, 0.0004, 0.0006, 0.0008, 0.001,

0.0012, 0.0014, 0.0016, 0.0018, 0.002, 0.02, 0.04, 0.06, 0.08, 0.1, 1.0, 2.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0);

static float b[23]={0.1648, 0.2753, 0.3493, 0.3990, 0.4322, 0.4545, 0.4695, 0.4795, 0.4862, 0.4907, 0.4999, 0.4998, 0.4998, 0.4998, 0.4998, 0.4986, 0.4973, 0.4936, 0.4872, 0.4808, 0.4743, 0.4677, 0.4610);

tobs 101 =O. 0; for (i=l; i<=nobs; i++) {

tobs [il =a [i-11 ; obs [il =b [i-11 ; cobs [il=2;

\ print£ ("\nThe observations were: \n"

I TOBS[I] COBS[I] OBS[I]\~"); for (i=l; i<=nobs; i++)

printf ( " %2d %7.4f %Id %6. 4f\n4', i, tobs [il ,cobs [il ,obs [il ) ;

1 void callystart(int n, int m, float par[], float y[l, float pax[]) I

int deriv(int n, int m, float par [I , float y 11, float X, float df [I )

{ float y2 ;

y2=y [21 ; df [I] = - (1.0-y2) *y Ell +exp(par [21 ) *y2; df [21 =exp(par[ll ) * ( (1.0-y2)*y[ll - (exp(part21 )+exp(par131) ) *y2) ; return 1;

1 int jacdfdy (int n, int m, float par [I, float y [I , float x,

float **fy) I

Copyright 1995 by CRC Press, Inc

Page 740: Numerical Library in C for Scientists and Engineers A

fy [ll [21 =exp (par [21 ) +y [ll ; fy121 [ll =exp(par[ll * (1.0-y[21 ; fy 121 [21 = -exp (par Ell ) * (exp (par [21 ) +exp (par [31 ) +y [ll ) ; return 1;

1 void monitor(int post, int ncol, int nrow, float par[],

float resll, int weight, int nis)

void main 0 I

float **allocate-real-matrix(int, int, int, int) ; void free-real-matrix(f1oat **, int, int, int); void peide (int, int, int, int * , float [I , f l0at [I ,

int [I, float **, float [I, float [I, int ( * ) (int, int, float [I ,float [I ,float, float 11 ) , int ( * ) (int, int, float [I, float [I, float, float * * ) , int ( * ) (int, int, float [I ,float [I, float, float * * I , void ( * ) (int,int,float [],float [],float[]), void ( * ) (int, float [I , float [I , int [I ) , void ( * ) (int,int,int,float [],float [I,int,int));

int m,n,nobs,nbp,bp[41 ; float fa,par[7],res[27] ,**jtjinv,in[7],out[81;

j tj inv=allocate-real-matrix (1,3,1,3) ; printf ( " E S C E P - problem\nl'); m=3; n=2; nobs=23; nbp=3; par[ll=log(1600.0); par[2l=log(0.8); par[31=log(1.2); in[O] =l.Oe-14; in[3] =in[4] =l.Oe-4; in[5] =SO. 0; in[6] =l.Oe-2; in[l] =l.Oe-4; in[2] =l.Oe-5; bp [l] =17; bp [21=19; bp [31=2l; fa=4.94; c o m m u n i c a t i o n ( l , f a , n , m , n o b s , n b p , p a r , r e s , b p , j t j i ~ ~ , ~ ~ , ~ ~ ~ ~ ~ ~ ~ ~ ; peide(n,m,nobs,&nbp,par,res,bp,jtjinv,in,out,deriv,jacdfdy,

jacdfdp, callystart, data,monitor) ; communication(2,fa,n,m,nobs,nbp,par,re~,bp,jtji~v,i~,~~t~0~0) ; free-real-matrix(j tjinv, 1,3,1) ;

1 Output:

E S C E P - problem Starting values of the parameters: +7.37776e+00 -2.23144e-01 +1.82322e-01

Numer of equations : 2 Number of observations: 23

Machine precision : 1.00e-14 Relative local error bound for integration: 1.00e-05 Relative tolerance for residual : 1.00e-04 Absolute tolerance for residual : 1.00e-04 Maximum number of integrations to perform : 50 Relative starting value of lambda : 1.00e-02 Relative minimal steplength : 1.00e-04 Break-points are the observations: 17 19 21 The alpha-point of the £-distribution: 4.94

The observations were: TOBS [I] COBS [I1 0.0002 2 0.0004 2 0.0006 2 0.0008 2 0.0010 2 0.0012 2 0.0014 2 0.0016 2 0.0018 2

OBS [I] 0.1648 0.2753 0.3493 0.3990 0.4322 0.4545 0.4695 0.4795 0.4862

Copyright 1995 by CRC Press, Inc

Page 741: Numerical Library in C for Scientists and Engineers A

Normal termination of the process Last integration was performed without break-points

Eucl. norm of the last residual vector : 1.43818e-04 Eucl. norm of the first residual vector: 1.33107e+00 Number of integrations performed : 12 Last improvement of the euclidean norm : 2.65941e-05 Condition number of J1*J : 2.57723e+02 Local error bound was exceeded (maxim.): 37

Parameters Confidence Interval +6.90767e+00 +3.21391e-04 -1.00394e-02 +1.69753e-04 -4.60523e+00 +1.95162e-03

Correlation matrix Covariance matrix 6.97e-09 1.42e-09 -9.19e-09

3.85e-01 1.94e-09 -1.43e-08 -2.17e-01 -6.39e-01 2.57e-07

The last residual vector RES [I]

+1.66893e-06 -2.91467e-05 +2.79844e-05 -3.89516e-05 +3.05176e-05 +3.08454e-05 -2.03252e-05 -3.99351e-06 +1.04308e-05 +1.37687e-05 -5.12600e-05 +2.36630e-05 -1.37091e-06 -2.63751e-05 -5.13792e-05 +2.25008e-05 +6.94096e-05 -1.31726e-05 +2.15769e-05 -1.93715e-05 -3.47793e-05 -2.28882e-05 +1.80006e-05

Examples for chapter 6 and 7 procedures

Function tested: ei

Example: Evaluate

for x = 0.5.

Copyright 1995 by CRC Press, Inc

Page 742: Numerical Library in C for Scientists and Engineers A

#include cstdio.hz

void main 0 {

float ei (float) ;

printf ("EI delivers: %e\nr', -ei (-0.5) ) ; 1 Output:

EI delivers: 5.59774e-01

Function tested: eialpha

Example: Evaluate

for x = 0.25 and i=0,1, ..., 5.

void main 0 I

void eialpha (float, int, float [ I ) ; int k; float a 161 ;

printf ("EIALPHA delivers : \n") ; eialpha(0.25,5,a) ; for (k=O; kc=5; k++) {

printf ( " %2d %e\n" , k, a [kl ) ;

1 1

Output:

EIALPHA delivers: 0 3.1152Oe+OO 1 1. SS76Oe+Ol 2 1.27723e+02 3 1.53SEOe+O3 4 2.45758e+04 5 4.91520e+05

Functions tested: enx, nonexpenx

Example: Evaluate in succession: a)

for x = 1.1 and n = 40, 41, 42, by means of a call of em; b) for x = 50.1 and n = 1, by means of a call of nonexpem.

Copyright 1995 by CRC Press, Inc

Page 743: Numerical Library in C for Scientists and Engineers A

void main 0 I ' float *allocate-real-vector(int, int);

void free-realgector(f1oat *, int); void enx(float, int, int, float 11 ) ; void nonexpenx(float, int, int, float 11 ) ; int i; float b 121 ,*a;

printf ("ENX and NONEXPENX deliver:\nti) ; a=allocate real-vector(40,42); enx(l.l,40;42,a); for (i=40; i<=42; i++) printf ( " E(%2d, 1.1) = %e\n1', i,a [il ) ; nonexpenx(50.l,l,l.b) ; printf (1s\nEXP(50.1) *E(1,50.1) = %e\n",btll ) ; f ree-real-vector (a, 40) ;

I Output:

ENX and NONEXPENX deliver: E(40,l.l) = 8.29521e-03 E(41,l.l) = 8.09366e-03 E (42.1.1) = 7.90166e-03

Functions tested: sincosint, sincosfg

Example: Evaluate

for x = 1.

#include <stdio.h>

void main 0 I

Copyright 1995 by CRC Press, Inc

Page 744: Numerical Library in C for Scientists and Engineers A

void sincosint(float, float *, float * ) ; void sincosfg(float, float * , float * ) ; float si,ci,f,g; sincosint(l.O,&si,&ci) ; sincosfg(l.O,&f ,&g) ; printf("S1NCOSINT and SINCOSFG deliver:\nt'); printf(" SI (1) = %+e CI (1) = %+e\nl'

F(1) = %+e G(1) = %+e\nW,si,ci,f ,g) ; 1 Output:

SINCOSINT and SINCOSFG deliver: SI (1) = +9.46083e-01 CI (1) = +3.37404e-01 F(1) = +6.21450e-01 G(1) = +3.43378e-01

Function tested: recipgamma

void main 0 I

float recipgamma(float, float *, float * ) ; float x,odd,even; printf ("RECIPGAMMA delivers: \n") ; x=recipgamma ( 0 .4, &odd, &even) ; printf ( " 0.4 %e %e %e\nU,x,odd,even) ; x=recipgamma (0.0, &odd, &even) ; printf ( " 0.0 %e %e %e\ntl,x, odd, even) ;

1 Output:

RECIPGAMMA delivers: 0.4 6.71505e-01 -5.69444e-01 8.99283e-01 0.0 1.00000e+00 -5.77216e-01 1.00000e+00

Function tested: gamma

Example: Evaluate r(x) for x = -8.5, 0.25, 1.5 and 22.

void main 0 I

float gamma (f loat) ; int i; static float x[41={-8.5, 0.25, 1.5, 22.0); printf ("GAMMA delivers : \ntt ) ; for (i=O; ic=3; i++)

print£ (la %6.2f %+e\nll,x [il , gamma(xB1) ) ; 1 Output:

GAMMA delivers: -8.50 -2.63352e-05

Copyright 1995 by CRC Press, Inc

Page 745: Numerical Library in C for Scientists and Engineers A

Function tested: loggamma

Example: Evaluate In(r(x)) for x = 0.25, 1.5, 12, 15 and 80.

void main 0 I

float loggamma(f1oat); int i; static float x[5]=(0.25, 1.5, 12.0, 15.0, 80.0); printf ("LOGGAMMA delivers : \nt') ; for (i=O; ic=4; i++)

printf ( I 1 %6.2f %+e\nl',x [i] , loggamma (x ti1 ) ) ;

1 Output:

LOGGAMMA delivers: 0.25 +1.28802e+00 1.50 -1.20782e-01 12.00 +1.75023e+01 15.00 +2. 519l2e+Ol 80.00 +2.69291e+02

Function tested: incomgam

Example: Evaluate y (4,3) and l"(4,3).

void main 0 I

float p,q; void incomgam (f loat, float, float *, float *, float, float) ; printf ("INCOMGAM delivers: \n") ; incomgam(3.0,4.0,&p,&q,1.0*2.0*3.0,1.0e-6); printf ( I ' KLGAM and GRGAM are : %e %e\nt',p,q);

I Output:

INCOMGAM delivers: KLGAM and GRGAM are : 2.11661e+00 3.88339e+00

Function tested: incbeta

Example: Evaluate I&q) for x = 0.3, p = 1.4, q = 1.5.

#include cstdio.h> void main 0 I

float incbeta(float, float, float, float);

Copyright 1995 by CRC Press, Inc

Page 746: Numerical Library in C for Scientists and Engineers A

printf("1NCBETA delivers: %e\n",incbeta(0.3,1.4,1.5,1.0e-6)); 1 Output:

INCBETA delivers: 2.79116e-01

Function tested: ibpplusn

Example: Evaluate Ix(p+n,q) for x = 0.3, p = 0.4, q = 1.5, and n = 0, 1, 2.

void main 0 t

void ibpplusn(float, float, float, int, float, float [I); float isubx [3l ;

Output:

IBPPLUSN delivers: 7.21671e-01 2.79116e-01 9.89328e

Function tested: ibqplusn

Example: Evaluate Ix(p,q+n) for x = 0.3, p = 1.4, q = 0.5, and n = 0, 1 , 2.

void main 0

void ibqplusn(float, float, float, int, float, float [I); float isubx 131 ;

ibqplusn(0.3,1.4,0.5,2,1.Oe-6,isubx); printf("1BQPLUSN delivers:\n %e %e %e\nn,

isubx [Ol , isubx [ll , isubx 121 ) ; 1

Output:

IBQPLUSN delivers: 8.94496e-02 2.79116e-01 4.47287e-01

Functions tested: errorfunction, nonexperfc

Example: Evaluate

Copyright 1995 by CRC Press, Inc

Page 747: Numerical Library in C for Scientists and Engineers A

for x = 100.

void main 0 I

void errorfunction (float, float *, float * ) ; float nonexperf c (float) ; float erf,erfc,p;

errorfunction(l.0, &erf,&erfc) ; p=nonexperfc (100.0) ; printf("ERR0RFUNCTION and NONEXPERFC deliver:\n\nl'

"ERF (1) = %e\nERFC (1) = %e\nNONEXPERFC (100) = %e\nt', erf,erfc,p) ;

1 Output:

ERRORFUNCTION and NONEXPERFC deliver:

Function tested: inverseerrorfunction

Example: Evaluate

for x = 0.6 and 1-10"',

void main 0 I

void inverseerrorfunction(float, float, float * ) ; float inverfl,inverf2;

inverseerrorfunction(0.6,0.0,&inverfl); inverseerrorfunction(l.O,1.Oe-30,&inverf2); printf(glINVERSEERRORFUNCTION delivers:\n\n9'

X = 0.6, INVERF = %e\n X = 1.0, INVERF = %e\nt',

Copyright 1995 by CRC Press, Inc

Page 748: Numerical Library in C for Scientists and Engineers A

1 Output:

INVERSEERRORFUNCTION delivers:

X = 0.6, INVERF = 5.95116e-01 X = 1.0, INVERF = 8.14862e+00

Functions tested: fresnel, fg

Example: Evaluate

for x = 1.

void main 0 {

void fresnel (float, float *, float *) ; void fg(float, float *, float *) ; float c,s,f ,g;

Output:

FRESNEL and FG deliver:

Functions tested: bessj0, bessjl, bessj

Example: Evaluate Jktr(x) - JkJ(x), k=0,1, where Jkfr(x) is Jk(x) as evaluated by bessj (k0 , l ) and

J,'(x), JI '(x) are J,(x), Jl(x) as evaluated by bessjO and bessjl, respectively, for x = 1, 5, 10, 25.

Copyright 1995 by CRC Press, Inc

Page 749: Numerical Library in C for Scientists and Engineers A

void main 0 I

void bessj (float, int, float [I ) ; float bessj0 (float) ; float bessjl(f1oat); int i: float' j [21; float x[4]={1.0, 5.0, 10.0, 25.0);

for (i=O; i<=3; i++) { bessj (x[il ,l, j) ; printf ( " $6. lf %+7.2e %+7. 2e\nfl,

x[i] , j [O] -bessjO (x[iI ) , j [ll -bessjl(x[il ) ) ; 1

Output:

Function tested: bessyOl

Example: Evaluate Y,(I) and Y,(I).

void main 0 i

void bessyOl(float, float *, float * ) ; float x,yO,yl;

Output:

BESSYOl delivers: 1.0 8.82570e-02 -7.81213e-01

Function tested: bessy

Example: Evaluate &(I) for i = 0, 1, 2.

void main 0 {

void bessy(float, int, float [I ) ; float y [3l ;

Output:

BESSY delivers:

Copyright 1995 by CRC Press, Inc

Page 750: Numerical Library in C for Scientists and Engineers A

Functions tested: besspq0, besspql

Example: Verify the relation

Po@) *PI fx) + Q,&) *QlW = 1 for x = 1, 3 , 5 , 10.

void main 0 1

void besspq0 (float, float * , float * ) ; void besspql (float, float *, float * ) ; int i; float p,q,r,s; float x[41={1.0, 3.0, 5.0, 10.0);

printf("BESSPQ0 and BESSPQl deliver:\nW); for (i=O; ic=3; i++) {

besspq0 (x [il , &p, &q) ; besspql (x [il , &r, &s) ; printf ( " %7 .2eW, fabs (p*r+q*s-1.0) ) ;

1 1

Output:

BESSPQO and BESSPQl deliver: 2.2e-08 1.2e-07 2.8e-08 4.8e-08

Functions tested: bessi, bessk

Example: Verify the relation

x * (In, (x) *Kn, (x) + In($ *&-I ($1 = 1 for x = 1 ,..., 20 and n = 1 ,..., 5 .

void main 0 1 ' void bessi (float, int, float [I ) ;

void bessk (float, int, float [I ) ; int j , n; float x, i t61 ,kt61 ;

printf ("BESSI and BESSK deliver: " 1 ; for (j=l; jc=20; j++) {

x=-J; printf ("\n %3.0f1',x); bessi(x,5,i) ; bessk (x, 5, k) ; for (n=l; nc=5; n++)

printf (I ' %+9.2ew,x* (i [nl *k[n-1

1 1

Output:

BESSI and BESSK deliver: 1 -2.0e-08 -3.le-09 +3.9e-08 +6.5e

Copyright 1995 by CRC Press, Inc

Page 751: Numerical Library in C for Scientists and Engineers A

Function tested: besskOl

Example: Evaluate KO&) and K,(x) for x = 0.5, 1.5 and 2.5.

void main 0 \

void besskOl(float, float *, float * ) ; int j ; float x, k0, kl;

printf ("BESSKO1 delivers :\no') ; x=o .5 ; for ( j d ; jc=3; j++) {

bessk01 (x, &k0, &kl) ; printf (I1 %4. lf %e %e\nM,x, kO, kl) ; X += 1.0;

I 1

Output:

BESSKOl delivers: 0.5 9.24419e-01 1.65644e+00 1.5 2.13806e-01 2.77388e-01 2.5 6.23475e-02 7.38908e-02

Function tested: nonexpbesskol

Example: Evaluate e'Ko(x) and e"K,(x) for x = 0.5, 1 .O, 1.5, 2.0 and 2.5.

#include cstdio.h>

void main 0 I 1

void nonexpbesskOl(float, float * , float * ) ; int j; float x,kO,kl;

(IINONEXPBESSKOI delivers : \n") ; x=o. 5; for (j=l; j<=5; j++) {

Copyright 1995 by CRC Press, Inc

Page 752: Numerical Library in C for Scientists and Engineers A

nonexpbessk01 (x, &k0, &kl) ; printf ( I1 %4. lf %e %e\nn,x..cO,kl) ;

Output:

NONEXPBESSKOl delivers: 0.5 1.52411e+00 2.73101e+00 1.0 1.14446e+00 1.63615e+00 :.5 9.58210e-01 1.24317e+00 2.0 8.41568e-01 1.03348e+00 2.5 7.59549e-01 9.00175e-01

Function tested: nonexpbessk

Example: Evaluate e'Ki(x) for x = 0.5, 1 .O, 1.5, 2.0 and i = 0, 1, 2.

void main 0 1

void nonexpbessk (float, int, float [I ; int j; float x,k[31 ;

printf("N0NEXPBESSK delivers:\n10; x=o .5 ; for (j=l; j<=4; j++) {

nonexpbessk (x, 2, k) ; printf ( " %4 .lf %e %e %e\nw,x,k [Ol , k [ll , k [21 ) ;

Output:

NONEXPBESSK delivers: 0.5 1.52411e+00 2.73101e+00 1.24481e+01 1.0 l.l4446e+OO 1.63615e+00 4.41677e+OO 1.5 9.58210e-01 1.24317e+00 2.61576e+00 2.0 8.41568e-01 1.03348e+00 1.87505e+00

Function tested: bessjaplusn

Example: Evaluate J,+,(x) for x = 2, a = 0.78 and i = 0, 1, 2.

#include <stdio.h>

void main 0 1 L

void bessjaplusn(float, float, int, float [I 1 ; int n;

x=2.0; a=0.78; n=2 ; bessjaplusn(a,x,n. ja) ; printf ( olBESSJAPLUSN delivers : \n"

x = %2.of A = %4.2f N = %d\nto " %e %e %e\nse,x,a,n, jato], ja[ll, ja[21);

Copyright 1995 by CRC Press, Inc

Page 753: Numerical Library in C for Scientists and Engineers A

1 Output:

BESSJAPLUSN delivers: X = 2 A = 0.78 N = 2 5.73061e-01 4.15295e-01 1.66163e-01

Function tested: besspqaol

Example: Verify the relation

Pa(x)*Pa+l(x) + Qa(x)*Qa+,(x) = 1 for a = 0 and x = 1 , 3, 5, 10, 15, 20, 50.

yoid main 0 i

void besspqaOl(float, float, float *, float * , float * , float * ) ; int i; float p,q,r,s; static float x[7]={1.0, 3.0, 5.0, 10.0, 15.0, 20.0, 50.0);

Output:

BESSPQAOl delivers: 1 2.18651e-08 3 1.17937e-07 5 2.78083e-08 1.0 4.84759e-08 15 1.29200e-08 20 4.45196e-08 50 2.90220e-08

Function tested: besszeros

Example: Compute the first two zeros of Y,,,,(z).

void main 0 I ' void besszeros (float, int, float [I , int) ;

int n,d; float a, z [31 ;

a=3.14; n=d=2 ; besszeros (a,n, z,d) ; printf("The first two zeros of the Bessel function Y of "

"the order 3.14 : \n %e %e\nl', z [ll , z [21 ) ; 1

Copyright 1995 by CRC Press, Inc

Page 754: Numerical Library in C for Scientists and Engineers A

Output:

The first two zeros of the Bessel function Y of the order 3.14: 4.68478e+00 8.27659e+00

Functions tested: spherbessi, nonexpspherbessi

Example: Compute

for x = 1 and j = 0, ..., 3.

void main 0 (

void spherbessi (float, int, float [ I ) ; void nonexpspherbessi(float, int, float [ I ) ; int n; float x, expx, i1[41 , i2 [41 ;

printf("SPHERBESS1 and NONEXPSPHERBESSI deliver:\nU); x=l.O; expx=exp (x) ; n=3 ; spherbessi (x,n, il) ; nonexpspherbessi (x,n, i2) ; for (n=O; nc=3; n++)

printf ( " %d %e %e\nH,n, il [n] , i2 [nl *expx) ; 1 Output:

SPHERBESSI and NONEXPSPHERBESSI deliver: 0 1.17520e+00 1.17520e+00 1 3.67879e-01 3.67879e-01 2 7.15629e-02 7.15629e-02 3 1.00651e-02 1.00651e-02

Functions tested: spherbessk, nonexpspherbessk

Example: Compute

for x = 2 and j = 0, ..., 3.

void main 0

Copyright 1995 by CRC Press, Inc

Page 755: Numerical Library in C for Scientists and Engineers A

I void spherbessk (float, int, float [I ) ; void nonexpspherbessk(float, int, float [I ) ; int n; float x, expx,kl[41 ,k2 141 ;

printf("SPHERBESSK and NONEXPSPHERBESSK deliver:\nl'); x=2.0; expx=exp ( -x) ; n=3 ; spherbessk (x, n, kl) ; nonexpspherbessk (x, n, k2) ; for (n=O; n<=3; n++)

printf ( " %d %e %e\n", n, kl [nl , k2 [nl *expx) ; 1 Output:

SPHERBESSK and NONEXPSPHERBESSK deliver: 0 1.06292e-01 1.06292e-01 1 1.59438e-01 1.59438e-01 2 3.45449e-01 3.45449e-01 3 1.02306e+00 1.02306e+00

Function tested: airy

Example: Compute Aifx), dAi(x)/dx, Bifx) and dBi(x)/dx for x = 9.654894.

yoid main 0 t

void airy(£ loat, float *, float *, float *, float *, float *, int);

float a,b,c,d,e;

airy (9.654894, &a, &b. &c,&d, &e, 1) ; printf ("AIRY delivers : \n"

A1 (9.654894) = %+e\n AID(9.654894) = %+e\nl' BI (9.654894) = %+e\n BID(9.654894) = %+e\nl',

a*exp(-e) ,b*exp(-e) ,c*exp(e) .d*exp(e)) ; 1 Output:

AIRY delivers: A1 (9.654894) = +3.28735e-10 AID(9.654894) = -1.02980e-09 BI (9.654894) = +1.55839e+08 BID(9.654894) = +4.80104e+08

Function tested: airyzeros

Example: Compute the i-th zero of Bi(x) and the value of dBi(x)/dx at this point for i = 3.

void main 0 {

float airyzeros (int, int, float [I , float [I ) ; float b, zbi [41 , vbid [41;

Copyright 1995 by CRC Press, Inc

Page 756: Numerical Library in C for Scientists and Engineers A

b=airyzeros (3,2, zbi, vbid) ; printf ("AIRYZEROS delivers : \nl'

" The third zero of BI (X) is %e\nl' The value of (D/DX)BI (X) in this point is %e\nl',

b,vbid[31 ) ; 1

Output:

AIRYZEROS delivers: The third zero of BI(X) is -4.83074e+00 The value of (D/DX)BI (X) in this point is 8.36986e-01

Function tested: newton

Example: Compute the divided differences Gif(xJ, j=0,1,2, from the function valuesf,=l, f,=f,=O

and associated arguments x,=O, x,=1/2. x,=l.

void main 0 I

void newton(int, float [I , float [I float x [31 , f [31 ;

x[O]=O.O; x[1]=0.5; x[21=1.0; f [0] rl.0; f [ll =f [21=0.0; newton(2,x,f); printf("The Newton coefficients are

f [OI , f [ll , f [2l ) ; I Output:

The Newton coefficients are:

Function tested: ini

Example: Determine integer approximations so, j=0,1,2, to the points in the range [0,20] at which

T,((x-1 O)/I 0) assumes its maximal absolute values.

void main 0 t

void ini (int, int, int 11 ) ; int s [31 ;

ini (2,20,s) ; printf("IN1 selects out of 0,1, . . . , 20 the numbers:\nn

%4d %4d %4d\nn, s [Ol , s [ll , s [21 ) ; 1 Output:

IN1 selects out of 0,1, . . . , 20 the numbers: 0 10 20

Copyright 1995 by CRC Press, Inc

Page 757: Numerical Library in C for Scientists and Engineers A

Function tested: sndremez

Example: Given the numbers g,, i=O ,..., 7, in order: 10, 12, -15, -10, -14, 15, 10, 1 1 and so),

j=0,1,2, in order: 0, 3, 6 (so that g , , = 10, g , , = -10, g,, = 10) selects an integer sequence SO, j=0,1,2, such that the numbers gso) have the properties described in the documentation to sndremez.

void main 0 t

int s [3l ; float em [21 , g [81 ;

printf (I1SNDREMEZ delivers : \n\nl') ; g[O]=lO.O; g[l]=12.0; g[21 = -15.0; g[31 = -10.0; g[4] = -14.0; g[5]=15.0; g[6]=10.0; g[7]=11.0; em[O] =lO.O; s [O] ~0.0; s [ll=3 .O; s [21=6.0; printf ("The numbers : \n S [J] : %d %d %d\n G [S [ j] 1 : "

%4. of %4. Of %4. 0f\n\nI1, s[Ol ,s[ll ,s[21 ,g[s[OlI ,g[s[lll ,g[s[211);

sndremez (2,7, s, g, em) ; printf ("are exchanged with: \n S [Jl : "

I t %d %d %d\n G [S [jl 1 : %4. Of $4. Of %4. Of\n\n" "The reference set of function values is:\nU " %4.0f %4.0f %4.0f %4.0f %4.0f %4.0f %4.0f %4.0f\n1', s[OI ,Sill ,s[21 ,g[s[OII ,g[s[1ll ,g[s[21l, g[Ol ,g[ll ,g[21 ,g[31 ,g[41 ,g[51 ,g[61 ,9[7]);

1 Output:

SNDREMEZ delivers:

The numbers: S[Jl: 0 3 6 G[S[j]]: 10 -10 10

are exchanged with: S[Jl: 0 2 5 G[S[jll: 10 -15 15

The reference set of function values is: 10 12 -15 -10 -14 15 10 11

Function tested: minmaxpol

Example: Determine co and c, such that

max IfW - co - ~ I Y , l where y, = -1 +O. 01j and f ( ' = I/(lO-y), is a minimum as j ranges over the values 0, ..., 200.

float £(float x) {

return l.O/(x-10.0) ; 1 void compute(int n, float a, float b, float (*f) (float)) I

int k,l,m; float r, idm, *coef ,em[41, *y, *fy;

Copyright 1995 by CRC Press, Inc

Page 758: Numerical Library in C for Scientists and Engineers A

float *allocate-real-vector(int, int); void free-real-vector(f1oat * , int); void minmaxpol (int, int, float [I , float [I , float [I , float [I ) ;

coef=allocate~real~vector(0,n); em [21=10*n+5; m=lOO*n+lO; y=allocate-real-vector(0,m); fy=allocate-real-vector(0,m); idm= (b-a) /m; r=y [O] =a; fy [OI =f (r) ; r=y [ml =b; fy [ml =f (r) ; l=m-1; for (k=l; k<=l; k++) {

r=y [k] =a+k*idm; fy [kl =f (r) ;

\ minmaxpol (n,m, y, fy, coef, em) ; printf ( " COEF: 'I) ; for (k=O; k<=n; k++) printf ( " %eu, coef [kl ) ; printf ("\n EM[O:3] : %e %e %4 .Of %3 .Of\nN,

em[Ol ,em[ll ,em121 ,em131 ) ; f ree-real-vector (coef,O) ; f ree-real-vector (y, 0) ; free-real-vector(fy,O);

1 void main 0 (

int n;

printf ("MINMAXPOL delivers: \n") ;

Output:

MINMAXPOL delivers: Degree = 1 COEF : -1.00504e-01 -1.01010e-02 EM[O:3] : -5.06310e-04 5.06310e-04 15 3

Copyright 1995 by CRC Press, Inc

Page 759: Numerical Library in C for Scientists and Engineers A

Appendix A: References

M. Abramowitz, I.A. Stegun, Handbook of Mathematical Functions, Dover Publications, Inc., 1965.

D.A. Adams, "A Stopping Criterion for Polynomial Root Finding", CACM 10, No. 10, October 1967, 655-658.

A.V. Aho, J.E. Hopcroft, J.D. Ullman, The Design and Analysis of Computer Algorithms, Addison-Wesley, 1974.

I. Babuska, "Numerical Stability in Problems of Linear Algebra", SIAM J. Numer. Anal. 9, 1972, 53-77.

M. Bakker, "Galerkin Methods in Spherical Regions", Report NW 50, Mathematical Centre, Amsterdam, 1977.

M. Bakker, P.W. Hemker, P.J. van der Houwen, S.J. Polak, M. van Veldhuizen, "Colloquium on Discretization Methods", MC Syllabus NR 27, Mathematisch Centrum, Amsterdam, 1976.

P.A. Beentjes, "An Algol 60 Version of Stabilized Runge Kutta Methods", Report NR 23, Mathematical Centre, Amsterdam, 1972.

P.A. Beentjes, "Some Special Formulas of the England Class of Fifth Order Runge-Kutta Schemes", Report NW 24, Mathematical Centre, Amsterdam, 1974.

[BeDHKW73] P.A. Beentjes, K. Dekker, H.C. Hemker, S.P.N. van Kampen, G.M. Willems, "Colloquium Stiff Differential Equations 2", MC Syllabus NR 15.2, Mathematical Centre, Amsterdam, 1973.

[BeDHV74] P.A. Beentjes, K. Dekker, H.C. Hemker, M.V. Veldhuizen, "Colloquium Stiff Differential Equations 3", MC Syllabus NR 15.3, Mathematical Centre, Amsterdam, 1974.

[BjG67] A. Bjorck, G.H. Golub, "Iterative Refinement of Least Squares Solutions by Householder Transformation", BIT 7, 1967, 322-337.

[Bla74] J.M. Blair, "Rational Chebyshev Approximations for the Modified Bessel Functions I,(x) and I,(x)", Math. Comp. 28, 1974, 581-583.

[Bre73] R.P. Brent, Algorithms for Minimization without Derivatives, Prentice- Hall, 1973.

Copyright 1995 by CRC Press, Inc

Page 760: Numerical Library in C for Scientists and Engineers A

[Bro71] C.G. Broyden, "The Convergence of an Algorithm for Solving Sparse Nonlinear Systems", Math. Comp. 25, No. 1 14, 1971, 285- 294.

[Bu167] R. Bulirsch, "Numerical Calculation of the Sine, Cosine and Fresnel Integrals", Numer. Math. 9, 1967, 380-385.

[BulS65] R. Bulirsch, J. Stoer, "Numerical Treatment of Ordinary Differential Equations by Extrapolation Methods", Numer. Math. 8, 1965, 1 - 13.

[BunK77] J.R. Bunch, L. Kaufinan, "Some Stable Methods for Calculating Inertia and Solving Symmetric Linear Systems", Math. Comp. 31, 1977, 163-180.

[BunKP76] J.R. Bunch, L. Kaufman, B.N. Parlett, "Decomposition of a Symmetric Matrix", Numerische Mathematik 27, 1976, 95-109.

[Bus72a] J.C.P. Bus, "Linear Systems with Calculation of Error Bounds and Iterative Refinement", LR 3.4.19, Mathematical Centre, Amsterdam, 1972.

[Bus72b] J.C.P. Bus, "Minimization of Functions of Several Variables", NR 29, Mathematical Centre, Amsterdam, 1972.

[Bus761 J .C.P. Bus (ed.), "Colloquium Numerieke Prograrnrnatuur", MC Syllabus NR 29. la, 29.1 b, Mathematical Centre, Amsterdam, 1976.

[BusD75] J.C.P. Bus, T.J. Dekker, "Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function", ACM Transactions on Mathematical Software, 1975, 330-345.

[BusDK75] J.C.P. Bus, B. van Domselaar, J. Kok, "Nonlinear Least Squares Estimation", Report NW 17, Mathematical Centre, Amsterdam, 1975.

[Busi71] P.A. Businger, "Monitoring the Numerical Stability of Gaussian Elimination", Numer. Math. 16, 1971, 360-361.

[BusiG65] P. Businger, G.H. Golub, "Linear Least Squares Solution by Householder Transformations", Numerische Mathematik 7, 1965, 269-276.

[Cle62] C.W. Clenshaw, "Chebyshev Series for Mathematical Functions", Mathematical Tables Vol. 5, Nat. Physical Lab., Her Majesty's Stationery Office, London, 1962.

[Cod681 W.J. Cody, "Chebyshev Approximations for the Fresnel Integrals", Math. Comp. 22, 1968, 450-453.

[Cod691 W.J. Cody, "Rational Chebyshev Approximations for the Error

Copyright 1995 by CRC Press, Inc

Page 761: Numerical Library in C for Scientists and Engineers A

Function", Math. Comp. 23, 1969, 631-637

[CodT68] W.J. Cody, H.C. Thacher, Jr., "Rational Chebyshev Approximations for the Exponential Integral ei(x)", Math. Comp. 22, 1968, 641-649.

[CodT69] W.J. Cody, H.C. Thacher, Jr., "Chebyshev Approximations for the Exponential Integral ei(x)", Math. Comp. 23, 1969, 289-303.

[CooHHS] T.M.T. Coolen, P.W. Hemker, P.J. van der Houwen, E. Slagt, "Algol 60 Procedures for Initial and Boundary Value Problems", MC Syllabus NR 20, Mathematical Centre, Amsterdam, 1973.

[Dan691 J.W. Daniel, "Summation of a Series of Positive Terms by Condensation Transformations", Math. Comp. 23, 1969, 91-96.

[Dav59] W.C. Davidon, "Variable Metric Methods for Minimization", Argonne National Lab., Report 5990, 1959.

[De72] K. Dekker, "An Algol 60 Version of Exponentially Fitted Runge- Kutta Methods", Report NR 25, Mathematical Centre, Amsterdam, 1972.

[Dek66] T.J. Dekker, "Newton-Laguerre Iteration", Mathematisch Centrum MR 82, Amsterdam, 1966.

[Dek68] T.J. Dekker, "ALGOL 60 Procedures in Numerical Algebra, Part I", Mathematical Centre Tract 22, Mathematisch Centrum, Amsterdam, 1968.

[Dek71] T.J. Dekker, "Numerical Algebra", MC Syllabus NR 12, Mathematical Centre, Amsterdam, 197 1.

[DekHH72] T.J. Dekker, P.W. Hemker, P.J. van der Houwen, "Colloquium Stiff Differential Equations l", MC Syllabus NR 15.1, Mathematical Centre, Amsterdam, 1972.

[DekHo68] T.J. Dekker, W. Hoffmann, "ALGOL 60 Procedures in Numerical Algebra, Part 2", Mathematical Centre Tract 23, Mathematisch Centrum, Amsterdam, 1968.

[DekR71] T.J. Dekker, C.J. Roothart, "Introduction to Numerical Analysis", Report CR 24, Mathematical Centre, Amsterdam, 1971.

[Engl2] R. England, "Error Estimates for Runge-Kutta Type Solutions to Systems of Ordinary Differential Equations", Computer Journal 12, 1969, 166-169.

[Fle63] R. Fletcher, "A New Approach to Variable Metric Algorithms", Computer Journal 6, 1963, 163-168.

Copyright 1995 by CRC Press, Inc

Page 762: Numerical Library in C for Scientists and Engineers A

L. Fox, I.B. Parker, Chebyshev Polynomials in Numerical Analysis, Oxford University Press, 1968.

P. Fox, "A Comparative Study of Computer Programs for Integrating Differential Equations", CACM 15, 1972, 94 1 - 948.

J.G. Francis, "The QR Transformation, Parts 1 and 2", Computer Journal 4, 1961, 265-271, 332-345.

W. Gautschi, "Recursive Computation of Certain Integrals", JACM 8, 1961, 21-40.

W. Gautschi, "Incomplete Beta Function Ratios", CACM 7, 1964, 143- 144.

W. Gautschi, "Computational Aspects of Three-term Recurrence Relations", SIAM Review 9, 1967, 24-82.

W. Gautschi, "Construction of Gauss-Christoffel Formulas", Math. Comp. 22, 1968, 251-270.

W. Gautschi, "Gaussian Quadrature Formulas", CACM 11, No. 6, 1968, 432-436.

W. Gautschi, "Generation of Gaussian Quadrature Rules and Orthogonal Polynomials", in "Colloquium Approximatietheorie", MC Syllabus NR 14, Mathematisch Centrum, Amsterdam, 1970.

W. Gautschi, "Exponential Integrals", CACM 16, 1973, 76 1-763.

W.M. Gentleman, "An Error Analysis of Goertzel's (Watt's) Method for Computing Fourier Coefficients", Cornput. J , Vol. 12, 1969, 160- 165.

A.A. Goldstein, J.F. Price, "An Effective Algorithm for Minimization", Numer. Math. 10, 1967, 184-189.

G.H. Golub, J.H. Welsch, "Calculation of Gauss Quadrature Rules", Math. Comp. 23, 1969, 221-230.

R.G. Gordon, "Evaluation of Airy Functions", The Journal of Chemical Physics 51, 1969, 23-24.

J.L. Greenstadt, "On the Relative Efficiencies of Gradient Methods", Math. Comp. 21, 1967, 360-367.

R.T. Gregory, D.L. Karney, A Collection of Matrices for Testing Computational Algorithms, Wiley-Interscience, 1969.

Copyright 1995 by CRC Press, Inc

Page 763: Numerical Library in C for Scientists and Engineers A

[ H W R.W. Hamming, Numerical Methods for Scientists and Engineers, McGraw-Hill, 1973.

J.F. Hart, E.W. Cheney, C.L. Lawson, H.J. Maehly, C.K. Mesztenyi, J.R. Rice, H.C. Thacher, Jr., C. Witzgall, Computer Approximations, Wiley, New York, 1968.

H.O. Hartley, "The Modified Gauss-Newton Method", Technometrics 3, 1961, 269-280.

P.W. Hemker, "An Algol 60 Procedure for the Solution of Stiff Differential Equations", Report MR 128, Mathematical Centre, Amsterdam, 197 1.

P.W. Hemker, "A Sequence of Nested Cubature Rules", Report NW 3, Mathematical Centre, Amsterdam, 1973.

P.W. Hemker, "Galerkin's Method and Lobatto Points", Report 24, Mathematisch Centrum, Amsterdam, 1975.

P.W. Hemker (ed.), "NUMAL, Numerical Procedures in ALGOL 60", MC Syllabus, 47.1-47.7, Mathematisch Centrum, Amsterdam, 1980.

T.E. Hull, W.H. Enright, B.M. Fellen, A.E. Sedgwick, "Comparing Numerical Methods for Ordinary Differential Equations", SIAM Journal on Numerical Analysis 9, 1972, 603-637.

D.B. Hunter, "The Calculation of Certain Bessel Functions", Math. Comp. 18, 1964, 123-128.

D.E. Knuth, The Art of Computer Programming, Seminumerical Algorithms, Vol. 2, Addison-Wesley Pub. Co., 1969.

D.E. Knuth, The Art of Computer Programming, Vol. 3, Sorting and Searching, Addison-Wesley, 1973.

C. Lanczos, Applied Analysis, Prentice Hall, 1957.

B. Lindberg, "IMPEX 2, A Procedure for the Solution of Systems of Stiff Differential Equations", Report TRITA-NA-7303, Royal Institute of Technology, Stockholm, 1973.

W. Liniger, R.A. Willoughby, "Efficient Integration Methods for Stiff Systems of Ordinary Differential Equations", SIAM J. Numer. Anal. 7, 1970, 47-66.

[Lu69] Y.L. Luke, The Special Functions and their Approximations, 2 Vols., Academic Press, 1969.

Copyright 1995 by CRC Press, Inc

Page 764: Numerical Library in C for Scientists and Engineers A

Appendix A: References 747

Y.L. Luke, "Evaluation of the Gamma Function by means of Pad6 Approximations", SIAM J. Math. Anal. 1, 1970, 266-281.

D.W. Marquardt, "An Algorithm for Least-Squares Estimation of Nonlinear Parameters", J. SIAM 11, 1963, 431-441.

G. Meinardus, Approximation of Function and their Numerical Treatment, Springer Tracts in Natural Philosophy, Vol. 4, 1964.

C.B. Moler, G.W. Stewart, "An algorithm for the Generalized Matrix Eigenvalue Problem Ax=hBxU, report STAN-(3-232-7 1, Stanford University.

D.J. Mueller, "Householder's Method for Complex Matrices and Eigensystems of Hermitian Matrices", Numerische Mathematik 8, 1966, 72-92.

A.C.R. Newbery, "Error Analysis for Fourier Series Evaluation", Math. Comp., Vol. 26, 1973, 923-924.

E.E. Osborne, "On Preconditioning of Matrices", J. Assoc. Comput. Mach. 7, 1960, 338-354.

B.N. Parlett, C. Reinsch, "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors", Numerische Mathematik 13, 1969, 293-304.

G. Peters, J.H. Wilkinson, "Practical Problems Arising in the Solution of Polynomial Equations", Journal of the Institute of Mathematics and Its Applications. 8, No. 1, 1971, 16-35.

M.J.D. Powell, "Rank One Methods for Unconstrained Optimization", in Integer and Nonlinear Programming, edited by J. Abadie, North- Holland, 1970.

W.H. Press, S.A. Teukolsky, W.T. Vetterling, B.P. Flannery, Numerical Recipes in C, second edition, Cambridge University Press, 1992.

J.K. Reid, "On the Method of Conjugate Gradients for the Solution of Large Sparse Systems of Linear Equations", in Large Sparse Sets of Linear Equations, edited by J.K. Reid, Academic Press, 1971.

C. Reinsch, "A note on Trigonometric Interpolation", Report No. 6709, Mathematics Department, Technische Universitat Munchen, 1967.

C.H. Reinsch, "A Stable, Rational QR Algorithm for the Computation of the Eigenvalues of an Hermitian, Tridiagonal

Copyright 1995 by CRC Press, Inc

Page 765: Numerical Library in C for Scientists and Engineers A

748 A Numerical Library in C for Scientists and Engineers

Matrix", Math. Comp. 25, 1971, 591-597.

Th.H.P. Reymer, "Berekening Van Nulpunten Van Reele Polynomen En Foutgrenzen Voor Deze Nulpunten", Doctoraal Scriptie UVA, April 1977.

H.J.J. te Riele (ed.), "Colloquium Numerieke Programmatuur", MC Syllabus NR 29.2, Mathematical Centre, Amsterdam, 1977.

T.J. Rivlin, The Chebyshev Polynomials, Wiley, 1974.

C.J. Roothart, H. Fiolet, "Quadrature Procedures", Report MR 137, Mathematical Centre, Amsterdam, 1972.

M. Shaw and J. Traub, "On the Number of Multiplications for the Evaluation of a Polynomial and some of its Derivatives", J. Assoc. Comput. Mach., 1974, Vol. 21, NO. 1, 161-167.

H. Spaeth, "The Damped Taylor's Series Method for Minimizing a Sum of Squares and for Solving Systems of Nonlinear Equations", CACM 10, 1967, 726-728.

J. Stoer, Einfuehrung in die Numerische Mathematik I, Heidelberger Taschenbuecher 105, Springer-Verlag, 1972.

G. Strang, G.J. Fix, An Analysis of the Finite Element Method, Prentice-Hall, 1973.

A.J. Strecok, "On the Calculation of the Inverse of the Error Function", Math. Comp. 22, 1968, 144-158.

N.M. Temme, "On the Numerical Evaluation of the Ordinary Bessel Function of the Third Kind", 3: Comput. Phys. 19, 1975, 324-337.

N.M. Temme, "On the Numerical Evaluation of the Ordinary Bessel Function of the Second Kind", J. Comput. Phys. 21, 1976, 343-350.

N.M. Temme, "Speciale Functies", in "Colloquium Numerieke Programmatuur", J.C.P. Bus (ed.), MC Syllabus NR 29. lb, Mathematical Centre, Amsterdam, 1976.

N.M. Temme, "An Algorithm with Algol 60 Implementation for the Calculation of the Zeros of a Bessel Function", Report TW 179, Mathematical Centre, Amsterdam, 1978.

P.J. van der Houwen, "Finite Difference Methods for Solving Partial Differential Equations", Mathematical Centre Tract 20, Mathematical Centre, Amsterdam, 1968.

[Vh70a] P.J. van der Houwen, "One-Step Methods for Linear Initial Value

Copyright 1995 by CRC Press, Inc

Page 766: Numerical Library in C for Scientists and Engineers A

Problems I, Polynomial Methods", Report TW 119, Mathematical Centre, Amsterdam, 1970.

[Vh70b] P.J. van der Houwen, "One-Step Methods for Linear Initial Value Problems 11, Polynomial Methods", Report TW 122, Mathematical Centre, Amsterdam, 1970.

[Vh71] P.J. van der Houwen, "Stabilized Runge Kutta Method with Limited Storage Requirements", Report TW 124, Mathematical Centre, Amsterdam, 197 1.

[Vh72] P.J. van der Houwen, "One-Step Methods with Adaptive Stability Functions for the Integration of Differential Equations", Lecture Notes of the Conference on Numerische Insbesondere Approximationstheoretische Behandlung Von Funktional- Gleichungen, Obenvolfach, December 3-12, 1972.

[VhBDS71] P.J. van der Houwen, P. Beentjes, K. Dekker, E. Slagt, "One Step Methods for Linear Initial Value Problems 111, Numerical Examples", Report TW 130, Mathematical Centre, Amsterdam, 1971.

P.J. van der Houwen, J. Kok, "Numerical Solution of a Minimax Problem'!, Report TW 123, Mathematical Centre, Amsterdam, 1971.

P.J. van der Houwen, J.G. Venver, "Generalized Linear Multistep Methods 1, Development of Algorithms with Zero-Parasitic Roots", Report NW 10, Mathematisch Centrum, Amsterdam, 1974.

B. van Domselaar, "Nonlinear Parameter Estimation in Initial Value Problems", Report NW 18, Mathematical Centre, Amsterdam, 1975.

A. van Wijngaarden, "Course Scientific Computing B, Process Analysis", Mathematisch Centrum CR 18, Amsterdam, 1965.

J.M. Varah, "Eigenvectors of a Real Matrix by Inverse Iteration", Technical Report No. CS 34, Stanford University, 1966.

J.G. Venver, "Generalized Linear Multistep Methods 2, Numerical Applications", Report NW 12, Mathematisch Centrum, Amsterdam, 1974.

G.N. Watson, A Treatise on the Theoly of Bessel Functions, Cambridge University Press, 1945.

J.H. Wilkinson, Rounding Errors in Algebraic Processes, London,

Copyright 1995 by CRC Press, Inc

Page 767: Numerical Library in C for Scientists and Engineers A

[Wi65] J.H. Wilkinson, The Eigenvalue Problem, Oxford, 1965.

[WiR71] J.H. Wilkinson, C. Reinsch, Handbook of Automatic Computation, Vol. 2, Linear Algebra, Springer-Verlag, 197 1.

[Wo74] H. Wozniakowski, "Rounding Error Analysis for the Evaluation of a Polynomial and some of its Derivatives", SIAM J. Numer. Anal., Vol. 11, NO. 4, 1974, 780-787.

[Wy81] P. Wynn, "NUMAL in FORTRAN", IIMAS, Universidad Nacional Authoma de MCxico, Comunicaciones tCcnicas Nos. 48.0-48.11, 1981.

K641 J.A. Zonneveld, "Automatic Numerical Integration", Mathematical Centre Tract 8, Mathematisch Centrum, Amsterdam, 1964.

Copyright 1995 by CRC Press, Inc

Page 768: Numerical Library in C for Scientists and Engineers A

Appendix B: Prototype Declarations

float absmaxmat(int, int, int, int, int * , int *, float * * ) ; void airy(float, float * , float * , float * , float *,

float * , int) ; float airyzeros (int, int, float [I , float [I ) ; void allchepol (int, float, float [I ) ; void alljaczer (int, float, float, float [I ) ; void alllagzer (int, float, float [I ) ; int **allocate-integer-matrix(int, int, int, int); int *allocate-integer-vector(int, int); float **allocate-real-matrix(int, int, int, int); float *allocate-real-vector(int, int) ; void allortpol (int, float, float [I , float [I , float [I ) ; void allortpolsym (int, float, float [I , float [I ) ; void allzerortpol(int, float [I, float [I, float [I, float [I); float arccosh (f loat) ; float arcsinh (f loat) ; float arctanh (float) ; void ark(f1oat * , float *, int * , int * , float [I,

void ( * ) (int * . int * . float * . float [ I ) . float [I . - - ~ -

void i*) iint *, int *, float *, float *, float [I, float [I));

void arkmat(f1oat *, float, int, int, float **, void ( * ) (int, int, float, float **, float * * ) , int, int *, float * , void ( * ) (float, float, int, int, float ** , int, int, float * ) ) ;

void backward(float, float, float, float, int, float, float [I); void bakcomhes (float **, float ** , float [I, float [I, float [I,

float ** , float ** , int, int, int) ; void bakhrmtri(f1oat ** , int, int, int, float ** ,

float **, float [I, float [I); void baklbr(int, int, int, float [I, int [I, float * * ) ;

f l . int I l , float * * . float * * I : void baklbrcom (int, int , int, float void bakreahesl(f1oat ** , int, int void bakreahes2(float ** , int, int, void baksymtril(f1oat [I, int, int, void baksymtriZ(f1oat ** , int, int, void besspqaol (float, float, float void bessi (float, int, float [I ) ; float bessi0 (float) ; float bessil (float) ; void bessiaplusn(float, float, int, void bessj (float, int, float [I ) ; float bessi0 (float) :

[ j; ' float .-[I ) ; int, int [I, float * * ) ; int, float * * ) ; int, float * * ) ;

*, float * , float * , float * ) ;

float [I) ;

float bessj 1 (float) ) void bessj aplusn (f loat, float, int , float [I ) ; void bessk (float, int, float [I ) ; void bessk0l (float, float *, float * ) ; void besskaOl(float, float, float * , float * ) ; void besskaplusn(float, float, int, float [ I ) ; void besspq0 (float, float *, float * ) ; void besspql (float, float *, float * ) ; void bessy(float, int, float [I ) ; void bessyOl(float, float *, float * ) ; void bessyaOl(float, float, float * , float * ) void bessyaplusn(float, float, int, float [I) void besszeros(float, int, float [ I , int); void bounds(int, float [I, float [I, float 11

float, float [I, float [I, float [I) ; void carpol (float, float, float *, float *, f float chepol(int, float); float chepolsum (int, float, float [I ) ; void chldecl (float [I , int, float [I ) ; void chldec2(float ** . int. float [I):

float,

oat * ) ;

- -

void chldecbnd (f loat I1 , int, int, float [I ) ; void chldecinvl (float [I , int, float [I ) ; void chldecinv2(float **, int, float [I); void chldecsoll (float [I , int, float [I , float [I ) ; void chldecsol2 (float **, int, float [I , float [I ) ; void chldecsolbnd(f1oat [I , int, int, float 11 , float [I ) ;

Copyright 1995 by CRC Press, Inc

Page 769: Numerical Library in C for Scientists and Engineers A

float chldeterml (float [I , int) ; float chldeterm2(float **, int); float chldetermbnd(f1oat [I , int, int) ; void chlinvl (float 11 , int) ; void chlinv2 (float **, int); void chlsoll (float [I , int, float [I ; void chlsol2 (float **, int, float [I ) ; void chlsolbnd(f1oat [I , int, int, float 11 ) ; void chsh2(float, float, float, float, float *, float *, void chspol (int, float [I ) ; void colcst (int, int, int, float **, float) ; float comabs (float, float) ; void comcolcst(int, int, int, float **, float **, float, void comdiv(float, float, float, float, float *, float * int comeigl (float **, int, float [I , float [I , float [I , int comeigval(f1oat **, int, float [I, float [I, float I float comeucnrm(f1oat ** , float **, int, int) ; void comfouserl (int, float, float [I , float [I , float *, void comfouser2 (int, float, float [I , float [I , float *, void comfouser(int, float, float [I, float *, float * ) ; void comkwd(float, float, float, float,

float *, float *, float *, float * ) ; void commatvec(int. int. int. float **. float ** .

float * ) ;

float) ; ,) ; float * * I ;

:I 1 ;

float * ) ; float * ) ;

float [ j , float '[I , float *, float *) ; . void commul (float, float, float, float, float *, float *) ; void comrowcst(int, int, int, float **, float **, float, float); void comscl (float **, int, int, int, float [I ) ; void comsqrt(float, float, float *, float * ) ; int comvalari (float **. int. float 11 . float [I . float [I) ; - - . - - . - . void comveches (float * * , int , float, float,

float [I, float [I, float [I); void conjgrad(void ( * ) (float [I, float [I), float [I, float [I,

int, int, int ( * ) (int, float), int *, float * ) ; float cosserfint, float, float [I); void davupd(f1oat [I, int, float [I, float [I, float, float) ; void dec (float **, int, float [I, int [ I ) ; void decbnd(f1oat [I, int, int, int, float [ I , float [I, int [I ) ; void decinv(f1oat **, int, float [I); void decsol (float **, int, float 11 , float [I ) ; void decsolbnd(f loat [I , int, int, int, float [I , float [I ) ; void decsolsym2(float **, int, float [I, float, int [I); void decsolsymtri(f1oat 1 1 , float [I, int, float [I, float [I); void decsoltri(f1oat [I, float [I, float [I, int,

float [I, float 11) ; void decsoltripiv(f loat [I , float [I , float [I , int,

float I1 , float [I) ; void decsym2 (float **, int, float, int [I, int [I, float [I ) ; void decsymtri(f1oat [I, float [I, int, float [I); void dectri (float [I, float [I, float [I, int, float [I ) ; void dectripiv(f1oat [I, float [I, float [I, int,

float [I, float [I, int [I) ; void derpol (int, int, float, float [I ) ; float determ(f1oat **, int, int) ; float determbnd(f1oat [I, int, int, int, int) ; float determsym2 (float [I , int, int [I ) ; void diffsys(f1oat *, float, int, float [I,

void ( * ) (int, float, float [I , float [I ) , float, float, float [I , float, void ( * ) (int, float, float, float [I, float [I ) ) ;

void dupcolvec (int, int, int, float **, float [I ) ; void dupmat (int, int, int, int, float **, float **) ; void duprowvec (int, int, int, float **, float [I ) ; void dupvec (int, int, int, float [I , float [I ) ; void dupveccol (int, int, int, float [ I , float **) ; void dupvecrow (int, int, int, float [I , float **) ; void eferk (float *, float, int, float [I , float *, float,

void ( * ) (int, float[]), float ** , void ( * ) (int, float **, float [I, float * ) , int *, int, int, float, float, float, float, int, void ( * ) (float, float, int, float [I, float **, int));

void ef rk (float *, float, int, int, float [I , float *, float *, float *, void (*) (int, int, float, float ) , int *, float *, float, float, float [I , int, float, void ( * ) (int, int, float, float, float [I , float *,

Copyright 1995 by CRC Press, Inc

Page 770: Numerical Library in C for Scientists and Engineers A

Copyright 1995 by CRC Press, Inc

Page 771: Numerical Library in C for Scientists and Engineers A

float fouser2 (int, float, float [I , float [I ) ; void free-integer-matrix(int **, int, int, int); void free-integer-vector(int *, int); void free-real-matrix(f1oat **, int, int, int); void free-real-vector(f1oat *, int); void fresnel(float, float *, float * ) ; void fulmatvec(int, int, int, int, float **, float [I, float [I ) ; void fulsymmatvec(int, int, int, int, float [I, float [I, float [I ) ; void fultamvec (int, int, int, int, float **, float 11 , float [I ) ; float gamma (float) ; void gms (float *, float, int, float [I , float, float,

float, float *, void ( * ) (int, float [I , float *) . void ( * ) (int, float **, float [I , float * ) , float, float, int *, int *, int *, int, int, void ( * ) (float, float, int, float [I , float,

int, int, int)); void grnnew(int, float [ I , float [I); void gssitisolerb (float **, int, float [I , float 11 ) ; void gsselm(f1oat **, int, float [I, int [I, int [I ) ; void gsserb(f1oat **, int, float [I , int [I, int [I ) ; void gssinv(f1oat **, int, float [I ) ; void gssinverb(f1oat **, int, float [I ) ; void gssitisol (float **, int, float [I, float [I ) ; void gssjacwghts (int, float, float, float [I , float [I ) ; void gsslagwghts (int, float, float [I , float [I ) ; void gssnewton (int, int, float [I , float [I , float **,

int ( * ) (int, int, float [ I , float [I ) , void ( * ) (int, int, float[l, float[], float * * ) ,

float [I, float [I) ; void gssnri (float **, int, float [I, int [I, int [I ) ; void gsssol (float **, int, float [I, float [I ) ; void gsssolerb (f loat **, int, float [I , float [I ) ; void gsswts (int, float [I , float [I , float [I , float [I ) ; void gsswtssym(int, float 11 , float [I , float [I ) ; void hestgl2(int, float **, float * * ) ; void hestgl3 (int, float **, float **, float **) ; int homsol (float **, int, int, float **, float [I ) ; void homsolsvd(f1oat **, float [I, float **, int, int); void hsh2col (int, int, int, int, float, float, float **, float **) ; void hsh2row2 (int, int, int, int, float, float,

float **, float * * ) ; void hsh2row3 (int, int, int, int, int, float, float,

float **, float **, float * * ) ; void hsh3col (int, int, int, int, float, float, float,

float **, float ** ) ; void hsh3row2 (int, int, int , float, float, float,

float **, float * * ) ; void hsh3row3 (int, int, int, int, float, float, float,

float **, float **, float ** ) ; void hshcolmat(int, int, int, int, int, float, float **, float * * ) ; void hshcoltam(int, int, int, int, int, float, float **, float * * ) ; int hshcomcol(int, int, int, float **, float **, float,

float *, float *, float *, float * ) ; void hshcomhes(f1oat **, float **, int, float [I, float [I,

float [I, float [I, float [I); void hshcomprd(int, int, int, int, int, float **,

float **, float **, float **, float); void hshdecmul(int, float **, float **, float); void hshhrmtri(f1oat **, int, float [I, float [ I , float [I,

float [I, float [I, float [I); void hshhrmtrival(f1oat **, int, float [I, float [I, float 11); void hshreabid(f loat **, int, int, float [I , float [I , float [I ) ; void hshrowmat(int, int, int, int, int, float, float **, float * * ) ; void hshrowtam(int, int, int, int, int, float, float **, float **) ; void hshvecmat (int, int, int, int, float, float [I, float **) ; void hshvectam(int, int, int, int, float, float [I, float **) ; void ibpplusn (float, float, float, int, float, float [I ) ; void ibqplusn (float, float, float, int, float, float [I ) ; void ichcol (int, int, int, int, float **) ; void ichrow(int, int, int, int, float **) ; void ichrowcol(int, int, int, int, float * * ) ; void ichseq(int, int, int, int, float [I); void ichseqvec (int, int, int, int, float [I ) ; void ichvec (int, int, int, float [I ) ;

Copyright 1995 by CRC Press, Inc

Page 772: Numerical Library in C for Scientists and Engineers A

void impex(int, float, float, float [I, void ( * ) (float, float [I, float [I, int), int ( * ) (float, float [I, float **, int) , float, float, int, float, float 11 , void ( * ) (float [I, float [I, int), int *, void ( * ) (float *. float. float, float, float * * ,

float [I, int, float)) ; float incbeta(float, float, float, float); void incomqam (f loat, float, float *, float * , float, float) ; float infn&col(int, int, int, int *, float * * ) ; float infnrmmat (int, int, int, int, int *, float * * ) ; float infnrmrow(int, int, int, int *, float **I; float infnrmvec(int, int, int * , float [I); void ini (int, int, int [I ) ; void inimat (int, int, int, int, float **, float) ; void inimatd(int, int, int, float ** , float); void inisymd(int, int, int, float [I , float) ; void inisymrow (int, int, int, float [I , float) ; void inivec (int, int, float [I , float) ; void intchs lint, float [I , float [I ) ; float integral(float, float, float ( * ) (float), float [I,

int, int) ; void inv(f1oat ** , int, int 11 ) ; float invl (f loat ** , int, int [I , int [I , int) ; void inverseerrorfunction(float, float, float * ) ; void itisol (float ** , float ** , int, float [I ,

int [I, int [I, float [I); void itisolerb(f1oat **, float **, int, float [I,

int [I, int [ I , float [I); void ixpfix(float, float, float, int, float, float [I); void ixqf ix (float, float, float, int, float, float [I ) ; void jacobnbndf (int, int, int, float [I , float [I ,

float [I, float ( * ) (int), int ( * ) (int, int, int, float[], float[]));

void jacobnmf (int, int, float [I, float [I, float ** , float ( * ) (int), void ( * ) (int, int, float[], float[]));

void jacobnnffint, float [I, float [I, float **, float ( * ) (int), void ( * ) (int, float[], float[]));

float jfrac(int, float [I, float [I) ; void linemin(int, float [I, float [I , float, float *, float [I ,

float ( * ) (int, float[], float[]), float, float *, float, float *, int *, int, float [I ) ;

void linigerlvs(f1oat *, float, int, float [I, float *, void ( * ) (int, float [I , float * ) , float **, void ( * ) (int, float **, float [I, float * ) , int, float, float, float, float, float [I , void ( * ) (float, float, int, float [ I , float,

float ** , float [I)); void liniger2 (float *, float, int, float [I , float *, float *,

float ( * ) (int, float[], int, float * , float * ) , int ( * ) (int), float ** , void ( * ) (int, float ** , float [I, float *, float * ) , int * . int. float. float. float. void I * ) (fioat, fioat, int, float [I, float, float,

float ** , int)) ; void lintfmpol(float, float, int, float [I); void lngintadd(int [I, int [I, int 11) ; void lngintdivide (int [I , int [ I , int [I , int [I ) ; void lngintmult (int [I, int [I, int 11 ) ; void lngintpower(int [I , int, int [I ) ; void lngintsubtract(int [I, int [I, int [I); float loggamma(f1oat); float logoneplusx ( f loat) ; void lsqdecomp(f1oat ** , int, int, int, float [I, float [I, void lsqdglinv(f1oat ** , int, float [I, int [I, float [I ) ; void lsqinv(f1oat ** , int, float [I , int [I ) ; void lsqortdec (float ** , int, int, float 11 , float [I , int void lsqortdecsol (float **, int, int, float [I , float [I, f void lsqrefsol(f1oat **, float **, int, int, int, float [I,

int [I, float [I, float *, float [I, float [I); void lsqsol (float ** , int, int, float [I, int [I, float 11 ) void lupzerortpol(int, int, float [I, float [I, float [I, f void marquardt (int, int, float 1 1 , float [I, float ** ,

int ( * ) (int, int, float[], float[]),

int [I) ;

I) ; oat [I ; float [I ,

oat [I) ;

Copyright 1995 by CRC Press, Inc

Page 773: Numerical Library in C for Scientists and Engineers A

void ( * ) (int, int, float [I , float [I , float * * ) , float [I, float [ I ) ;

float matmat(int, int, int, int, float **, float * * ) ; float mattam(int, int, int, int, float **, float * * ) ; float matvec (int, int, int, float **, float [I ) ; int maxelmrow(int, int, int, int, float **, float **, float) ; void mergesort(f1oat [I, int [I, int, int); float minin(f1oat *, float *, float * , float ( * ) (float) ,

float ( * ) (float)) ; float mininder (float *, float *, float ( * ) (float) ,

float ( * ) (float), float ( * ) (float)) ; void minmaxpol (int, int, float [I , float [I , float [I , float [I ) ; void modif iedtaylor (f loat * , float, int, int, float [I ,

float ( * ) (float, int, int) , float, void ( * ) (float, int, int, int, float [I ) , int *, float [I, float, int, float ( * ) (float, int, int) , float ( * ) (float, int, int), float *, float *, void ( * ) (float, float, int, int, float [I,

int, float, float) ) ; void mulcol (int, int, int, int, float **, float **, float) ; void mulrow(int, int, int, int, float **, float **, float); int multistep(f1oat *, float, float [I, float, float,

float [I , float, int *, float [I , void ( * ) (float [I, int, float, float[]), int ( * ) (int, float, float [I, float * * I , float ** , int, int, void ( * ) (float, int, int, float, float [I ) ) ;

void mulvec (int, int, int, float [I, float [I, float) ; void nonexpbessi(float, int, float [I ) ; float nonexpbessiO(f1oat); float nonexpbessil(f1oat) ; void nonexpbessiaplusn(float, float, int, float [I); void nonexpbessk (float, int, float 11 ) ; void nonexpbesskOl(float, float *, float * ) ; void nonexpbesskaOl(float, float, float * , float * ) ; void nonexpbesskaplusn(float, float, int, float [I); void nonexpspherbessi (float, int, float [I ) ; void nonexpspherbessk (f loat, int, float [I ) ; void newgrn (int, float [I , float [I ) ; void newton(int, float [I , float [I ) ; void nonexpenx(float, int, int, float 11 1 ; float nonexperfc (float) ; void nonlinfemlagskew(f1oat [I, float [I, int,

float ( * ) (float, float, float) , float ( * ) (float, float, float), float ( * ) (float, float, float), int, float [I ) ;

void norderpol (int, int, float, float [I ) ; float oddchepolsum(int, float, float 11 ) ; float onenrmcol(int, int, int, float * * I ; float onenrminv(f1oat **, int); float onenrmmat(int, int, int, int, int *, float * * ) ; float onenrmrow (int, int, int, float * * ) ; float onenrmvec (int, int, float [I ) ; void orthog(int, int, int, float * * ) ; float ortpol (int, float, float 11 , float 11 ) ; float ortpolsym (int, float, float [I ) ; void peide (int, int, int, int *, float [I , float [I ,

int [I, float ** , float [I, float [I, int (*)(int,int,float [],float [I,float,float [I), int ( * ) (int,int,float [],float [l,float,float * * ) , int ( * ) (int,int,float [I ,float [l,float,float * * ) , void (*)(int,int,float [],float [],float[]), void ( * ) (int,float [I ,float [I ,int[l), void ( * ) (int,int,int,float [],float [l,int,int));

float pol (int, float, float [I ) ; void polchs (int, float [I ) ; void polshtchs (int, float 11 ) ; void praxis (int, float [I, float ( * ) (int, float [I ) ,

float [I, float [I); void pretfmmat(f1oat **, int, int, float 11 1 ; int psdinv(f1oat **, int, int, float [I ) ; void psdinvsvd(f1oat **, float [I, float **, int, int, float [I ) ; void psttfmmat (float **, int, float **, float [I ) ; float qadrat (float *, float, float, float ( * ) (float) , float [I ) ; int qricom(f1oat **, float **, float [I, int, float [I,

Copyright 1995 by CRC Press, Inc

Page 774: Numerical Library in C for Scientists and Engineers A

float [I, float [I, float ** , float * * ) ; int qrihrm(f1oat **, int, float [I, float **, float **, float [I ) ; int qrisngval(f1oat ** , int, int, float [I, float [I ) ; int qrisngvalbid (f loat [I , float [I , int, float [I ) ; int qrisngvaldec(f1oat ** , int, int, float [I, float ** , float [I); int qrisngvaldecbid(f1oat [I, float [I, int, int, float ** ,

float **, float [I) ; int qrisym(f1oat **, int, float [I, float [I ) ; int qrisymtri (float ** , int, float [I , float [I, int qrivalhrm(f1oat **, int, float [I , float [I ) ; int qrivalsyml(f1oat [I, int, float [I, float [I) int qrivalsym2 (float ** , int, float [I, float [I ) int qrivalsymtri (float [I , float [I , int, float void quanewbnd(int, int, int, float [I, float [I,

int ( * ) (int. int. int, float [ I , float [ I ) .

float [I, float [I) ;

I); float 11 ,

- - . - - . float '[I., fioat [I ) ; '

void quanewbndl (int, int, int, f l0at [I , float [I , int ( * ) (int, int, int, float[], float[]), float [I, float [I);

void qzi (int, float ** , float **, float **, float [I , float [I, float [I, int [I, float 11);

void qzival (int, float **, float ** , float [I, float [I, float [I, int [I, float [I);

int reaeigl (float ** , int, float [I, float [I, float * * ) ; int reaeig3 (float * * , int, float [I , float 11 , float * * ) ; int reaeigval (float **, int, float [I , float [I ) ; int reaqri (float ** , int, float [I, float [I, float * * ) ; void reascl (float ** , int, int, int) ; int reavalqri (float **, int, float [I, float [I ) ; void reaveches(f10at ** , int, float, float [I, float [I); void reccof (int, int, float * , float ( * ) (float), float [I,

float [I, float [I, int); float recipgamma(float, float * , float * ) ; void resvec (int, int, int, int, float ** , float [I, float [I, float) ; void richardson(f1oat **, int, int, int, int,

int, void ( * ) (int, int, int, int, float * * ) , float, float, int, float [I , int *, float *, float *, void ( * ) (float **, int, int, int, int, int, float 1 1 ,

int, float, float) ) ; void rkl(f1oat *, float, float, float *, float,

float ( * ) (float, float), float [I, float [I, int) ; void rk2(float *, float, float, float *, float, float * , float,

float ( * ) (float, float, float), float [I, float [I, int); void rk2n (f loat * , float, float, float [I , float [I , float [I

float [I, float ( * ) (int, int, float, float [I, float [I), float [I, float [I, int, int) ;

void rk3(float * , float, float, float *, float, float *, float, float ( * ) (float, float), float [I, float [I, int) ;

void rk3n (float *, float, float, float [I , float [I , float [I , float [I, float ( * ) (int, int, float, float[]), float [I, float [I, int, int);

void rk4a (float *, float, float ( * ) (float, float) , float *, float, float ( * ) (float, float), float [I, float [I, int, int, int) ;

void rk4na (f loat [I , float [I , float ( * ) (int, float [I ) , float ( * ) (int, int, float [I), float [I, float [I, int, int, int, int);

void rk5na(float [I, float [I, float ( * ) (int, float [I ) , float ( * ) (int, int, float[]), float [I, float [I, int, int, int, int);

void rke (float *, float * , int, float [I , void ( * ) (int, float, float [I ) , float , int, void ( * ) (int, float, float, float [I , float [I ) ) ;

float rnklmin(int, float [ I . float [I. float [I. float ( * ) iint, float [I , float [I ) , float [I, float [I);

void rnklupd (float [I , int, float [I , float) ; void rotcol(int, int, int, int, float **, float, float); void rotcomcol(int, int, int, int, float ** , float ** ,

float. float. float) : void rotcomrdw (int, .int, int, int, float ** , float ** ,

float, float, float) ; void rotrow(int, int, int, int, float ** , float, float); void rowcst (int, int, int, float **, float) ;

Copyright 1995 by CRC Press, Inc

Page 775: Numerical Library in C for Scientists and Engineers A

void rowperm (int [I , int, int, int, float * * ) ; float scaprdl (int, int, int, int, int, float [I , float 11 ) ; void sclcom(f1oat **, float ** , int, int, int); void selzerortpol(int, int, int, float [I, float [I,

float [I , float [I ) ; float seqvec(int, int, int, int, float [I, float 11) ; void shtchspol (int , float [I ) ; void sincosfg(float, float * , float * ) ; void sincosint(float, float * , float * ) ; float sinser (int, float, float [I ) ; void sndremez(int, int, int [I, float [I, float [I); void sol(f1oat **, int, int [ I , float [I ) ; void solbnd(f1oat [I, int, int, int, float [I, int [I, float [I ) ; void solelm(f1oat **, int, int [I, int [I, float [I ) ; int solovr (float ** , int, int, float [I, float [I ) ; void solsvdovr(f1oat **, float [I, float **, int, int,

float [I , float [I ) ; void solsvdund(f1oat **, float [I, float **, int, int,

float [I, float [I) ; void solsym2 (float ** , int, float [I, int [I, float [I) ; void solsymtri (float [I, float [I, int, float [I ) ; void soltri (float [I, float [I, float [I, int, float [I ) ; void soltripiv(f1oat [I, float [I, float [I, int,

float [I, int [I, float [I); int solund(f1oat **, int, int, float [I, float [I ; void spherbessi (float, int, float [I ) ; void spherbessj (float, int, float [I ) ; void spherbessk (float, int, float [I ) ; void spherbessy(float, int, float [I ) ; int start (float, int, int) ; float sumortpol(int, float, float [I, float [I, float 11 ; float sumortpolsym (int, float, float [I , float 11 ) ; float sumposseries (float ( * ) (float) , int, float, int, int, int) ; void symeigimp(int, float ** , float ** , float [I, float [ I ,

float [I, float [I); float symmatvec (int, int, int, float [I , float [I ) ; void symresvec(int, int, int, int, float [I, float [I, float [I, float) ; void system-error(char [I); float tammat(int, int, int, int, float **, float * * ) ; float tamvec(int, int, int, float ** , float [I ) ; void taypol(int, int, float, float 1 1 ) ; void tfmprevec(f1oat **, int); void tfmreahes (float **, int, float [I , int 11 ) ; void tfmsymtril(f1oat [I, int, float [I, float [I, float [I,

float [I); void tfmsymtri2(float **, int, float [I, float [I, float [I,

float [I ) ; float tricub(float, float, float, float, float, float,

float ( * ) (float,float), float, float); int valqricom(f1oat ** , float **, float [I, int, float [I,

float [I , float [I ) ; void valsymtri (float [I , float [I , int, int, int,

float [I, float [I); void vecperm(int [I , int, int, float [I ) ; void vecsymtri (float [I, float [I , int, int, int,

float [I, float **, float [I) ; float vecvec (int, int, int, float [I, float [I ) ; int zeroin(f1oat * , float *, float ( * ) (float), float ( * ) (float)); int zeroinder (float *, float *, float ( * I (float),

float ( * ) (float), float ( * ) (float)) ; int zeroinrat(f1oat *, float * , float ( * ) (float), float ( * ) (float)); int zerpol (int, float [I, float [I, float [I, float [I, float [I) ;

Copyright 1995 by CRC Press, Inc

Page 776: Numerical Library in C for Scientists and Engineers A

Appendix C: Procedure Descriptions

INIVEC initializes a vector with a constant. INIMAT initializes a matrix with a constant. INIMATD initializes a (co)diagonal of a matrix. INISYMD initializes a (co)diagonal of a symmetric matrix, whose

upper triangle is stored columnwise in a one-dimensional array.

INISYMROW initializes a row of a symmetric matrix, whose upper triangle is stored columnwise in a one-dimensional array.

DUPVEC copies a vector into another vector. DUPVECROW copies a row vector into a vector. DUPROWVEC copies a vector into a row vector. DUPVECCOL copies a column vector into a vector. DUPCOLVEC copies a vector into a column vector. DUPMAT MULVEC MULROW

MULCOL

COLCST ROWCST VECVEC MATVEC TAMVEC MATMAT

TAMMAT

MATTAM SEQVEC

SCAPRD 1

copies a matrix into another matrix. stores a constant multiplied by a vector into a vector. stores a constant multiplied by a row vector into a row vector. stores a constant multiplied by a solumn vector into a column vector.

multiplies a column vector by a constant. multiplies a row vector by a constant.

forms the scalar product of a vector and a vector. forms the scalar product of a row vector and a vector. forms the scalar product of a column vector and a vector. forms the scalar product of a row vector and a column vector. forms the scalar product of a column vector and a column vector. forms the scalar product of a row vector and a row vector.

forms the scalar product of two vectors given in one- dimensional arrays, where the mutual spacings between the indices of the first vector change linearly.

forms the scalar product of two vectors given in one- dimensional arrays, where the spacings of both vectors are constant.

SYMMATVEC forms the scalar product of a vector and a row of a symmetric matrix, whose upper triangle is given columnwise in a one-dimensional array.

FULMATVEC forms the product A*B of a given matrix A and a vector

Copyright 1995 by CRC Press, Inc

Page 777: Numerical Library in C for Scientists and Engineers A

B. FULTAMVEC forms the product A~*B, where is the transpose of a

given matrix A and B is a vector. FULSYMMATVEC forms the product A*B, where A is a symmetric

matrix whose upper triangle is stored columnwise in a one-dimensional array and B is a vector.

RESVEC calculates the residual vector A*B+X*C, where A is a given matrix, B and C are vectors and X is a scalar.

SYMRESVEC

HSHVECMAT

HSHCOLMAT

HSHROWMAT

HSHVECTAM

HSHCOLTAM

HSHROWTAM

ELMVEC ELMCOL ELMROW ELMVECCOL ELMCOLVEC ELMVECROW ELMRO WVEC ELMCOLROW ELMROWCOL MAXELMRO W

calculates the residual vector A*B+X*C, where A is a symmetric matrix whose upper triangle is stored columnwise in a one-dimensional array, B and C are vectors and X is a scalar. premultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given in a one- dimensional array. premultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given as a column in a two-dimensional array. premultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given as a row in a two-dimensional array. postmultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given in a one-dimensional array. postmultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given as a column in a two-dimensional array. postmultiplies a matrix by a Householder matrix, the vector defining this Householder matrix being given as a row in a two-dimensional array. adds a constant times a vector to a vector. adds a constant times a column vector to a column vector. adds a constant times a row vector to a row vector. adds a constant times a column vector to a vector. adds a constant times a vector to a column vector. adds a constant times a row vector to a vector. adds a constant times a vector to a row vector. adds a constant times a row vector to a column vector. adds a constant times a column vector to a row vector. adds a constant times a row vector to a row vector, it also delivers the subscript of an element of the new row vector which is of maxim& absolute value.

Copyright 1995 by CRC Press, Inc

Page 778: Numerical Library in C for Scientists and Engineers A

ICHVEC interchanges two vectors given in a one-dimensional array. ICHCOL interchanges two columns of a matrix. ICHROW interchanges two rows of a matrix. ICHROWCOL interchanges a row and a column of a matrix. ICHSEQVEC interchanges a row and a column of an upper

triangular matrix, which is stored columnwise in a one- dimensional array.

ICHSEQ interchanges two columns of an upper triangular matrix, which is stored columnwise in a one-dimensional array.

ROTCOL replaces two column vectors X and Y by two vectors CX+SY and CY-SX.

ROTROW replaces two row vectors X and Y by two vectors CX+SY and CY-SX.

INFNRMYEC calculates the infinity norm of a vector. INFNRMROW calculates the infinity norm of a row vector. INFNRMCOL calculates the infinity norm of a column vector. INFNRMMAT calculates the infinity norm of a matrix. ONENRMYEC calculates the 1-norm of a vector. ONENRMROW calculates the 1-norm of a row vector. ONENRMCOL calculates the 1-norm of a column vector. ONENRMMAT calculates the 1 -norm of a matrix. ABSMAXMAT calculates the modulus of the largest element of a matrix

and delivers the indices of the maximal element. REASCL normalizes the columns of a two-dimensional array. COMCOLCST multiplies a complex column vector by a complex number. COMROWCST multiplies a complex row vector by a complex number. COMMATVEC forms the scalar product of a complex row vector and a

complex vector. HSHCOMCOL transforms a complex vector into a vector proportional to

a unit vector. HSHCOMPRD premultiplies a complex matrix with a complex

Householder matrix. ELMCOMVECCOL adds a complex number times a complex column

vector to a complex vector. ELMCOMCOL adds a complex number times a complex column vector to

a complex column vector. ELMCOMROWVEC adds a complex number times a complex vector to

a complex row vector. ROTCOMCOL replaces two complex column vectors X and Y by two

complex vectors CX+SY and CY-SX. ROTCOMROW replaces two complex row vectors X and Y by two

complex vectors CX+SY and CY-SX.

Copyright 1995 by CRC Press, Inc

Page 779: Numerical Library in C for Scientists and Engineers A

CHSH2 finds a complex rotation matrix. COMEUCNRM calculates the Euclidean norm of a complex matrix with

some lower diagonals. COMSCL normalizes real and complex eigenvectors. SCLCOM normalizes the columns of a complex matrix. COMABS calculates the modulus of a complex number. COMSQRT calculates the square root of a complex number. CARPOL transforms the Cartesian coordinates of a complex number

into polar coordinates. COMMUL calculates the product of two complex numbers. COMDIV calculates the quotient of two complex numbers. LNGINTADD computes the sum of long nonnegative integers. LNGINTSUBTRACT computes the difference of long nonnegative

integers. LNGINTMULT computes the product of long nonnegative integers. LNGINTDIVIDE computes the quotient with remainder of long

nonnegative integers. LNGINTPOWER computes up , where U is a long nonnegative integer

and P is the positive (single-length) exponent. POL evaluates a polynomial. TAYPOL evaluates the first k terms of a Taylor series. NORDERPOL evaluates the first k normalized derivatives of a

polynomial. DERPOL evaluates the first k derivatives of a polynomial. ORTPOL evaluates the value of an n-degree orthogonal polynomial,

given by a set of recurrence coefficients. ORTPOLSYM evaluates the values of an n-degree orthogonal polynomial,

given by a set of recurrence coefficients. ALLORTPOL evaluates the value of all orthogonal polynomials up to a

given degree, given a set of recurrence coefficients. ALLORTPOLSYM evaluates the values of all orthogonal polynomials up

to a given degree, given a set of recurrence coefficients.

SUMORTPOL evaluates a finite series expressed in orthogonal polynomials, given by a set of recurrence coefficients.

SUMORTPOLSYM evaluates a finite series expressed in orthogonal polynomials, given by a set of recurrence coefficients.

CHEPOLSUM evaluates a finite sum of Chebyshev polynomials. ODDCHEPOLSUM evaluates a finite sum of Chebyshev polynomials of

odd degree. CHEPOL evaluates a Chebyshev polynomial. ALLCHEPOL evaluates all Chebyshev polynomials up to a certain

Copyright 1995 by CRC Press, Inc

Page 780: Numerical Library in C for Scientists and Engineers A

degree. SINSER evaluates a sine series. COSSER evaluates a cosine series. FOUSER evaluates a fourier series with equal sine and cosine

coefficients. FOUSERl evaluates a fourier series. FOUSER2 evaluates a fourier series. COMFOUSER evaluates a complex fourier series with real coefficients. COMFOUSERl evaluates a complex fourier series. COMFOUSER2 evaluates a complex fourier series. JFRAC calculates a terminating continued fraction. POLCHS transforms a polynomial from power sum into Chebyshev sum

form. CHSPOL transforms a polynomial from Chebyshev sum into power sum

form. POLSHTCHS transforms a polynomial from power sum into shifted

Chebyshev sum form. SHTCHSPOL transforms a polynomial from shifted Chebyshev sum form

into power sum form. GRNNEW transforms a polynomial from power sum into Newton

sum form. NEWGRN transforms a polynomial from Newton sum into power

sum form. LINTFMPOL transforms a polynomial in X into a polynomial in Y

(Y=A*X+B). INTCHS computes the indefinite integral of a given Chebyshev series. DEC performs a triangular decomposition with partial pivoting. GSSELM performs a triangular decomposition with a combination of

partial and complete pivoting. ONENRMINV calculates the 1-norm of the inverse of a matrix whose

triangularly decomposed form is delivered by GSSELM. ERBELM calculates a rough upper bound for the error in the

solution of a system of linear equations whose matrix is triangularly decomposed by GSSELM.

GSSERB performs a triangular decomposition of the matrix of a system of linear equations and calculates an upper bound for the relative error in the solution of that system.

GSSNRI performs a triangular decomposition and calculates the 1 -norm of the inverse matrix.

DETERM calculates the determinant of a triangularly decomposed matrix.

SOL solves a system of linear equations whose matrix has been

Copyright 1995 by CRC Press, Inc

Page 781: Numerical Library in C for Scientists and Engineers A

triangularly decomposed by DEC. DECSOL solves a system of linear equations whose order is small

relative to the number of binary digits in the number representation.

SOLELM solves a system of linear equations whose matrix has been triangularly decomposed by GSSELM or GSSERB.

GSSSOL solves a system of linear equations. GSSSOLERB calculates the inverse of a matrix and 1-norm, an upper

bound for the error in the inverse matrix is also given. INV calculates the inverse of a matrix that has been triangularly

decomposed by DEC. DECINV calculates the inverse of a matrix whose order is small relative

to the number of binary digits in the number representation. INV 1 calculates the inverse of a matrix that has been triangularly

decomposed by GSSELM or GSSERB, the 1-norm of the inverse matrix might also be calculated.

GSSINV calculates the inverse of a matrix. GSSINVERB calculates the inverse of a matrix and 1-norm, an upper

bound for the error in the inverse matrix is also given. ITISOL solves a system of linear equations whose matrix has been

triangularly decomposed by GSSELM or GSSERE?, this solution is improved iteratively.

GSSITISOL

ITISOLERB

GSSITISOLERE?

CHLDEC2

CHLDECl

CHLDETERM2

CHLDETERMl

solves a system of linear equations and the solution is improved iteratively. solves a system of linear equations whose matrix has been triangularly decomposed by GSSNRI, this solution is improved iteratively and an upper bound for the error in the solution is calculated. solves a system of linear equations, this solution is improved iteratively and an upper bound for the error in the solution is calculated. calculates the Cholesky decomposition of a positive definite symmetric matrix whose upper triangle is given in a two-dimensional array. calculates the Cholesky decomposition of a positive definite symmetric matrix whose upper triangle is given colurnnwise in a one-dimensional array. calculates the determinant of a positive definite symmetric matrix, the Cholesky decomposition being given in a two- dimensional array. calculates the determinant of a positive definite symmetric matrix, the Cholesky decomposition being given

Copyright 1995 by CRC Press, Inc

Page 782: Numerical Library in C for Scientists and Engineers A

CHLSOLl

CHLDECSOLl

CHLINV 1

CHLDECINV 1

DECSOLSYM2

LSQORTDEC

LSQDGLINV

columnwise in a one-dimensional array. solves a system of linear equations if the coefficient matrix has been decomposed by CHLDEC2 or CHLDECSOL2. solves a system of linear equations if the coefficient matrix has been decomposed by CHLDECl or CHLDECSOLl . solves a positive definite symmetric system of linear equations by Cholesky's square root method, the coefficient matrix should be given in the upper triangle of a two-dimensional array. solves a positive definite symmetric system of linear equations by Cholesky's square root method, the coefficient matrix should be given columnwise in a one- dimensional array. calculates the inverse of a positive definite symmetric matrix, if the matrix has been decomposed by CHLDEC2 or CHLDECSOL2. calculates the inverse of a positive definite symmetric matrix, if the matrix has been decomposed by CHLDECl or CHLDECSOL 1. calculates the inverse of a positive definite symmetric matrix by Cholesky's square root method, the coefficient matrix given in the upper triangle of a two-dimensional array. calculates the inverse of a positive definite symmetric matrix by Cholesky's square toot method, the coefficient matrix given columnwise in a one-dimensional array. calculates the symmetric decomposition of a symmetric matrix. calculates the determinant of a symmetric matrix, the symmetric decomposition being given. solves a symmetric system of linear equations if the coefficient matrix has been decomposed by DECSYM2 or DECSOLSYM2. solves a symmetric system of linear equations by symmetric decomposition. delivers the Householder triangularization with column interchanges of a matrix of a linear least squares problem. calculates the diagonal elements of the inverse of MTM, where M is the coefficient matrix of a linear least squares problem.

Copyright 1995 by CRC Press, Inc

Page 783: Numerical Library in C for Scientists and Engineers A

LSQSOL solves a linear least squares problem if the coefficient matrix has been decomposed by LSQORTDEC.

LSQORTDECSOL solves a linear least squares problem by Householder triangularization with column interchanges and calculates the diagonal of the inverse of MTM, where M is the coefficient matrix.

LSQINV calculates the inverse of the matrix STS, where S is the coefficient matrix of a linear least squares problem.

LSQDECOMP computes the QR decomposition of a linear least squares problem with linear constraints.

LSQREFSOL solves a linear least squares problem with linear constraints if the coefficient matrix has been decomposed by LSQDECOMP.

SOLSVDOVR solves an overdetermined system of linear equations, multiplying the right hand side by the pseudo-inverse of the given matrix.

SOLOVR calculates the singular values decomposition and solves an overdetermined system of linear equations.

SOLSVDUND solves an underdetermined system of linear equations, multiplying the right hand side by the pseudo-inverse of the given matrix.

SOLUND calculates the singular values decomposition and solves an underdetermined system of linear equations.

HOMSOLSVD solves the homogeneous system of linear equations AX=O and X=A=O, where A denotes a matrix and X a vector (the singular value decomposition being given).

HOMSOL solves the homogeneous system of linear equations AX=O and XTA=O, where A denotes a matrix and X a vector.

PSDINVSVD calculates the pseudo-inverse of a matrix (the singular value decomposition being given).

PSDINV calculates the pseudo-inverse of a matrix. DECBND performs a triangular decomposition of a band matrix,

using partial pivoting. DETERMBND calculates the determinant of a band matrix. SOLBND solves a system of linear equations, the matrix being

decomposed by DECBND. DECSOLBND solves a system of linear equations by Gaussian

elimination with partial pivoting if the coefficient matrix is in band form and is stored rowwise in a one- dimensional array.

DECTRI performs a triangular decomposition of a tridiagonal matrix. DECTRIPIV performs a triangular decomposition of a tridiagonal

Copyright 1995 by CRC Press, Inc

Page 784: Numerical Library in C for Scientists and Engineers A

matrix, using partial pivoting. SOLTRI solves a tridiagonal system of linear equations, the triangular

decomposition being given. DECSOLTRI solves a tridiagonal system of linear equations and

performs the triangular decomposition without pivoting. SOLTRIPIV solves a tridiagonal system of linear equations, the

triangular decomposition being given. DECSOLTRIPIV solves a tridiagonal system of linear equations and

performs the triangular decomposition with partial pivoting.

CHLDECBND performs the Cholesky decomposition of a positive definite symmetric band matrix.

CHLDETERMBND calculates the determinant of a positive definite symmetric band matrix.

CHLSOLBND solves a positive definite symmetric linear system, the triangular~de~om~osition being given.

CHLDECSOLBND solves a positive definite symmetric linear system and performs the triangular decomposition by Cholesky's method.

DECSYMTRI performs the triangular decomposition of a symmetric tridiagonal matrix.

SOLSYMTRI solves a symmetric tridiagonal system of linear equations, the triangular decomposition being given.

DECSOLSYMTRI solves a symmetric tridiagonal system of linear equations and performs the tridiagonal decomposition.

CONJGRAD solves a positive definite symmetric system of linear equations by the method of conjugate gradients.

EQILBR equilibrates a matrix by means of a diagonal similarity transformation.

BAKLBR

EQILBRCOM BAKLBRCOM

TFMPREVEC

TFMSYMTRI 1

performs the back transformation corresponding to EQILBR. equilibrates a complex matrix. transforms the eigenvectors of a complex equilibrated (by EQILBRCOM) matrix into the eigenvectors of the original matrix. transforms a real symmetric matrix into a similar tridiagonal one by means of Householder's transformation. performs the back transformation corresponding to TFMSYMTRI2. in combination with TFMSYMTRI2 calculates the transforming matrix. transforms a real symmetric matrix into a similar

Copyright 1995 by CRC Press, Inc

Page 785: Numerical Library in C for Scientists and Engineers A

BAKSYMTRIl

TFMREAHES

BAKREAHES 1

BAKREAHES2

HSHHRMTRI

tridiagonal one by means of Householder's transformation. performs the back transformation corresponding to TFMSYMTRI 1. transforms a matrix into a similar upper Hessenberg matrix by means of Wilkinson's transformation. performs the back transformation (on a vector) corresponding to TFMREAHES. performs the back transformation (on columns) corresponding to TFMREAHES. transforms a Hermitian matrix into a similar real symmetric tridiagonal matrix.

HSHHRMTRIVAL delivers the main diagonal elements and the squares of the codiagonal elements of a Hermitian tridiagonal

BAKHRMTRI

HSHCOMHES

BAKCOMHES

HSHREABID

PSTTFMMAT

PRETFMMAT

VALSYMTRI

VECSYMTRI

matrix which is unitary similar with a given Hermitian matrix.

performs the back transformation corresponding to HSHHRMTRI. transforms a complex matrix by means of Householder's transformation followed by a complex diagonal transformation into a similar unitary upper Hessenberg matrix with a real nonnegative subdiagonal. performs the back transformation corresponding to HSHCOMHES. transforms a matrix to bidiagonal form, by premultiplying and postmultiplying with orthogonal matrices. calculates the postmultiplying matrix from the data generated by HSHREABID. calculates the premultiplying matrix from the data generated by HSHREABID. calculates all, or some consecutive, eigenvalues of a symmetric tridiagonal matrix by means of linear interpolation using a Sturm sequence. calculates eigenvectors of a symmetric tridiagonal matrix by means of inverse iteration.

QRIVALSYMTRI calculates the eigenvalues of a symmetric tridiagonal matrix by means of QR iteration.

QRISYMTRI calculates the eigenvalues and eigenvectors of a symmetric tridiagonal matrix by means of QR iteration.

EIGVALSYM2 calculates all (or some) eigenvalues of a symmetric matrix using linear interpolation of a function derived from a Sturm sequence.

EIGSYM2 calculates eigenvalues and eigenvectors by means of

Copyright 1995 by CRC Press, Inc

Page 786: Numerical Library in C for Scientists and Engineers A

inverse iteration. EIGVALSYMl calculates all (or some) eigenvalues of a symmetric matrix

using linear interpolation of a function derived from a Sturm sequence.

EIGSYMI calculates eigenvalues and eigenvectors by means of inverse iteration.

QRIVALSYM2 calculates the eigenvalues of a symmetric matrix by means of QR iteration.

QRISYM calculates all eigenvalues and eigenvectors of a symmetric matrix by means of QR iteration.

QRIVALSYMl

MERGESORT

VECPERM

ROWPERM

ORTHOG

SYMEIGIMP

REAVALQRI

REAVECHES

calculates the eigenvalues of a symmetric matrix by means of QR iteration. delivers a permutation of indices corresponding to sorting the elements of a given vector into non-decreasing order. permutes the elements of a given vector according to a given permutation of indices. permutes the elements of a given row according to a given permutation of indices. orthogonalizes some adjacent matrix columns according to the modified Gram-Schmidt method.

improves an approximation of a real symmetric eigensystem and calculates error bounds for the eigenvalues.

calculates the eigenvalues of a real upper Hessenberg matrix, provided that all eigenvalues are real, by means of single QR iteration. calculates an eigenvector corresponding to a given real eigenvalue of a real upper Hessenberg matrix by means of inverse iteration.

REAQRI calculates all eigenvalues and eigenvectors of a real upper Hessenberg matrix, provided that all eigenvalues are real, by means of single QR iteration.

COMVALQRI calculates the real and complex eigenvalues of a real upper Hessenberg matrix by means of double QR iteration.

COMVECHES calculates the eigenvector corresponding to a given complex eigenvalue of a real upper Hessenberg matrix by means of inverse iteration.

REAEIGVAL calculates the eigenvalues of a matrix, provided that all eigenvalues are real.

REAEIG1 calculates the eigenvalues and eigenvectors of a matrix, provided that they are all real.

REAEIG3 calculates the eigenvalues and eigenvectors of a matrix,

Copyright 1995 by CRC Press, Inc

Page 787: Numerical Library in C for Scientists and Engineers A

provided that they are all real. COMEIGVAL calculates the eigenvalues of a matrix. COMEIGl calculates the eigenvalues and eigenvectors of a matrix. EIGVALHRM calculates the eigenvalues of a complex Hermitian matrix. EIGHRM calculates the eigenvalues and eigenvectors of a complex

Hermitian matrix. QRIVALHRM calculates the eigenvalues of a complex Hermitian matrix. QRIHRM calculates the eigenvalues and eigenvectors of a complex

Herrnitian matrix. VALQRICOM calculates the eigenvalues of a complex upper Hessenberg

matrix with a real subdiagonal. QRICOM calculates the eigenvalues and eigenvectors of a complex

upper Hessenberg matrix. EIGVALCOM calculates the eigenvalues of a complex matrix. EIGCOM calculates the eigenvalues and eigenvectors of a complex

matrix. QZIVAL computes generalized eigenvalues by means of QZ iteration. QzI computes generalized eigenvalues and eigenvectors by means

of QZ iteration. HSHDECMUL is an auxiliary procedure for the computation of

generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure generalized eigenvalues. is an auxiliary procedure

for the

for the

for the

for the

for the

for the

for the

for the

computation

computation

computation

computation

computation

computation

computation

computation generalized eigenvalues.

QRISNGVALBID calculates the singular values of a bidiagonal matrix. QRISNGVALDECBID calculates the singular values decomposition of a

matrix of which the bidiagonal and the pre- and postmultiplying matrices are given.

QRISNGVAL calculates the singular values of a given matrix.

Copyright 1995 by CRC Press, Inc

Page 788: Numerical Library in C for Scientists and Engineers A

QRISNGVALDEC calculates the singular values decomposition U D V ~ , with U and V orthogonal and D positive diagonal.

ZERPOL calculates all roots of a polynomial with real coefficients by Laguerre's method.

BOUNDS calculates the error in approximated zeros of a polynomial with real coefficients.

ALLZERORTPOL calculates all zeros of an orthogonal polynomial. LUPZERORTPOL calculates a number of adjacent upper or lower zeros

of an orthogonal polynomial. SELZERORTPOL calculates a number of adjacent zeros of an orthogonal

polynomial. ALLJACZER calculates the zeros of a Jacobian polynomial. ALLLAGZER calculates the zeros of a Laguerre polynomial. COMKWD calculates the roots of a quadratic equation with complex

coefficients. EULER performs the summation of an alternating infinite series. SUMPOSSERIES performs the summation of an infinite series with

positive monotonically decreasing terms using the van Wijngaarden transformation.

QADRAT computes the definite integral of a function of one variable over a finite interval.

INTEGRAL calculates the definite integral of a function of one variable over a finite or infinite interval or over a number of consecutive intervals.

TRICUB computes the definite integral of a function of two variables over a triangular domain.

RECCOF calculates recurrence coefficients of an orthogonal polynomial, a weight function being given.

GSSWTS calculates the Gaussian weights of a weight function, the recurrence coefficients being given.

GSSWTSSYM calculates the Gaussian weights of a weight function, the recurrence coefficients being given.

GSSJACWGHTS computes the abscissae and weights for Gauss-Jacobi quadrature.

GSSLAGWGHTS computes the abscissae and weights for Gauss- Lagrange quadrature.

JACOBNNF calculates the Jacobian matrix of an n-dimensional function of n variables using forward differences.

JACOBNMF calculates the Jacobian matrix of an n-dimensional function of m variables using forward differences.

JACOBNBNDF calculates the Jacobian matrix of an n-dimensional function of n variables, if the Jacobian is known to be a

Copyright 1995 by CRC Press, Inc

Page 789: Numerical Library in C for Scientists and Engineers A

band matrix. ZEROIN finds (in a given interval) a zero of a function of one variable. ZEROINRAT finds (in a given interval) a zero of a function of one

variable. ZEROINDER finds (in a given interval) a zero of a function of one

variable using values of the function and of its derivative.

QUANEWBND solves a system of non-linear equations of which the Jacobian (being a band matrix) is given.

QUANEWBNDl solves a system of non-linear equations of which the Jacobian is a band matrix.

MININ minimizes a function of one variable in a given interval. MININDER minimizes a function of one variable in a given interval,

using values of the function and of its derivative. LINEMIN minimizes a function of several variables in a given

direction. RNKlUPD adds a rank-1 matrix to a symmetric matrix. DAVUPD adds a rank-2 matrix to a symmetric matrix. FLEUPD adds a rank-2 matrix to a symmetric matrix. PRAXIS minimizes a function of several variables. RNKIMIN minimizes a function of several variables. FLEMIN minimizes a function of several variables. MARQUARDT calculates the least squares solution of an overdetermined

system of non-linear equations with Marquardt's method. GSSNEWTON calculates the least squares solution of an overdetermined

system of non-linear equations with the Gauss-Newton method.

RKl solves a single first order differential equation by means of a fifth order Runge-Kutta method.

RICE solves a system of first order differential equations (initial value problem) by means of a fifth order Runge-Kutta method.

RK4A solves a single first order differential equation by means of a fifth order Runge-Kutta method; the integration is terminated as soon as a condition on X and Y, which is supplied by the user, is satisfied.

RK4NA solves a system of first order differential equations (initial value problem) by means of a fifth order Runge-Kutta method; the integration is terminated as soon as a condition on X[O], X[1], ..., X[n], supplied by the user, is satisfied.

RKSNA solves a system of first order differential equations (initial value problem) by means of a fifth order Runge-Kutta

Copyright 1995 by CRC Press, Inc

Page 790: Numerical Library in C for Scientists and Engineers A

method; the arc length is introduced as an integration variable; the integration is terminated as soon as a condition on X[O], X[l], ..., X[n], supplied by the user, is satisfied.

MULTISTEP solves a system of first order differential equations (initial

DIFFSYS

ARK

EFRK

EFSIRK

EFERK

value problem) by means of a variable order multistep method Adams-Moulton, Adams-Bashforth or Gear's method; the order of accuracy is automatic, up to fifth order; this method is suitable for stiff systems.

solves a system of first order differential equations (initial value problem) by extrapolation, applied to low order results, a high order of accuracy is obtained; this method is suitable for smooth problems when high accuracy is required. solves a system of first order differential equations (initial value problem) by means of a stabilized Runge-Kutta method with limited storage requirements. solves a system of first order differential equations (initial value problem) by means of a first, second or third order, exponentially fitted Runge-Kutta method; automatic step size control is not provided; this method can be used to solve stiff systems with known eigenvalue spectrum. solves an autonomous system of first order differential equations (initial value problem) by means of a third order, exponentially fitted, semi-implicit Runge-Kutta method; this method can be used to solve stiff systems. solves an autonomous system of first order differential equations (initial value problem) by means of an exponentially fitted, third order Runge-Kutta method; this method can be used to solve stiff systems with known eigenvalue spectrum.

LINIGERlVS solves an autonomous system of first order differential equations (initial value problem) by means of an implicit, exponentially fitted first order one-step method; this method can be used to solve stiff systems.

LINIGER2 solves an autonomous system of first order differential equations (initial value problem) by means of an implicit, exponentially fitted first order one-step method; automatic step size control is not provided; this method can be used to solve stiff systems.

GMS solves an autonomous system of first order differential equations (initial value problem) by means of a third order multistep method; this method can be used to solve stiff systems.

IMPEX solves an autonomous system of first order differential

Copyright 1995 by CRC Press, Inc

Page 791: Numerical Library in C for Scientists and Engineers A

EFT

equations (initial value problem) by means of the implicit midpoint rule with smoothing and extrapolation; this method is suitable for the integration of stiff differential equations.

MODIFIEDTAYLOR solves a system of first order differential equations (initial value problem) by means of a first, second or third order one-step Taylor method; this method can be used to solve large and sparse systems, provided higher order derivatives can easily be obtained.

solves a system of first order differential equations (initial value problem) by means of a variable order Taylor method; this method can be used to solve stiff systems, with known eigenvalue spectrum, provided higher order derivatives can easily be obtained. solves a single second order differential equation (initial value problem) by means of a fifth order Runge-Kutta method.

solves a system of second order differential equations (initial value problem) by means of a fifth order Runge- Kutta method.

solves a single second order differential equation (initial value problem) by means of a fifth order Runge-Kutta method; this method can only be used if the right hand side of the differential equation does not depend on y'.

FEMLAGSYM

FEMLAG

solves a system of second order differential equations (initial value problem) by means of a fifth order Runge- Kutta method; this method can only be used if the right hand side of the differential equation does not depend on Y'. solves a system of first order differential equations (initial boundary-value problem) by means of a stabilized Runge- Kutta method, in particular suitable for systems arising from two-dimensional time-dependent partial differential equations. solves a linear two-point boundary-value problem for a second order self-adjoint differential equation by a Ritz- Galerkin method. solves a linear two-point boundary-value problem for a second order self-adjoint differential equation by a Ritz- Galerkin method; the coefficient of y' is supposed to be unity.

FEMLAGSPHER solves a linear two-point boundary-value problem for a second order self-adjoint differential equation with

Copyright 1995 by CRC Press, Inc

Page 792: Numerical Library in C for Scientists and Engineers A

spherical coordinates by a Ritz-Galerkin method. FEMLAGSKEW solves a linear two-point boundary-value problem for a

second order differential equation by a Ritz-Galerkin method.

FEMHERMSYM solves a linear two-point boundary-value problem for a fourth order self-adjoint differential equation with Dirichlet boundary conditions by a Ritz-Galerkin method.

NONLINFEMLAGSKEW solves a nonlinear two-point boundary-value problem for a second order differential equation with spherical coordinates by a Ritz-Galerkin method and Newton iteration.

RICHARDSON solves a system of linear equations with positive real eigenvalues (elliptic boundary value problem) by means of a non-stationary second order iterative method.

ELIMINATION solves a system of linear equations with positive real eigenvalues (elliptic boundary value problem) by means of a non-stationary second order iterative method, which is an acceleration of Richardson's method.

PEIDE estimates unknown parameters in a system of first order differential equations; the unknown variables may appear non- linearly both in the differential equations and its initial values; a set of observed values of some components of the solution of the differential equations must be given.

ARCSINH computes the inverse hyperbolic sine for a real argument. ARCCOSH computes the inverse hyperbolic cosine for a real

argument. ARCTANH computes the inverse hyperbolic tangent for a real

argument. LOGONEPLUSX evaluates the logarithmic function ln(l+x). EI calculates the exponential integral. EIALPHA calculates a sequence of integrals of the form (e-"ft" dt),

from t=l to t=infinity. ENX calculates a sequence of exponential integrals E(n,x) = the

integral from 1 to infinity of e-*/tn dt. NONEXPENX calculates a sequence of integrals ex * E(n,x), see ENX. SINCOSINT calculates the sine integral SI(x) and the cosine integral

CI(x). SINCOSFG is an auxiliary procedure for the sine and cosine integrals. RECIPGAMMA calculates the reciprocal of the gamma function for

arguments in the range [ O S , 1.51; moreover odd and even parts are delivered.

Copyright 1995 by CRC Press, Inc

Page 793: Numerical Library in C for Scientists and Engineers A

GAMMA calculates the gamma function. LOGGAMMA calculates the natural logarithm of the gamma function for

positive arguments. INCOMGAM calculates the incomplete gamma functions. INCBETA calculates the incomplete beta function I(x,p,q) for 01x11,

p>O, q>o. IBPPLUSN calculates the incomplete beta function ratios I(x,p+n,q)

for n=0, 1 ,. . .,nmax, 05x11, p>O, q>O. IBQPLUSN calculates the incomplete beta function ratios I(x,p,q+n)

for n=0, 1, ..., nmax, 01x11, p>O, q>O. IXQFIX is an auxiliary procedure for the computation of incomplete

bessel functions. IXPFIX is an auxiliary procedure for the computation of incomplete

bessel functions. FORWARD is an auxiliary procedure for the computation of

incomplete bessel functions. BACKWARD is an auxiliary procedure for the computation of

incomplete bessel functions. ERRORFUNNCTION computes the error function (erf) and

complementary error function (erfc) for a real argument.

NONEXPERFC computes erfc(x) * exp(x2); see ERRORFUNCTION. INVERSEERRORFUNCTION calculates the inverse error function y =

inverf(x). FRESNEL calculates the fresnel integrals C(x) and S(x). FG is an auxiliary procedure for the computation of fresnel

integrals. BESSJO calculates the ordinary bessel function of the first kind of

order zero. BESSJl calculates the ordinary bessel function of the first kind of

order one. BESSJ calculates the ordinary bessel functions of the first kind of

order 1, 1=0 ,..., n. BESSYOl calculates the ordinary bessel functions of the second kind

of orders zero and one with argument x, x>O. BESSY calculates the ordinary bessel functions of the second kind of

order 1, 1=0 ,..., n, with argument x, x>O. BESSPQO is an auxiliary procedure for the computation of the

ordinary bessel functions of order zero for large values of their argument.

BESSPQl is an auxiliary procedure for the computation of the ordinary bessel functions of order one for large values of

Copyright 1995 by CRC Press, Inc

Page 794: Numerical Library in C for Scientists and Engineers A

their argument. BESSIO calculates the modified bessel function of the first kind of

order zero. BESSI 1 calculates the modified bessel function of the first kind of

order one. BESSI calculates the modified bessel functions of the first kind of

order 1, 1=0 ,..., n. BESSKOl calculates the modified bessel functions of the third kind

of orders zero and one with argument x, x>O. BESSK calculates the modified bessel functions of the third kind of

order 1, 1=0 ,..., n, with argument x, x>O. NONEXPBESSIO calculates the modified bessel function of the first kind

of order zero; the result is multiplied by e-'"1. NONEXPBESSIl calculates the modified bessel function of the first kind

of order one; the result is multiplied by e-1'1. NONEXPBESSI calculates the modified bessel functions of the first kind of

order 1, 1=0, ..., n; the result is multiplied by e-IXI. NONEXPBESSKOl calculates the modified bessel functions of the third

kind of orders zero and one with argument x, x>O; the result is multiplied by ex.

NONEXPBESSK calculates the modified bessel functions of the third kind of order 1, 1=0, ..., n, with argument x, x>O; the result is multiplied by ex.

BESSJAPLUSN calculates the bessel functions of the first kind of order a+k, O&%, O<a<l.

BESSYAOl calculates the bessel functions of the second kind (also called Neumann's functions) of order a and a+l, a20, and argument x>O.

BESSYAPLUSN calculates the bessel functions of the second kind of order a+n, n=O ,..., nmax, &0, and argument x>O.

BESSPQAOl is an auxiliary procedure for the computation of the bessel functions for large values of their argument.

BESSZEROS calculates zeros of a bessel function (of first or second kind) and of its derivative.

START is an auxiliary procedure in bessel function procedures. BESSIAPLUSN calculates the modified bessel functions of the first kind of

order a+n, n=O ,..., nmax, a>O, and argument x20. BESSKAOl calculates the modified bessel functions of the third kind

of orders a and a+l, a20, and argument x>O. BESSKAPLUSN calculates the modified bessel functions of the third

kind of order a+n, n=0, ..., nmax, a>O, and argument x>o.

Copyright 1995 by CRC Press, Inc

Page 795: Numerical Library in C for Scientists and Engineers A

NONEXPBESSIAPLUSN calculates the modified bessel functions of the first kind of order a+n, n=O ,..., nmax, &O and argument x20, multiplied by e-".

NONEXPBESSKAOl calculates the modified bessel functions of the third kind of order a and a+l, &0 and argument x, x>O, multiplied by the factor ex.

NONEXPBESSKAPLUSN calculates the modified bessel functions of the third kind of order a+n, n=0, ..., nmax, &O and argument x>O, multiplied by ex.

SPHERBESSJ calculates the spherical bessel functions of the first kind. SPHERBESSY calculates the spherical bessel functions of the third kind. SPHERBESSI calculates the modified spherical bessel functions of the

first kind. SPHERBESSK calculates the modified spherical bessel functions of the

third kind. NONEXPSPHERBESSI calculates the modified spherical bessel

functions of the first kind multiplied by e-". NONEXPSPHERBESSK calculates the modified spherical bessel

functions of the third kind multiplied by ex. AIRY evaluates the Airy functions AI(z) and BI(z) and their

derivatives. AIRYZEROS computes the zeros and associated values of the Airy

functions AI(z) and BI(z) and their derivatives. NEWTON calculates the coefficients of the Newton polynomial

through given interpolation points and corresponding function values.

IN1 selects a subset of integers out of a given set of integers; it is an auxiliary procedure for MINMAXPOL.

SNDREMEZ exchanges at most n+l numbers with numbers out of a reference set; it is an auxiliary procedure for MINMAXPOL.

MINMAXPOL calculates the coefficients of the polynomial that approximates a function, given for discrete arguments, such that the infinity norm of the error vector is minimized.

Copyright 1995 by CRC Press, Inc

Page 796: Numerical Library in C for Scientists and Engineers A

Appendix D: Memory Management Utilities

Dynamic storage allocation is effected in C by the use of manipulation procedures. For example, placed at the beginning of a procedure, the code

integer *p; p=allocate-integer-vector(1,u);

reserves storage for an integer vector p of range [I,u]; at the end of the procedure the code

free-integer-vector(p,l);

frees the storage for alternative use. Similarly, the code

float **q; q=allocate~real~matrix(lr,ur,lc,uc);

reserves storage for a real matrix q of range [Ir:ur,lc:uc] (this is done by allocating pointers to an array of pointers in C). The code

free-real-matrix(q, lr,ur, lc) ;

frees storage. (In this usage, array elements are referred to in the form q[i]b].)

The following utilities are used in the library.

void system-error(char error-message[]) {

void exit (int) ;

print£ ("%sf', error-message) ; exit (1) ;

}

int *allocate-integer-vector(int 1, int u) ( I

/ * Allocates an integer vector of range [l..ul. * /

void system-error(char * ) ; int *p;

p= (int * ) malloc ( (unsigned) (u-l+l) *sizeof (int) ) ; if ( !p) system-error ("Failure in allocate-integer-vector ( ) . " ) ; return p-1;

1

float *allocate-real-vector(int 1, int u) I 1

/ * Allocates a real vector of range [l..u]. */

void system-error (char *) ; float *p;

p= (float * ) malloc ( (unsigned) (u-l+l) *sizeof (float) ) ; if ( !p) system-error ("Failure in allocate-realgector 0 . " 1 ;

Copyright 1995 by CRC Press, Inc

Page 797: Numerical Library in C for Scientists and Engineers A

return p-1; 1

int **allocate-integer-matrix(int lr, int ur, int lc, int uc) I

/ * Allocates an integer matrix of range [lr..url [lc..ucl . * /

void system-error(char * ) ; int i, **p;

p= (int **)malloc ( (unsigned) (ur-lr+l) *sizeof (int*) ) ; if ( !p) system-error ("Failure in allocate-integer-matrix0 . I f ) ; p - = lr;

for (i=lr; ic=ur; i++) ( p [il= (int *)malloc ( (unsigned) (uc-lc+l) *sizeof (int) ) ; if ( !p [il ) system-error ("Failure in allocate-integer-matrix0 . " ) ; p[il -= lc;

1 return p;

1

float **allocate-real-matrix(int lr, int ur, int lc, int uc) {

/* Allocates a real matrix of range [lr..url [lc..ucl. */

void system-error(char * ) ; int i; float **p;

p= (float **)malloc ( (unsigned) (ur-lr+l) *sizeof (float*) ) ; if ( !p) system-error (''Failure in allocate-real-matrix 0 . " ) ; p - = lr;

for (i=lr; i<=ur; i++) { p [il =(float *)malloc ( (unsigned) (uc-lc+l) *sizeof (float) ) ; if ( !p [i] ) system-error ("Failure in allocate-real-matrix 0 . " ) ; p[il - = lc;

I return p;

void free-integer-vector(int *v, int 1) {

/ * Frees an integer vector of range [l..ul. */

void free-real-vector(f1oat I

/ * Frees a real vector

free ( (char*) (v+l) ) ; 1

*v, int 1)

of range [l..ul. * /

void free-integer-matrix(int **m, int lr, int ur, int lc) l

/ * Frees an integer matrix of range [lr. .url [lc. .uc] . * /

int i;

for (i=ur; i>=lr; i--) free ( (char*) (m[il +lc) ; free ( (char*) (m+lr) ) ;

Copyright 1995 by CRC Press, Inc

Page 798: Numerical Library in C for Scientists and Engineers A

void free-real-rnatrix(f1oat **m, int lr, int ur, int lc) I

/ * Frees a real matrix of range [lr. .url [lc. .uc] . * /

int i;

for (i=ur; i>=lr; i--) free((char*) (m[il+lc)); free ( (char*) (m+lr) ) ;

1

Copyright 1995 by CRC Press, Inc