Mercurial > hg > ishara
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{:});