%% Secant Method Root Solver
% Authors: Shen Ge and Stefan San Miguel
% Purpose:
% Allows user to approximate a real root using the Secant Method. 
% User is prompted for an equation and their initial guesses for the
% min and max of the root. The program then completes iterations until the
% root is found, rounded to the nearest three decimal places.
% NOTE:
% This is only for continuous functions as of now.

clear;
clc;
format long
syms x

%% CONSTANTS
% User inputs / % Calculation parameters
f(x) = input('Please enter a expression for f(x): '); % symbolic stored
a = input('Please enter the minimum root guess: '); % double stored
b = input('Please enter the maximum root guess: '); % double stored
err = 0.001;

% Figure / Animation constants
pausetime = .005; % pause between each iteration
ftitle = 15; % font size
min = a-1;
max = b+1;
step = 0.01; 
xplot = min : step : max;

% Calculate function values at maximum and minimum guessed roots
fx1 = subs(f,x,b); % function value at max guess
fx0 = subs(f,x,a); % function value at min guess

% Generate data chart and figure
fprintf('\n\n Iteration      Est. Root')
figure('units','normalized','outerposition',[0 0 .5 .8])

%% ITERATION
i = 0;
x1 = b;
x0 = a;
% keep looping until either max or min function value is close enough to 0
while (abs(fx0)>err) || (abs(fx1)>err)
    % Calculate function with iterated minimum & maximum roots
    fx1 = subs(f,x,x1); % function value at new max 
    fx0 = subs(f,x,x0); % function value at new min 
    
    % Calculate set of y values for secant line
    % Note this is only used for plotting purposes!
    sec = ((fx1-fx0)/(x1-x0))*(xplot-x1)+fx1;
    
    % Calculate next value of the possible root with secant formula
    x2 = x1 - fx1*(x1-x0)/(fx1-fx0); 
    
    % Calculate y values (for plotting purpose only!)
    % Note that this should be close to 0 at the end of the loop
    fx2 = subs(f,x,x2);
       
    % Move to next set of max and min values
    x0 = x1;
    x1 = x2;

    % reset graph
    pause(pausetime)
    clf('reset')
    
    % Plot updated chart
    hold on
    plot(xplot,f(xplot),'k','LineWidth',3); % original function
    plot(xplot,sec,':m','LineWidth',3); % secant line
    plot(x0,fx0,'o','MarkerSize',10,'MarkerEdgeColor','k','MarkerFaceColor','green')
    plot(x1,fx1,'o','MarkerSize',10,'MarkerEdgeColor','k','MarkerFaceColor','red')
    
    % Plot x and y value of the possible root
    plot(x2,fx2,'og','MarkerSize',10,'MarkerEdgeColor','k','MarkerFaceColor','blue');
    
    % graph parameters
    axis([min, max, -inf, inf]);
    grid on
    title('Iterations on f(x) - Secant Method','fontsize',ftitle)                                                   
    labels = legend('f(x)','Secant Line','Est min root','Est max root','Est next root');
    set(labels,'location','northwest')
    set(labels,'fontsize', 15);
    
    i = i+1;  
    % fprintf('\n\n Iteration      Est. Root')
    fprintf('\n %5i %18f', i, double(x2)) 
end

%% FINAL PRINTOUTS

if isnan(double(x2)) ~= 1
    fprintf('\n \n The approximated root is %3f after %1i iterations', double(x2), i);
    fprintf('\n')
elseif isnan(double(x0)) ~= 1 
    % if a nonsensical answer results from division by 0, choose previous
    i = i-1;
    fprintf('\n \n The estimated root is %3f after %1i iterations', double(x0), i);
    fprintf('\n')
else % secant method failed
    fprintf('\n Secant method failed. Please guess another set of bounds.\n');
end