Code for Iterative Solver


In our previous lecture we introduced the general concept of an iterative solver, and then demonstrated code using this technique for computing a square root. We would like to demonstrate how the same approach can be used for the gambler problem. But rather than develop the entire code base from scratch, we would like to use a more general design framework. As our first version, we suggest the following iterativeSolver function.

function soln = simpleIeterative(initial, updateFunc, params)
    error = 1e-10;
    soln = initial;
    solved = false;
    while ~solved
        prev = soln;
        soln = updateFunc(prev, params);
        solved = all(abs(soln-prev) <= error);
    end
Here, we assume that initial is an array that represents the initial guess, that updateFunc is a function handle representing the function that is able to use one guess to create the subsequent guess, and that params is used to hold information that may need to be passed to updateFunc.

function handles

In MATLAB, sometimes one function needs to be given access to another function as a runtime parameter. This is done by passing a "handle" to one function as a parameter to another. Syntactically, the @ character is used to create a function handle. For example, the expression @sum is a handle to the built-in function sum.

square root example

As a simple example, here is an m-file that uses our iterative solver to compute square roots.

function x = simpleSqrt(n)
    guess = 1;
    x = simpleIterative(guess, @newtonUpdate, n);

function val = newtonUpdate(x, n)
    val = (x + n/x) / 2;
The newtonUpdate function uses Newton's method to compute a better approximation for the square root by taking the average of x and n/x. A handle to this function is passed as a parameter to the simpleIterative function.

more robust version

We offer a more robust version of our software named iterativeSolver.m. This uses the same logic as our original version, but it allows for more customization by the caller in monitoring the number of iterations that are used as well as to see the intermediate results within the main loop. Those intermediate results are reported by using a "callback" function as an extra parameter. The callback is similar to the update function, in that it is presumed to be a function handler sent by the caller. The this callback function can be coded to do what we want, such as to generate plots of the successive approximations.

As a further demonstration, we provide a more robust version of the square root code, named newSqrt.m, that uses the new solver.

Revisiting the gambler problem

When computing the square root, the form of our solution was a scalar. For the gambler problem, we wish to consider a solution that is a vector representing key information for each possible bankroll from 0 to the goal. In this case, an update rule must construct a new vector of values based on a previous vector.

As an example, if we are interested in knowing the chance of an overall win, when starting at a given bankroll, our update function can be written as follows.

function new = winUpdate(old, p)
    new = zeros(1, length(old));
    new(1) = 0;                   % gambler loses with bankroll 0
    new(end) = 1;                 % gambler wins with bankroll goal
    for k = 2:(length(new)-1)
        new(k) = (1-p) * old(k-1) + p * old(k+1);
    end
This logic is based on the analysis from last lecture. To demonstrate this approach, with full animation of itermediate results, download the file win.m and use it together with our robust iterative solver.

If we want to compute the average number of bets for a given starting bankroll, we only need to make a minor modification to the above approach. We write a betsUpdate function as follows.

function new = betsUpdate(old, p)
    new = zeros(1, length(old));
    new(1) = 0;                     % no more betting with bankroll 0
    new(end) = 0;                   % no more betting with bankroll goal
    for k = 2:(length(new)-1)
        new(k) = 1 + (1-p) * old(k-1) + p * old(k+1);  % one bet plus more...
    end
The full version of this program can be download as the file bets.m.

Finally, we offer a program placed.m that computes how many bets would be expeced to be placed with each intermediate bankroll, given a fixed goal and initial bankroll. Its update rule is written as follows, expecting auxillary parameters to designate the p value and the assumed starting bankroll.

function new = placedUpdate(old, params)
    p = params(1);
    start = params(2);
    new = zeros(1, length(old));
    new(1) = 0;     % never places a bet with bankroll 0
    new(end) = 0;   % never places a bet with bankroll goal
    for k = 2:(length(new)-1)
        new(k) = p * old(k-1) + (1-p) * old(k+1); % must have recently won from index-1
    end                                           % or lost from index+1
    new(start) = new(start)+1;                    % initial bankroll gets one extra