function varargout = predictor_corrector_gui(varargin)
% PREDICTOR_CORRECTOR_GUI MATLAB code for predictor_corrector_gui.fig
%      PREDICTOR_CORRECTOR_GUI, by itself, creates a new PREDICTOR_CORRECTOR_GUI or raises the existing
%      singleton*.
%
%      H = PREDICTOR_CORRECTOR_GUI returns the handle to a new PREDICTOR_CORRECTOR_GUI or the handle to
%      the existing singleton*.
%
%      PREDICTOR_CORRECTOR_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in PREDICTOR_CORRECTOR_GUI.M with the given input arguments.
%
%      PREDICTOR_CORRECTOR_GUI('Property','Value',...) creates a new PREDICTOR_CORRECTOR_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before predictor_corrector_gui_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to predictor_corrector_gui_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help predictor_corrector_gui

% Last Modified by GUIDE v2.5 20-Aug-2012 09:41:34

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @predictor_corrector_gui_OpeningFcn, ...
                   'gui_OutputFcn',  @predictor_corrector_gui_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before predictor_corrector_gui is made visible.
function predictor_corrector_gui_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to predictor_corrector_gui (see VARARGIN)

% Choose default command line output for predictor_corrector_gui
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes predictor_corrector_gui wait for user response (see UIRESUME)
% uiwait(handles.figure1);
reset_globals(handles);


% --- Outputs from this function are returned to the command line.
function varargout = predictor_corrector_gui_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in reset.
function reset_Callback(hObject, eventdata, handles)
% hObject    handle to reset (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
reset_globals(handles);

% --- Executes on button press in step_forward.
function step_forward_Callback(hObject, eventdata, handles)
% hObject    handle to step_forward (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
next_step(handles,0);


function step_size_Callback(hObject, eventdata, handles)
% hObject    handle to step_size (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of step_size as text
%        str2double(get(hObject,'String')) returns contents of step_size as a double


% --- Executes during object creation, after setting all properties.
function step_size_CreateFcn(hObject, eventdata, handles)
% hObject    handle to step_size (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in repeat_step.
function repeat_step_Callback(hObject, eventdata, handles)
% hObject    handle to repeat_step (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
next_step(handles,1);


function function_edit_Callback(hObject, eventdata, handles)
% hObject    handle to function_edit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of function_edit as text
%        str2double(get(hObject,'String')) returns contents of function_edit as a double


% --- Executes during object creation, after setting all properties.
function function_edit_CreateFcn(hObject, eventdata, handles)
% hObject    handle to function_edit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function tolerance_Callback(hObject, eventdata, handles)
% hObject    handle to tolerance (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of tolerance as text
%        str2double(get(hObject,'String')) returns contents of tolerance as a double


% --- Executes during object creation, after setting all properties.
function tolerance_CreateFcn(hObject, eventdata, handles)
% hObject    handle to tolerance (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function y_next = next_predictor (f, t_start, y_start, step)
y_next = y_start + step * f (t_start, y_start);

function y_next = next_corrector (f, t_start, y_start, y_guess, step)
options = optimset('Display', 'off');
y_next = fsolve ( @(z)(y_start+step*f(t_start+step,z)-z), y_guess, options);

function tol = get_tolerance (handles)
tol = str2double(get(handles.tolerance,'String'));
assert(~isnan(tol) && isreal(tol) && ~isinf(tol) && tol > 0,...
    'Tolerance must be positive!');

function f = get_function (handles)
% f = @(x,y) (y);
f = inline(get(handles.function_edit,'String'),'x','y');

function h = get_step_size (handles)
h = str2double(get(handles.step_size, 'String'));
assert(~isnan(h) && isreal(h) && ~isinf(h) && h > 0,...
    'Step size must be positive!');

function ic = get_initial_conditions (handles)
ic = str2num(get(handles.initial_conditions,'String'));
assert(ndims(ic)==2 && size(ic,1)==1 && size(ic,2)==2 && ...
    all(isreal(ic)) && all(~isinf(ic)),...
    '[x0 y0] must be a real row vector of length 2');

function next_step (handles, type)
global x_axis y_pred y_corr index l_error;

index = index - type;

try
    f = get_function(handles);
    h = get_step_size(handles);
    t = get_tolerance(handles);

    y_pred(index+1) = next_predictor(f, x_axis(index), y_corr(index), h);
    y_corr(index+1) = next_corrector(f, x_axis(index), y_corr(index), y_pred(index+1), h);
    x_axis(index+1) = x_axis(index) + h;
    l_error(index+1) = 0.5*abs(y_pred(index+1)-y_corr(index+1))/h;

    index = index + 1;

    plot(handles.axes1, x_axis, y_corr, x_axis, [y_corr(1:(index-1)) y_pred(index)] );
    set(handles.axes1, 'XLim', [x_axis(1) x_axis(index)]);
    plot(handles.axes2, x_axis, l_error);
    set(handles.axes2, 'XLim', [x_axis(1) x_axis(index)], 'YLim', [0 max([t l_error])*(1.05)]);
    if l_error(index) <= t
        colour_top = 'green';
    else
        colour_top = 'red';
    end

    if l_error(index) >= 0.1*t
        colour_bottom = 'green';
    else
        colour_bottom = 'red';
    end

    axes(handles.axes2);
    line([x_axis(1) x_axis(index)], 0.1*[t t], 'Color', colour_bottom);
    line([x_axis(1) x_axis(index)], [t t], 'Color', colour_top);
    
    if type == 0 % if we've taken at least one step
        set(handles.repeat_step,'Enable','on');
    end
catch exception
     if (strcmp(exception.identifier,'MATLAB:inlineeval:InlineExprError')) || (strcmp(exception.identifier,'MATLAB:arrayfun:NotAScalarOutput'))
         waitfor(msgbox('The function you have entered cannot be understood by MATLAB(R)', 'Error', 'error'));
     elseif strcmp(exception.identifier, 'MATLAB:m_missing_operator')
         waitfor(msgbox('The function you have typed in appears to me missing an operator', 'Error', 'error'));
     else
         waitfor(msgbox(exception.message,'Error','error'));
     end
end


function show_latex(handles)
axes(handles.axes3);
text('Position', [3.5 2], 'String', '$$y'' = f(x,y)$$', 'interpreter', 'latex', 'fontsize', 20);
text('Position', [3 -0.5], 'String', 'Tolerance:');
text('Position', [3 -1.5], 'String', 'Step size:');
text('Position', [3 -2.5], 'String', '$$f(x,y) = $$', 'interpreter', 'latex', 'fontsize', 10);
text('Position', [3 -3.24], 'String', '$$[x_0 y_0] = $$', 'interpreter', 'latex', 'fontsize', 10);
axes(handles.axes1);

function reset_globals (handles)
global x_axis y_pred y_corr index l_error

set(handles.repeat_step,'Enable','off');

try
    index = 1;
    ic = get_initial_conditions(handles);
    x_axis = [ ic(1) ];
    y_pred = [ ic(2) ];
    y_corr = [ ic(2) ];
    l_error = [ 0 ];

    t = get_tolerance(handles);
    h = get_step_size(handles);

    plot( handles.axes1, x_axis, y_pred, x_axis, y_corr );
    set(handles.axes1, 'XLim', [x_axis(1) x_axis(1)+0.5*h]);
    plot( handles.axes2, x_axis, l_error );
    set(handles.axes2, 'XLim', [x_axis(1) x_axis(1)+0.5*h], 'YLim', [0, t*1.05]);
    axes(handles.axes2);
    line([0 (x_axis(1)+0.5*h)], [t t], 'Color', 'green');
    line([0 (x_axis(1)+0.5*h)], 0.1*[t t], 'Color', 'green');
    set(handles.axes3, 'XLim', [0 1], 'YLim', [0 1]);
    show_latex(handles);
    % axis([0 1 0 3]);
catch exception
     if (strcmp(exception.identifier,'MATLAB:inlineeval:InlineExprError')) || (strcmp(exception.identifier,'MATLAB:arrayfun:NotAScalarOutput'))
         waitfor(msgbox('The function you have entered cannot be understood by MATLAB(R)', 'Error', 'error'));
     elseif strcmp(exception.identifier, 'MATLAB:m_missing_operator')
         waitfor(msgbox('The function you have typed in appears to me missing an operator', 'Error', 'error'));
     else
         waitfor(msgbox(exception.message,'Error','error'));
     end
end



function initial_conditions_Callback(hObject, eventdata, handles)
% hObject    handle to initial_conditions (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of initial_conditions as text
%        str2double(get(hObject,'String')) returns contents of initial_conditions as a double


% --- Executes during object creation, after setting all properties.
function initial_conditions_CreateFcn(hObject, eventdata, handles)
% hObject    handle to initial_conditions (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
