function TCM_extrema_rectangle

% TCM_extrema_rectangle Interactive illustration of the extremum of
% bivariate polynomials on a predefined rectangle.
%
%   TCM_extrema_rectangle illustrates the guaranteed existence of an extrema
%   (maxmimum or minimum) of a polynomial on a rectangle. The examples
%   show that these points do not have to be unique.
%   
%   EXAMPLES
%
%   Basic Example: The maximum lies in the rectangle because the rectangle 
%   contains the global maximum of the function and the function is monotonically 
%   decreasing.
%
%   Boundary Extrema: If there is no local extrema in the rectangle, the
%   extrema has to be searched on its boundary.
%   
%   Multiple Extrema: Depending on the shape of the function, there can
%   even be multiple extrema in the rectangle.
%    
%   To investigate other cases, insert a function and a rectangle in the 
%   corresponding fields. 
%
%   TCM_extrema_rectangle is part of the <a href="http://www2.imng.uni-stuttgart.de/LstNumGeoMod/TCM/">TCM</a> project.
%   Related course materials can be found at <a href="http://www.mathematics-online.org/inhalt/aussage/aussage526">Mathematics Online</a>.

% Authors: Florian Martin, Lars von Wolff
% Last updated: 27.03.2017

% Initialize data
TCM_Data.fun = @(x,y) x.*exp(-x.^2-y.^2);  
TCM_Data.funstring = '@(x,y) x.*exp(-x.^2-y.^2)';
TCM_Data.deg = [];
TCM_Data.coeff = [];
TCM_Data.crit_points = [];
TCM_Data.type = [];
TCM_Data.rect = [0 1 0 1];
TCM_Data.selected = 0;
TCM_Data.move = 0;

% Do not delete these Variables
TCM_Data.plot_window = [-2 2 -2 2];
TCM_Data.LmbMenuString = '';
TCM_Data.examples = {'Basic Example','Boundary Extrema','Multiple Extrema'};

% Layout:
% ---------------------------------------
% |               Title                 |
% | ------------ --------- ------------ |
% | | Settings | |Buttons| | Feedback | |
% | ------------ --------- ------------ |
% | ----------------------------------- |
% | |           Axis (Plot)           | |
% | ----------------------------------- |
% | Info-Button         Hint            |
% ---------------------------------------
% Initialize Layout:
TCM_UI.TitleHeightMin = 10;        % minimal height of the title
TCM_UI.TitleHeightMax = 32;        % maximal height of the title
TCM_UI.HintHeightMin = 8;          % minimal height of the hint
TCM_UI.HintHeightMax = 15;         % maximal height of the hint
TCM_UI.SettingsHeightMin = 40;     % minimal height of the feedback, buttons and 
                                   % setting panel
TCM_UI.SettingsHeightMax = 70;     % maximal height of the feedback, buttons and 
                                   % setting panel
TCM_UI.SettingsRatio = 4.5;          % aspect ratio of the settings  
                                   % (increase if more settings needed)
TCM_UI.ButtonsRatio = 1.4;         % aspect ratio of the Buttons panel
TCM_UI.FeedbackRatio = 3.4;        % aspect ratio of the feedback
TCM_UI.AxisHeightTarget = 0.73;    % desired fraction of figure 
                                   % used for the plot
TCM_UI.InfoPortion = 1/8;          % Portion of the Info Button in the last  
                                   % line 
TCM_UI.Title = 'Global Extrema of Polynomials on a Rectangle';
TCM_UI.mono = get(0,'FixedWidthFontName');
% Strings for generating the information window
TCM_UI.Author = 'F. Martin and L. von Wolff';
TCM_UI.Date = '27.03.2017';
TCM_UI.Web = 'http://www.mathematics-online.org/inhalt/aussage/aussage526';
      
CreateUI();

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% UI-Elements in Settings %%%%%%%%%%%%%%%%%%%%
% Text for Function
TCM_UI.funtext = uicontrol('Units','normalized', 'Parent',TCM_UI.settingspanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontUnits','normalized','FontSize',0.67,...
        'HorizontalAlignment','left', ...
	'Position',[.01,.70,.5,.30],...
	'String','Function:',...
	'Style','text');

% Input for Function
TCM_UI.funinput=uicontrol('Units','normalized', 'Parent',TCM_UI.settingspanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontWeight','bold',...
        'FontUnits','normalized','FontSize',0.65,'FontName',TCM_UI.mono,...
        'HorizontalAlignment','left', ...
	'Position',[.30,.70,.68,.30],...
	'String','',...
	'Style','edit',...
	'Callback',@function_update);

% Text for rectangle
TCM_UI.recttext = uicontrol('Units','normalized', 'Parent',TCM_UI.settingspanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontUnits','normalized','FontSize',0.67,...
        'HorizontalAlignment','left', ...
	'Position',[.01,.35,.29,.30],...
	'String','Rectangle:',...
	'Style','text');

% Input the rectangle
TCM_UI.rectinput=uicontrol('Units','normalized', 'Parent',TCM_UI.settingspanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontWeight','bold',...
        'FontUnits','normalized','FontSize',0.65,'FontName',TCM_UI.mono,...
        'HorizontalAlignment','left', ...
	'Position',[.30,.35,.69,.30],...
	'String','[0 1 0 1]',...
	'Style','edit','Callback',@rectangle_update);

% Text for the type
TCM_UI.typetext=uicontrol('Units','normalized','Parent',TCM_UI.settingspanel,...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
        'FontUnits','normalized','FontSize',0.7,...
	'Position',[.01,.00,.29,.3],...
	'String','Type:',...
	'Style','text');

% Popup for choice of the type
TCM_UI.typepopup=uicontrol('Units','normalized', 'Parent',TCM_UI.settingspanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontWeight','bold',...
        'FontUnits','normalized','FontSize',0.65,...
        'HorizontalAlignment','left', ...
	'Position',[.30,.00,.4,.3],...
	'String','NaN',...
	'Style','popup','Callback',@myplot,...
    'String',{'Minimum','Maximum'});

%%%%%%%%%%%%%%%%%%%%%%%%% UI-Elements in Buttons Panel %%%%%%%%%%%%%%%%%%%%
% Reset-Button
TCM_UI.reset=uicontrol('Units','normalized','Parent',TCM_UI.buttonspanel, ...
	'BackgroundColor',get(gcf,'Color'), ...
	'String','Reset', ...
    'FontUnits','normalized','FontSize',0.7,...
	'Position',[.01,.70,.98,.30], ...
	'Callback',@reset,...
	'Style','pushbutton');

% Example button
TCM_UI.examples=uicontrol('Units','normalized','Parent',TCM_UI.buttonspanel, ...
	'BackgroundColor',get(gcf,'Color'), ...
	'String','Examples', ...
    'FontUnits','normalized','FontSize',0.7,...
	'Position',[.01,.35,.98,.30], 'Callback',@OpenExampleMenu,...
	'Style','pushbutton');

% Next button
TCM_UI.next=uicontrol('Units','normalized','Parent',TCM_UI.buttonspanel, ...
	'BackgroundColor',get(gcf,'Color'), ...
	'String','Next Point', ...
    'FontUnits','normalized','FontSize',0.7,...
	'Position',[.01,0,.98,.30], ...
	'Callback',@examples,...
	'Style','pushbutton','Callback',@next);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% UI-Elements in Feedback %%%%%%%%%%%%%%%%%%%%

% Text for the current extremal point
TCM_UI.pointtext=uicontrol('Units','normalized','Parent',TCM_UI.feedbackpanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
        'FontUnits','normalized','FontSize',0.7,...
	'Position',[.1,.7,.9,.3],...
	'String','Marked Point: NaN',...
	'Style','text');

% Text for the function value
TCM_UI.valuetext=uicontrol('Units','normalized','Parent',TCM_UI.feedbackpanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
        'FontUnits','normalized','FontSize',0.7,...
	'Position',[.1,.35,1,.3],...
	'String','Functionvalue: NaN',...
	'Style','text');

% Text for noncompatible input
TCM_UI.inputtext=uicontrol('Units','normalized','Parent',TCM_UI.feedbackpanel, ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', 'ForegroundColor','red',...
        'FontUnits','normalized','FontSize',0.7,...
	'Position',[.1,.01,1,.3],...
	'String','No compatible input.',...
	'Style','text','Visible','off');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% UI-Elements in Axis %%%%%%%%%%%%%%%%%%%%%%%%
% Axis for Function display
TCM_UI.ax=axes('Position',[.05,.1,.45,.85],'Parent',TCM_UI.axispanel);
axis(TCM_UI.ax,'equal');
TCM_UI.modification = uicontextmenu('Callback',@reset_zoom_limits);  
TCM_UI.mpan = uimenu('Parent',TCM_UI.modification,'Label','Enable pan',...
        'Callback',@axis_context);
TCM_UI.mzoomi = uimenu('Parent',TCM_UI.modification,'Label','Enable zoom in',...
    'Callback',@axis_context); 
TCM_UI.mzoomo = uimenu('Parent',TCM_UI.modification,'Label','Enable zoom out',...
        'Callback',@axis_context); 
TCM_UI.ax.UIContextMenu = TCM_UI.modification;

% functions for smoothless zooming and panning
panfun = pan(TCM_UI.fig);
panfun.UIContextMenu = TCM_UI.modification;
set(panfun,'ActionPostCallback',@pan_modify);
zoomfun = zoom(TCM_UI.fig);
zoomfun.UIContextMenu = TCM_UI.modification; 
set(zoomfun,'ActionPostCallback',@zoom_modify);
set(zoomfun,'ButtonDownFilter',@set_zoom_limits);
set(zoomfun,'RightClickAction','PostContextMenu');
set(findall(TCM_UI.fig,'tag','Exploration.Pan'),'enable','off');
set(findall(TCM_UI.fig,'tag','Exploration.ZoomOut'),'enable','off');
set(findall(TCM_UI.fig,'tag','Exploration.ZoomIn'),'enable','off');

% Second axis for a 3D plot with its own Contextmenu
TCM_UI.ax2=axes('Position',[.55,.1,.44,.85],'Parent',TCM_UI.axispanel);
linkaxes([TCM_UI.ax, TCM_UI.ax2], 'xy');
axis equal
TCM_UI.rotatemenu = uicontextmenu;
TCM_UI.rotate = uimenu('Parent',TCM_UI.rotatemenu,'Label','Enable rotate',...
        'Callback',@axis2_context);
TCM_UI.ax2.UIContextMenu = TCM_UI.rotatemenu;
rotatefun = rotate3d(TCM_UI.ax2);
rotatefun.UIContextMenu = TCM_UI.rotatemenu;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Start the program %%%%%%%%%%%%%%%%%%%%%%%%%%
changeexample(1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%% Callback functions %%%%%%%%%%%%%%%%%%%%%%%%%%%

% new function input
function function_update(varargin)
TCM_Data.funstring = get(TCM_UI.funinput,'String');
var1 = TCM_Data.funstring(find(TCM_Data.funstring=='(',1)+1:...
    find(TCM_Data.funstring==',',1)-1);
var2 = TCM_Data.funstring(find(TCM_Data.funstring==',',1)+1:...
    find(TCM_Data.funstring==')',1)-1);

try
    TCM_Data.fun = eval(TCM_Data.funstring);    
    compute_crit_points();
catch
%     v = ver;
%     if any(strcmp('Symbolic Math Toolbox', {v.Name}))    
%         xsym = sym('xsym','real'); 
%         ysym = sym('ysym','real'); 
%         f(xsym,ysym) = TCM_Data.fun(xsym,ysym);
%         taylor(f, [xsym,ysym],'Order',5)
%     else
%         TCM_UI.inputtext.Visible = 'on';
%     end
    TCM_Data.fun = eval([TCM_Data.funstring '+0*' var1 '+0*' var2]);
    TCM_Data.extrema = TCM_Data.rect([1 3])';
    TCM_UI.inputtext.Visible = 'on';
    reset;
    return
end
TCM_UI.inputtext.Visible = 'off';
determine_types();
boundary_extrema();
TCM_Data.fun = eval([TCM_Data.funstring '+0*' var1 '+0*' var2]);
reset;
end

% rectangle update
function rectangle_update(varargin)
rect = eval(get(TCM_UI.rectinput,'String'));
h = diff(rect)/3;
if h(1) > 0 && h(3) > 0
    TCM_Data.rect = rect;
    TCM_Data.plot_window = TCM_Data.rect + [-h(1) h(1) -h(3) h(3)];
    try
        boundary_extrema();
    end        
else
    set(TCM_UI.rectinput,'String',['[' num2str(TCM_Data.rect) ']']);
end
reset;
end

% cycle through the extremal points
function next(varargin)
TCM_Data.selected = TCM_Data.selected + 1;
myplot;
end

% refresh all data from UI
function reset(varargin)
window_disable.Label = 'Disable pan';
axis_context(window_disable);
axis2_context(window_disable);
TCM_Data.selected = 1;
myplot;
end

% mouse button pressed 
function myDownfct(varargin)
p = getClickPosition(TCM_UI.ax);
if isnan(p)
    return
end
if strcmp(get(gcf,'SelectionType'),'normal')    
    h = diff(TCM_Data.plot_window);
    maxd = 0.05*sqrt(h(1)^2+h(3)^2);
    
    if abs(p(1)-TCM_Data.rect(1))<maxd && p(2)>= TCM_Data.rect(3) && p(2)<= TCM_Data.rect(4)
        TCM_Data.move = 1;
        TCM_Data.rect(1) = p(1);
    elseif abs(p(1)-TCM_Data.rect(2))<maxd && p(2)>= TCM_Data.rect(3) && p(2)<= TCM_Data.rect(4)
        TCM_Data.move = 2;
        TCM_Data.rect(2) = p(1);       
    elseif abs(p(2)-TCM_Data.rect(3))<maxd && p(1)>= TCM_Data.rect(1) && p(1)<= TCM_Data.rect(2)
        TCM_Data.move = 3;
        TCM_Data.rect(3) = p(2);  
    elseif abs(p(2)-TCM_Data.rect(4))<maxd && p(1)>= TCM_Data.rect(1) && p(1)<= TCM_Data.rect(2)
        TCM_Data.move = 4;
        TCM_Data.rect(4) = p(2);         
    end
    
    if TCM_Data.move > 0
        boundary_extrema();
        myplot();
        set(TCM_UI.rectinput,'String',sprintf('[%.3f %.3f %.3f %.3f]',TCM_Data.rect(1),TCM_Data.rect(2),...
            TCM_Data.rect(3),TCM_Data.rect(4)));
    end
end
end

% moving the mouse in the axis
function myMovefct(varargin)
if TCM_Data.move > 0
    p = getClickPosition(TCM_UI.ax);
    if(isnan(p))
       return;
    end
    switch TCM_Data.move
        case 1
            TCM_Data.rect(1) = p(1);
        case 2
            TCM_Data.rect(2) = p(1);
        case 3
            TCM_Data.rect(3) = p(2);
        case 4
            TCM_Data.rect(4) = p(2);
    end
    boundary_extrema();
    myplot();
    set(TCM_UI.rectinput,'String',sprintf('[%.3f %.3f %.3f %.3f]',TCM_Data.rect(1),TCM_Data.rect(2),...
        TCM_Data.rect(3),TCM_Data.rect(4)));
end
end

% releasing a mouse button
function myUpfct(varargin)
TCM_Data.move = 0;
myplot;
end

function p = getClickPosition(myaxes)
x = get(myaxes,'xlim');
y = get(myaxes,'ylim');
newpoint=get(myaxes,'CurrentPoint');
if (newpoint(1) < x(1) || newpoint(1) > x(2) || ...
    newpoint(3) < y(1) || newpoint(3) > y(2))
    p = NaN;
else
    p = newpoint([1 3]);
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% kernel functions %%%%%%%%%%%%%%%%%%%%%%%%%%%

% determine the types of the critical points
function determine_types(varargin)
deg = TCM_Data.deg; coeff = TCM_Data.coeff;
xdeg = [deg(1,:)-1;deg(2,:)]; xcoeff = coeff.*deg(1,:);
del = find(xdeg(1,:)==-1); xdeg(:,del) = []; xcoeff(del) = [];
ydeg = [deg(1,:);deg(2,:)-1]; ycoeff = coeff.*deg(2,:);
del = find(ydeg(2,:)==-1); ydeg(:,del) = []; ycoeff(del) = [];

xxdeg = [xdeg(1,:)-1;xdeg(2,:)]; xxcoeff = xcoeff.*xdeg(1,:);
del = find(xxdeg(1,:)==-1); xxdeg(:,del) = []; xxcoeff(del) = [];

xydeg = [xdeg(1,:);xdeg(2,:)-1]; xycoeff = xcoeff.*xdeg(2,:);
del = find(xydeg(2,:)==-1); xydeg(:,del) = []; xycoeff(del) = [];

yydeg = [ydeg(1,:);ydeg(2,:)-1]; yycoeff = ycoeff.*ydeg(2,:);
del = find(yydeg(2,:)==-1); yydeg(:,del) = []; yycoeff(del) = [];

TCM_Data.type = zeros(1,size(TCM_Data.crit_points,2));
for i=1:numel(TCM_Data.type)
    hesse = [sum(xxcoeff.*TCM_Data.crit_points(1,i).^xxdeg(1,:)...
        .*TCM_Data.crit_points(2,i).^xxdeg(2,:)) sum(xycoeff.*TCM_Data.crit_points(1,i).^xydeg(1,:)...
        .*TCM_Data.crit_points(2,i).^xydeg(2,:)); 0 sum(yycoeff.*TCM_Data.crit_points(1,i).^yydeg(1,:)...
        .*TCM_Data.crit_points(2,i).^yydeg(2,:))];
    hesse(2,1) = hesse(1,2);
    E = eig(hesse); s = sign(E);
    if min(s) == 1 
        TCM_Data.type(i) = 1;
    elseif max(s) == -1
        TCM_Data.type(i) = 2;
    end
end
end

% calculate the critical points
function compute_crit_points(varargin)
[deg,coeff] = multi_poly(TCM_Data.fun);
if any(isnan(coeff)) 
    error('input');
end
xdeg = [deg(1,:)-1;deg(2,:)]; xcoeff = coeff.*deg(1,:);
del = find(xdeg(1,:)==-1); xdeg(:,del) = []; xcoeff(del) = [];
ydeg = [deg(1,:);deg(2,:)-1]; ycoeff = coeff.*deg(2,:);
del = find(ydeg(2,:)==-1); ydeg(:,del) = []; ycoeff(del) = [];

if isempty(xdeg)
    xdeg = [0;0]; xcoeff = 0;
end
if isempty(ydeg)
    ydeg = [0;0]; ycoeff = 0;
end

dR = max(xdeg(1,:))*max(ydeg(2,:)) + max(xdeg(2,:))*max(ydeg(1,:));
if dR == 0
    if (isequal(xdeg,[0;0]) && xcoeff ~= 0) || (isequal(ydeg,[0;0]) && ycoeff ~= 0)
        TCM_Data.crit_points = [];
        TCM_Data.deg = deg; TCM_Data.coeff = coeff;
        return
    end
    if isequal(xdeg,[0;0]) && xcoeff == 0 
        ypoly = zeros(1,max(ydeg(2,:))+1);
        for i=1:numel(ycoeff)
            ypoly(ydeg(2,i)+1) = ypoly(ydeg(2,i)+1) + ycoeff(i);
        end
        TCM_Data.crit_points = roots(fliplr(ypoly));
        TCM_Data.crit_points(abs(imag(TCM_Data.crit_points))>10^-6) = [];
        TCM_Data.crit_points = [0*TCM_Data.crit_points; TCM_Data.crit_points];
        if isempty(TCM_Data.crit_points) && isequal(ypoly,0)
            TCM_Data.crit_points = [0;0];
        end
        TCM_Data.deg = deg; TCM_Data.coeff = coeff;
        return
    end
    if isequal(ydeg,[0;0]) && ycoeff == 0  
        xpoly = zeros(1,max(xdeg(1,:))+1);
        for i=1:numel(xcoeff)
            xpoly(xdeg(1,i)+1) = xpoly(xdeg(1,i)+1) + xcoeff(i);
        end
        TCM_Data.crit_points = roots(fliplr(xpoly));
        TCM_Data.crit_points(abs(imag(TCM_Data.crit_points))>10^-6) = [];
        TCM_Data.crit_points = [TCM_Data.crit_points;0*TCM_Data.crit_points];
        if isempty(TCM_Data.crit_points) && isequal(xpoly,0)
            TCM_Data.crit_points = [0;0];
        end
        TCM_Data.deg = deg; TCM_Data.coeff = coeff;
        return
    end
end
points = 0:dR;
yR = 0*points;

xmax = max(xdeg(2,:)); 
ymax = max(ydeg(2,:));
Res = zeros(xmax+ymax);

for i=1:numel(points)
    xpoly = zeros(1,max(xdeg(2,:))+1);
    ypoly = zeros(1,max(ydeg(2,:))+1);
    for j=1:numel(xcoeff)
        xpoly(xdeg(2,j)+1) = xpoly(xdeg(2,j)+1) + xcoeff(j)*points(i)^xdeg(1,j);
    end
    for j=1:numel(ycoeff)
        ypoly(ydeg(2,j)+1) = ypoly(ydeg(2,j)+1) + ycoeff(j)*points(i)^ydeg(1,j);
    end
    xpoly = fliplr(xpoly);
    ypoly = fliplr(ypoly);
    for j=1:ymax
        Res(j,j+[0:numel(xpoly)-1]) = xpoly;
    end
    for j=1:xmax
        Res(ymax+j,j+[0:numel(ypoly)-1]) = ypoly;
    end
    yR(i) = det(Res);
end
R = round(polyfit(points,yR,dR),5);
zero = unique(round(roots(R),5));
if isempty(zero) && max(abs(R))<10^-6
    zero = 0;
end
zero(abs(imag(zero))>10^-6) = [];

totalzeros = {};
for i=1:numel(zero)
    newxcoeff = xcoeff.*(zero(i).^xdeg(1,:));
    f1 = zeros(1,max(xdeg(2,:))+1);
    for j=1:numel(xdeg(2,:))
        f1(xdeg(2,j)+1) = f1(xdeg(2,j)+1) + newxcoeff(j);
    end
    xzeros = roots(fliplr(f1));
    xzeros(abs(imag(xzeros))>10^-6) = [];
    
    newycoeff = ycoeff.*(zero(i).^ydeg(1,:));
    f2 = zeros(1,max(ydeg(2,:))+1);
    for j=1:numel(ydeg(2,:))
        f2(ydeg(2,j)+1) = f2(ydeg(2,j)+1) + newycoeff(j);
    end
    yzeros = roots(fliplr(f2));
    yzeros(abs(imag(yzeros))>10^-6) = [];
    
    if ~isempty(xzeros) && isempty(yzeros) && max(abs(f2))<10^-6
        totalzeros{i} = xzeros;
    elseif ~isempty(yzeros) && isempty(xzeros) && max(abs(f1))<10^-6
        totalzeros{i} = yzeros;
    else
        totalzeros{i} = intersect(xzeros,yzeros);
    end
end
TCM_Data.crit_points = [];
for i=1:numel(totalzeros)
    for j=1:numel(totalzeros{i})
        TCM_Data.crit_points = [TCM_Data.crit_points [zero(i); totalzeros{i}(j)]];
    end
end
TCM_Data.deg = deg; TCM_Data.coeff = coeff;
end

% convert a function handle input into an adequate internal representation
function [degree,coeff] = multi_poly(p)
ps = func2str(p);
var1 = ps(find(ps=='(',1)+1:find(ps==',',1)-1);
var2 = ps(find(ps==',',1)+1:find(ps==')',1)-1);
ps = ps(find(ps==')',1)+1:end);
plus = find(ps=='+');
minus = find(ps=='-');
terms = union(plus,minus);

if isempty(terms) || terms(1) ~= 1
    terms = [1 terms];
end
terms = [terms numel(ps)+1];

coeff = zeros(1,numel(terms)-1);
degree = zeros(2,numel(terms)-1);
for i=1:numel(terms)-1
    term = ps(terms(i):terms(i+1)-1);
    if strcmp(term(1),'+') || strcmp(term(1),'-')
        sign = term(1);
        term = [term(2:end) blanks(max(numel(var1),numel(var2)))];
        length = numel(term)-1;
    else
        sign = '+';
        length = numel(term);
    end
    
    ind = find(term=='*',1)-1;
    if isempty(ind) 
        if strcmp(term(1:numel(var1)),var1) || strcmp(term(1:numel(var2)),var2)
            coeffstr = '1';
        else
            coeffstr = term;
        end
        ind = -1;        
    else
        if strcmp(term(1:numel(var1)),var1) || strcmp(term(1:numel(var2)),var2)
            coeffstr = '1';
            ind = -1; 
        else
            coeffstr = term(1:ind);
        end
    end
    
    if coeffstr(end) == '.'
        coeffstr = coeffstr(1:end-1);
    end
    
    coeff(i) = str2double([sign coeffstr]);
    term = term(1:length);
    degree(:,i) = extract_degree(term(ind+2:end),var1,var2);
end

end

% extract the degrees (a,b) of a term in the form var1.^a.*var2.^b
function degree = extract_degree(string,var1,var2)
degree = [0 0];
if isempty(string)
    return
end
mult = strfind(string,'.*');
string([mult mult+1]) = '';
v1 = [strfind(string, var1) numel(string)+1];
v2 = [strfind(string, var2) numel(string)+1];
l1 = numel(var1); l2 = numel(var2);
string = [string blanks(2)];

for i=1:numel(v1)-1
    if strcmp('.^',string(v1(i)+l1+[0:1]))
        degree(1) = degree(1)+str2double(string(v1(i)+l1+2:(min(v1(i+1),v2(find(v2>v1(i),1)))-1)));
    else 
        degree(1) = degree(1)+1;
    end
end

for i=1:numel(v2)-1
    if strcmp('.^',string(v2(i)+l2+[0:1]))
        degree(2) = degree(2)+str2double(string(v2(i)+l2+2:(min(v2(i+1),v1(find(v1>v2(i),1)))-1)));
    else 
        degree(2) = degree(2)+1;
    end
end
end

% calculate the extrema on the boundary of a rectangle
function boundary_extrema(varargin)
values = [Inf -Inf];
points = {};
for i=1:2
    coeff = TCM_Data.coeff.*TCM_Data.rect(2+i).^TCM_Data.deg(2,:);
    poly = zeros(1,max(TCM_Data.deg(1,:))+1);
    for j=1:numel(coeff)
        poly(TCM_Data.deg(1,j)+1) = poly(TCM_Data.deg(1,j)+1) + coeff(j);
    end
    poly = fliplr(poly);
    crit = unique([TCM_Data.rect(1) roots(polyder(poly))' TCM_Data.rect(2)]);
    crit(abs(imag(crit))>10^-6) = [];
    crit(crit < TCM_Data.rect(1) | crit > TCM_Data.rect(2)) = [];
    if polyder(poly) == 0
        crit = [crit(2:end-1) linspace(TCM_Data.rect(1),TCM_Data.rect(2))];
    end
    val = polyval(poly,crit);
    [maxvalue,~] = max(val);
    ind = find(abs(val-maxvalue)<10^-6);
    if maxvalue > values(2)
        values(2) = maxvalue; points{2} = [crit(ind);TCM_Data.rect(2+i)*ones(size(ind))];
    elseif abs(maxvalue-values(2))<10^-6
        points{2} = [points{2} [crit(ind);TCM_Data.rect(2+i)*ones(size(ind))]];
    end
    [minvalue,~] = min(val);
    ind = find(abs(val-minvalue)<10^-6);
    if minvalue < values(1)
        values(1) = minvalue; points{1} = [crit(ind);TCM_Data.rect(2+i)*ones(size(ind))];
    elseif abs(minvalue-values(1))<10^-6
        points{1} = [points{1} [crit(ind);TCM_Data.rect(2+i)*ones(size(ind))]];
    end
end

for i=1:2
    coeff = TCM_Data.coeff.*TCM_Data.rect(i).^TCM_Data.deg(1,:);
    poly = zeros(1,max(TCM_Data.deg(2,:))+1);
    for j=1:numel(coeff)
        poly(TCM_Data.deg(2,j)+1) = poly(TCM_Data.deg(2,j)+1) + coeff(j);
    end
    poly = fliplr(poly);
    crit = unique([TCM_Data.rect(3) roots(polyder(poly))' TCM_Data.rect(4)]);
    crit(abs(imag(crit))>10^-6) = [];
    crit(crit < TCM_Data.rect(3) | crit > TCM_Data.rect(4)) = [];
    if polyder(poly) == 0
        crit = [crit(2:end-1) linspace(TCM_Data.rect(3),TCM_Data.rect(4))];
    end
    val = polyval(poly,crit);
    [maxvalue,~] = max(val);
    ind = find(abs(val-maxvalue)<10^-6);
    if maxvalue > values(2)
        values(2) = maxvalue; points{2} = [TCM_Data.rect(i)*ones(size(ind));crit(ind)];
    elseif abs(maxvalue-values(2))<10^-6
        points{2} = [points{2} [TCM_Data.rect(i)*ones(size(ind));crit(ind)]];
    end
    [minvalue,~] = min(val);
    ind = find(abs(val-minvalue)<10^-6);
    if minvalue < values(1)
        values(1) = minvalue; points{1} = [TCM_Data.rect(i)*ones(size(ind));crit(ind)];
    elseif abs(minvalue-values(1))<10^-6
        points{1} = [points{1} [TCM_Data.rect(i)*ones(size(ind));crit(ind)]];
    end
end
if isempty(TCM_Data.crit_points)
    inrect = [];
else
    inrect = inpolygon(TCM_Data.crit_points(1,:),TCM_Data.crit_points(2,:),...
        TCM_Data.rect([1 2 2 1 1]),TCM_Data.rect([3 3 4 4 3]));
end
TCM_Data.extrema = [TCM_Data.crit_points(:,inrect) points{1} points{2}];
end

% plot function
function myplot(varargin)
axes(TCM_UI.ax)
cla reset; hold off; axis equal

% evaluating and plotting of the input function on a square containing the
% current window for smoothless panning and zooming
hx = TCM_Data.plot_window(2) - TCM_Data.plot_window(1);
x = linspace(TCM_Data.plot_window(1)-hx,TCM_Data.plot_window(2)+hx,100);
hy = TCM_Data.plot_window(4) - TCM_Data.plot_window(3);
y = linspace(TCM_Data.plot_window(3)-hy,TCM_Data.plot_window(4)+hy,100);
[X,Y] = meshgrid(x(x>=TCM_Data.plot_window(1) & x<=TCM_Data.plot_window(2)),...
    y(y>=TCM_Data.plot_window(3) & y<=TCM_Data.plot_window(4)));
f = TCM_Data.fun(X,Y);
[~,h1]=contour(X,Y,f);
Level1 = h1.LevelList;

if ~isempty(get(TCM_UI.ax2, 'Children'))
    [az,el]=view(TCM_UI.ax2);
else
    az = NaN;
end
cla(TCM_UI.ax2,'reset');

s = surf(TCM_UI.ax2,X,Y,f,'EdgeColor','none','LineStyle','none','FaceLighting','phong');
s.UIContextMenu = TCM_UI.rotatemenu;
shading(TCM_UI.ax2,'interp');
hold(TCM_UI.ax2,'on');
if ~isnan(az)
    view(TCM_UI.ax2,az,el);
end

minval = min(TCM_Data.fun(TCM_Data.extrema(1,:),TCM_Data.extrema(2,:)));
maxval = max(TCM_Data.fun(TCM_Data.extrema(1,:),TCM_Data.extrema(2,:)));

xc = linspace(TCM_Data.rect(1),TCM_Data.rect(2),1000);
yc = linspace(TCM_Data.rect(3),TCM_Data.rect(4),1000);
[Xc,Yc] = meshgrid(xc,yc);
fc = TCM_Data.fun(Xc,Yc);

if minval > min(fc(:))+10^-6 || maxval < max(fc(:))-10^-6
    minval = min(fc(:));
    ind = abs(fc-minval)<10^-6;
    TCM_Data.extrema = Xc(ind)';
    TCM_Data.extrema(2,:) = Yc(ind);
    
    maxval = max(fc(:));
    ind = abs(fc-maxval)<10^-6;
    TCM_Data.extrema = [TCM_Data.extrema [Xc(ind)';Yc(ind)']];
end


[X,Y] = meshgrid(x,y);
f = TCM_Data.fun(X,Y);
[~,h2]=contour(TCM_UI.ax,X,Y,f);

if TCM_Data.move == 0
    Level2 = union(h2.LevelList,linspace(minval,maxval,10));
else
    Level2 = h2.LevelList;
end
contour(TCM_UI.ax,X,Y,f,union(Level1,Level2));
hold on
xlim([TCM_Data.plot_window(1) TCM_Data.plot_window(2)]);
ylim([TCM_Data.plot_window(3) TCM_Data.plot_window(4)]);
plot(TCM_UI.ax,TCM_Data.rect([1 2 2 1 1]),TCM_Data.rect([3 3 4 4 3]),'black',...
    'LineWidth',1);

x = linspace(TCM_Data.rect(1),TCM_Data.rect(2));
y = linspace(TCM_Data.rect(3),TCM_Data.rect(4));
plot3(TCM_UI.ax2,x,TCM_Data.rect(3)*ones(size(x)),TCM_Data.fun(x,TCM_Data.rect(3)*ones(size(x))),...
    'black','LineWidth',1);
plot3(TCM_UI.ax2,x,TCM_Data.rect(4)*ones(size(x)),TCM_Data.fun(x,TCM_Data.rect(4)*ones(size(x))),...
    'black','LineWidth',1);
plot3(TCM_UI.ax2,TCM_Data.rect(1)*ones(size(x)),y,TCM_Data.fun(TCM_Data.rect(1)*ones(size(x)),y),...
    'black','LineWidth',1);
plot3(TCM_UI.ax2,TCM_Data.rect(2)*ones(size(x)),y,TCM_Data.fun(TCM_Data.rect(2)*ones(size(x)),y),...
    'black','LineWidth',1);

type = TCM_UI.typepopup.Value;
if type == 1
    value = minval;
else
    value = maxval;
end
ind = find(abs(TCM_Data.fun(TCM_Data.extrema(1,:),TCM_Data.extrema(2,:))-value)<10^-6);

if TCM_Data.selected > numel(ind)
    TCM_Data.selected = 1;
end

plot(TCM_UI.ax,TCM_Data.extrema(1,ind),TCM_Data.extrema(2,ind),'ored','MarkerSize',7,'MarkerFaceColor','red');
scatter3(TCM_UI.ax2,TCM_Data.extrema(1,ind),TCM_Data.extrema(2,ind),value*ones(size(ind)),'red','filled');
plot(TCM_UI.ax,TCM_Data.extrema(1,ind(TCM_Data.selected)),TCM_Data.extrema(2,ind(TCM_Data.selected)),'oblack','MarkerSize',12,'LineWidth',1.5);
scatter3(TCM_UI.ax2,TCM_Data.extrema(1,ind(TCM_Data.selected)),TCM_Data.extrema(2,ind(TCM_Data.selected)),value,'black','filled');

TCM_UI.pointtext.String = sprintf('Marked Point: [%.3f,%.3f]',TCM_Data.extrema(1,ind(TCM_Data.selected)),TCM_Data.extrema(2,ind(TCM_Data.selected)));
TCM_UI.valuetext.String = sprintf('Functionvalue: %.3f',value);

SetWindowLimits;
end

% Update the Hinttext
function UpdateHinttext
LmbString = 'Left Mouse = Move boundaries. ';
if(numel(TCM_Data.LmbMenuString) == 0)
    set(TCM_UI.hinttext,'String',[LmbString 'Right Mouse = Access window menus.']);
else
    set(TCM_UI.hinttext,'String',[TCM_Data.LmbMenuString 'Right Mouse = Access window menus.']);
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% example functions %%%%%%%%%%%%%%%%%%%%%%%%%%%

function CreateExampleMenu
TCM_UI.UICexamples = uicontextmenu;
for i=1:numel(TCM_Data.examples)
    uimenu('Parent',TCM_UI.UICexamples,'Label',TCM_Data.examples{i},'Callback',{@changeexample,i});
end
end

function OpenExampleMenu(varargin)
TCM_UI.examples.Units = 'pixels';
TCM_UI.buttonspanel.Units = 'pixels';
TCM_UI.UICexamples.Position = TCM_UI.examples.Position(1:2) + TCM_UI.buttonspanel.Position(1:2);
TCM_UI.examples.Units = 'normalized';
TCM_UI.buttonspanel.Units = 'points';
TCM_UI.UICexamples.Visible = 'on';
end
 
              
function changeexample(varargin) 
switch varargin{numel(varargin)}      
    case 1
        set(TCM_UI.funinput,'String','@(x,y) -x.^2-3*y.^2');
        function_update; 
        TCM_UI.rectinput.String = '[-1 0.5 -1 0.5]';
        TCM_UI.typepopup.Value = 2;
        rectangle_update;
        view(TCM_UI.ax2,-37.5,30);
    case 2
        set(TCM_UI.funinput,'String','@(x,y) x.^3.*y-2*y.*x');
        function_update; 
        TCM_UI.rectinput.String = '[-1.3 1 -1 0.5]';
        TCM_UI.typepopup.Value = 1;
        rectangle_update;
        view(TCM_UI.ax2,34,21);
    case 3
        set(TCM_UI.funinput,'String','@(x,y) -2*x.^2+x.^4+y.^2');
        function_update; 
        TCM_UI.rectinput.String = '[-1 1 -1 1]';
        TCM_UI.typepopup.Value = 2;
        rectangle_update;
        view(TCM_UI.ax2,23,28);
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% zoom functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% function for updating the internal plot window
function zoom_modify(varargin)
if max(abs(TCM_Data.plot_window-axis(TCM_UI.ax)))< 10^-10
    ZoomOut;
end
pan_modify;
end

function pan_modify(varargin)
TCM_Data.plot_window = axis(TCM_UI.ax);
myplot;
end

% functions for proper zooming in (prevent double-click zoom out)
function [flag] = set_zoom_limits(varargin)
if(strcmp(TCM_UI.fig.SelectionType,'open'))
    flag = true;
else
    flag = false;
end
end

function reset_zoom_limits(varargin)
SetWindowLimits;
end

% handling the axis context menu
function axis_context(varargin)
zoom(TCM_UI.fig, 'off'); pan(TCM_UI.fig, 'off');
mode_strings = {'pan','zoom in','zoom out'};
status_strings = {'Enable ','Disable '};
switch varargin{1}.Label(1:7)
    case 'Enable '
        mode = strcmp(varargin{1}.Label(8:end),mode_strings);
        TCM_Data.LmbMenuString = ['Left Mouse = ' mode_strings{mode} ' the window. '];
        set(TCM_UI.mpan,'Label',horzcat(status_strings{mode(1)+1},mode_strings{1}));
        set(TCM_UI.mzoomi,'Label',horzcat(status_strings{mode(2)+1},mode_strings{2}));
        set(TCM_UI.mzoomo,'Label',horzcat(status_strings{mode(3)+1},mode_strings{3}));
        split_mode = strsplit(mode_strings{mode},' ');
        if numel(split_mode) == 1
            pan(TCM_UI.fig, 'on');
        else
            zoomh = zoom(TCM_UI.fig);
            zoomh.Enable = 'on';
            zoomh.Direction = split_mode{2};
        end
    case 'Disable'
        TCM_Data.LmbMenuString = '';
        set(TCM_UI.mpan,'Label','Enable pan');
        set(TCM_UI.mzoomi,'Label','Enable zoom in');
        set(TCM_UI.mzoomo,'Label','Enable zoom out');     
end
UpdateHinttext;
end

function axis2_context(varargin)
if strcmp(varargin{1}.Label,'Enable rotate')
    set(TCM_UI.rotate,'Label','Disable rotate');
    TCM_Data.LmbMenuString = 'Left Mouse = Rotate the Box. ';
    rotate3d(TCM_UI.ax2,'on');
else
    rotate3d(TCM_UI.ax2,'off');
    set(TCM_UI.rotate,'Label','Enable rotate');
    TCM_Data.LmbMenuString = '';
end
UpdateHinttext;
end

function SetWindowLimits
ZoomOut;
xlim(TCM_UI.ax,[TCM_Data.plot_window(1) TCM_Data.plot_window(2)]);
ylim(TCM_UI.ax,[TCM_Data.plot_window(3) TCM_Data.plot_window(4)]);
end

function ZoomOut
hx = TCM_Data.plot_window(2) - TCM_Data.plot_window(1);
hy = TCM_Data.plot_window(4) - TCM_Data.plot_window(3);
xlim(TCM_UI.ax,[TCM_Data.plot_window(1)-hx/2 TCM_Data.plot_window(2)+hx/2]);
ylim(TCM_UI.ax,[TCM_Data.plot_window(3)-hy/2 TCM_Data.plot_window(4)+hy/2]);
zoom(TCM_UI.fig, 'reset');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% layout functions %%%%%%%%%%%%%%%%%%%%%%%%%%%

% functions for creating the different UI-Parts and managing the resize of
% the window
function CreateUI
TCM_UI.fig = figure('Visible','off', 'Units','points','Toolbar','none',...
    'SizeChangedFcn',@calculate_layout, 'WindowButtonDownFcn',@myDownfct,'WindowButtonMotionFcn',...
    @myMovefct,'WindowButtonUpFcn',@myUpfct,'numbertitle','off','name',TCM_UI.Title);
TCM_UI.titletext = uicontrol('Units','points','BackgroundColor',TCM_UI.fig.Color, ...
	'HorizontalAlignment','center',  'FontWeight','bold', ...
    'FontUnits','normalized',        'FontSize',0.7,...
	'String',TCM_UI.Title,        'Style','text');
TCM_UI.hinttext = uicontrol('Units','points','BackgroundColor',TCM_UI.fig.Color, ...
    'HorizontalAlignment','right',...
    'FontUnits','normalized',        'FontSize',0.635,...
	'String','','Style','text');
TCM_UI.infobutton=uicontrol('Units','points', ...
	'BackgroundColor',TCM_UI.fig.Color, ...
	'String','Info', 'HorizontalAlignment','left',...
    'FontUnits','normalized','FontSize',0.7,...
	'Callback',@information,'Style','pushbutton');
TCM_UI.feedbackpanel = uipanel('Units','points','BackgroundColor',TCM_UI.fig.Color,'BorderType','none');
TCM_UI.buttonspanel = uipanel('Units','points','BackgroundColor',TCM_UI.fig.Color,'BorderType','none');
TCM_UI.settingspanel = uipanel('Units','points','BackgroundColor',TCM_UI.fig.Color,'BorderType','none');
TCM_UI.axispanel = uipanel('Units','points','BackgroundColor',TCM_UI.fig.Color,'BorderType','none');
CreateExampleMenu
TCM_UI.fig.Visible= 'on';
end


function calculate_layout(varargin) 
figpos = TCM_UI.fig.Position;
WMax = TCM_UI.SettingsHeightMax*(TCM_UI.SettingsRatio + TCM_UI.FeedbackRatio + TCM_UI.ButtonsRatio);
WMin = TCM_UI.SettingsHeightMin*(TCM_UI.SettingsRatio + TCM_UI.FeedbackRatio + TCM_UI.ButtonsRatio);
HMax = TCM_UI.TitleHeightMax + TCM_UI.HintHeightMax;
HMin = TCM_UI.TitleHeightMin + TCM_UI.HintHeightMin;

wratio = max(0,min(1,(min(figpos(3),1.3*figpos(4))-WMin)/(WMax-WMin)));
XCoords = [1,0,0,0,0,0,0,figpos(3)];
SWidth =      wratio*TCM_UI.SettingsHeightMax*TCM_UI.SettingsRatio...
        + (1-wratio)*TCM_UI.SettingsHeightMin*TCM_UI.SettingsRatio;
BWidth =      wratio*TCM_UI.SettingsHeightMax*TCM_UI.ButtonsRatio...
        + (1-wratio)*TCM_UI.SettingsHeightMin*TCM_UI.ButtonsRatio; 
FWidth =      wratio*TCM_UI.SettingsHeightMax*TCM_UI.FeedbackRatio...
        + (1-wratio)*TCM_UI.SettingsHeightMin*TCM_UI.FeedbackRatio; 
RemWidth = figpos(3)-3-SWidth-FWidth-BWidth;
XCoords(2) = max(1,0.3*RemWidth);
XCoords(3) = XCoords(2) + 1 + SWidth;
XCoords(4) = XCoords(3) + max(0,0.2*RemWidth);
XCoords(5) = XCoords(4) + 1 + BWidth;
XCoords(6) = XCoords(5) + max(0,0.2*RemWidth);
XCoords(7) = XCoords(6) + 1 + FWidth;
SHeight = wratio*TCM_UI.SettingsHeightMax + (1-wratio)*TCM_UI.SettingsHeightMin;
if(HMin > min(figpos(4),0.9*figpos(3))*(1-TCM_UI.AxisHeightTarget)-5-SHeight)
    hratio = 0;
elseif(HMax <  min(figpos(4),0.9*figpos(3))*(1-TCM_UI.AxisHeightTarget)-5-SHeight)
    hratio = 1;
else
    hratio = (( min(figpos(4),0.9*figpos(3))*(1-TCM_UI.AxisHeightTarget)-5-SHeight)  -HMin)/(HMax-HMin);
end
YCoords = [1,0,0,0,figpos(4)-1];
YCoords(2) = YCoords(1) + 1 + hratio*TCM_UI.HintHeightMax     + (1-hratio)*TCM_UI.HintHeightMin;
YCoords(4) = YCoords(5) - 1 - hratio*TCM_UI.TitleHeightMax    - (1-hratio)*TCM_UI.TitleHeightMin;
YCoords(3) = YCoords(4) - 1 - SHeight;
TCM_UI.titletext.Position =     [XCoords(1)+1,  YCoords(4)+1,  XCoords(8)-XCoords(1)-1,  YCoords(5)-YCoords(4)-1];
TCM_UI.settingspanel.Position = [XCoords(2)+1,  YCoords(3)+1,  XCoords(3)-XCoords(2)-1,  YCoords(4)-YCoords(3)-1];
TCM_UI.buttonspanel.Position =  [XCoords(4)+1,  YCoords(3)+1,  XCoords(5)-XCoords(4)-1,  YCoords(4)-YCoords(3)-1];
TCM_UI.feedbackpanel.Position = [XCoords(6)+1,  YCoords(3)+1,  XCoords(7)-XCoords(6)-1,  YCoords(4)-YCoords(3)-1];
TCM_UI.axispanel.Position =     [XCoords(1)+1,  YCoords(2)+1,  XCoords(8)-XCoords(1)-1,  max(0,YCoords(3)-YCoords(2)-1)];
TmpXCoord = TCM_UI.InfoPortion*(XCoords(8)-XCoords(1)-1);
TCM_UI.infobutton.Position =    [XCoords(1)+1,  YCoords(1)+1,  TmpXCoord-XCoords(1)-1,   YCoords(2)-YCoords(1)-1];
TCM_UI.hinttext.Position =      [TmpXCoord+1,   YCoords(1)+1,  XCoords(8)-TmpXCoord-1,   YCoords(2)-YCoords(1)-1];
end

% function for opening the information webpage
function information(varargin)
pos = TCM_UI.fig.OuterPosition;
infodialog = dialog('Name','Information','Units','points',...
    'OuterPosition',[pos(1)+pos(3)/4 pos(2)+pos(4)/4 pos(3)/2 pos(4)/2]);
uicontrol('Units','normalized', 'Parent',infodialog, ...
        'FontUnits','normalized', 'FontSize',0.67,...
        'HorizontalAlignment','center', 'Position',[.01,.6,.98,.15],...
	'String','Mathematics Online Link', 'Style','text',...
    'ForegroundColor','blue','ButtonDownFcn',@linkfun,...
    'Enable','inactive');
uicontrol('Units','normalized', 'Parent',infodialog, ...
        'FontUnits','normalized', 'FontSize',0.4,...
        'HorizontalAlignment','center', 'Position',[.01,.4,.98,.15],...
	'String',{horzcat('Created by ',TCM_UI.Author,'.');horzcat('Version: ',TCM_UI.Date)} , 'Style','text');
end

function linkfun(varargin)
web(TCM_UI.Web)
end
end
