From 245d8892ef7b32126fc6cc5a3991608df02c2100 Mon Sep 17 00:00:00 2001 From: Marcel Kronfeld Date: Tue, 9 Dec 2008 15:18:54 +0000 Subject: [PATCH] Updates to the OptimizerFactory and the MatlabInterface. Better access to EvAClient. --- .../@JEInterface/JEInterface.m | 80 ++++--- .../MatlabInterface/@JEInterface/getOpt.m | 2 +- .../@JEInterface/makeOptions.m | 65 ++++++ .../MatlabInterface/@JEInterface/optimize.m | 7 +- .../MatlabInterface/@JEInterface/setOpt.m | 8 +- .../MatlabInterface/@JEInterface/setOptions.m | 24 +- .../MatlabInterface/@JEInterface/setVerbose.m | 24 ++ .../@JEInterface/testEvalFunc.m | 56 +++++ src/eva2/EvAInfo.java | 2 + src/eva2/OptimizerFactory.java | 220 ++++++++++++------ src/eva2/OptimizerRunnable.java | 6 + .../go/problems/MatlabEvalMediator.java | 22 +- .../server/go/problems/MatlabProblem.java | 39 +++- .../go/problems/WaitForEvARunnable.java | 11 +- .../go/strategies/ClusterBasedNichingEA.java | 12 +- 15 files changed, 433 insertions(+), 145 deletions(-) create mode 100644 resources/MatlabInterface/@JEInterface/makeOptions.m create mode 100644 resources/MatlabInterface/@JEInterface/setVerbose.m create mode 100644 resources/MatlabInterface/@JEInterface/testEvalFunc.m diff --git a/resources/MatlabInterface/@JEInterface/JEInterface.m b/resources/MatlabInterface/@JEInterface/JEInterface.m index 4040928e..06076d81 100644 --- a/resources/MatlabInterface/@JEInterface/JEInterface.m +++ b/resources/MatlabInterface/@JEInterface/JEInterface.m @@ -1,41 +1,46 @@ -function int = JEInterface(interfaceName, fhandle, range, varargin) +function int = JEInterface(fhandle, range, varargin) % EvA2 Interface for Matlab -% JEInterface(interfaceName, fhandle, range [, optset, defaultargs]) +% JEInterface(interfaceName, fhandle, range) +% JEInterface(interfaceName, fhandle, range, defaultargs) +% JEInterface(interfaceName, fhandle, range, defaultargs, options...) + + % arguments: -% interfaceName: a JEInterface instance needs to know its own -% name as a String to allow callbacks from Java. % fhandle: a function handle defining the optimization target. % range: a 2 x dim array defining the solution subspace with lower and -% upper bounds - or a scalar defining the bitwidth for binary problems. -% optset: (optional) an optimset struct defining optimization parameters, -% especially tolerance and maximum function calls. Defaults to the -% EvA2 default values. +% upper bounds - or a scalar defining the bitwidth for binary +% problems. % defaultArgs: (optional) additional constant argument to the target % function, empty by default. -% Recognized options are: +% options: (optional) options as name-value pairs defining optimization parameters, +% especially tolerance and maximum function calls. +% Check makeOoptions for default settings. + +% Further options may be specified using setOptions with a JE options struct. +% Main options are: % TolX: convergence criterion in the solution space % TolFun: convergence criterion in the target space % MaxFunEvals: maximum number of function evaluations % Display: 'off'/'final'/'notify'/'iter', where 'notify' corresponds to -% displaying every k-th iteration, which k=10 as default. +% displaying every k-th iteration, with k=10 as default. % The termination criterion of a run is a combination of the TolX, TolFun and % MaxFunEvals criteria. The run terminates if MaxFunEvals has been reached % or the best solution changes both in domain and codomain less than TolX -% and TolFun for a certain time, e.g. 100 evaluations. +% and TolFun for a certain number of evaluations, which may be set using +% TolXEvals and TolFunEvals, respectively. % To ignore a criterion, set it to 0. E.g. to perform 10^5 evaluations in % any case, set TolX=TolFun=0 and MaxFunEvals=10^5. % -% You may define a 2xdim range with a double valued function handle or for +% Define a 2 x dim range with a double valued function, or for % binary problems set a scalar as range defining the number of bits to be % used. The values passed to the function handle will then be arrays of % uint32, each of them representing 32 bits. int.args = []; -int.opts = optimset('MaxFunEvals', eva2.OptimizerFactory.getDefaultFitCalls, 'TolX', 1e-4, 'TolFun', 1e-4); +int.opts = []; int.finished = 1; int.result = []; int.resultArr = []; -int.callback=''; int.f = ''; int.dim = 0; int.range = []; @@ -47,50 +52,51 @@ int.optParams = []; int.optParamValues = []; int.hexMask=hex2dec('ffffffff'); -if (isa(interfaceName, 'char')); - int.callback = interfaceName; -else - error('Wrong first argument type, expected char'); -end if (isa(fhandle, 'function_handle')) int.f = fhandle; else error('Wrong second argument type, expected function_handle'); end +disp('Setting up JEInterface...'); if (isa(range, 'double') && (size(range,1) == 2)) - int.dim=size(range, 2); + int.dim=size(range,2); int.range=transpose(range); + s = sprintf('Double valued search space, dimension: %d', int.dim); + disp(s); else - %error('Wrong third argument type, expected double array of 2 x dim'); - if (size(range,1)==size(range,2)==1) + if (length(range)==1) int.range=[]; int.dim=range; + s = sprintf('Binary valued search space, dimension: %d', int.dim); + disp(s); + else + error('Wrong third argument type, expected double array of 2 x dim (double ranges) or scalar (binary bit width).'); end end int = class(int,'JEInterface'); +int.opts = makeOptions(int); -switch nargin - case {3} - case {4,5} - if (isa(varargin{1}, 'struct')) - int.opts = varargin{1}; - % DONT set default values if user leaves them blank -% if (isempty(int.opts.TolX)) ; int.opts.TolX = 1e-4; end -% if (isempty(int.opts.TolFun)) ; int.opts.TolFun = 1e-4; end - else - error('Wrong fifth argument type, expected optimset struct'); +if (nargin>2) + int.args = varargin{1}; + disp('Fitness function argument: '); disp(int.args); + if (nargin > 3) + if (rem(nargin,2)==0) + error('Invalid number of arguments!'); end - if (nargin > 4) - int.args = varargin{2}; + disp('Reading options...'); + for i=2:2:nargin-2 + int=setOpt(int, varargin{i}, varargin{i+1}); end - otherwise - error('Wrong number of arguments!') -end + end +end % finally create the java object int.mp = eva2.server.go.problems.MatlabProblem(int.dim, int.range); +disp('Java object created'); + +testEvalFunc(int); diff --git a/resources/MatlabInterface/@JEInterface/getOpt.m b/resources/MatlabInterface/@JEInterface/getOpt.m index fc0b24ae..71bb5c01 100644 --- a/resources/MatlabInterface/@JEInterface/getOpt.m +++ b/resources/MatlabInterface/@JEInterface/getOpt.m @@ -5,4 +5,4 @@ function val = getOpt(int, optName) % optName: name of the option to change, e.g. 'MaxFunEvals' % optVal: new value -val = optimget(int.opts, optName); \ No newline at end of file +val = int.opts.(optName); \ No newline at end of file diff --git a/resources/MatlabInterface/@JEInterface/makeOptions.m b/resources/MatlabInterface/@JEInterface/makeOptions.m new file mode 100644 index 00000000..c0b7e65d --- /dev/null +++ b/resources/MatlabInterface/@JEInterface/makeOptions.m @@ -0,0 +1,65 @@ +function opts = makeOptions(int, varargin) +% Create a JEInterface options set from scratch. Possible fields are: +%'Display'; +%'MaxFunEvals';'MaxIter';'TolFun';'TolFunEvals';TolX';'TolXEvals', where +% all but 'TolFunEvals', 'TolXEvals' are used similar to the optimset. +% The latter two are interpreted as the numbers of evaluations required +% to assume convergence. Default values are TolXEvals=TolFunEvals=200, +% TolX=TolFun=1e-4, MaxFunEvals uses a default from EvA2. +% Notice that this method creates a parameter set but does not assign it +% to the interface instance. Use setOptions to do that. + +allfields = {'Display'; 'MaxFunEvals';'MaxIter';'TolFun';'TolFunEvals';... + 'TolX';'TolXEvals'}; + +specialfields={'TolFunEvals', 'TolXEvals'}; + +nvararg=nargin-1; +if rem(nvararg,2)==1 + error('Pass options in name-value pairs!'); +end + +% create cell array +structinput = cell(2,length(allfields)); +% fields go in first row +structinput(1,:) = allfields'; +% []'s go in second row +structinput(2,:) = {[]}; +% turn it into correctly ordered comma separated list and call struct +opts = struct(structinput{:}); + +stdSet=optimset(); + +% standard options: +opts.('MaxFunEvals') = eva2.OptimizerFactory.getDefaultFitCalls; +opts.('TolX') = 1e-4; +opts.('TolXEvals') = 200; +opts.('TolFun') = 1e-4; +opts.('TolFunEvals') = 200; + +for i=1:nvararg/2 + name=varargin{2*i-1}; + value=varargin{(2*i)}; + % parse arguments + if ~ischar(name) + error('Expected char parameter name at index %d!', 2*i+1); + else + optIndex=strmatch(name,allfields, 'exact'); + if isempty(optIndex) + error('Unknown option %s !', name); + else + if ~isempty(strmatch(name, specialfields,'exact')) + % test for integer + if (~isscalar(value) || ~isnumeric(value) || round(value)<1) + error('invalid value type for %s, expecting numeric scalar > 1!', name); + end + value=round(value); + else + % test using optimset + optimset(stdSet, name, value); + end + % assign to struct + opts.(allfields{optIndex,:}) = value; + end + end +end \ No newline at end of file diff --git a/resources/MatlabInterface/@JEInterface/optimize.m b/resources/MatlabInterface/@JEInterface/optimize.m index b07cbb12..eba8455a 100644 --- a/resources/MatlabInterface/@JEInterface/optimize.m +++ b/resources/MatlabInterface/@JEInterface/optimize.m @@ -43,15 +43,14 @@ if ((nargin == 2) || (nargin == 3)) if (isempty(int.opts.TolX)) ; xTol = 1e-4; end if (isempty(int.opts.TolFun)) ; fTol = 1e-4; end - evalsForConv=100; % construct Terminators if ((xTol > 0) && (fTol > 0)) % both criteria are given, use combination - convTerm = CombinedTerminator(FitnessConvergenceTerminator(fTol, evalsForConv, 1, 1), PhenotypeConvergenceTerminator(xTol, evalsForConv, 1, 1), 1); + convTerm = CombinedTerminator(FitnessConvergenceTerminator(fTol, int.opts.TolFunEvals, 1, 1), PhenotypeConvergenceTerminator(xTol, int.opts.TolXEvals, 1, 1), 1); else if (xTol > 0) % only phenotye convergence - convTerm = PhenotypeConvergenceTerminator(xTol, evalsForConv, 1, 1); + convTerm = PhenotypeConvergenceTerminator(xTol, int.opts.TolXEvals, 1, 1); else if (fTol > 0 ) % only fitness covnergence - convTerm = FitnessConvergenceTerminator(fTol, evalsForConv, 1, 1); + convTerm = FitnessConvergenceTerminator(fTol, int.opts.TolFunEvals, 1, 1); else convTerm = 'undef'; % signal that there is no terminator yet end diff --git a/resources/MatlabInterface/@JEInterface/setOpt.m b/resources/MatlabInterface/@JEInterface/setOpt.m index 7330cb0f..64a6d71c 100644 --- a/resources/MatlabInterface/@JEInterface/setOpt.m +++ b/resources/MatlabInterface/@JEInterface/setOpt.m @@ -1,9 +1,13 @@ function int = setOpt(int, optName, optVal) -% Set a single optimset value within the JI instance. +% Set a single option value within the JI instance. % Arguments: % int: the JEInterface instance % optName: name of the option to change, e.g. 'MaxFunEvals' % optVal: new value -opts = optimset(int.opts, optName, optVal); +% this only makes sure the option actally exists and is valid +makeOptions(int, optName, optVal); + +opts = int.opts; +opts.(optName) = optVal; int.opts = opts; \ No newline at end of file diff --git a/resources/MatlabInterface/@JEInterface/setOptions.m b/resources/MatlabInterface/@JEInterface/setOptions.m index 85e5bac5..c72c470e 100644 --- a/resources/MatlabInterface/@JEInterface/setOptions.m +++ b/resources/MatlabInterface/@JEInterface/setOptions.m @@ -1,7 +1,25 @@ -function int = setOptions(int, options) -% Set the optimization options for the interface. +function int = setOptions(int, usrOpts) +% Set the optimization options for the interface. The existing options are +% overwritten by the given setings. % parameters: % int: an interface instance -% options: an optimset instance +% usrOpts: a JE options structure + +fn=fieldnames(usrOpts); + +options = int.opts; + +try + for i=1:length(fn) + % make sure all option fields and values are valid + % fn(i) + % ischar(fn(i)) + makeOptions(int, char(fn(i)), usrOpts.(char(fn(i)))); + options.(char(fn(i))) = usrOpts.(char(fn(i))); + end +catch ME + error('invalid option "%s"... check makeOptions to learn about available options', char(fn(i))); + +end int.opts = options; \ No newline at end of file diff --git a/resources/MatlabInterface/@JEInterface/setVerbose.m b/resources/MatlabInterface/@JEInterface/setVerbose.m new file mode 100644 index 00000000..0a87f233 --- /dev/null +++ b/resources/MatlabInterface/@JEInterface/setVerbose.m @@ -0,0 +1,24 @@ +function int=setVerbose(int, bOn, varargin) +% Activate debug output for the MatlabProblem. +% setVerbose(JI, bOn [, dbgfile]) +% It is written to a file with given name or to matlabproblem-debug.log +% if none is given. +% JI: the interface instance +% bOn: 1 activates debug output, 0 deactivates it +% dbgfile: optional filename +% + +if (nargin > 2) + if ischar(varargin{1}) + fname=varargin{1}; + disp('Writing debug output to '); + disp(fname); + else + disp('Invalid third argument, expected char. Using default output file name'); + end +else + fname=null; +end + +int.mp.setDebugOut( bOn==1, fname); + diff --git a/resources/MatlabInterface/@JEInterface/testEvalFunc.m b/resources/MatlabInterface/@JEInterface/testEvalFunc.m new file mode 100644 index 00000000..e076bc45 --- /dev/null +++ b/resources/MatlabInterface/@JEInterface/testEvalFunc.m @@ -0,0 +1,56 @@ +function testEvalFunc(int) +% Test the fitness function output format. +wordwidth=32; + +if (isempty(int.range)==1) + % binary problem + s=sprintf('Binary problem of bitwidth %d', int.dim); + disp(s); + numInts=ceil(int.dim/wordwidth); + % generate trial vector + x=ceil(rand(1,numInts).*(2^wordwidth)); + overheadBits=numInts*wordwidth-int.dim; + x(numInts)=bitshift(x(numInts),-overheadBits); % shift right by overhead +else + % double problem + x=rand(1, int.dim); + s=sprintf('Real valued problem in %d dimensions and range %s ', int.dim, mat2str(int.range)); + disp(s); + for i=1:int.dim + x(i)=int.range(i,1)+x(i)*(int.range(i,2)-int.range(i,1)); + end +end + +disp('Testing value: ') +disp(x); + +try + if (isempty(int.args)) + res = feval(int.f, x); + else + res = feval(int.f, x, int.args); + end +catch ME + disp('Function evaluation failed:'); + disp(ME.message); + error('Test failed!'); +end + +disp('Function returned: '); +disp(res); + +if (min(size(res)) > 1) + disp('Warning: unable to optimize matrix representations - use 1 times m output only'); +else + if (size(res,1)>1) + disp('Warning: use dimensions 1 times m instead of m times 1'); + else + if ~(sum(isnumeric(res))==size(res,1)*size(res,2)) + disp('Warning: result seems to contain non-numeric elements!'); + else + disp('Ok.'); + end + end; +end + + \ No newline at end of file diff --git a/src/eva2/EvAInfo.java b/src/eva2/EvAInfo.java index e9c97282..22179143 100644 --- a/src/eva2/EvAInfo.java +++ b/src/eva2/EvAInfo.java @@ -4,6 +4,8 @@ package eva2; * Main product and version information strings. * * --- Changelog + * 2.031: Some updates to the OptimizerFactory. Review of the MatlabInterface with adding an own options structure. + * Better access to the EvAClient, which now may have a RemoteStateListener added monitoring the optimization run. * 2.030: Added an EnumEditor to access enums easily through the GUI, which will replace SelectedTags sometimes. * IPOP-ES and RankMuCMA mutator have been added lately (wow!). * Cleaned up the IndividualInterface and reduced the usage of InterfaceESIndividual. This diff --git a/src/eva2/OptimizerFactory.java b/src/eva2/OptimizerFactory.java index e59f8046..6d4cc4d1 100644 --- a/src/eva2/OptimizerFactory.java +++ b/src/eva2/OptimizerFactory.java @@ -35,7 +35,6 @@ import eva2.server.go.operators.selection.InterfaceSelection; import eva2.server.go.operators.selection.SelectBestIndividuals; import eva2.server.go.operators.terminators.CombinedTerminator; import eva2.server.go.operators.terminators.EvaluationTerminator; -import eva2.server.go.operators.terminators.FitnessConvergenceTerminator; import eva2.server.go.populations.Population; import eva2.server.go.problems.AbstractOptimizationProblem; import eva2.server.go.strategies.ClusterBasedNichingEA; @@ -67,9 +66,8 @@ import eva2.server.modules.GOParameters; * the methods initialize the respective optimization procedure. To perform an * optimization one has to do the following: * InterfaceOptimizer optimizer = OptimizerFactory.createCertainOptimizer(arguments); - * EvaluationTerminator terminator = new EvaluationTerminator(); - * terminator.setFitnessCalls(numOfFitnessCalls); - * while (!terminator.isTerminated(mc.getPopulation())) mc.optimize(); + * EvaluationTerminator terminator = new EvaluationTerminator(numOfFitnessCalls); + * while (!terminator.isTerminated(optimizer.getPopulation())) optimizer.optimize(); * *

* @@ -80,7 +78,7 @@ import eva2.server.modules.GOParameters; * @date 17.04.2007 */ public class OptimizerFactory { - private static InterfaceTerminator term = null; + private static InterfaceTerminator userTerm = null; public final static int STD_ES = 1; @@ -110,24 +108,6 @@ public class OptimizerFactory { private static OptimizerRunnable lastRunnable = null; - /** - * Add an InterfaceTerminator to any new optimizer in a boolean combination. - * The old and the given terminator will be combined as in (TOld && TNew) if - * bAnd is true, and as in (TOld || TNew) if bAnd is false. - * - * @param newTerm - * a new InterfaceTerminator instance - * @param bAnd - * indicate the boolean combination - */ - public static void addTerminator(InterfaceTerminator newTerm, boolean bAnd) { - if (OptimizerFactory.term == null) - OptimizerFactory.term = term; - else - setTerminator(new CombinedTerminator(OptimizerFactory.term, - newTerm, bAnd)); - } - /** * This method optimizes the given problem using differential evolution. * @@ -501,10 +481,8 @@ public class OptimizerFactory { } // /////////////////////////// Termination criteria - public static InterfaceTerminator defaultTerminator() { - if (term == null) - term = new EvaluationTerminator(defaultFitCalls); - return term; + public static InterfaceTerminator makeDefaultTerminator() { + return new EvaluationTerminator(defaultFitCalls); } /** @@ -582,21 +560,38 @@ public class OptimizerFactory { public static OptimizerRunnable getOptRunnable(final int optType, AbstractOptimizationProblem problem, int fitCalls, String outputFilePrefix) { + return getOptRunnable(optType, problem, new EvaluationTerminator(fitCalls), outputFilePrefix); + } + + /** + * Produce a runnable optimizer from a strategy identifier, a problem instance and with a given + * terminator. Output is written to a file if the prefix String is given. If the terminator is null + * the current user-defined terminator will be used and if none is set, the default number of fitness + * calls will be performed. + * + * @param optType + * @param problem + * @param terminator + * @param outputFilePrefix + * @return a runnable optimizer + */ + public static OptimizerRunnable getOptRunnable(final int optType, + AbstractOptimizationProblem problem, InterfaceTerminator terminator, + String outputFilePrefix) { OptimizerRunnable opt = null; GOParameters params = getParams(optType, problem); if (params != null) { opt = new OptimizerRunnable(params, outputFilePrefix); - if (fitCalls != defaultFitCalls) - opt.getGOParams().setTerminator( - new EvaluationTerminator(fitCalls)); + if (terminator != null) opt.getGOParams().setTerminator(terminator); + else opt.getGOParams().setTerminator(getTerminator()); } return opt; } - + // /////////////////////////// constructing a default OptimizerRunnable /** - * Produce a runnable optimizer from a strategy identifier, a problem instance and with the default - * number of fitness calls to be performed. Output is written to a file if the prefix String is given. + * Produce a runnable optimizer from a strategy identifier, a problem instance and with the current + * static terminator in use. Output is written to a file if the prefix String is given. * @see #getOptRunnable(int, AbstractOptimizationProblem, int, String) * @param optType * @param problem @@ -605,17 +600,17 @@ public class OptimizerFactory { */ public static OptimizerRunnable getOptRunnable(final int optType, AbstractOptimizationProblem problem, String outputFilePrefix) { - return getOptRunnable(optType, problem, defaultFitCalls, - outputFilePrefix); + return getOptRunnable(optType, problem, getTerminator(), outputFilePrefix); } /** - * Return the current default terminator. + * Return the current user-defined or, if none was set, the default terminator. * * @return the current default terminator */ public static InterfaceTerminator getTerminator() { - return OptimizerFactory.term; + if (OptimizerFactory.userTerm != null) return OptimizerFactory.userTerm; + else return makeDefaultTerminator(); } /** @@ -638,7 +633,7 @@ public class OptimizerFactory { */ public static GOParameters makeESParams(EvolutionStrategies es, AbstractOptimizationProblem problem) { - return makeParams(es, es.getLambda(), problem, randSeed, defaultTerminator()); + return makeParams(es, es.getLambda(), problem, randSeed, makeDefaultTerminator()); } /** @@ -651,7 +646,7 @@ public class OptimizerFactory { * @return */ public static GOParameters makeParams(InterfaceOptimizer opt, int popSize, AbstractOptimizationProblem problem) { - return makeParams(opt, popSize, problem, randSeed, defaultTerminator()); + return makeParams(opt, popSize, problem, randSeed, makeDefaultTerminator()); } public static GOParameters makeParams(InterfaceOptimizer opt, @@ -709,17 +704,39 @@ public class OptimizerFactory { * @param optType * @param problem * @param outputFilePrefix - * @return + * @return the OptimizerRunnable instance just started */ - public static OptimizerRunnable optimizeInThread(final int optType, - AbstractOptimizationProblem problem, String outputFilePrefix) { - OptimizerRunnable runnable = getOptRunnable(optType, problem, - outputFilePrefix); - if (runnable != null) - new Thread(runnable).start(); - return runnable; + public static OptimizerRunnable optimizeInThread(final int optType, AbstractOptimizationProblem problem, String outputFilePrefix) { + return optimizeInThread(getOptRunnable(optType, problem, outputFilePrefix)); + } + + /** + * Create a runnable optimization Runnable and directly start it in an own + * thread. The Runnable will notify waiting threads and set the isFinished + * flag when the optimization is complete. If the optType is invalid, null + * will be returned. + * + * @param params + * @param outputFilePrefix + * @return the OptimizerRunnable instance just started + */ + public static OptimizerRunnable optimizeInThread(GOParameters params, String outputFilePrefix) { + return optimizeInThread(new OptimizerRunnable(params, outputFilePrefix)); } + /** + * Start a runnable optimizer in a concurrent thread. + * @param runnable + * @return the started runnable + */ + public static OptimizerRunnable optimizeInThread(OptimizerRunnable runnable) { + if (runnable != null) { + new Thread(runnable).start(); + lastRunnable = runnable; + } + return runnable; + } + // ///////////////////////////// Optimize a given parameter instance public static BitSet optimizeToBinary(GOParameters params, String outputFilePrefix) { @@ -810,12 +827,30 @@ public class OptimizerFactory { return (lastRunnable == null) ? null : postProcess(lastRunnable, ppp); } + /** + * Post process the given runnable with given parameters. The runnable will + * not be stored. + * + * @param runnable + * @param steps + * @param sigma + * @param nBest + * @return + */ public static Population postProcess(OptimizerRunnable runnable, int steps, double sigma, int nBest) { PostProcessParams ppp = new PostProcessParams(steps, sigma, nBest); return postProcess(runnable, ppp); } + /** + * Post process the given runnable with given parameters. The runnable will + * not be stored. + * + * @param runnable + * @param ppp + * @return + */ public static Population postProcess(OptimizerRunnable runnable, InterfacePostProcessParams ppp) { runnable.setDoRestart(true); @@ -845,6 +880,14 @@ public class OptimizerFactory { nBest)); } + /** + * Post process the given runnable with given parameters. Return the solution set + * as a vector of BitSets. The runnable will not be stored. + * + * @param runnable + * @param ppp + * @return + */ public static Vector postProcessBinVec(OptimizerRunnable runnable, InterfacePostProcessParams ppp) { Population resPop = postProcess(runnable, ppp); @@ -875,7 +918,15 @@ public class OptimizerFactory { return postProcessDblVec(runnable, new PostProcessParams(steps, sigma, nBest)); } - + + /** + * Post process the given runnable with given parameters. Return the solution set + * as a vector of double arrays. The runnable will not be stored. + * + * @param runnable + * @param ppp + * @return + */ public static Vector postProcessDblVec( OptimizerRunnable runnable, InterfacePostProcessParams ppp) { Population resPop = postProcess(runnable, ppp); @@ -906,7 +957,15 @@ public class OptimizerFactory { return postProcessIndVec(runnable, new PostProcessParams(steps, sigma, nBest)); } - + + /** + * Post process the given runnable with given parameters. Return the solution set + * as a vector of AbstractEAIndividuals. The runnable will not be stored. + * + * @param runnable + * @param ppp + * @return + */ public static Vector postProcessIndVec( OptimizerRunnable runnable, InterfacePostProcessParams ppp) { Population resPop = postProcess(runnable, ppp); @@ -922,19 +981,48 @@ public class OptimizerFactory { } ///////////////////////////// termination management + /** + * Replace the current user-defined terminator by the given one. + * + * @param term + */ + public static void setTerminator(InterfaceTerminator term) { + OptimizerFactory.userTerm = term; + } + + /** + * Add a new InterfaceTerminator to the current user-defined optimizer in a boolean combination. + * The old and the given terminator will be combined as in (TOld && TNew) if + * bAnd is true, and as in (TOld || TNew) if bAnd is false. + * If there was no user-defined terminator (or it was set to null) the new one is used without conjunction. + * + * @param newTerm + * a new InterfaceTerminator instance + * @param bAnd + * indicate the boolean combination + */ + public static void addTerminator(InterfaceTerminator newTerm, boolean bAnd) { + if (OptimizerFactory.userTerm == null) + OptimizerFactory.userTerm = newTerm; + else + setTerminator(new CombinedTerminator(OptimizerFactory.userTerm, + newTerm, bAnd)); + } + + /** + * Convenience method setting an EvaluationTerminator with the given + * number of evaluations. + * + * @param maxEvals + */ public static void setEvaluationTerminator(int maxEvals) { setTerminator(new EvaluationTerminator(maxEvals)); } - public static void setFitnessConvergenceTerminator(double fitThresh) { - setTerminator(new FitnessConvergenceTerminator(fitThresh, 100, true, - true)); - } - - public static void setTerminator(InterfaceTerminator term) { - OptimizerFactory.term = term; - } - + /** + * Return the termination message of the last runnable, if available. + * @return + */ public static String terminatedBecause() { return (lastRunnable != null) ? lastRunnable.terminatedBecause() : null; } @@ -947,12 +1035,12 @@ public class OptimizerFactory { */ public static final GOParameters hillClimbing( AbstractOptimizationProblem problem) { - return makeParams(new HillClimbing(), 50, problem, randSeed, defaultTerminator()); + return makeParams(new HillClimbing(), 50, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters monteCarlo( AbstractOptimizationProblem problem) { - return makeParams(new MonteCarloSearch(), 50, problem, randSeed, defaultTerminator()); + return makeParams(new MonteCarloSearch(), 50, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters cbnES(AbstractOptimizationProblem problem) { @@ -967,7 +1055,7 @@ public class OptimizerFactory { cbn.setDifferentationCA(clustering); cbn.setShowCycle(0); // don't do graphical output - return makeParams(cbn, 100, problem, randSeed, defaultTerminator()); + return makeParams(cbn, 100, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters clusteringHillClimbing( @@ -982,7 +1070,7 @@ public class OptimizerFactory { chc.setNotifyGuiEvery(0); chc.setStepSizeThreshold(0.000001); chc.setSigmaClust(0.05); - return makeParams(chc, 100, problem, randSeed, defaultTerminator()); + return makeParams(chc, 100, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters cmaES(AbstractOptimizationProblem problem) { @@ -1052,7 +1140,7 @@ public class OptimizerFactory { de.setK(0.6); de.setLambda(0.6); de.setMt(0.05); - return makeParams(de, 50, problem, randSeed, defaultTerminator()); + return makeParams(de, 50, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters standardES( @@ -1082,7 +1170,7 @@ public class OptimizerFactory { GeneticAlgorithm ga = new GeneticAlgorithm(); ga.setElitism(true); - return makeParams(ga, 100, problem, randSeed, defaultTerminator()); + return makeParams(ga, 100, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters standardPSO( @@ -1090,10 +1178,10 @@ public class OptimizerFactory { ParticleSwarmOptimization pso = new ParticleSwarmOptimization(); pso.setPhiValues(2.05, 2.05); pso.getTopology().setSelectedTag("Grid"); - return makeParams(pso, 30, problem, randSeed, defaultTerminator()); + return makeParams(pso, 30, problem, randSeed, makeDefaultTerminator()); } public static final GOParameters tribes(AbstractOptimizationProblem problem) { - return makeParams(new Tribes(), 1, problem, randSeed, defaultTerminator()); + return makeParams(new Tribes(), 1, problem, randSeed, makeDefaultTerminator()); } } diff --git a/src/eva2/OptimizerRunnable.java b/src/eva2/OptimizerRunnable.java index de308899..db285844 100644 --- a/src/eva2/OptimizerRunnable.java +++ b/src/eva2/OptimizerRunnable.java @@ -4,6 +4,8 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.BitSet; +import wsi.ra.jproxy.RemoteStateListener; + import eva2.server.go.IndividualInterface; import eva2.server.go.InterfaceGOParameters; import eva2.server.go.InterfaceTerminator; @@ -88,6 +90,10 @@ public class OptimizerRunnable implements Runnable { this.listener = lsnr; if (listener != null) proc.getStatistics().addTextListener(listener); } + + public void addRemoteStateListener(RemoteStateListener rsl) { + if (proc != null) proc.addListener(rsl); + } public void setDoRestart(boolean restart) { doRestart = restart; diff --git a/src/eva2/server/go/problems/MatlabEvalMediator.java b/src/eva2/server/go/problems/MatlabEvalMediator.java index 91e21947..5494150d 100644 --- a/src/eva2/server/go/problems/MatlabEvalMediator.java +++ b/src/eva2/server/go/problems/MatlabEvalMediator.java @@ -1,8 +1,5 @@ package eva2.server.go.problems; -import java.lang.reflect.Array; -import java.util.BitSet; - import eva2.gui.BeanInspector; /** @@ -34,7 +31,7 @@ public class MatlabEvalMediator implements Runnable { boolean quit = false; volatile Object optSolution = null; volatile Object[] optSolSet = null; -// MatlabProblem mp = null; + MatlabProblem mp = null; // no good: even when waiting for only 1 ms the Matlab execution time increases by a factor of 5-10 final static int sleepTime = 0; @@ -45,7 +42,7 @@ public class MatlabEvalMediator implements Runnable { * @return */ double[] requestEval(MatlabProblem mp, Object x) { -// this.mp = mp; + this.mp = mp; question = x; // System.err.println("IN REQUESTEVAL, x is " + BeanInspector.toString(x)); if (question.getClass().isArray()) { @@ -54,11 +51,12 @@ public class MatlabEvalMediator implements Runnable { // BitSet b = (BitSet)x; // Integer.decode() // + if (question == null) System.err.println("Error: requesting evaluation for null array!"); } else System.err.println("Error, requesting evaluation for non array!"); requesting = true; // int k=0; -// System.out.println("Requesting eval for " + BeanInspector.toString(x) + ", req state is " + requesting + "\n"); + mp.log("-- Requesting eval for " + BeanInspector.toString(x) + ", req state is " + requesting + "\n"); while (requesting && !quit) { // wait for matlab to answer the question if (sleepTime > 0) try { Thread.sleep(sleepTime); } catch(Exception e) {}; @@ -67,8 +65,9 @@ public class MatlabEvalMediator implements Runnable { // } // k++; } -// System.out.println("Requesting done \n"); + mp.log("-- Requesting done\n"); // matlab is finished, answer is here + //return null; return getAnswer(); // return to JE with answer } @@ -102,11 +101,12 @@ public class MatlabEvalMediator implements Runnable { * @return */ public Object getQuestion() { -// mp.log("-- Question: " + BeanInspector.toString(question) + "\n"); + mp.log("-- Question: " + BeanInspector.toString(question) + "\n"); return question; } double[] getAnswer() { + mp.log("-- mediator delivering " + BeanInspector.toString(answer) + "\n"); return answer; } @@ -116,10 +116,14 @@ public class MatlabEvalMediator implements Runnable { * @param y */ public void setAnswer(double[] y) { -// mp.log("-- setAnswer: " + BeanInspector.toString(y) + "\n"); // System.err.println("answer is " + BeanInspector.toString(y)); + if (y==null) { + System.err.println("Error: Matlab function returned null array - this is bad."); + System.err.println("X-value was " + BeanInspector.toString(getQuestion())); + } answer = y; requesting = false; // answer is finished, break request loop + mp.log("-- setAnswer: " + BeanInspector.toString(y) + ", req state is " + requesting + "\n"); } void setFinished(boolean val) { diff --git a/src/eva2/server/go/problems/MatlabProblem.java b/src/eva2/server/go/problems/MatlabProblem.java index 7329cb01..c4c52034 100644 --- a/src/eva2/server/go/problems/MatlabProblem.java +++ b/src/eva2/server/go/problems/MatlabProblem.java @@ -30,13 +30,13 @@ import eva2.server.stat.InterfaceTextListener; */ public class MatlabProblem extends AbstractOptimizationProblem implements InterfaceTextListener, Serializable { private static final long serialVersionUID = 4913310869887420815L; - public static final boolean TRACE = true; + public static boolean TRACE = false; transient OptimizerRunnable runnable = null; protected boolean allowSingleRunnable = true; protected int problemDimension = 10; transient PrintStream dos = null; private double range[][] = null; - private static final String defTestOut = "matlabproblem-testout.dat"; + private static String defTestOut = "matlabproblem-debug.log"; int verbosityLevel = 0; private MatlabEvalMediator handler = null; private boolean isDouble = true; @@ -123,18 +123,35 @@ public class MatlabProblem extends AbstractOptimizationProblem implements Interf // System.err.println("range: " + BeanInspector.toString(range)); initTemplate(); // res = new ResultArr(); - if ((dos == null) && TRACE) { - try { - dos = new PrintStream(new FileOutputStream(outFile)); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } + + setDebugOut(TRACE, defTestOut); // log("range is " + BeanInspector.toString(range)+ "\n"); // log("template len: " + ((ESIndividualDoubleData)m_Template).getDGenotype().length + "\n"); } + /** + * If swtch is true and no output file is open yet, open a new one which will be used for debug output. + * if fname is null, the default filename will be used. + * if swtch is false, close the output file and deactivate debug output. + * + * @param swtch + * @param fname + */ + public void setDebugOut(boolean swtch, String fname) { + TRACE=swtch; + if (!swtch && (dos != null)) { + dos.close(); + dos = null; + } else if ((dos == null) && swtch) { + try { + dos = new PrintStream(new FileOutputStream(fname==null ? defTestOut : fname)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + public void setStatsOutput(int verboLevel) { if ((verboLevel >= 0) && (verboLevel <= 3)) { verbosityLevel = verboLevel; @@ -386,10 +403,10 @@ public class MatlabProblem extends AbstractOptimizationProblem implements Interf @Override public void evaluate(AbstractEAIndividual indy) { - log("evaluating " + BeanInspector.toString(indy) + "\n"); + log("evaluating " + AbstractEAIndividual.getDefaultStringRepresentation(indy) + "\n"); double[] res = handler.requestEval(this, AbstractEAIndividual.getIndyData(indy)); + log("evaluated to " + BeanInspector.toString(res) + "\n"); indy.SetFitness(res); -// System.err.println("evaluated to " + BeanInspector.toString(res)); } @Override diff --git a/src/eva2/server/go/problems/WaitForEvARunnable.java b/src/eva2/server/go/problems/WaitForEvARunnable.java index 311f774e..3acef52e 100644 --- a/src/eva2/server/go/problems/WaitForEvARunnable.java +++ b/src/eva2/server/go/problems/WaitForEvARunnable.java @@ -19,24 +19,23 @@ class WaitForEvARunnable implements Runnable { public void run() { if (runnable != null) { mp.log("\nStarting optimize runnable!\n"); - synchronized (runnable) { try { // whole optimization thread goes in here new Thread(runnable).start(); - mp.log("Starting optimize thread done!\n"); + mp.log("Started optimize thread\n"); runnable.wait(); // wait for the runnable to finish - mp.log("After wait!\n"); + mp.log("runnable continues...\n"); } catch (InterruptedException e) { e.printStackTrace(); mp.log("WaitForEvARunnable was interrupted with " + e.getMessage()); } } try { - mp.log("runnable.getDoubleSolution: " + BeanInspector.toString(runnable.getDoubleSolution())); - mp.log("runnable.getIntegerSolution: " + BeanInspector.toString(runnable.getIntegerSolution())); - mp.log("\ngetAllSols best: " + AbstractEAIndividual.getDefaultDataString(runnable.getGOParams().getOptimizer().getAllSolutions().getSolutions().getBestEAIndividual())); + mp.log("runnable.getDoubleSolution: " + BeanInspector.toString(runnable.getDoubleSolution()) + "\n"); + mp.log("runnable.getIntegerSolution: " + BeanInspector.toString(runnable.getIntegerSolution()) + "\n"); + mp.log("getAllSols best: " + AbstractEAIndividual.getDefaultDataString(runnable.getGOParams().getOptimizer().getAllSolutions().getSolutions().getBestEAIndividual()) + "\n"); mp.log("\n"); // write results back to matlab mp.exportResultToMatlab(runnable); diff --git a/src/eva2/server/go/strategies/ClusterBasedNichingEA.java b/src/eva2/server/go/strategies/ClusterBasedNichingEA.java index c41cb8e6..c6c3c337 100644 --- a/src/eva2/server/go/strategies/ClusterBasedNichingEA.java +++ b/src/eva2/server/go/strategies/ClusterBasedNichingEA.java @@ -150,13 +150,13 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis population.incrGeneration(); } - private void plot() { + private void plot(int gen) { double[] a = new double[2]; a[0] = 0.0; a[1] = 0.0; if (this.m_Problem instanceof TF1Problem) { // now i need to plot the pareto fronts - Plot plot = new Plot("TF3Problem", "y1", "y2", a, a); + Plot plot = new Plot("TF3Problem at gen. "+gen, "y1", "y2", a, a); plot.setUnconnectedPoint(0,0,0); plot.setUnconnectedPoint(1,5,0); GraphPointSet mySet = new GraphPointSet(10, plot.getFunctionArea()); @@ -191,7 +191,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis InterfaceDataTypeDouble tmpIndy1, best; Population pop; - this.m_Topology = new TopoPlot("CBN-Species","x","y",a,a); + this.m_Topology = new TopoPlot("CBN-Species at gen. " + gen,"x","y",a,a); this.m_Topology.gridx = 60; this.m_Topology.gridy = 60; this.m_Topology.setTopology((Interface2DBorderProblem)this.m_Problem); @@ -358,9 +358,9 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis // plot the populations if (this.m_ShowCycle > 0) { if ((this.m_Undifferentiated.getGeneration() == 0) || (this.m_Undifferentiated.getGeneration() == 1) || (this.m_Undifferentiated.getGeneration() == 2)) { - this.plot(); + this.plot(this.m_Undifferentiated.getGeneration()); } else { - if (this.m_Undifferentiated.getGeneration()%this.m_ShowCycle == 0) this.plot(); + if (this.m_Undifferentiated.getGeneration()%this.m_ShowCycle == 0) this.plot(this.m_Undifferentiated.getGeneration()); } } @@ -706,7 +706,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis * @return description */ public String globalInfo() { - return "This is a versatible species based niching EA method."; + return "This is a versatile species based niching EA method."; } /** This method will return a naming String * @return The name of the algorithm