changeset 6:0ce3c2070089

Removed duplicate code and fixed doc in timed_action.
author samer
date Mon, 14 Jan 2013 14:33:37 +0000
parents 8972a4071294
children 47cb292350f3
files general/algo/iterate_timed.m general/algo/iterate_timed2.m sched/rsched.m sched/timed_action.m
diffstat 4 files changed, 43 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/general/algo/iterate_timed.m	Sat Jan 12 22:32:08 2013 +0000
+++ b/general/algo/iterate_timed.m	Mon Jan 14 14:33:37 2013 +0000
@@ -1,126 +1,54 @@
-function api=iterate_timed(varargin)
+function Sched=iterate_timed(nextfn,X0,T,varargin)
 % iterate_timed - Iterate function under control of timer
 %
 % iterate_timed :: 
 %    (A=>A)          ~'state transformer action',
 %    A               ~'initial state',
-%    real            ~'timer between updates in seconds',
-%    options iterate_timed_options ~'options (see below)'
-% -> sched(A) ~'scheduler API'.
-%
-% iterate_timed :: 
-%    cell {
-%       (A=>A)          ~'state transformer action',
-%       A               ~'initial state'
-%    } ~'iterated system as a cell array',
-%    real            ~'timer between updates in seconds',
-%    options iterate_timed_options ~'options (see below)'
-% -> sched(A) ~'scheduler API'.
-%
-% iterate_timed_options = {
+%    real            ~'timer between updates in seconds'
+%    options {
 %       drawnow   :: {0,1} /0 ~'call drawnow after each iteration';
 %       busy_mode :: {'queue','drop'} /'queue'  ~'See TIMER';
 %       exec_mode :: {'fixedRate','fixedDelay','fixedSpacing'} /'fixedRate' ~'See TIMER';
 %       its       :: natural / inf ~'iteration limit';
-%       onstart   :: A->void / @nop ~'do this when timer starts';
-%       onstop    :: A->void / @nop ~'do this when timer stops';
-%       onfinish  :: A->void / @nop ~'do this when iterator terminates';
-%       pre       :: A->void / []  ~'something to do before each iteration';
-%       post      :: A->void / []  ~'something to do after each iteration';
-%       drawnow   :: bool / 0      ~'whether to update graphics every it';
+%       onstart   :: (A=>void)/ @nop ~'do this when timer starts';
+%       onstop    :: (A=>void)/ @nop ~'do this when timer stops';
+%       onfinish  :: (A=>void)/ @nop ~'do this when iterator terminates';
+%       pre       :: (A=>void)/ @nop ~'do before each iteration';
+%       post      :: (A=>void)/ @nop ~'do after each iteration';
 %       defer     :: bool / 0      ~'if true then don't start the timer';
-%       props     :: {[[_]]} / {}  ~'extra name/value pairs for timer'
-% }
+% -> timer, (A=>void) ~'function to seek to given state'.
 %
-% sched(A) ::= struct {
-%		dispose   :: void => void;
-%		isrunning :: void => bool;
-%		startat	 :: real => void;
-%		start		 :: void => void;
-%		stop		 :: void => void;
-%		rewind	 :: void => void;
-%		getstate	 :: void => A;
-%		setstate	 :: A    => void
-% }.
-%	
 % NB: Unlike ITERATE, this does NOT respect the id, save, and recover properties.
 % Neither does it respect the OPTPAUSE property 'pause'.
 
-	warning('off','MATLAB:TIMER:STARTDELAYPRECISION');
-	warning('off','MATLAB:TIMER:RATEPRECISION');
-
-	if iscell(varargin{1})
-		[nextfn,X0]=varargin{1}{:};
-		T=varargin{2};
-		options=varargin(3:end);
-	else
-		nextfn=varargin{1};
-		X0=varargin{2};
-		T=varargin{3};
-		options=varargin(4:end);
-	end
-
 	opts=prefs('its',inf,'drawnow',0, 'quiet', 0, 'defer', 0, ...
 		'busy_mode','queue','exec_mode','fixedRate', ...
-		'onfinish',@nop,'onstart',@nop,'onstop',@nop,options{:});
+		'onfinish',@nop,'onstart',@nop,'onstop',@nop,varargin{:});
+
+	it={nextfn,X0}; 
+	if isfield(opts,'pre') || isfield(opts,'post')
+		it=bracket_it(it, getparam(opts,'pre',@nop), getparam(opts,'post',@nop));
+	end
+	if opts.drawnow, it=drawnow_it(it); end
+	stfn=it{1};
 	
-	X=X0; %% !!! NB: this is a mutable shared local variable used by timercb
+	Sched=rsched(@action,it{2},T,nows,opts,'defer',1,...
+			'onstart',@onstart,'onstop',@onstop,'onfinish',@onfinish);
+	if ~opts.defer, Sched.start(); end
 
-	if ~isfield(opts,'pre') && ~isfield(opts,'post') && ~opts.drawnow
-		stfn=nextfn; % streamlined version with no checks
-	else % version with calls to pre,post, and drawnow
-		prefn=getparam(opts,'pre',@nop);
-		postfn=getparam(opts,'post',@nop);
-		stfn=@bracket;
-	end
-	
-	tm=timer('ExecutionMode',opts.exec_mode,'BusyMode',opts.busy_mode, ...
-			'TimerFcn',@timercb,'StartFcn',@startfn,'StopFcn',@stopfn, ...
-			'TasksToExecute',opts.its,'Period',T);
-
-	api=struct( ...
-		'dispose',  @()delete(tm), ...
-		'isrunning',@()isrunning(tm), ...
-		'startat',	@(t)startat(tm,t/86400), ...
-		'start',		@()start(tm), ...
-		'stop',		@()stop(tm), ...
-		'rewind',	@()setstate(X0), ...
-		'getstate',	@getstate, ...
-		'setstate',	@setstate ...
-	);
-
-	if ~opts.defer, start(tm); end
-
-	function setstate(x), X=x; end
-	function x=getstate,  x=X; end
-
-	function X=bracket(X), 
-		prefn(X); X=nextfn(X); postfn(X); 
-		if opts.drawnow, drawnow; end
-	end
-
-	function startfn(tm,a)
-		if ~opts.quiet, status(tm,'starting',X,a.Data.time); end 
-		opts.onstart(X); 
-	end
-
-	function stopfn(tm,a)
-		if ~opts.quiet, status(tm,'stopping',X,a.Data.time); end 
-		opts.onstop(X); 
-		if isempty(X), 
-			if ~opts.quiet, status(tm,'finished',X,a.Data.time); end 
-			opts.onfinish(X); 
+	function [err,s]=action(t_sched,dt,s), err=nows-t_sched; s=stfn(s); end
+	function onstart(X,t_sched,t_actual), status('starting',X,t_actual); opts.onstart(X); end
+	function onstop(X,t_actual), status('stopping',X,t_actual); opts.onstop(X); end
+	function onfinish(t_actual), status('finishing',[],t_actual); opts.onfinish(); end
+	function status(msg,x,t),
+		if ~opts.quiet
+			fprintf('| %s at %s with %s\n',msg,mat2str(t),tostring(x)); 
 		end
 	end
-
-	% well, we have mutable variables captured by closure so we may 
-	% as well use them...
-	function timercb(tm,ev)
-		if isempty(X), stop(tm); else, X=stfn(X); end
-	end
 end
 
-function status(tm,msg,x,t),
-	fprintf('| %s %s at %s with %s\n',get(tm,'name'),msg,mat2str(t),tostring(x)); 
+function it=drawnow_it(it), 
+	f=it{1}; it{1}=@fdraw;
+	function x=fdraw(x), x=f(x); drawnow; end
 end
 
--- a/general/algo/iterate_timed2.m	Sat Jan 12 22:32:08 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-function Sched=iterate_timed(nextfn,X0,T,varargin)
-% iterate_timed - Iterate function under control of timer
-%
-% iterate_timed :: 
-%    (A=>A)          ~'state transformer action',
-%    A               ~'initial state',
-%    real            ~'timer between updates in seconds'
-%    options {
-%       drawnow   :: {0,1} /0 ~'call drawnow after each iteration';
-%       busy_mode :: {'queue','drop'} /'queue'  ~'See TIMER';
-%       exec_mode :: {'fixedRate','fixedDelay','fixedSpacing'} /'fixedRate' ~'See TIMER';
-%       its       :: natural / inf ~'iteration limit';
-%       onstart   :: (A=>void)/ @nop ~'do this when timer starts';
-%       onstop    :: (A=>void)/ @nop ~'do this when timer stops';
-%       onfinish  :: (A=>void)/ @nop ~'do this when iterator terminates';
-%       pre       :: (A=>void)/ @nop ~'do before each iteration';
-%       post      :: (A=>void)/ @nop ~'do after each iteration';
-%       defer     :: bool / 0      ~'if true then don't start the timer';
-% -> timer, (A=>void) ~'function to seek to given state'.
-%
-% NB: Unlike ITERATE, this does NOT respect the id, save, and recover properties.
-% Neither does it respect the OPTPAUSE property 'pause'.
-
-	opts=prefs('its',inf,'drawnow',0, 'quiet', 0, 'defer', 0, ...
-		'busy_mode','queue','exec_mode','fixedRate', ...
-		'onfinish',@nop,'onstart',@nop,'onstop',@nop,varargin{:});
-
-	if ~isfield(opts,'pre') && ~isfield(opts,'post') && ~opts.drawnow
-		stfn=nextfn; % streamlined version with no checks
-	else % version with calls to pre,post, and drawnow
-		prefn=getparam(opts,'pre',@nop);
-		postfn=getparam(opts,'post',@nop);
-		stfn=@bracket;
-	end
-	
-	Sched=rsched(@schedfn,X0,T,0,opts,'defer',1, ...
-			'onstart',@onstart,'onstop',@onstop,'onfinish',@onfinish);
-
-	if ~opts.defer, Sched.start(); end
-
-	function [s,t_sched]=schedfn(s,dt,t_sched,t_actual), s=stfn(s); end
-
-	function X=bracket(X), 
-		prefn(X); X=nextfn(X); postfn(X); 
-		if opts.drawnow, drawnow; end
-	end
-
-	function onfinish(X,t_actual), opts.onfinish(X); end
-
-	function onstart(X,t_sched,t_actual)
-		if ~opts.quiet, status('starting',X,t_actual); end
-		opts.onstart(X); 
-	end
-
-	function onstop(X,t_actual)
-		if ~opts.quiet, status('stopping',X,t_actual); end
-		opts.onstop(X); 
-	end
-end
-
-function status(msg,x,t),
-	fprintf('| %s at %s with %s\n',msg,mat2str(t),tostring(x)); 
-end
-
-
--- a/sched/rsched.m	Sat Jan 12 22:32:08 2013 +0000
+++ b/sched/rsched.m	Mon Jan 14 14:33:37 2013 +0000
@@ -13,17 +13,17 @@
 %
 %       onstart :: (
 %             S       ~'current state', 
-%             real    ~'scheduled start time'
-%             datenum ~'actual time'
+%             real    ~'scheduled start time',
+%             datenum ~'actual start date-stamp'
 %          => void)/@nop ~ 'called on timer start';
 %
 %       onstop  :: (
 %             S       ~'current state',
-%             datenum ~'actual time' %          => void)/@nop ~ 'called on timer stop';
+%             datenum ~'actual start date-stamp'
+%          => void)/@nop ~ 'called on timer stop';
 %
 %       onfinish:: (
-%             S       ~'final state', 
-%             datanum ~'actual time'
+%             datenum ~'actual start date-stamp'
 %          => void)/@nop ~ 'called if state seq finishes';
 %
 %       busy_mode :: {'queue','drop'};
@@ -76,8 +76,8 @@
 		'getstate',	@getstate, ...
 		'setstate',	@setstate, ...
 		'trim',   	@trim, ...
-		'timer',    @()Timer ...
-		'wait',     @sched_wait
+		'timer',    @()Timer, ...
+		'wait',     @sched_wait ...
 	);
 	
 	if opts.final, api.finalstate=@()FinalState; end
@@ -112,9 +112,7 @@
 
 	function stopfn(o,e), 
 		opts.onstop(State,e.Data.time); 
-		if isempty(State), 
-			opts.onfinish(State,e.Data.time); 
-		end
+		if isempty(State), opts.onfinish(e.Data.time); end
 	end
 
 	function startfn(o,e)
@@ -140,3 +138,4 @@
 	function sched_wait
 		while Timer.isrunning(); pause(0.05); end
 	end
+end
--- a/sched/timed_action.m	Sat Jan 12 22:32:08 2013 +0000
+++ b/sched/timed_action.m	Mon Jan 14 14:33:37 2013 +0000
@@ -2,6 +2,10 @@
 %
 % timed_action :: 
 %    (A1, A2, ... => B1, B2, ...) ~'some action',
+%    options {
+%       print   :: bool/false     ~'if true, then print timing error on action';
+%       errorfn :: (time => real) ~'action to compute timing error from scheduled time'
+%    }
 % -> timed_action({A1,A2,...},{B1,B2,...}).
 function a0=timed_action(x,varargin)
 	opts=prefs('print',0,'errorfn',@(t)nows-t,varargin{:});