function demo_weierstrass_approximation
% plots Bernstein approximations to a function 
% and computes the error

% Initialize data
global AMB_Data;
AMB_data=[];
AMB_Data.npts = 257;  
AMB_Data.Fun = @(x) sqrt(x).*abs(x-1/2);  
AMB_Data.Funstring = '@(x) sqrt(x).*abs(x-1/2)';  
AMB_Data.error = inf;
AMB_Data.errorbound = 0.1;
AMB_Data.degree = 1;  

% Initialize GUI
clf reset;

% Text for Title
uicontrol('Units','normalized', ...
  	'BackgroundColor',get(gcf,'Color'), ...
	'HorizontalAlignment','center', ...
        'FontWeight','bold',...
        'FontSize',20,...
	'Position',[.05,.92,.9,.07],...
	'String','Weierstrass Approximation Theorem',...
	'Style','text');

% Text for Function
uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontWeight','bold',...
        'HorizontalAlignment','left', ...
	'Position',[.05,.85,.3,.05],...
	'String','Function:',...
	'Style','text');

% Input for Function
AMB_Data.uicontrols(1)=uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'FontWeight','bold',...
        'HorizontalAlignment','left', ...
	'Position',[.2,.85,.4,.05],...
	'String',sprintf('%s',AMB_Data.Funstring),...
	'Style','edit',...
	'Callback',@function_update);

% Text for Degree
AMB_Data.uicontrols(2)=uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
	'Position',[.05,0,.2,.05],...
	'String',sprintf('Degree: %3d',AMB_Data.degree),...
	'Style','text');

% Text for Errorbound
uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
	'Position',[.05,.8,.2,.05],...
	'String','Error bound:',...
	'Style','text');

% Input for Errorbound
AMB_Data.uicontrols(3)=uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
	'Position',[.2,.8,.15,.05],...
	'String',sprintf('%5.3f',AMB_Data.errorbound),...
	'Style','edit',...
	'Callback',@errorbound_update);

% Text for Error
AMB_Data.uicontrols(4)=uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
	'Position',[.3,0,.3,.05],...
	'String',sprintf('Error: %5.3f',AMB_Data.error),...
	'Style','text');

% Next-Button
AMB_Data.uicontrols(5)=uicontrol('Units','normalized', ...
	'BackgroundColor',get(gcf,'Color'), ...
	'String','Next', ...
	'Position',[.85,.8,.1,.05], ...
	'Callback',@nextstep,...
	'Style','pushbutton');

% Restart-Button
uicontrol('Units','normalized', ...
	'BackgroundColor',get(gcf,'Color'), ...
	'String','Restart', ...
	'Position',[.85,.85,.1,.05], ...
	'Callback',@restart,...
	'Style','pushbutton');


% Text for Errorbound reached
AMB_Data.uicontrols(6)=uicontrol('Units','normalized', ...
        'BackgroundColor',get(gcf,'Color'), ...
        'HorizontalAlignment','left', ...
        'FontWeight','bold', ...
        'ForegroundColor','red', ...
	'Position',[.4,.8,.3,.05],...
	'String','Error bound reached',...
        'visible','off',...
	'Style','text');


% Axis for Function display
AMB_Data.axis(1)=subplot('position',[.05,.1,.9,.65]);

% Display first approximation
myplot;

%%%  Callback Functions %%%

% new function input
function function_update(varargin)
global AMB_Data;
AMB_Data.Funstring = get(AMB_Data.uicontrols(1),'String');
AMB_Data.Fun= eval(AMB_Data.Funstring);
restart;

% new errorbound input
function errorbound_update(varargin)
global AMB_Data;
AMB_Data.errorbound = str2double(get(AMB_Data.uicontrols(3),'String'));
myplot;

% button next pressed
function nextstep(varargin)
global AMB_Data;
if AMB_Data.error <  AMB_Data.errorbound return,end 
AMB_Data.degree = AMB_Data.degree+1;
myplot;

% button restart pressed
function restart(varargin)
global AMB_Data;
AMB_Data.degree=1;
AMB_Data.error=inf;
myplot;

%%% Internal Functions %%%
function myplot

global AMB_Data;
subplot(AMB_Data.axis(1))
cla;hold on
% display actual degree
set(AMB_Data.uicontrols(2),'String',sprintf('Degree: %3d',AMB_Data.degree));

% compute Bernstein approximation 
x = [0:AMB_Data.npts-1]'/(AMB_Data.npts-1); y = AMB_Data.Fun(x);
xn = [0:AMB_Data.degree]'/AMB_Data.degree; fxn = AMB_Data.Fun(xn);
b = bernstein(AMB_Data.degree,x);
p= b*fxn;  

% plot function and visualize prescribed tolerance
fill([x;x(end:-1:1)],[y-AMB_Data.errorbound; y(end:-1:1)+AMB_Data.errorbound],...
     [195,195,230]/255,'facealpha',1)
plot(x,y,'-','linewidth',2,'color',[0,0,.6]) 

% plot Bernstein approximation 
plot(x,p,'k-',xn,fxn,'ko');

% display error and check for bound
AMB_Data.error = norm(y-p,inf);
set(AMB_Data.uicontrols(4),'String',sprintf('Error: %5.3f',AMB_Data.error));
if AMB_Data.error <  AMB_Data.errorbound 
  set(AMB_Data.uicontrols(6),'visible','on');
  set(AMB_Data.uicontrols(5),'enable','off');
else
  set(AMB_Data.uicontrols(6),'visible','off');
  set(AMB_Data.uicontrols(5),'enable','on');
end 

%%% Functions from AMB_Programs (included for standalone use) %%% 

function b = bernstein(n,t)
% BERNSTEIN: Bernstein polynomials
% b = bernstein(n,t)
% values b(j,k) of b^n_{k-1} at t(j)

% initialization for degree 0 
b = zeros(length(t),2*n+1); 
b(:,n+1) = 1;

% recursion for Bernstein polynomials
for k=1:n
   tk = repmat(t,1,2*n+1-k);
   b = (1-tk).*b(:,2:end) + tk.*b(:,1:end-1);
end
