X-Git-Url: http://gitweb.michael.orlitzky.com/?p=octave.git;a=blobdiff_plain;f=forward_euler.m;h=6984cfc8dc9c14963bc1f8f1eb83b67f36869419;hp=c6ef21722dbbd3fa1c405f2a594ad793d0c48f79;hb=99b1398f7acd8c15e42160c047dcaff816643020;hpb=07247e6b4d7d4656c9db15583871cc6ae2651b2a diff --git a/forward_euler.m b/forward_euler.m index c6ef217..6984cfc 100644 --- a/forward_euler.m +++ b/forward_euler.m @@ -1,45 +1,78 @@ -function df = forward_euler(integer_order, h, f, x) - ## - ## Use the forward Euler method to compute the derivative of `f` at - ## a point `x`. - ## - ## INPUTS: - ## - ## * ``integer_order`` - The order of the derivative. - ## - ## * ``h`` - The step size. - ## - ## * ``f`` - The function whose derivative we're computing. - ## - ## * ``x`` - The point at which to compute the derivative. - ## +function coefficients = forward_euler(integer_order, xs, x) + % + % Return the coefficients of u(x0), u(x1), ..., u(xn) as a vector. + % Take for example a first order approximation, with, + % + % xs = [x0,x1,x2,x3,x4] + % + % f'(x1) ~= [f(x2)-f(x1)]/(x2-x1) + % + % This would return [0, -1/(x2-x1), 2/(x2-x1), 0, 0]. This aids the + % solution of linear systems. + % + % + % INPUTS: + % + % * ``integer_order`` - The order of the derivative which we're + % approximating. + % + % * ``xs`` - The vector of x-coordinates. + % + % * ``x`` - The point `x` at which you'd like to evaluate the + % derivative of the specified `integer_order`. This should be an + % element of `xs`. + % + % + % OUTPUTS: + % + % * ``coefficients`` - The vector of coefficients, in order, of + % f(x0), f(x1), ..., f(xn). + % + + if (integer_order < 0) + % You have made a grave mistake. + coefficients = NA; + return; + end if (integer_order == 0) - df = x; + coefficients = x; return; end - - ## We need a few points around `x` to compute the derivative at `x`. - ## The number of points depends on the order. + + if (length(xs) < 2) + % You can't approximate a derivative of order greater than zero + % with zero or one points! + coefficients = NA + return; + end + if (even(integer_order)) offset_b = integer_order / 2; offset_f = offset_b; else - ## When the order is odd, we need one more "forward" point than we - ## do "backward" points. + % When the order is odd, we need one more "forward" point than we + % do "backward" points. offset_b = (integer_order - 1) / 2; offset_f = offset_b + 1; end - backward_xs = [x-(offset_b*h) : h : x]; + % Zero out the coefficients for terms that won't appear. We compute + % where `x` is, and we just computed how far back/forward we need to + % look from `x`, so we just need to make the rest zeros. + x_idx = find(xs == x); + first_nonzero_idx = x_idx - offset_b; + last_nonzero_idx = x_idx + offset_f; + leading_zero_count = first_nonzero_idx - 1; + leading_zeros = zeros(1, leading_zero_count); + trailing_zero_count = length(xs) - last_nonzero_idx; + trailing_zeros = zeros(1, trailing_zero_count); - ## We'll always have at least one forward point, so start this vector - ## from (x + h) and include `x` itself in the backward points. - forward_xs = [x+h : h : x+(offset_f*h)]; + targets = xs(first_nonzero_idx : last_nonzero_idx); - xs = horzcat(backward_xs, forward_xs); + % The multiplier comes from the Taylor expansion. + multiplier = factorial(integer_order); + cs = divided_difference_coefficients(targets) * multiplier; - ## Now that we have all of the points that we need in xs, we can use - ## the divided_difference function to compute the derivative. - df = divided_difference(f, xs); + coefficients = horzcat(leading_zeros, cs, trailing_zeros); end