diff --git a/API/events/eventManager.m b/API/events/eventManager.m index 28155865b..37243a033 100644 --- a/API/events/eventManager.m +++ b/API/events/eventManager.m @@ -26,6 +26,8 @@ function setEvents(value) persistent events if isempty(events) + % Events are stored in a 3 column cell containing the ID, + % event type and callback for the event. events = cell(0, 3); end @@ -36,6 +38,15 @@ function setEvents(value) value = events; end + function state=hasEvent(event_type) + + state = false; + events = eventManager.getEvents(); + if any(find([events{:, 2}] == event_type, 1)) + state = true; + end + end + function funcID = getCallbackID(callback) % Generates a id for a callback handle function % diff --git a/API/events/hasPlotHandler.m b/API/events/hasPlotHandler.m new file mode 100644 index 000000000..10b56fa9d --- /dev/null +++ b/API/events/hasPlotHandler.m @@ -0,0 +1,32 @@ +function state = hasPlotHandler() + % Checks if a function is listening for the plot event + % + % state = hasPlotHandler(); + persistent helper; + + initialised = false; + state = false; + coder.extrinsic('eventManager.hasEvent') + if coder.target('MATLAB') || coder.target('MEX') + if eventManager.hasEvent(coderEnums.eventTypes.Plot) + state = true; + end + else + coder.cinclude('eventHelper.hpp'); + coder.updateBuildInfo('addLinkFlags','-ldl'); + if isempty(helper) + % Declaration for coder + helper = coder.opaque('eventHelper','NULL','HeaderFile','eventHelper.hpp'); + + % Make an instance + helper = coder.ceval('eventHelper'); + path = [getenv('RAT_PATH'), 0]; + coder.ceval('std::mem_fn(&eventHelper::init)', helper, path); + end + + initialised = coder.ceval('std::mem_fn(&eventHelper::isInitialised)', helper); + if initialised + state = coder.ceval('std::mem_fn(&eventHelper::hasPlotHandler)', helper); + end + end +end diff --git a/API/events/triggerEvent.m b/API/events/triggerEvent.m index 4e458be4a..7fe8ecd49 100644 --- a/API/events/triggerEvent.m +++ b/API/events/triggerEvent.m @@ -60,11 +60,6 @@ function triggerEvent(eventType, varargin) elseif eventType == coderEnums.eventTypes.Progress coder.ceval('std::mem_fn(&eventHelper::updateProgress)', helper, [varargin{1},0], varargin{2}); elseif eventType == coderEnums.eventTypes.Plot - hasPlotHandler = coder.ceval('std::mem_fn(&eventHelper::hasPlotHandler)', helper); - if ~hasPlotHandler - return; - end - result = varargin{1}; problemStruct = varargin{2}; subRoughs = result.contrastParams.subRoughs; diff --git a/cppDeploy.m b/cppDeploy.m index acaf49d54..25fa0678d 100644 --- a/cppDeploy.m +++ b/cppDeploy.m @@ -12,5 +12,5 @@ % Clean up delete 'compile/fullCompile/deploy.zip' 'compile/fullCompile/cppDeploy/buildInfo.mat'... - 'compile/fullCompile/cppDeploy/rtw_proj.tmw' 'compile/fullCompile/cppDeploy/defines.txt' - 'compile/fullCompile/cppDeploy/RATMain.a'; + 'compile/fullCompile/cppDeploy/rtw_proj.tmw' 'compile/fullCompile/cppDeploy/defines.txt'... + 'compile/fullCompile/cppDeploy/RATMain.a' 'compile/fullCompile/cppDeploy/RATMain.lib'; diff --git a/minimisers/DE/deopt.m b/minimisers/DE/deopt.m index a49e9e708..026cd8a34 100644 --- a/minimisers/DE/deopt.m +++ b/minimisers/DE/deopt.m @@ -112,6 +112,8 @@ I_refresh = S_struct.I_refresh; I_plotting = S_struct.I_plotting; +doPlotEvent = hasPlotHandler(); + %-----Check input variables--------------------------------------------- if (I_NP < 5) I_NP=5; @@ -343,8 +345,10 @@ end % Trigger the output event... - if rem(I_iter, controls.updatePlotFreq) == 0 + if doPlotEvent && rem(I_iter, controls.updatePlotFreq) == 0 + controls.calcSLD = true; [~,result] = fname(FVr_bestmem,problem,controls); + controls.calcSLD = false; triggerEvent(coderEnums.eventTypes.Plot, result, problem); end @@ -366,9 +370,11 @@ triggerEvent(coderEnums.eventTypes.Message, ... sprintf('Iteration: %g, Best: %f, fWeight: %f, F_CR: %f, I_NP: %g\n\n', I_iter-1,S_bestval.FVr_oa(1),fWeight,F_CR,I_NP)); end -if rem(I_iter-1, controls.updatePlotFreq) ~= 0 +if doPlotEvent && rem(I_iter-1, controls.updatePlotFreq) ~= 0 % This should ensure the final result is always plotted irrespective of update frequency + controls.calcSLD = true; [~,result] = fname(FVr_bestmem,problem,controls); + controls.calcSLD = false; triggerEvent(coderEnums.eventTypes.Plot, result, problem); end end diff --git a/minimisers/simplex/fMinSearch.m b/minimisers/simplex/fMinSearch.m index 2df5cd6ae..d843d86c2 100644 --- a/minimisers/simplex/fMinSearch.m +++ b/minimisers/simplex/fMinSearch.m @@ -63,7 +63,6 @@ tolf = optimget(options,'TolFun',defaultopt,'fast'); maxfun = optimget(options,'MaxFunEvals',defaultopt,'fast'); maxiter = optimget(options,'MaxIter',defaultopt,'fast'); -funValCheck = strcmp(optimget(options,'FunValCheck',defaultopt,'fast'),'on'); switch dis % Changed from TMW fminsearch case {'notify','notify-detailed'} @@ -85,20 +84,10 @@ % Convert to function handle as needed. % funfcn = fcnchk(funfcn,length(varargin)); % Add a wrapper function to check for Inf/NaN/complex values -controls = varargin{2}; problemStruct = varargin{1}; -if funValCheck - % Add a wrapper function, CHECKFUN, to check for NaN/complex values without - % having to change the calls that look like this: - % f = funfcn(x,varargin{:}); - % x is the first argument to CHECKFUN, then the user's function, - % then the elements of varargin. To accomplish this we need to add the - % user's function to the beginning of varargin, and change funfcn to be - % CHECKFUN. - varargin = [{funfcn}, varargin]; - funfcn = @checkfun; -end -% +controls = varargin{2}; +params = varargin{3}; +doPlotEvent = hasPlotHandler(); n = numel(x); % Initialize parameters @@ -112,7 +101,11 @@ v = zeros(n,n+1); fv = zeros(1,n+1); v(:,1) = xin; % Place input guess in the simplex! (credit L.Pfeffer at Stanford) x(:) = xin; % Change x to the form expected by funfcn -[fv(:,1), result] = funfcn(x,varargin{:}); +if doPlotEvent + controls.calcSLD = true; +end +[fv(:,1), result] = funfcn(x, problemStruct, controls, params); +controls.calcSLD = false; func_evals = 1; itercount = 0; coder.varsize('how',[1 Inf],[0 1]); @@ -164,7 +157,9 @@ % fprintf('%g \n', func_evals) end -triggerEvent(coderEnums.eventTypes.Plot, result, problemStruct); +if doPlotEvent + triggerEvent(coderEnums.eventTypes.Plot, result, problemStruct); +end % OutputFcn and PlotFcns call % if haveoutputfcn || haveplotfcn @@ -191,10 +186,13 @@ y(j) = zero_term_delta; end v(:,j+1) = y; - x(:) = y; [f, result] = funfcn(x,varargin{:}); + if doPlotEvent && j==n + controls.calcSLD = true; + end + x(:) = y; [f, result] = funfcn(x, problemStruct, controls, params); fv(1,j+1) = f; end - +controls.calcSLD = false; % sort so v(1,:) has the lowest function value [fv,j] = sort(fv); v = v(:,j); @@ -215,7 +213,7 @@ % fprintf('%s \n', 'func_evals = ') % fprintf('%g \n', func_evals) end -if rem(itercount, controls.updatePlotFreq) == 0 +if doPlotEvent && rem(itercount, controls.updatePlotFreq) == 0 triggerEvent(coderEnums.eventTypes.Plot, result, problemStruct); end if isRATStopped(controls.IPCFilePath) @@ -247,6 +245,9 @@ % The iteration stops if the maximum number of iterations or function evaluations % are exceeded while func_evals < maxfun && itercount < maxiter + if doPlotEvent + controls.calcSLD = true; + end if max(abs(fv(1)-fv(2:n+1))) <= max(tolf,10*eps(fv(1))) && ... max(max(abs(v(:,2:n+1)-v(:,onesn)))) <= max(tolx,10*eps(max(v(:,1)))) break @@ -257,13 +258,14 @@ % xbar = average of the n (NOT n+1) best points xbar = sum(v(:,1:n), 2)/n; xr = (1 + rho)*xbar - rho*v(:,end); - x(:) = xr; [fxr, result] = funfcn(x,varargin{:}); + x(:) = xr; [fxr, result] = funfcn(x, problemStruct, controls, params); func_evals = func_evals+1; if fxr < fv(:,1) % Calculate the expansion point xe = (1 + rho*chi)*xbar - rho*chi*v(:,end); - x(:) = xe; [fxe, result] = funfcn(x,varargin{:}); + + x(:) = xe; [fxe, result] = funfcn(x, problemStruct, controls, params); func_evals = func_evals+1; if fxe < fxr v(:,end) = xe; @@ -284,7 +286,7 @@ if fxr < fv(:,end) % Perform an outside contraction xc = (1 + psi*rho)*xbar - psi*rho*v(:,end); - x(:) = xc; [fxc, result] = funfcn(x,varargin{:}); + x(:) = xc; [fxc, result] = funfcn(x, problemStruct, controls, params); func_evals = func_evals+1; if fxc <= fxr @@ -298,7 +300,7 @@ else % Perform an inside contraction xcc = (1-psi)*xbar + psi*v(:,end); - x(:) = xcc; [fxcc, result] = funfcn(x,varargin{:}); + x(:) = xcc; [fxcc, result] = funfcn(x, problemStruct, controls, params); func_evals = func_evals+1; if fxcc < fv(:,end) @@ -313,7 +315,7 @@ if strcmp(how,'shrink') for j=2:n+1 v(:,j)=v(:,1)+sigma*(v(:,j) - v(:,1)); - x(:) = v(:,j); [fv(:,j), result] = funfcn(x,varargin{:}); + x(:) = v(:,j); [fv(:,j), result] = funfcn(x, problemStruct, controls, params); end func_evals = func_evals + n; end @@ -334,7 +336,8 @@ % fprintf('%s \n', 'func_evals = ') % fprintf('%s \n', num2str(func_evals)) end - if rem(itercount, controls.updatePlotFreq) == 0 + controls.calcSLD = false; + if doPlotEvent && rem(itercount, controls.updatePlotFreq) == 0 triggerEvent(coderEnums.eventTypes.Plot, result, problemStruct); end if isRATStopped(controls.IPCFilePath) @@ -362,7 +365,7 @@ % This should ensure the final result is printed at the end of a run irrespective of update frequency triggerEvent(coderEnums.eventTypes.Message, sprintf(' %5.0f %5.0f %12.6g %s\n', itercount, func_evals, fv(1), how)); end -if rem(itercount, controls.updatePlotFreq) ~= 0 +if doPlotEvent && rem(itercount, controls.updatePlotFreq) ~= 0 % This should ensure the final result is always plotted irrespective of update frequency triggerEvent(coderEnums.eventTypes.Plot, result, problemStruct); end