From 676fbb8498e2330225a273200c443bd0e00a0752 Mon Sep 17 00:00:00 2001 From: Marcel Kronfeld Date: Tue, 16 Sep 2008 13:11:48 +0000 Subject: [PATCH] Merging mk branch rev 205, added post-processing methods (nelder-mead, cma-es); some cosmetics. --- src/eva2/EvAInfo.java | 1 + src/eva2/OptimizerFactory.java | 12 +- src/eva2/client/EvAClient.java | 6 +- src/eva2/gui/FunctionArea.java | 14 +- src/eva2/gui/LogPanel.java | 179 +++---- .../server/go/enums/PostProcessMethod.java | 5 + .../go/individuals/AbstractEAIndividual.java | 27 +- .../operators/mutation/MutateESRankMuCMA.java | 19 +- .../InterfacePostProcessParams.java | 6 + .../go/operators/postprocess/PostProcess.java | 448 +++++++++++++++++- .../postprocess/PostProcessParams.java | 23 + .../selection/SelectParticleWheel.java | 92 +++- .../AbstractMultiModalProblemKnown.java | 26 +- src/eva2/server/go/problems/F1Problem.java | 29 +- src/eva2/server/go/problems/F8Problem.java | 4 - .../server/go/problems/MatlabProblem.java | 2 +- .../go/strategies/NelderMeadSimplex.java | 420 ++++++++++++++++ .../ParticleFilterOptimization.java | 66 ++- .../strategies/ParticleSwarmOptimization.java | 4 +- src/eva2/server/modules/GOParameters.java | 2 +- src/eva2/tools/Mathematics.java | 14 + 21 files changed, 1215 insertions(+), 184 deletions(-) create mode 100644 src/eva2/server/go/enums/PostProcessMethod.java create mode 100644 src/eva2/server/go/strategies/NelderMeadSimplex.java diff --git a/src/eva2/EvAInfo.java b/src/eva2/EvAInfo.java index 99e1d2f9..e9c97282 100644 --- a/src/eva2/EvAInfo.java +++ b/src/eva2/EvAInfo.java @@ -13,6 +13,7 @@ package eva2; * Cleaned up MutateXXDefault to a single MutateDefault, too. DE may now do range checking. * The "Description" button has made space for a "Show Solution" button. The Rank-Mu-CMA was improved * to use a CMAParameterSet which is associated with populations and not static any more. + * Included Nelder-Mead-Simplex and CMA-ES as post processing methods. * 2.029: Tuned the 2d-graphs which now paints quicker and changes size depending on the * surrounding plot window. Added a preloader-thread to accelerate the GUI at starting time. * 2.028: Tuned the Population to sort only when necessary on calls to getBestN... Added StatisticsDummy. diff --git a/src/eva2/OptimizerFactory.java b/src/eva2/OptimizerFactory.java index 2d9d545b..e59f8046 100644 --- a/src/eva2/OptimizerFactory.java +++ b/src/eva2/OptimizerFactory.java @@ -10,6 +10,7 @@ import eva2.server.go.IndividualInterface; import eva2.server.go.InterfacePopulationChangedEventListener; import eva2.server.go.InterfaceTerminator; import eva2.server.go.enums.DETypeEnum; +import eva2.server.go.enums.PostProcessMethod; import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.individuals.InterfaceDataTypeBinary; import eva2.server.go.individuals.InterfaceDataTypeDouble; @@ -798,11 +799,13 @@ public class OptimizerFactory { return (runnable != null) ? runnable.getSolutionSet() : null; } - public static Population postProcess(int steps, double sigma, int nBest) { - return (lastRunnable == null) ? null : postProcess(lastRunnable, - new PostProcessParams(steps, sigma, nBest)); - } + ///////////////////////////// post processing + public static Population postProcess(PostProcessMethod method, int steps, double sigma, int nBest) { + return (lastRunnable == null) ? null : postProcess(lastRunnable, + new PostProcessParams(method, steps, sigma, nBest)); + } + public static Population postProcess(InterfacePostProcessParams ppp) { return (lastRunnable == null) ? null : postProcess(lastRunnable, ppp); } @@ -898,7 +901,6 @@ public class OptimizerFactory { : null; } - ///////////////////////////// post processing public static Vector postProcessIndVec( OptimizerRunnable runnable, int steps, double sigma, int nBest) { return postProcessIndVec(runnable, new PostProcessParams(steps, sigma, diff --git a/src/eva2/client/EvAClient.java b/src/eva2/client/EvAClient.java index 8d99aef1..921453c6 100644 --- a/src/eva2/client/EvAClient.java +++ b/src/eva2/client/EvAClient.java @@ -249,9 +249,12 @@ public class EvAClient implements RemoteStateListener, Serializable { m_LogPanel.logMessage("Class path is: " + System.getProperty("java.class.path",".")); if (!(m_Frame.isVisible())) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + m_Frame.setLocation((int)((screenSize.width-m_Frame.getWidth())/2), (int)((screenSize.height-m_Frame.getHeight())/2.5)); m_Frame.pack(); m_Frame.setVisible(true); } + m_LogPanel.logMessage("EvA2 ready"); // if this message is omitted, the stupid scroll pane runs to the end of the last line which is ugly for a long class path } /** @@ -583,6 +586,7 @@ public class EvAClient implements RemoteStateListener, Serializable { JPanel moduleContainer = Temp.createContentPane(); // MK the frame is actually painted in here // m_Frame.setLayout(new BorderLayout()); + boolean wasVisible = m_Frame.isVisible(); m_Frame.setVisible(false); m_Frame.getContentPane().removeAll(); @@ -599,7 +603,7 @@ public class EvAClient implements RemoteStateListener, Serializable { m_Frame.add(infoPanel, BorderLayout.SOUTH); m_Frame.pack(); - m_Frame.setVisible(true); + m_Frame.setVisible(wasVisible); currentModule = selectedModule; // m_ModulGUIContainer.add(Temp); diff --git a/src/eva2/gui/FunctionArea.java b/src/eva2/gui/FunctionArea.java index 9ec53c56..db26bd87 100644 --- a/src/eva2/gui/FunctionArea.java +++ b/src/eva2/gui/FunctionArea.java @@ -318,6 +318,13 @@ public class FunctionArea extends DArea implements Serializable { } + /** + * + */ + public void setConnectedPoint(double[] p, int graphLabel) { + setConnectedPoint(p[0], p[1], graphLabel); + } + /** * */ @@ -334,8 +341,8 @@ public class FunctionArea extends DArea implements Serializable { // y = 1e-30; // } getGraphPointSet(graphLabel).addDPoint(x, y); - } + // public void setConnectedPoint(double x, double y, int GraphLabel) { // if (m_log == true && y <= 0.0) { //// y = Double.MIN_VALUE; @@ -454,7 +461,10 @@ public class FunctionArea extends DArea implements Serializable { //addGraphPointSet(NewPointSet); already done within GraphPointSet!!! return NewPointSet; } - + + public void setUnconnectedPoint(double[] p, int GraphLabel) { + setUnconnectedPoint(p[0], p[1], GraphLabel); + } /** * */ diff --git a/src/eva2/gui/LogPanel.java b/src/eva2/gui/LogPanel.java index b686eb6b..53351db1 100644 --- a/src/eva2/gui/LogPanel.java +++ b/src/eva2/gui/LogPanel.java @@ -32,100 +32,101 @@ import javax.swing.event.ChangeListener; import wsi.ra.tool.BasicResourceLoader; import eva2.EvAInfo; /*==========================================================================* -* CLASS DECLARATION -*==========================================================================*/ + * CLASS DECLARATION + *==========================================================================*/ /** * */ public class LogPanel extends JPanel { -// protected JLabel m_Message = new JLabel("OK"); - protected JTextArea m_LogText = new JTextArea(10,20); - protected boolean m_first = true; - /** - * - */ - public LogPanel() { - m_LogText.setEditable(false); - m_LogText.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); -// m_Message.setBorder(BorderFactory.createCompoundBorder( -// BorderFactory.createTitledBorder("Message"), -// BorderFactory.createEmptyBorder(0,4,4,4))); - JPanel panel_1 = new JPanel(); - panel_1.setBorder(BorderFactory.createTitledBorder("Info")); - panel_1.setLayout(new BorderLayout()); - final JScrollPane scrollpane = new JScrollPane(m_LogText); - panel_1.add(scrollpane, BorderLayout.CENTER); - scrollpane.getViewport().addChangeListener(new ChangeListener() { - private int lastHeight; - // - public void stateChanged(ChangeEvent e) { - JViewport viewport = (JViewport)e.getSource(); - int Height = viewport.getViewSize().height; - if (Height != lastHeight) { - lastHeight = Height; - int x = Height - viewport.getExtentSize().height; - viewport.setViewPosition(new Point(0, x)); +// protected JLabel m_Message = new JLabel("OK"); + protected JTextArea m_LogText = new JTextArea(10,20); + protected boolean m_first = true; + /** + * + */ + public LogPanel() { + m_LogText.setEditable(false); + m_LogText.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); +// m_Message.setBorder(BorderFactory.createCompoundBorder( +// BorderFactory.createTitledBorder("Message"), +// BorderFactory.createEmptyBorder(0,4,4,4))); + JPanel panel_1 = new JPanel(); + panel_1.setBorder(BorderFactory.createTitledBorder("Info")); + panel_1.setLayout(new BorderLayout()); + final JScrollPane scrollpane = new JScrollPane(m_LogText); +// scrollpane.setAutoscrolls(false); + panel_1.add(scrollpane, BorderLayout.CENTER); + scrollpane.getViewport().addChangeListener(new ChangeListener() { + private int lastHeight; + // + public void stateChanged(ChangeEvent e) { + JViewport viewport = (JViewport)e.getSource(); + int Height = viewport.getViewSize().height; + if (Height != lastHeight) { + lastHeight = Height; + int x = Height - viewport.getExtentSize().height; + viewport.setViewPosition(new Point(0, x)); + } + } + }); + setLayout(new BorderLayout()); + add(panel_1, BorderLayout.CENTER); + JPanel panel_2 = new JPanel(); + panel_2.setLayout(new BorderLayout()); +// panel_2.add(m_Message,BorderLayout.CENTER); + add(panel_2, BorderLayout.SOUTH); } - } - }); - setLayout(new BorderLayout()); - add(panel_1, BorderLayout.CENTER); - JPanel panel_2 = new JPanel(); - panel_2.setLayout(new BorderLayout()); -// panel_2.add(m_Message,BorderLayout.CENTER); - add(panel_2, BorderLayout.SOUTH); - } - /** - * - */ - protected static String getTimestamp() { - return (new SimpleDateFormat("HH:mm:ss:")).format(new Date()); - } - /** - * - */ - public void logMessage(String message) { - if (m_first) - m_first = false; - m_LogText.append("\n"); - m_LogText.append(LogPanel.getTimestamp() + ' ' + message); - } -// /** -// * -// */ -// public void statusMessage(String message) { -// m_Message.setText(message); -// } - /** - * - */ - public static void main(String [] args) { - try { - final JFrame frame = new JFrame("Log_Panel_Test"); - frame.getContentPane().setLayout(new BorderLayout()); - BasicResourceLoader loader = BasicResourceLoader.instance(); - byte[] bytes = loader.getBytesFromResourceLocation(EvAInfo.iconLocation); - try { - frame.setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); - } catch (java.lang.NullPointerException e) { - System.out.println("Could not find EvA2 icon, please move resources folder to working directory!"); - } - LogPanel panel = new LogPanel(); - frame.getContentPane().add(panel, BorderLayout.CENTER); - frame.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - frame.dispose(); - System.exit(0); + /** + * + */ + protected static String getTimestamp() { + return (new SimpleDateFormat("HH:mm:ss:")).format(new Date()); } - }); - frame.pack(); - frame.setVisible(true); - panel.logMessage("HI!"); - panel.logMessage("Test"); + /** + * + */ + public void logMessage(String message) { + if (m_first) + m_first = false; + m_LogText.append("\n"); + m_LogText.append(LogPanel.getTimestamp() + ' ' + message); + } +// /** +// * +// */ +// public void statusMessage(String message) { +// m_Message.setText(message); +// } + /** + * + */ + public static void main(String [] args) { + try { + final JFrame frame = new JFrame("Log_Panel_Test"); + frame.getContentPane().setLayout(new BorderLayout()); + BasicResourceLoader loader = BasicResourceLoader.instance(); + byte[] bytes = loader.getBytesFromResourceLocation(EvAInfo.iconLocation); + try { + frame.setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); + } catch (java.lang.NullPointerException e) { + System.out.println("Could not find EvA2 icon, please move resources folder to working directory!"); + } + LogPanel panel = new LogPanel(); + frame.getContentPane().add(panel, BorderLayout.CENTER); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + System.exit(0); + } + }); + frame.pack(); + frame.setVisible(true); + panel.logMessage("HI!"); + panel.logMessage("Test ------------------------------------------------------------------------"); - } catch (Exception e) { - e.printStackTrace(); - System.out.println(e.getMessage()); - } - } + } catch (Exception e) { + e.printStackTrace(); + System.out.println(e.getMessage()); + } + } } diff --git a/src/eva2/server/go/enums/PostProcessMethod.java b/src/eva2/server/go/enums/PostProcessMethod.java new file mode 100644 index 00000000..d5603fc6 --- /dev/null +++ b/src/eva2/server/go/enums/PostProcessMethod.java @@ -0,0 +1,5 @@ +package eva2.server.go.enums; + +public enum PostProcessMethod { + hillClimber, nelderMead, cmaES; +} \ No newline at end of file diff --git a/src/eva2/server/go/individuals/AbstractEAIndividual.java b/src/eva2/server/go/individuals/AbstractEAIndividual.java index 58de0d29..e19ffeae 100644 --- a/src/eva2/server/go/individuals/AbstractEAIndividual.java +++ b/src/eva2/server/go/individuals/AbstractEAIndividual.java @@ -16,6 +16,7 @@ import eva2.server.go.operators.crossover.NoCrossover; import eva2.server.go.operators.mutation.InterfaceMutation; import eva2.server.go.operators.mutation.NoMutation; import eva2.server.go.populations.Population; +import eva2.server.go.problems.AbstractOptimizationProblem; import eva2.server.go.problems.InterfaceOptimizationProblem; import eva2.tools.EVAERROR; @@ -61,7 +62,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. protected HashMap m_dataHash = new HashMap(); // introduced for the nichingPSO/ANPSO (M.Aschoff) - private int individualIndex; + private int individualIndex = -1; public AbstractEAIndividual() { m_IDcounter++; @@ -77,7 +78,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. return individualIndex; } - public void setIndividualIndex(int index) { + public void SetIndividualIndex(int index) { this.individualIndex = index; } @@ -94,13 +95,31 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. * @param coOp * @param pCross */ - public void initOperators(InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross) { + public void setOperators(InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross) { m_MutationProbability = pMut; m_MutationOperator = mutOp; m_CrossoverProbability = pCross; m_CrossoverOperator = coOp; } + /** + * Clone and init the mutation/crossover operator for the individual + * and initialize the operators and probabilities to the given values. + * + * @param mutOp + * @param pMut + * @param coOp + * @param pCross + */ + public void initCloneOperators(InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross, InterfaceOptimizationProblem problem) { + m_MutationProbability = pMut; + m_MutationOperator = (InterfaceMutation)mutOp.clone(); + m_MutationOperator.init(this, problem); + m_CrossoverProbability = pCross; + m_CrossoverOperator = (InterfaceCrossover)coOp.clone(); + m_CrossoverOperator.init(this, problem); + } + /** * Set the mutation/crossover operator and probabilities of the given individual to the given values. * @@ -112,7 +131,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. * @return the modified AbstractEAIndividual */ public static AbstractEAIndividual setOperators(AbstractEAIndividual indy, InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross) { - indy.initOperators(mutOp, pMut, coOp, pCross); + indy.setOperators(mutOp, pMut, coOp, pCross); return indy; } diff --git a/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java b/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java index 8a4dae55..4cb8f95b 100644 --- a/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java +++ b/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java @@ -43,7 +43,7 @@ class CMAParamSet implements InterfacePopulationChangedEventListener, Serializab protected boolean firstAdaptionDone = false; public String toString() { - return "d_sig " + d_sig + ", c_sig" + ", sigma " + sigma + ", firstSigma " + firstSigma+ ", firstAdaptionDone " + firstAdaptionDone + return "d_sig " + d_sig + ", c_sig " + c_sig + ", sigma " + sigma + ", firstSigma " + firstSigma+ ", firstAdaptionDone " + firstAdaptionDone + ",\n meanX " + Arrays.toString(meanX) + ", pathC " + Arrays.toString(pathC)+ ", pathS " + Arrays.toString(pathS)+ ", eigenvalues " + Arrays.toString(eigenvalues) + ", weights " + Arrays.toString(weights)+ ",\n mC " + mC.toString() + ",\n mB " + mB.toString(); } @@ -100,6 +100,10 @@ class CMAParamSet implements InterfacePopulationChangedEventListener, Serializab params.d_sig = params.c_sig+1+2*Math.max(0, Math.sqrt((muEff-1)/(dim+1)) - 1); if (initialSigma<0) initialSigma = getAvgRange(params.range); + if (initialSigma <= 0) { + EVAERROR.errorMsgOnce("warning: initial sigma <= zero! Working with converged population?"); + initialSigma = 10e-10; + } params.sigma = initialSigma; // System.out.println("INitial sigma: "+sigma); params.firstSigma = params.sigma; @@ -273,7 +277,7 @@ public class MutateESRankMuCMA implements InterfaceMutationGenerational, Seriali mu = selectedP.size(); lambda = oldGen.size(); if (mu>= lambda) { - EVAERROR.errorMsgOnce("Warning: invalid mu/lambda ratio (" + mu + "/" + lambda + ") ! Setting mu to lambda/2."); + EVAERROR.errorMsgOnce("Warning: invalid mu/lambda ratio! Setting mu to lambda/2."); mu = lambda/2; } CMAParamSet params; @@ -282,7 +286,7 @@ public class MutateESRankMuCMA implements InterfaceMutationGenerational, Seriali else params = CMAParamSet.initCMAParams(mu, lambda, oldGen, getInitSigma(oldGen)); } else { if (!oldGen.hasData(cmaParamsKey)) { - if (oldGen.getGeneration() > 1) System.err.println("pop had no params at gen " + oldGen.getGeneration()); + if (oldGen.getGeneration() > 1) EVAERROR.errorMsgOnce("Error: population lost cma parameters. Incompatible optimizer?"); params = CMAParamSet.initCMAParams(mu, lambda, oldGen, getInitSigma(oldGen)); } else params = (CMAParamSet)oldGen.getData(cmaParamsKey); } @@ -676,7 +680,7 @@ public class MutateESRankMuCMA implements InterfaceMutationGenerational, Seriali x[i] += RNG.gaussianDouble(getSigma(params, i)); } } - if (isInRange(x, range)) return x; + if (Mathematics.isInRange(x, range)) return x; else { if (count > 5) return repairMutation(x, range); // allow some nice tries before using brute force else return mutate(params, x, range, count+1); // for really bad initial deviations this might be a quasi infinite loop @@ -695,13 +699,6 @@ public class MutateESRankMuCMA implements InterfaceMutationGenerational, Seriali } return x; } - - private boolean isInRange(double[] x, double[][] range) { - for (int i=0; irange[i][1])) return false; - } - return true; - } /** * After optimization start, this returns the initial sigma value diff --git a/src/eva2/server/go/operators/postprocess/InterfacePostProcessParams.java b/src/eva2/server/go/operators/postprocess/InterfacePostProcessParams.java index 76069582..9c4f5e4b 100644 --- a/src/eva2/server/go/operators/postprocess/InterfacePostProcessParams.java +++ b/src/eva2/server/go/operators/postprocess/InterfacePostProcessParams.java @@ -1,5 +1,7 @@ package eva2.server.go.operators.postprocess; +import eva2.server.go.enums.PostProcessMethod; + /** * Parameters for an optional post processing of found solutions. Mainly contains * parameters for a hill climbing step, namely the number of evaluations and @@ -25,4 +27,8 @@ public interface InterfacePostProcessParams { public int getPrintNBest(); public void setPrintNBest(int nBest); public String printNBestTipText(); + + public void setPPMethod(PostProcessMethod meth); + public PostProcessMethod getPPMethod(); + public String PPMethodTipText(); } diff --git a/src/eva2/server/go/operators/postprocess/PostProcess.java b/src/eva2/server/go/operators/postprocess/PostProcess.java index dfdc1614..1b70f532 100644 --- a/src/eva2/server/go/operators/postprocess/PostProcess.java +++ b/src/eva2/server/go/operators/postprocess/PostProcess.java @@ -1,28 +1,44 @@ package eva2.server.go.operators.postprocess; +import java.util.ArrayList; import java.util.Collection; import eva2.OptimizerFactory; import eva2.OptimizerRunnable; import eva2.gui.BeanInspector; +import eva2.gui.Plot; +import eva2.gui.TopoPlot; import eva2.server.go.InterfaceTerminator; +import eva2.server.go.enums.ESMutationInitialSigma; +import eva2.server.go.enums.PostProcessMethod; import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.ESIndividualDoubleData; +import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.individuals.InterfaceESIndividual; import eva2.server.go.operators.cluster.ClusteringDensityBased; import eva2.server.go.operators.cluster.InterfaceClustering; +import eva2.server.go.operators.crossover.CrossoverESDefault; import eva2.server.go.operators.distancemetric.InterfaceDistanceMetric; import eva2.server.go.operators.distancemetric.PhenotypeMetric; import eva2.server.go.operators.mutation.InterfaceMutation; import eva2.server.go.operators.mutation.MutateESFixedStepSize; import eva2.server.go.operators.mutation.MutateESMutativeStepSizeControl; +import eva2.server.go.operators.mutation.MutateESRankMuCMA; +import eva2.server.go.operators.selection.SelectBestIndividuals; import eva2.server.go.operators.terminators.EvaluationTerminator; import eva2.server.go.populations.Population; import eva2.server.go.problems.AbstractMultiModalProblemKnown; import eva2.server.go.problems.AbstractOptimizationProblem; import eva2.server.go.problems.FM0Problem; +import eva2.server.go.problems.Interface2DBorderProblem; import eva2.server.go.problems.InterfaceMultimodalProblemKnown; +import eva2.server.go.strategies.EvolutionStrategies; import eva2.server.go.strategies.HillClimbing; +import eva2.server.go.strategies.NelderMeadSimplex; +import eva2.server.modules.GOParameters; import eva2.server.stat.InterfaceTextListener; import eva2.server.stat.StatsParameter; +import eva2.tools.Mathematics; import eva2.tools.Pair; @@ -35,12 +51,14 @@ import eva2.tools.Pair; public class PostProcess { protected static InterfaceDistanceMetric metric = new PhenotypeMetric(); private static final boolean TRACE = false; + private static final boolean DRAW_PPPOP = true; + // the default mutation step size for HC post processing private static double defaultMutationStepSize = 0.01; // lower limit mutation step size for HC post processing private static double minMutationStepSize = 0.0000000000000001; // used for hill climbing post processing and only alive during that period - private static OptimizerRunnable hcRunnable = null; + private static OptimizerRunnable ppRunnable = null; public static final int BEST_ONLY = 1; public static final int BEST_RAND = 2; @@ -251,9 +269,9 @@ public class PostProcess { double lower = lowerBound; double step = (upperBound - lowerBound) / nBins; for (int i=0; i localSolverNMS(AbstractEAIndividual cand, int hcSteps, + double initPerturbation, AbstractOptimizationProblem prob) { + + Population pop = new Population(1); + pop.add(cand); + int evalsDone = processSingleCandidates(PostProcessMethod.nelderMead, pop, hcSteps, initPerturbation, prob); + + return new Pair(pop.getBestEAIndividual(), evalsDone); + +// Population candidates = NelderMeadSimplex.createNMSPopulation(cand, initPerturbation , range, false); +// prob.evaluate(candidates); +//// refSet.incrFunctionCallsby(candidates.size()); +// int evalsDone = candidates.size(); +// int hcStepsRest = hcSteps - candidates.size(); +// +// candidates.add(cand); +// candidates.setPopulationSize(candidates.size()); +// if (hcStepsRest < 1) { +// System.err.println("Error: Less steps than dimensions! " + hcSteps + " vs " + candidates.size()); +// return new Pair(candidates.getBestEAIndividual(), evalsDone); +// } else { +//// candidates.setEvaluated(); // they have all been evaluated at this point and no mod. is due +//// if (!candidates.isEvaluated()) { +//// System.err.println("this is bad!"); +//// } +// InterfaceTerminator term = new EvaluationTerminator(hcStepsRest); +// +// evalsDone += PostProcess.processWithNMS(candidates, prob, term); +// if (Math.abs(evalsDone-hcSteps)>1) { +// System.err.println("Error in localSolverNMS " + evalsDone + " / " + hcSteps); +// } +// } +// return new Pair(candidates.getBestEAIndividual(), evalsDone); + } + + /** + * Create a subpopulation around an indicated individual from the candidate set. + * Depending on the post processing method, this is done slightly differently. For hill-climbing, + * an error message is produced. + */ + private static Population createLSSupPopulation(PostProcessMethod method, AbstractOptimizationProblem problem, Population candidates, int index, double maxPerturbation, boolean includeCand) { + Population subPop = null; + switch (method) { + case cmaES: + subPop = createPopInSubRange(maxPerturbation, problem, candidates.getEAIndividual(index)); + break; + case hillClimber: + System.err.println("INVALID in createLSSupPopulation"); + break; + case nelderMead: + double[][] range = ((InterfaceDataTypeDouble)candidates.getEAIndividual(index)).getDoubleRange(); + double perturb = findNMSPerturn(candidates, index, maxPerturbation); + if (TRACE) System.out.println("perturb " + index + " is " + perturb); + subPop = NelderMeadSimplex.createNMSPopulation(candidates.getEAIndividual(index), perturb, range, false); + } + return subPop; + } + + /** + * For each candidate individual, create an own nm-population and optimize it separately. + * The allowed steps must be large enough to perform a Nelder-Mead-Simplex step for all individuals, namely + * for problem dimension n it should be (n+k)*candPopSize for a positive integer k. + * At the moment, the function calls are distributed evenly between all candidate solutions. This could be + * improved by checking the convergence state in the future. + * + * @param candidates + * @param steps + * @param maxPerturbation + * @param prob + * @return + */ + public static int processSingleCandidates(PostProcessMethod method, Population candidates, int steps, double maxPerturbation, AbstractOptimizationProblem prob) { + ArrayList nmPops = new ArrayList(); + int stepsPerf = 0; + Population subPop; + + for (int i=0; i 0) { clusteredPop = (Population)PostProcess.clusterBest(inputPop, params.getPostProcessClusterSigma(), 0, PostProcess.KEEP_LONERS, PostProcess.BEST_ONLY).clone(); if (clusteredPop.size() < inputPop.size()) { if (listener != null) listener.println("Initial clustering reduced population size from " + inputPop.size() + " to " + clusteredPop.size()); } else if (listener != null) listener.println("Initial clustering yielded no size reduction."); } else clusteredPop = inputPop; - +// if (DRAW_PPPOP) { +// plot = draw((params.getPostProcessClusterSigma()>0) ? "After first clustering" : "Initial population", null, clusteredPop, null, problem); +// } + + int stepsDone = 0; if (params.getPostProcessSteps() > 0) { - int stepsDone = processWithHC(clusteredPop, problem, params.getPostProcessSteps()); - if (listener != null) listener.println("HC post processing: " + stepsDone + " steps done."); + double stepSize = selectMaxSearchRange(params.getPPMethod(), params.getPostProcessClusterSigma()); + stateBeforeLS = (Population)clusteredPop.clone(); + // Actual local search comes here + if (params.getPPMethod() == PostProcessMethod.hillClimber){ + stepsDone = processWithHC(clusteredPop, problem, params.getPostProcessSteps(), stepSize, minMutationStepSize); + } else { + stepsDone = processSingleCandidates(params.getPPMethod(), clusteredPop, params.getPostProcessSteps(), stepSize, problem); + } + + if (listener != null) listener.println("Post processing: " + stepsDone + " steps done."); + if (DRAW_PPPOP) { + plot = draw("After " + stepsDone + " steps", null, stateBeforeLS, clusteredPop, problem); + } // some individuals may have now converged again if (params.getPostProcessClusterSigma() > 0) { // so if wished, cluster again. @@ -543,6 +901,9 @@ public class PostProcess { } else outputPop = clusteredPop; } else outputPop = clusteredPop; + if (DRAW_PPPOP) { + plot = draw("After " + stepsDone + " steps" + ((params.getPostProcessClusterSigma()>0) ? " and second clustering" : ""), null, outputPop, null, problem); + } double upBnd = PhenotypeMetric.norm(outputPop.getWorstEAIndividual().getFitness())*1.1; upBnd = Math.pow(10,Math.floor(Math.log10(upBnd)+1)); double lowBnd = 0; @@ -565,5 +926,56 @@ public class PostProcess { return nBestPop; } else return inputPop; } + + /** + * Select a local search range for a given method based on the clustering parameter. + * If clustering was deactivated (sigma <= 0), then the default mutation step size is used. + * The specific search method may interpret the search range differently. + * + * @param method + * @param postProcessClusterSigma + * @return + */ + private static double selectMaxSearchRange(PostProcessMethod method, + double postProcessClusterSigma) { + double resolution = defaultMutationStepSize*2; // somewhat keep the ratio between mutation and resolution + if (postProcessClusterSigma > 0.) resolution = postProcessClusterSigma; + switch (method) { + case hillClimber: + return resolution/2.; + case nelderMead: + return resolution/3.; + default: + System.err.println("Invalid method!"); + case cmaES: + return resolution; + } + } + + + /** + * Select a perturbation for individual i fitting to the population - avoiding overlap. + * In this case, return the third of the minimum distance to the next neighbor in the population. + * The maxPerturb can be given as upper bound of the perturbation if it is > 0. + * + * @param candidates population of solutions to look at + * @param i index of the individual in the population to look at + * @param maxPerturb optional upper bound of the returned perturbation + * @return + */ + private static double findNMSPerturn(Population candidates, int i, double maxPerturb) { + double minDistNeighbour = Double.MAX_VALUE; + AbstractEAIndividual indy = candidates.getEAIndividual(i); + for (int k=0; k0) return Math.min(maxPerturb, minDistNeighbour/3.); + else return minDistNeighbour/3.; + } } diff --git a/src/eva2/server/go/operators/postprocess/PostProcessParams.java b/src/eva2/server/go/operators/postprocess/PostProcessParams.java index 6046d100..9b0a1e50 100644 --- a/src/eva2/server/go/operators/postprocess/PostProcessParams.java +++ b/src/eva2/server/go/operators/postprocess/PostProcessParams.java @@ -3,6 +3,7 @@ package eva2.server.go.operators.postprocess; import java.io.Serializable; import eva2.gui.GenericObjectEditor; +import eva2.server.go.enums.PostProcessMethod; public class PostProcessParams implements InterfacePostProcessParams, Serializable { @@ -11,6 +12,7 @@ public class PostProcessParams implements InterfacePostProcessParams, Serializab private boolean postProcess = false; protected double postProcessClusterSigma = 0.05; protected int printNBest = 10; + protected PostProcessMethod method = PostProcessMethod.nelderMead; public PostProcessParams() { postProcessSteps = 5000; @@ -36,6 +38,14 @@ public class PostProcessParams implements InterfacePostProcessParams, Serializab printNBest = nBest; } + public PostProcessParams(PostProcessMethod meth, int steps, double clusterSigma, int nBest) { + method = meth; + postProcessSteps = steps; + postProcess = true; + postProcessClusterSigma = clusterSigma; + printNBest = nBest; + } + public void hideHideable() { setDoPostProcessing(isDoPostProcessing()); } @@ -54,6 +64,7 @@ public class PostProcessParams implements InterfacePostProcessParams, Serializab GenericObjectEditor.setShowProperty(this.getClass(), "postProcessSteps", postProcess); GenericObjectEditor.setShowProperty(this.getClass(), "postProcessClusterSigma", postProcess); GenericObjectEditor.setShowProperty(this.getClass(), "printNBest", postProcess); + GenericObjectEditor.setShowProperty(this.getClass(), "PPMethod", postProcess); } public String doPostProcessingTipText() { return "Toggle post processing of the solutions."; @@ -102,4 +113,16 @@ public class PostProcessParams implements InterfacePostProcessParams, Serializab public String globalInfo() { return "Combined clustering and hill-climbing for post-processing of solutions."; } + + public PostProcessMethod getPPMethod() { + return method; + } + + public String PPMethodTipText() { + return "The method to use for post-processing."; + } + + public void setPPMethod(PostProcessMethod meth) { + method=meth; + } } diff --git a/src/eva2/server/go/operators/selection/SelectParticleWheel.java b/src/eva2/server/go/operators/selection/SelectParticleWheel.java index b43d2d12..c34f2f87 100644 --- a/src/eva2/server/go/operators/selection/SelectParticleWheel.java +++ b/src/eva2/server/go/operators/selection/SelectParticleWheel.java @@ -25,6 +25,7 @@ public class SelectParticleWheel implements InterfaceSelection, java.io.Serializ */ private static final long serialVersionUID = 1L; private InterfaceSelectionProbability m_SelProbCalculator = new SelProbStandard(); + private boolean selectFixedSteps = false; public SelectParticleWheel() { } @@ -55,22 +56,8 @@ public class SelectParticleWheel implements InterfaceSelection, java.io.Serializ Population result = new Population(); result.setPopulationSize(size); - // use a fixed segment roulette wheel selection - double segment = 1./(size+1); - double selPoint = RNG.randomDouble(0., segment); - - int selIndex = 0; - double selFitSum = ((AbstractEAIndividual)population.getIndividual(selIndex)).getSelectionProbability(0); - - for (int i=0; i < size; i++) { - while (selFitSum < selPoint) { - selIndex++; - selFitSum += ((AbstractEAIndividual)population.getIndividual(selIndex)).getSelectionProbability(0); - } - result.add(((AbstractEAIndividual)population.get(selIndex)).clone()); - ((AbstractEAIndividual)result.getIndividual(i)).SetAge(0); - selPoint += segment; - } + if (selectFixedSteps ) selectFixed(population, size, result); + else selectDrawIndependent(population, size, result); //// Unfortunately, this was really problem specific (mk) // @@ -96,6 +83,42 @@ public class SelectParticleWheel implements InterfaceSelection, java.io.Serializ return result; } + private void selectDrawIndependent(Population population, int size, + Population result) { + double sum=0, selPoint=0; + int selIndex; + for (int i=0; i < size; i++) { + selPoint = RNG.randomDouble(); + selIndex = 0; + sum = ((AbstractEAIndividual)population.getIndividual(0)).getSelectionProbability(0); + while (selPoint>=sum) { + selIndex++; + sum += ((AbstractEAIndividual)population.getIndividual(selIndex)).getSelectionProbability(0); + } + result.add(((AbstractEAIndividual)population.get(selIndex)).clone()); + ((AbstractEAIndividual)result.getIndividual(i)).SetAge(0); + } + } + + private void selectFixed(Population population, int size, Population result) { + // use a fixed segment roulette wheel selection + double segment = 1./(size+1); + double selPoint = RNG.randomDouble(0., segment); + + int selIndex = 0; + double selFitSum = ((AbstractEAIndividual)population.getIndividual(selIndex)).getSelectionProbability(0); + + for (int i=0; i < size; i++) { + while (selFitSum < selPoint) { + selIndex++; + selFitSum += ((AbstractEAIndividual)population.getIndividual(selIndex)).getSelectionProbability(0); + } + result.add(((AbstractEAIndividual)population.get(selIndex)).clone()); + ((AbstractEAIndividual)result.getIndividual(i)).SetAge(0); + selPoint += segment; + } + } + /** This method allows you to select partners for a given Individual * @param dad The already seleceted parent * @param avaiablePartners The mating pool. @@ -138,4 +161,41 @@ public class SelectParticleWheel implements InterfaceSelection, java.io.Serializ public String obeyDebsConstViolationPrincipleToolTip() { return "Toggle the use of Deb's coonstraint violation principle(todo)."; } + + /** + * @return the selectFixedSteps + */ + public boolean isSelectFixedSteps() { + return selectFixedSteps; + } + + /** + * @param selectFixedSteps the selectFixedSteps to set + */ + public void setSelectFixedSteps(boolean selectFixedSteps) { + this.selectFixedSteps = selectFixedSteps; + } + + public String selectFixedStepsTipText() { + return "Use fixed segment wheel for selection if marked or independent draws if not."; + } + + /** + * @return the m_SelProbCalculator + */ + public InterfaceSelectionProbability getSelProbCalculator() { + return m_SelProbCalculator; + } + + /** + * @param selProbCalculator the m_SelProbCalculator to set + */ + public void setSelProbCalculator( + InterfaceSelectionProbability selProbCalculator) { + m_SelProbCalculator = selProbCalculator; + } + + public String selProbCalculatorTipText() { + return "The method for calculating selection probability from the fitness."; + } } \ No newline at end of file diff --git a/src/eva2/server/go/problems/AbstractMultiModalProblemKnown.java b/src/eva2/server/go/problems/AbstractMultiModalProblemKnown.java index 00d49e4f..2be8aedf 100644 --- a/src/eva2/server/go/problems/AbstractMultiModalProblemKnown.java +++ b/src/eva2/server/go/problems/AbstractMultiModalProblemKnown.java @@ -12,6 +12,7 @@ import eva2.server.go.operators.postprocess.PostProcess; import eva2.server.go.populations.Population; import eva2.server.go.problems.Interface2DBorderProblem; +import eva2.tools.EVAERROR; public abstract class AbstractMultiModalProblemKnown extends AbstractProblemDouble implements Interface2DBorderProblem, InterfaceMultimodalProblemKnown { protected static InterfaceDistanceMetric m_Metric = new PhenotypeMetric(); @@ -239,17 +240,26 @@ public abstract class AbstractMultiModalProblemKnown extends AbstractProblemDoub } public static double getMaximumPeakRatio(InterfaceMultimodalProblemKnown mmProb, Population pop, double epsilon) { - double optimaInvertedSum = 0, foundInvertedSum = 0; - Population realOpts = mmProb.getRealOptima(); + double foundInvertedSum = 0, sumRealMaxima = 0; + Population realOpts = mmProb.getRealOptima(); + double maxOpt = realOpts.getEAIndividual(0).getFitness(0); + sumRealMaxima = maxOpt; + for (int i=1; i m_Listener; + private String m_Identifier = "NelderMeadSimplex"; + + public NelderMeadSimplex() { + setPopulation(new Population(populationSize)); + } + + public NelderMeadSimplex(NelderMeadSimplex a) { + m_Problem = (AbstractOptimizationProblem)a.m_Problem.clone(); + setPopulation((Population)a.m_Population.clone()); + populationSize = a.populationSize; + generationCycle = a.generationCycle; + m_Identifier = a.m_Identifier; + } + + public NelderMeadSimplex clone() { + return new NelderMeadSimplex(this); + } + + + public void SetIdentifier(String name) { + m_Identifier = name; + + } + + public void SetProblem(InterfaceOptimizationProblem problem) { + m_Problem = (AbstractOptimizationProblem)problem; + } + + public boolean setProblemAndPopSize(InterfaceOptimizationProblem problem) { + SetProblem(problem); + if (m_Problem instanceof AbstractProblemDouble) { + setPopulationSize(((AbstractProblemDouble)problem).getProblemDimension()+1); + return true; + } else { + Object ret=BeanInspector.callIfAvailable(problem, "getProblemDimension", null); + if (ret!=null) { + setPopulationSize(((Integer)ret)+1); + return true; + } + } + return false; + } + + public void addPopulationChangedEventListener( + InterfacePopulationChangedEventListener ea) { + if (m_Listener == null) m_Listener = new Vector(); + if (!m_Listener.contains(ea)) m_Listener.add(ea); + } + + public void freeWilly() {} + + public AbstractEAIndividual simplexStep(Population subpop) { + // parameter + + + // hole die n-1 besten individuen + Population bestpop = subpop.getBestNIndividuals(subpop.size()-1); + // und das schlechteste + AbstractEAIndividual worst = subpop.getWorstEAIndividual(); + AbstractEAIndividual best=subpop.getBestEAIndividual(); + double[] u_q = ((InterfaceDataTypeDouble) worst).getDoubleData(); + int dim = u_q.length; + + // Centroid berechnen + double[] g = new double[dim]; + for (int i=0; ir_ind.getFitness(0)){ //neues besser als bisher bestes => Expansion + + double[] e = new double[dim]; + for (int i=0; i= bestpop.getWorstEAIndividual().getFitness(0)){//kontrahiere da neues indi keine verbesserung brachte + double[] c = new double[dim]; + for (int i=0; i 0 ) try { Thread.sleep(sleepTime); } catch(Exception e) {} + if (withShow) clearPlot(); + // predict step predict(nextGeneration); @@ -166,9 +178,8 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S // collectStatistics(m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); - if (sleepTime > 0 ) try { Thread.sleep(sleepTime); } catch(Exception e) {} } // protected void collectStatistics(Population population) { @@ -194,6 +205,9 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S */ public void SetProblem (InterfaceOptimizationProblem problem) { this.m_Problem = problem; + if (problem instanceof AbstractOptimizationProblem) { + ((AbstractOptimizationProblem)problem).informAboutOptimizer(this); + } } public InterfaceOptimizationProblem getProblem () { return this.m_Problem; @@ -252,6 +266,7 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S return this.m_Population; } public void setPopulation(Population pop){ +// if (pop.size()!=pop.getPopulationSize()) pop.fitToSize(); this.m_Population = pop; } public String populationTipText() { @@ -281,6 +296,17 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S return withShow; } + protected void clearPlot() { + if (myPlot!=null) { + myPlot.clearAll(); + double[][] range = null; + if ((m_Population != null) && (m_Population.size() > 0)) range = ((InterfaceDataTypeDouble)this.m_Population.get(0)).getDoubleRange(); + if (range != null) { + myPlot.setCornerPoints(range, 0); + } + } + } + /** * @param withShow the withShow to set **/ @@ -297,7 +323,7 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S range[0][1] = 0; range[1] = range[0]; // this is evil } - myPlot = new eva2.gui.Plot("PF", "x1", "x2", true); + myPlot = new eva2.gui.Plot("PF", "x1", "x2", range[0], range[1]); } } diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java index 0946cdf9..a6f0502d 100644 --- a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java @@ -406,7 +406,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se initIndividualDefaults(indy); } indy.putData(indexKey, i); - indy.setIndividualIndex(i); + indy.SetIndividualIndex(i); } } @@ -1435,7 +1435,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se initIndividualDefaults(indy); initIndividualMemory(indy); indy.putData(indexKey, i); - indy.setIndividualIndex(i); + indy.SetIndividualIndex(i); if (TRACE) System.err.println("init indy " + i + " " + AbstractEAIndividual.getDefaultDataString(indy)); } } diff --git a/src/eva2/server/modules/GOParameters.java b/src/eva2/server/modules/GOParameters.java index 748beb34..3cf1e359 100644 --- a/src/eva2/server/modules/GOParameters.java +++ b/src/eva2/server/modules/GOParameters.java @@ -51,7 +51,7 @@ public class GOParameters extends AbstractGOParameters implements InterfaceGOPar */ public GOParameters() { super(new GeneticAlgorithm(), new F1Problem(), new EvaluationTerminator(1000)); - ((F1Problem)m_Problem).setEAIndividual(new GAIndividualDoubleData()); +// ((F1Problem)m_Problem).setEAIndividual(new GAIndividualDoubleData()); } /** diff --git a/src/eva2/tools/Mathematics.java b/src/eva2/tools/Mathematics.java index 99a962b7..feec7d5c 100644 --- a/src/eva2/tools/Mathematics.java +++ b/src/eva2/tools/Mathematics.java @@ -688,6 +688,20 @@ public class Mathematics { return minVal; } + /** + * Check whether the given vector lies within the range in every dimension. + * + * @param x + * @param range + * @return true if the vector lies within the range, else false + */ + public static boolean isInRange(double[] x, double[][] range) { + for (int i=0; irange[i][1])) return false; + } + return true; + } + /** * Project the values in x to the range given. The range must be an vector of 2d-arrays * each of which containing lower and upper bound in the i-th dimension.