bisection_method = function(a, b, root_fn, xtol=1.e-6, ftol=1e-3){ # Algo 3.1: EPage 91 # fa = root_fn(a) fb = root_fn(b) stopifnot( fa*fb<0 ) n=0 done = FALSE while( !done ){ w = b-a # how wide is our interval m = 0.5 * ( a + b ) fm = root_fn(m) if( fa*fm <= 0 ){ b = m }else{ a = m } if( w 0 ){ F = F/2 } }else{ anp1 = wnp1 bnp1 = bn F = fwnp1 if( fwn*fwnp1 > 0 ){ G = G/2 } } an = anp1 bn = bnp1 wn = wnp1 fwn = fwnp1 if( abs(bn-an)1.e-9 ) # add an assert to flag if f'(x_n)=0 xnp1 = xn - fn / fn_prime # Check for convergence: # if( abs(xn-xnp1)=ntol ){ done = TRUE } # Update root estimate: # xn = xnp1 fn = root_fn(xn) n = n+1 } return( c(xn, fn, n) ) } fixed_point_iteration = function(xn, root_fn, iter_fn, xtol=1.e-6, ftol=1.e-3, ntol=1000){ # Algo 3.6 (fixed point iteration): EPage 109 # fn = root_fn(xn) xsize = abs(xn) fsize = abs(fn) n=0 done = FALSE while( !done ){ xnp1 = iter_fn(xn) fnp1 = root_fn(xnp1) # Check for convergence: # if( abs(xn-xnp1)=ntol ){ done = TRUE } # Update root estimate: # xn = xnp1 fn = fnp1 n = n+1 } return( c(xn, fn, n) ) } aitkens_delta2 = function(xn){ # Algo 3.7: EPage 112 & 114 (we compute r_n and x_hat_n from x_n) # # xn[1] = x_0 the initial iterate value # xn[N+1] = x_N the last iterate # N = length(xn)-1 dxn = c( NaN, diff(xn) ) # = x_n - x_{n-1} dxnp1 = c( diff(xn), NaN ) # holds = x_{n+1} - x_n rn = dxn / dxnp1 # = Second Equation 3.27 on EPage 112 xnp1 = c( xn[2:(N+1)], NaN ) xhatn = xnp1 + (xnp1 - xn)/(rn-1) # = First Equation 3.72 on EPage 112 return( list(rn=rn, xhatn=xhatn) ) } steffensen_iteration = function(y0, iter_fn, xtol=1.e-6, ntol=1000){ # Algo 3.8: EPage 114 # x0 = y0 xsize = abs(x0) n=0 done = FALSE while( !done ){ x1 = iter_fn(x0) x2 = iter_fn(x1) # Check for convergence and update our root estimate # d = x2 - x1 if( d==0 ){ done = TRUE x0 = x1 }else{ r = (x1 - x0)/d y1 = x2 + d/(r-1) if( abs(y1-y0)=ntol ){ done = TRUE } x0 = y1 } n = n+1 } return( c(x0, n) ) } number_of_sign_changes = function(an){ # Computes the number of sign changes in the polynomial with coefficients an (ignoring zeros). # # The coefficients of the polynomial are stored as the elements of the vector an such that # # p(x) = a[1] + a[2] x + a[3] x^2 + ... + a[n] x^{n-1} + a[n+1] x^n # an_no_zeros = an[an!=0] n = length(an_no_zeros) - 1 n_sign_changes = 0 current_sign = sign(an_no_zeros[n+1]) for( ni in seq(n, 1, -1) ){ if( current_sign * an_no_zeros[ni] < 0 ){ n_sign_changes = n_sign_changes+1 current_sign = sign(an_no_zeros[ni]) } } return(n_sign_changes) } polynomial_root_bounds = function(an){ # # Returns some information on root bounds from the discussions on EPage 126 - 128 # # The coefficients of the polynomial are stored as the elements of the vector an such that # # p(x) = a[1] + a[2] x + a[3] x^2 + ... + a[n] x^{n-1} + a[n+1] x^n # n = length(an) - 1 # the degree of the polynomial # Descarts' rule of signs: # nu_p = number_of_sign_changes(an) # maximal number of positive roots nu_n = number_of_sign_changes(an * rep(-1, n+1)^seq(0, n)) # maximal number of negative roots print(sprintf('Descarts rule of sign: degree= %d, max positive roots: %d, max negative roots: %d', n, nu_p, nu_n)) # rho_1 = n * abs(an[1]) / abs(an[2]) rho_n = ( abs(an[1]) / abs(an[n+1]) )^(1./n) print(sprintf('At least one zero of this polynomial satisfies: |x| <= %.4f', min(c(rho_1, rho_n)))) # All zeros of the original polynomial i.e inside r <= le <= R. # One would need to plot P(x) and Q(x) to find estimates for the numbers R and r: # P_polynomial = abs(an) P_polynomial[1:n] = -P_polynomial[1:n] # P(x) has one real positive zero R Q_polynomial = abs(an) Q_polynomial[1] = -Q_polynomial[1] # Q(x) has one real positive zero r # r = 1 + max( abs( an[1:n] / an[n+1] ) ) print(sprintf('Every zero of this polynomial satisfies: |x| <= %.4f', r)) return( list(P=P_polynomial, Q=Q_polynomial) ) } evaluate_polynomial = function(z, an){ # Reduces a polynomial as in Equations 3.47 on EPage 128 # # The coefficients of the polynomial are stored as the elements of the vector an such that # # p(x) = a[1] + a[2] x + a[3] x^2 + ... + a[n] x^{n-1} + a[n+1] x^n # n = length(an) an_prime = rep(NA, n) for( ni in seq(n, 1, -1) ){ if( ni==n ){ an_prime[ni] = an[ni] }else{ an_prime[ni] = an[ni] + z * an_prime[ni+1] } } return(an_prime) } vector_evaluate_polynomial = function(z, an){ # # Evaluates a polynomial over a vector of inputs. # res = rep(NA, length(z)) for( zi in 1:length(z) ){ ep = evaluate_polynomial(z[zi], an) res[zi] = ep[1] } return(res) } polynomial_newton = function(xm, an, xtol=1.e-6, mtol=100){ # Algo 3.9 on EPage 129 # # The coefficients of the polynomial are stored as the elements of the vector an such that # # p(x) = a[1] + a[2] x + a[3] x^2 + ... + a[n] x^{n-1} + a[n+1] x^n # n = length(an) - 1 # the degree of the polynomial an_prime = evaluate_polynomial(xm, an) # compute a_n' an_prime_prime = rep(NA, n) m = 0 while( m < mtol ){ z = xm an_prime_prime[n+1] = an_prime[n+1] an_prime[n+1] = an[n+1] for( k in seq(n, 2, -1) ){ an_prime[k] = an[k] + z * an_prime[k+1] an_prime_prime[k] = an_prime[k] + z * an_prime_prime[k+1] } an_prime[1] = an[1] + z * an_prime[2] delta_x = an_prime[1] / an_prime_prime[2] if( abs(delta_x)abs(denom_plus) ){ denom = denom_minus }else{ denom = denom_plus } hp1 = -2 * fx / denom if( verbose ){ print(sprintf('ki= %5d; m= %5d, x= %12.6g %12.6g; f_x_xm1_xm2= %12.6g %12.6g; ci= %12.6g %12.6g; rad= %12.6g %12.6g; denom= %12.6g %12.6g; abs(hp1)= %12.6g; xtol*abs(x)= %12.6g; abs(fx)= %12.6g; ftol= %12.6g', ki, m, Re(x), Im(x), Re(f_x_xm1_xm2), Im(f_x_xm1_xm2), Re(ci), Im(ci), Re(rad), Im(rad), Re(denom), Im(denom), abs(hp1), xtol*abs(x), abs(fx), ftol)) } x_tol_met = abs(hp1)