diff --git a/src/eva2/OptimizerFactory.java b/src/eva2/OptimizerFactory.java index 6d4cc4d1..7db0bd17 100644 --- a/src/eva2/OptimizerFactory.java +++ b/src/eva2/OptimizerFactory.java @@ -101,6 +101,8 @@ public class OptimizerFactory { public final static int CL_HILLCL = 10; public final static int CMA_ES_IPOP = 11; + + public final static int CBN_GA = 12; public final static int defaultFitCalls = 10000; @@ -142,6 +144,8 @@ public class OptimizerFactory { de.addPopulationChangedEventListener(listener); de.init(); + listener.registerPopulationStateChanged(de.getPopulation(), ""); + return de; } @@ -208,13 +212,14 @@ public class OptimizerFactory { AbstractEAIndividual tmpIndi = problem.getIndividualTemplate(); AbstractEAIndividual.setOperators(tmpIndi, mutationoperator, pm, crossoveroperator, pc); - EvolutionStrategies es = new EvolutionStrategies(); - es.addPopulationChangedEventListener(listener); - //es.setParentSelection(selection); - //es.setPartnerSelection(selection); - es.setEnvironmentSelection(selection); - es.SetProblem(problem); - es.init(); + theES.addPopulationChangedEventListener(listener); +// theES.setParentSelection(selection); +// theES.setPartnerSelection(selection); + theES.setEnvironmentSelection(selection); + theES.SetProblem(problem); + theES.init(); + + if (listener != null) listener.registerPopulationStateChanged(theES.getPopulation(), ""); return theES; } @@ -254,6 +259,8 @@ public class OptimizerFactory { ga.addPopulationChangedEventListener(listener); ga.init(); + listener.registerPopulationStateChanged(ga.getPopulation(), ""); + return ga; } @@ -365,6 +372,8 @@ public class OptimizerFactory { hc.SetProblem(problem); hc.init(); + listener.registerPopulationStateChanged(hc.getPopulation(), ""); + return hc; } @@ -394,10 +403,11 @@ public class OptimizerFactory { mc.SetProblem(problem); mc.init(); + listener.registerPopulationStateChanged(mc.getPopulation(), ""); + return mc; } - /** * This method performs a particle swarm optimization. Standard topologies are * linear (0), grid (1) and star (2). @@ -438,6 +448,8 @@ public class OptimizerFactory { pso.addPopulationChangedEventListener(listener); pso.init(); + listener.registerPopulationStateChanged(pso.getPopulation(), ""); + return pso; } @@ -477,6 +489,8 @@ public class OptimizerFactory { sa.addPopulationChangedEventListener(listener); sa.init(); + listener.registerPopulationStateChanged(sa.getPopulation(), ""); + return sa; } @@ -526,9 +540,11 @@ public class OptimizerFactory { case CBN_ES: return cbnES(problem); case CL_HILLCL: - return clusteringHillClimbing(problem); + return stdClusteringHillClimbing(problem); case CMA_ES_IPOP: return cmaESIPOP(problem); + case CBN_GA: + return cbnGA(problem); default: System.err.println("Error: optimizer type " + optType + " is unknown!"); @@ -602,7 +618,6 @@ public class OptimizerFactory { AbstractOptimizationProblem problem, String outputFilePrefix) { return getOptRunnable(optType, problem, getTerminator(), outputFilePrefix); } - /** * Return the current user-defined or, if none was set, the default terminator. * @@ -649,6 +664,18 @@ public class OptimizerFactory { return makeParams(opt, popSize, problem, randSeed, makeDefaultTerminator()); } + /** + * Set the population size, initialize the population and return a parameter structure containing all + * given parts. + * + * @see #makeParams(InterfaceOptimizer, Population, AbstractOptimizationProblem, long, InterfaceTerminator) + * @param opt + * @param popSize + * @param problem + * @param seed + * @param term + * @return + */ public static GOParameters makeParams(InterfaceOptimizer opt, int popSize, AbstractOptimizationProblem problem, long seed, InterfaceTerminator term) { @@ -1035,9 +1062,20 @@ public class OptimizerFactory { */ public static final GOParameters hillClimbing( AbstractOptimizationProblem problem) { - return makeParams(new HillClimbing(), 50, problem, randSeed, makeDefaultTerminator()); + return hillClimbing(problem, 50); } - + + /** + * Create a standard multi-start hill-climber parameter set with the given number of + * individuals. + * + * @return a standard multi-start hill-climber + */ + public static final GOParameters hillClimbing( + AbstractOptimizationProblem problem, int popSize) { + return makeParams(new HillClimbing(), popSize, problem, randSeed, makeDefaultTerminator()); + } + public static final GOParameters monteCarlo( AbstractOptimizationProblem problem) { return makeParams(new MonteCarloSearch(), 50, problem, randSeed, makeDefaultTerminator()); @@ -1058,21 +1096,84 @@ public class OptimizerFactory { return makeParams(cbn, 100, problem, randSeed, makeDefaultTerminator()); } + public static final GOParameters cbnGA(AbstractOptimizationProblem problem) { + ClusterBasedNichingEA cbn = new ClusterBasedNichingEA(); + GeneticAlgorithm ga = new GeneticAlgorithm(); + cbn.setOptimizer(ga); + ClusteringDensityBased clustering = new ClusteringDensityBased(0.1); + cbn.setConvergenceCA((ClusteringDensityBased) clustering.clone()); + cbn.setDifferentationCA(clustering); + cbn.setShowCycle(0); // don't do graphical output + + return makeParams(cbn, 100, problem, randSeed, makeDefaultTerminator()); + } + + /** + * Create a standard clustering hill climbing employing simple ES mutation with adaptive + * step size, starting in parallel 100 local searches and clustering intermediate populations + * to avoid optima being found several times by the same population (density based clustering with + * sigma = 0.05). + * The population is reinitialized if the average progress of one cycle does not exceed 1e-6. + * + * @param problem + * @return + */ + public static final GOParameters stdClusteringHillClimbing( + AbstractOptimizationProblem problem) { + return clusteringHillClimbing(problem, 1000, 100, 0.000001, + PostProcessMethod.hillClimber, 0.05, 0.000001, 0.05); + } + + /** + * Create a clustering hillclimber using nelder mead and additional given parameters. + * + * @param problem + * @param evalCycle + * @param popSize + * @param minImprovement + * @param method + * @param sigmaClust + * @return + */ + public static final GOParameters clusteringHillClimbingNM(AbstractOptimizationProblem problem, + int evalCycle, int popSize, double minImprovement, double sigmaClust) { + return clusteringHillClimbing(problem, evalCycle, popSize, minImprovement, + PostProcessMethod.nelderMead, 0.01, 0.00000001, sigmaClust); + } + + /** + * Create a custom clustering hillclimber using ES mutation (simple or CMA) or nelder mead. + * The parameters hcInitialStep and hcStepThresh are + * only relevant for the simple mutation based hc method. + * + * @param problem + * @param evalCycle + * @param popSize + * @param minImprovement + * @param method + * @param hcInitialStep + * @param hcStepThresh + * @param sigmaClust + * @return + */ public static final GOParameters clusteringHillClimbing( - AbstractOptimizationProblem problem) { + AbstractOptimizationProblem problem, int evalCycle, int popSize, double minImprovement, + PostProcessMethod method, double hcInitialStep, double hcStepThresh, double sigmaClust) { ClusteringHillClimbing chc = new ClusteringHillClimbing(); chc.SetProblem(problem); - chc.setHcEvalCycle(1000); - chc.setInitialPopSize(100); - chc.setStepSizeInitial(0.05); - chc.setMinImprovement(0.000001); + chc.setEvalCycle(evalCycle); + chc.setInitialPopSize(popSize); + chc.setStepSizeInitial(hcInitialStep); + chc.setLocalSearchMethod(method); + chc.setMinImprovement(minImprovement); chc.setNotifyGuiEvery(0); - chc.setStepSizeThreshold(0.000001); - chc.setSigmaClust(0.05); - return makeParams(chc, 100, problem, randSeed, makeDefaultTerminator()); + chc.setStepSizeThreshold(hcStepThresh); + chc.setSigmaClust(sigmaClust); + return makeParams(chc, popSize, problem, randSeed, makeDefaultTerminator()); } + public static final GOParameters cmaES(AbstractOptimizationProblem problem) { EvolutionStrategies es = new EvolutionStrategies(); es.setMu(15); diff --git a/src/eva2/gui/PropertyPanel.java b/src/eva2/gui/PropertyPanel.java index ce6e6563..377acebe 100644 --- a/src/eva2/gui/PropertyPanel.java +++ b/src/eva2/gui/PropertyPanel.java @@ -25,67 +25,71 @@ import javax.swing.JPanel; import eva2.tools.EVAHELP; /*==========================================================================* -* CLASS DECLARATION -*==========================================================================*/ + * CLASS DECLARATION + *==========================================================================*/ /** * */ public class PropertyPanel extends JPanel { - private PropertyEditor m_PropertyEditor; - private PropertyDialog m_PropertyDialog; - /** - * - */ - public PropertyPanel(PropertyEditor Editor) { - setBorder(BorderFactory.createEtchedBorder()); - setToolTipText("Click to edit properties for this object"); - setOpaque(true); - m_PropertyEditor = Editor; - addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent evt) { - if (m_PropertyEditor.getValue() != null) { - if (m_PropertyDialog == null) { - int x = getLocationOnScreen().x; - int y = getLocationOnScreen().y; - m_PropertyDialog = new PropertyDialog(m_PropertyEditor, EVAHELP.cutClassName(m_PropertyEditor.getClass().getName()) , x, y); - } - else { - m_PropertyDialog.updateFrameTitle(m_PropertyEditor); - m_PropertyDialog.setVisible(true); - } + private PropertyEditor m_PropertyEditor; + private PropertyDialog m_PropertyDialog; + /** + * + */ + public PropertyPanel(PropertyEditor Editor) { + setBorder(BorderFactory.createEtchedBorder()); + setToolTipText("Click to edit properties for this object"); + setOpaque(true); + m_PropertyEditor = Editor; + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + if (m_PropertyEditor.getValue() != null) { + if (m_PropertyDialog == null) { + int x = getLocationOnScreen().x; + int y = getLocationOnScreen().y; + m_PropertyDialog = new PropertyDialog(m_PropertyEditor, EVAHELP.cutClassName(m_PropertyEditor.getClass().getName()) , x, y); + } + else { + m_PropertyDialog.updateFrameTitle(m_PropertyEditor); + m_PropertyDialog.setVisible(true); + } + } + } + }); + Dimension newPref = getPreferredSize(); + newPref.height = getFontMetrics(getFont()).getHeight() * 6 / 4; //6 / 4; + newPref.width = newPref.height * 6; //5 + setPreferredSize(newPref); } - } - }); - Dimension newPref = getPreferredSize(); - newPref.height = getFontMetrics(getFont()).getHeight() * 6 / 4; //6 / 4; - newPref.width = newPref.height * 6; //5 - setPreferredSize(newPref); - } - /** - * - */ - public void removeNotify() { - if (m_PropertyDialog != null) { - //System.out.println(" m_PropertyDialog.dispose();"); - m_PropertyDialog.dispose(); - m_PropertyDialog = null; - } - } - /** - * - */ - public void paintComponent(Graphics g) { - Insets i = getInsets(); - Rectangle box = new Rectangle(i.left, i.top, - getSize().width - i.left - i.right , - getSize().height - i.top - i.bottom); - g.clearRect(i.left, i.top, - getSize().width - i.right - i.left, - getSize().height - i.bottom - i.top); - m_PropertyEditor.paintValue(g, box); + /** + * + */ + public void removeNotify() { + if (m_PropertyDialog != null) { + //System.out.println(" m_PropertyDialog.dispose();"); + m_PropertyDialog.dispose(); + m_PropertyDialog = null; + } + } + /** + * + */ + public void paintComponent(Graphics g) { + Insets i = getInsets(); + Rectangle box = new Rectangle(i.left, i.top, + getSize().width - i.left - i.right , + getSize().height - i.top - i.bottom); + g.clearRect(i.left, i.top, + getSize().width - i.right - i.left, + getSize().height - i.bottom - i.top); + m_PropertyEditor.paintValue(g, box); -// Rectangle box = new Rectangle(i.left,i.top, -// this.getWidth() - i.right, -// this.getHeight() - i.bottom ); - } +// Rectangle box = new Rectangle(i.left,i.top, +// this.getWidth() - i.right, +// this.getHeight() - i.bottom ); + } + + public PropertyEditor getEditor() { + return m_PropertyEditor; + } } diff --git a/src/eva2/gui/PropertySheetPanel.java b/src/eva2/gui/PropertySheetPanel.java index cb72d4b0..1836d3c8 100644 --- a/src/eva2/gui/PropertySheetPanel.java +++ b/src/eva2/gui/PropertySheetPanel.java @@ -51,7 +51,13 @@ import eva2.tools.StringTools; * CLASS DECLARATION *==========================================================================*/ /** - * + * TODO: document those tricks somewhere + * Trick methods: + * String[] getGOEPropertyUpdateLinks() + * void hideHideable() + * void globalInfo() + * Trick statics: + * boolean hideFromGOE */ public class PropertySheetPanel extends JPanel implements PropertyChangeListener { public final static boolean TRACE = false; @@ -232,7 +238,7 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener } } // end for (int i = 0; i < m_Methods.length; i++) { - // Now lets search for the individual properties their + // Now lets search for the individual properties, their // values, views and editors... m_Editors = new PropertyEditor[m_Properties.length]; m_Values = new Object[m_Properties.length]; @@ -319,77 +325,7 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener } // end try // Add some specific display for some greeks here - if (name.equalsIgnoreCase("alpha")) - name = "\u03B1"; - if (name.equalsIgnoreCase("beta")) - name = "\u03B2"; - if (name.equalsIgnoreCase("gamma")) - name = "\u03B3"; - if (name.equalsIgnoreCase("gammab")) - name = "\u0393"; - if (name.equalsIgnoreCase("delta")) - name = "\u03B4"; - if (name.equalsIgnoreCase("deltab")) - name = "\u0394"; - if ((name.equalsIgnoreCase("epsi")) || (name.equalsIgnoreCase("epsilon"))) - name = "\u03B5"; - if (name.equalsIgnoreCase("zeta")) - name = "\u03B6"; - if (name.equalsIgnoreCase("theta")) - name = "\u03D1"; - if (name.equalsIgnoreCase("thetab")) - name = "\u0398"; - if (name.equalsIgnoreCase("iota")) - name = "\u03B9"; - if (name.equalsIgnoreCase("kappa")) - name = "\u03BA"; - if (name.equalsIgnoreCase("lambda")) - name = "\u03BB"; - if (name.equalsIgnoreCase("lambdab")) - name = "\u039B"; - if (name.equalsIgnoreCase("rho")) - name = "\u03C1"; - if (name.equalsIgnoreCase("sigma")) - name = "\u03C3"; - if (name.equalsIgnoreCase("sigmab")) - name = "\u03A3"; - if (name.equalsIgnoreCase("tau")) - name = "\u03C4"; - if (name.equalsIgnoreCase("upsilon")) - name = "\u03C5"; - if (name.equalsIgnoreCase("upsilonb")) - name = "\u03D2"; - if (name.equalsIgnoreCase("omega")) - name = "\u03C9"; - if (name.equalsIgnoreCase("omegab")) - name = "\u03A9"; - - // these are too small - if (name.equalsIgnoreCase("eta")) - name = "\u03B7"; - if (name.equalsIgnoreCase("psi")) - name = "\u03C8"; - if (name.equalsIgnoreCase("psib")) - name = "\u03A8"; - if (name.equalsIgnoreCase("phi")) - name = "\u03D5"; - if (name.equalsIgnoreCase("phib")) - name = "\u03A6"; - if (name.equalsIgnoreCase("chi")) - name = "\u03C7"; - if ((name.equalsIgnoreCase("mu")) || (name.equalsIgnoreCase("my")) || (name.equalsIgnoreCase("myu"))) - name = "\u03BC"; - if (name.equalsIgnoreCase("nu")) - name = "\u03BD"; - if (name.equalsIgnoreCase("xi")) - name = "\u03BE"; - if (name.equalsIgnoreCase("xib")) - name = "\u039E"; - if (name.equalsIgnoreCase("pi")) - name = "\u03C0"; - if (name.equalsIgnoreCase("pib")) - name = "\u03A0"; - + name = translateGreek(name); m_Labels[i] = new JLabel(name, SwingConstants.RIGHT); m_Labels[i].setBorder(BorderFactory.createEmptyBorder(10,10,0,5)); @@ -449,7 +385,83 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener setVisible(true); } - /** + private String translateGreek(String name) { + // Add some specific display for some greeks here + if (name.equalsIgnoreCase("alpha")) + return "\u03B1"; + if (name.equalsIgnoreCase("beta")) + return "\u03B2"; + if (name.equalsIgnoreCase("gamma")) + return "\u03B3"; + if (name.equalsIgnoreCase("gammab")) + return "\u0393"; + if (name.equalsIgnoreCase("delta")) + return "\u03B4"; + if (name.equalsIgnoreCase("deltab")) + return "\u0394"; + if ((name.equalsIgnoreCase("epsi")) || (name.equalsIgnoreCase("epsilon"))) + return "\u03B5"; + if (name.equalsIgnoreCase("zeta")) + return "\u03B6"; + if (name.equalsIgnoreCase("theta")) + return "\u03D1"; + if (name.equalsIgnoreCase("thetab")) + return "\u0398"; + if (name.equalsIgnoreCase("iota")) + return "\u03B9"; + if (name.equalsIgnoreCase("kappa")) + return "\u03BA"; + if (name.equalsIgnoreCase("lambda")) + return "\u03BB"; + if (name.equalsIgnoreCase("lambdab")) + return "\u039B"; + if (name.equalsIgnoreCase("rho")) + return "\u03C1"; + if (name.equalsIgnoreCase("sigma")) + return "\u03C3"; + if (name.equalsIgnoreCase("sigmab")) + return "\u03A3"; + if (name.equalsIgnoreCase("tau")) + return "\u03C4"; + if (name.equalsIgnoreCase("upsilon")) + return "\u03C5"; + if (name.equalsIgnoreCase("upsilonb")) + return "\u03D2"; + if (name.equalsIgnoreCase("omega")) + return "\u03C9"; + if (name.equalsIgnoreCase("omegab")) + return "\u03A9"; + + // these are too small + if (name.equalsIgnoreCase("eta")) + return "\u03B7"; + if (name.equalsIgnoreCase("psi")) + return "\u03C8"; + if (name.equalsIgnoreCase("psib")) + return "\u03A8"; + if (name.equalsIgnoreCase("phi")) + return "\u03D5"; + if (name.equalsIgnoreCase("phib")) + return "\u03A6"; + if (name.equalsIgnoreCase("chi")) + return "\u03C7"; + if ((name.equalsIgnoreCase("mu")) || (name.equalsIgnoreCase("my")) || (name.equalsIgnoreCase("myu"))) + return "\u03BC"; + if (name.equalsIgnoreCase("nu")) + return "\u03BD"; + if (name.equalsIgnoreCase("xi")) + return "\u03BE"; + if (name.equalsIgnoreCase("xib")) + return "\u039E"; + if (name.equalsIgnoreCase("pi")) + return "\u03C0"; + if (name.equalsIgnoreCase("pib")) + return "\u03A0"; + + return name; + } + + /** * Get the html help file name. * * @return @@ -496,6 +508,109 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener public int editableProperties() { return m_NumEditable; } + + /** + * Return true if the modification was successful. + * + * @param i + * @param newValue + * @return + */ + synchronized boolean updateValue(int i, Object newValue) { + PropertyDescriptor property = m_Properties[i]; + Method getter = m_Properties[i].getReadMethod(); + m_Values[i] = newValue; + Method setter = property.getWriteMethod(); + // @todo: Streiche so something was changed, i could check if i have to change the editor + + if (TRACE) System.out.println("Updating prop index " + i + " with " + newValue); + PropertyEditor tmpEdit = null; + // the findEditor method using properties may retrieve a primitive editor, the other one, for obscure reasons, cant. + // so Ill use the mightier first. + tmpEdit = PropertyEditorProvider.findEditor(m_Properties[i], newValue); + if (tmpEdit == null) tmpEdit = PropertyEditorProvider.findEditor(m_Properties[i].getPropertyType()); + if (tmpEdit.getClass() != m_Editors[i].getClass()) { + m_Values[i] = newValue; + m_Editors[i] = tmpEdit; + if (tmpEdit instanceof GenericObjectEditor) ((GenericObjectEditor) tmpEdit).setClassType(m_Properties[i].getPropertyType()); + m_Editors[i].setValue(newValue); + JComponent NewView = null; + if (tmpEdit instanceof sun.beans.editors.BoolEditor) { + NewView = new PropertyBoolSelector(tmpEdit); + } else { + if (tmpEdit instanceof sun.beans.editors.DoubleEditor) { + NewView = new PropertyText(tmpEdit); + } else { + if (tmpEdit.isPaintable() && tmpEdit.supportsCustomEditor()) { + NewView = new PropertyPanel(tmpEdit); + } else { + if (tmpEdit.getTags() != null ) { + NewView = new PropertyValueSelector(tmpEdit); + } else { + if (tmpEdit.getAsText() != null) { + NewView = new PropertyText(tmpEdit); + } else { + System.out.println("Warning: Property \"" + m_Properties[i].getDisplayName() + + "\" has non-displayabale editor. Skipping."); + return false; + } + } + } + } + } + m_Editors[i].addPropertyChangeListener(this); + m_Views[i] = NewView; + if (m_TipTexts[i] != null) m_Views[i].setToolTipText(m_TipTexts[i]); + m_ViewWrapper[i].removeAll(); + m_ViewWrapper[i].setLayout(new BorderLayout()); + m_ViewWrapper[i].add(m_Views[i], BorderLayout.CENTER); + m_ViewWrapper[i].repaint(); + } + +// System.out.println("Value: "+value +" / m_Values[i]: " + m_Values[i]); + // Now try to update the target with the new value of the property + // and allow the target to do some changes to the value, therefore + // reread the new value from the target + try { + Object args[] = { newValue }; + args[0] = newValue; + Object args2[] = { }; + // setting the current value to the target object + setter.invoke(m_Target, args); + // i could also get the new value + //value = getter.invoke(m_Target, args2); + // Now i'm reading the set value from the target to my local values + m_Values[i] = getter.invoke(m_Target, args2); + + if (newValue instanceof Integer) { + // This could check whether i have to set the value back to + // the editor, this would allow to check myu and lambda + // why shouldn't i do this for every property!? +// System.out.println("value: "+((Integer)value).intValue()); +// System.out.println(" m_Values[i]: "+ ((Integer) m_Values[i]).intValue()); + if (((Integer)newValue).intValue() != ((Integer) m_Values[i]).intValue()) { + m_Editors[i].setValue(m_Values[i]); + } + } + } catch (InvocationTargetException ex) { + if (ex.getTargetException() instanceof PropertyVetoException) { + System.out.println("PropertySheetPanel.wasModified(): WARNING: Vetoed; reason is: " + ex.getTargetException().getMessage()); + } else { + System.out.println("PropertySheetPanel.wasModified(): InvocationTargetException while updating " + property.getName()); + System.out.println("PropertySheetPanel.wasModified(): "+ex.getMessage()); + ex.printStackTrace(); + } + } catch (Exception ex) { + System.out.println("PropertySheetPanel.wasModified(): Unexpected exception while updating " + property.getName()); + } + //revalidate(); + if (m_Views[i] != null && m_Views[i] instanceof PropertyPanel) { + //System.err.println("Trying to repaint the property canvas"); + m_Views[i].repaint(); + revalidate(); + } + return true; + } /** Updates the propertysheet when a value has been changed (from outside * the propertysheet?). @@ -503,171 +618,48 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener */ synchronized void wasModified(PropertyChangeEvent evt) { if (TRACE) { - System.out.println("PropertySheetPanel.wasModified(): My Target is "+this.m_Target.getClass()); + System.out.println("*********** PropertySheetPanel.wasModified(): My Target is "+this.m_Target.getClass()); System.out.println("PropertySheetPanel.wasModified(): "+evt.toString()+" - "+evt.getNewValue()); } + int propIndex=-1; if (evt.getSource() instanceof PropertyEditor) { PropertyEditor editor = (PropertyEditor) evt.getSource(); for (int i = 0 ; i < m_Editors.length; i++) { if (m_Editors[i] == editor) { - PropertyDescriptor property = m_Properties[i]; - Method getter = m_Properties[i].getReadMethod(); - Object value = editor.getValue(); - m_Values[i] = value; - Method setter = property.getWriteMethod(); - // @todo: Streiche so something was changed, i could check if i have to change the editor - - PropertyEditor tmpEdit = null; - Object newValue = evt.getNewValue(); - if (newValue == null) newValue = editor.getValue(); - // the findEditor method using properties may retrieve a primitive editor, the other one, for obscure reasons, cant. - // so Ill use the mightier first. - tmpEdit = PropertyEditorProvider.findEditor(m_Properties[i], newValue); - if (tmpEdit == null) tmpEdit = PropertyEditorProvider.findEditor(m_Properties[i].getPropertyType()); - if (tmpEdit.getClass() != m_Editors[i].getClass()) { - value = newValue; - m_Values[i] = newValue; - m_Editors[i] = tmpEdit; - if (tmpEdit instanceof GenericObjectEditor) ((GenericObjectEditor) tmpEdit).setClassType(m_Properties[i].getPropertyType()); - m_Editors[i].setValue(newValue); - JComponent NewView = null; - if (tmpEdit instanceof sun.beans.editors.BoolEditor) { - NewView = new PropertyBoolSelector(tmpEdit); - } else { - if (tmpEdit instanceof sun.beans.editors.DoubleEditor) { - NewView = new PropertyText(tmpEdit); - } else { - if (tmpEdit.isPaintable() && tmpEdit.supportsCustomEditor()) { - NewView = new PropertyPanel(tmpEdit); - } else { - if (tmpEdit.getTags() != null ) { - NewView = new PropertyValueSelector(tmpEdit); - } else { - if (tmpEdit.getAsText() != null) { - NewView = new PropertyText(tmpEdit); - } else { - System.out.println("Warning: Property \"" + m_Properties[i].getDisplayName() - + "\" has non-displayabale editor. Skipping."); - continue; - } - } - } - } - } - m_Editors[i].addPropertyChangeListener(this); - m_Views[i] = NewView; - if (m_TipTexts[i] != null) m_Views[i].setToolTipText(m_TipTexts[i]); - m_ViewWrapper[i].removeAll(); - m_ViewWrapper[i].setLayout(new BorderLayout()); - m_ViewWrapper[i].add(m_Views[i], BorderLayout.CENTER); - m_ViewWrapper[i].repaint(); - } - -// System.out.println("Value: "+value +" / m_Values[i]: " + m_Values[i]); - // Now try to update the target with the new value of the property - // and allow the target to do some changes to the value, therefore - // reread the new value from the target - try { - Object args[] = { value }; - args[0] = value; - Object args2[] = { }; - // setting the current value to the target object - setter.invoke(m_Target, args); - // i could also get the new value - //value = getter.invoke(m_Target, args2); - // Now i'm reading the set value from the target to my local values - m_Values[i] = getter.invoke(m_Target, args2); - - if (value instanceof Integer) { - // This could check whether i have to set the value back to - // the editor, this would allow to check myu and lambda - // why shouldn't i do this for every property!? -// System.out.println("value: "+((Integer)value).intValue()); -// System.out.println(" m_Values[i]: "+ ((Integer) m_Values[i]).intValue()); - if (((Integer)value).intValue() != ((Integer) m_Values[i]).intValue()) { - editor.setValue(m_Values[i]); - } - } - } catch (InvocationTargetException ex) { - if (ex.getTargetException() instanceof PropertyVetoException) { - System.out.println("PropertySheetPanel.wasModified(): WARNING: Vetoed; reason is: " + ex.getTargetException().getMessage()); - } else { - System.out.println("PropertySheetPanel.wasModified(): InvocationTargetException while updating " + property.getName()); - System.out.println("PropertySheetPanel.wasModified(): "+ex.getMessage()); - ex.printStackTrace(); - } - } catch (Exception ex) { - System.out.println("PropertySheetPanel.wasModified(): Unexpected exception while updating " + property.getName()); - } - //revalidate(); - if (m_Views[i] != null && m_Views[i] instanceof PropertyPanel) { - //System.err.println("Trying to repaint the property canvas"); - m_Views[i].repaint(); - revalidate(); - } - break; - } // end if (m_Editors[i] == editor) - } // end for (int i = 0 ; i < m_Editors.length; i++) { - boolean doRepaint = false; - for (int i = 0 ; i < m_Editors.length; i++) { // check the views for out-of-date information. this is different than checking the editors - if (m_Editors[i] != editor) { - // looking at another field (not changed explicitly, maybe implicitely - boolean valChanged = false; - Object args[] = { }; - Method getter = m_Properties[i].getReadMethod(); - if (m_Properties[i].isHidden() || m_Properties[i].isExpert()) { - if ((m_Labels[i] != null) && (m_Labels[i].isVisible())) { - // something is set to hidden but was visible up to now - m_ViewWrapper[i].setVisible(false); - m_Labels[i].setVisible(false); - doRepaint = true; - } - continue; - } else { - if ((m_Labels[i] != null) && !(m_Labels[i].isVisible())) { - // something is invisible but set to not hidden in the mean time - m_ViewWrapper[i].setVisible(true); - m_Labels[i].setVisible(true); - doRepaint = true; - } - } - try { // check if view i is up to date and in sync with the value of the getter - if (m_Views[i] != null) { - Object val = getter.invoke(m_Target, args); - if (m_Views[i] instanceof PropertyBoolSelector) { - valChanged = (((PropertyBoolSelector)m_Views[i]).isSelected() != ((Boolean)val)); - if (valChanged) ((PropertyBoolSelector)m_Views[i]).setSelected(((Boolean)val)); - } else if (m_Views[i] instanceof PropertyText) { - valChanged = !(((PropertyText)m_Views[i]).getText()).equals(val.toString()); - if (valChanged) ((PropertyText)m_Views[i]).setText(val.toString()); - } else if (m_Views[i] instanceof PropertyPanel) { - valChanged = false;//!((PropertyPanel)m_Views[i]).equals(value); - // disregard whole panels and hope for the best - if (TRACE) System.out.println("not checking for internal change of PropertyPanel"); - } else if (m_Views[i] instanceof PropertyValueSelector) { - //changed = !((SelectedTag)val).isSelectedString((String)((PropertyValueSelector)m_Views[i]).getSelectedItem()); - // interestingly there seems to be an implicit update of the ValueSelector, possible changes - // are already applied, all we need to see it is a repaint - m_Views[i].repaint(); - } else { - System.out.println("Warning: Property \"" + i - + "\" not recognized. Skipping."); - } - } - } catch(Exception exc) { - System.err.println("Exception in PropertySheetPanel"); - } - }// end if (m_Editors[i] == editor) { - } // end for (int i = 0 ; i < m_Editors.length; i++) { - if (doRepaint) { // some components have been hidden or reappeared - // MK this finally seems to work right - Container p=this; - while (p != null) { - p.setSize(p.getPreferredSize()); - p = p.getParent(); - } + propIndex = i; + if (wasModified(i, editor.getValue(), true)) break; + } } - } // end if (evt.getSource() instanceof PropertyEditor) { + if (propIndex == -1) System.err.println("error: could not identify event editor! (PropertySheetPanel)"); + } else System.err.println("unknown event source! (PropertySheetPanel)"); + } + + /** Updates the propertysheet when a value has been changed (from outside + * the propertysheet?). + * @param evt a value of type 'PropertyChangeEvent' + */ + synchronized boolean wasModified(int propIndex, Object value, boolean followDependencies) { + if (TRACE) { + System.out.println("****PropertySheetPanel.wasModified(): My Target is "+ m_Properties[propIndex].getName() + ", new val: " + BeanInspector.toString(value)); + } + + if (!updateValue(propIndex, value)) return false; + + boolean doRepaint = false; + + for (int i = 0 ; i < m_Editors.length; i++) { // check the views for out-of-date information. this is different than checking the editors + if (i != propIndex) { + if (updateFieldView(i)) doRepaint = true; + }// end if (m_Editors[i] == editor) { + } // end for (int i = 0 ; i < m_Editors.length; i++) { + if (doRepaint) { // some components have been hidden or reappeared + // MK this finally seems to work right + Container p=this; + while (p != null) { + p.setSize(p.getPreferredSize()); + p = p.getParent(); + } + } // Now re-read all the properties and update the editors // for any other properties that have changed. @@ -682,7 +674,8 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener } catch (Exception ex) { o = null; } - if (o == m_Values[i]) { + if (TRACE) System.out.println("# cmp " + BeanInspector.toString(o) + "\n# vs. " + BeanInspector.toString(m_Values[i])); + if (o == m_Values[i] && (BeanInspector.isJavaPrimitive(o.getClass()))) { // The property is equal to its old value. continue; } @@ -705,14 +698,133 @@ public class PropertySheetPanel extends JPanel implements PropertyChangeListener } } + if (followDependencies) { + // Handle the special method getGOEPropertyUpdateLinks which returns a list of pairs + // of strings indicating that on an update if the i-th property, the i+1-th property + // should be updated. This is useful for changes within sub-classes of the target + // which are not directly displayed in this panel but in sub-panels (and there have an own view etc.) + Object o = BeanInspector.callIfAvailable(m_Target, "getGOEPropertyUpdateLinks", null); + if ((o != null) && (o instanceof String[])) { + maybeTriggerUpdates(propIndex, (String[])o); + } + } + // Make sure the target bean gets repainted. if (Beans.isInstanceOf(m_Target, Component.class)) { //System.out.println("Beans.getInstanceOf repaint "); ((Component)(Beans.getInstanceOf(m_Target, Component.class))).repaint(); } + return true; } - /** This method simply looks for an appropriate tiptext + /** + * Check a property for consistency with the object data and update the + * view if necessary. Return true if a repaint is necessary. + * @param i + * @return + */ + private boolean updateFieldView(int i) { + // looking at another field (not changed explicitly, maybe implicitely + boolean valChanged = false; + boolean doRepaint = false; + Object args[] = { }; + Method getter = m_Properties[i].getReadMethod(); + if (m_Properties[i].isHidden() || m_Properties[i].isExpert()) { + if ((m_Labels[i] != null) && (m_Labels[i].isVisible())) { + // something is set to hidden but was visible up to now + m_ViewWrapper[i].setVisible(false); + m_Labels[i].setVisible(false); + doRepaint = true; + } + return doRepaint; + } else { + if ((m_Labels[i] != null) && !(m_Labels[i].isVisible())) { + // something is invisible but set to not hidden in the mean time + m_ViewWrapper[i].setVisible(true); + m_Labels[i].setVisible(true); + doRepaint = true; + } + } + try { // check if view i is up to date and in sync with the value of the getter + if (m_Views[i] != null) { + Object val = getter.invoke(m_Target, args); + if (m_Views[i] instanceof PropertyBoolSelector) { + valChanged = (((PropertyBoolSelector)m_Views[i]).isSelected() != ((Boolean)val)); + if (valChanged) ((PropertyBoolSelector)m_Views[i]).setSelected(((Boolean)val)); + } else if (m_Views[i] instanceof PropertyText) { + valChanged = !(((PropertyText)m_Views[i]).getText()).equals(val.toString()); + if (valChanged) ((PropertyText)m_Views[i]).setText(val.toString()); + } else if (m_Views[i] instanceof PropertyPanel) { + valChanged = false;//!((PropertyPanel)m_Views[i]).equals(value); + // disregard whole panels and hope for the best + if (TRACE) { + System.out.println("not checking for internal change of PropertyPanel " + !((PropertyPanel)m_Views[i]).equals(val)); + if (!((PropertyPanel)m_Views[i]).equals(val)) { + System.out.println("# " + BeanInspector.toString(m_Views[i])); + System.out.println("# " + BeanInspector.toString(val)); + System.out.println("Ed.: " + BeanInspector.toString(((PropertyPanel)m_Views[i]).getEditor())); + } + } + } else if (m_Views[i] instanceof PropertyValueSelector) { + //changed = !((SelectedTag)val).isSelectedString((String)((PropertyValueSelector)m_Views[i]).getSelectedItem()); + // interestingly there seems to be an implicit update of the ValueSelector, possible changes + // are already applied, all we need to see it is a repaint + m_Views[i].repaint(); + } else { + System.out.println("Warning: Property \"" + i + + "\" not recognized. Skipping."); + } + } + } catch(Exception exc) { + System.err.println("Exception in PropertySheetPanel"); + } + return doRepaint; + } + + /** + * Check the given link list and trigger updates of indicated properties. + * + * @param propIndex + * @param links + */ + private void maybeTriggerUpdates(int propIndex, String[] links) { + int max = links.length; + if (max % 2 == 1) { + System.err.println("Error in PropertySheetPanel:maybeTriggerUpdates: odd number of strings provided!"); + max -= 1; + } + if (TRACE) System.out.println("maybeTriggerUpdates: " + BeanInspector.toString(links)); + for (int i = 0; i= 0) is > 0, then the number of evaluations is set as + * number of evaluations before the optimization using the given terminator. * * @param pop * @param problem * @param term + * @param baseEvals * @return */ - public static int processWithNMS(Population pop, AbstractOptimizationProblem problem, InterfaceTerminator term) { + public static int processWithNMS(Population pop, AbstractOptimizationProblem problem, InterfaceTerminator term, int baseEvals) { NelderMeadSimplex nms = new NelderMeadSimplex(); nms.setProblemAndPopSize(problem); nms.setGenerationCycle(5); nms.initByPopulation(pop, false); int funCallsBefore = pop.getFunctionCalls(); - pop.SetFunctionCalls(0); + pop.SetFunctionCalls(baseEvals); ppRunnable = new OptimizerRunnable(OptimizerFactory.makeParams(nms, pop, problem, 0, term), true); // as nms creates a new population and has already evaluated them, send a signal to stats @@ -418,8 +426,8 @@ public class PostProcess { runPP(); - int funCallsDone = pop.getFunctionCalls(); - pop.SetFunctionCalls(funCallsBefore+funCallsDone); + int funCallsDone = pop.getFunctionCalls()-baseEvals; + pop.SetFunctionCalls(funCallsBefore); return funCallsDone; } @@ -428,13 +436,18 @@ public class PostProcess { * Search for a local minimum using nelder mead and return the solution found and the number of steps * (evaluations) actually performed. This uses the whole population as starting population for nelder mead * meaning that typically only one best is returned. + * Returns the number of function calls really performed by the method; sets the number of function calls + * in the population back to the original count. If the baseEvals parameter (which should be >= 0) is > 0, + * then the number of evaluations is set as + * number of evaluations before the optimization using the given terminator. * * @param pop * @param problem * @param term + * @param baseEvals * @return */ - public static int processWithCMA(Population pop, AbstractOptimizationProblem problem, InterfaceTerminator term) { + public static int processWithCMA(Population pop, AbstractOptimizationProblem problem, InterfaceTerminator term, int baseEvals) { // GOParameters cmaParams = OptimizerFactory.cmaESIPOP(problem); MutateESRankMuCMA mutator = new MutateESRankMuCMA(); mutator.setInitializeSigma(ESMutationInitialSigma.avgInitialDistance); @@ -449,7 +462,7 @@ public class PostProcess { GOParameters cmaParams = OptimizerFactory.makeParams(es, pop, problem, 0, term); int funCallsBefore = pop.getFunctionCalls(); - pop.SetFunctionCalls(0); + pop.SetFunctionCalls(baseEvals); ppRunnable = new OptimizerRunnable(cmaParams, true); ppRunnable.getStats().createNextGenerationPerformed(cmaParams.getOptimizer().getPopulation(), null); @@ -458,8 +471,8 @@ public class PostProcess { pop.clear(); pop.addPopulation(es.getPopulation()); - int funCallsDone = es.getPopulation().getFunctionCalls(); - pop.SetFunctionCalls(funCallsBefore+funCallsDone); + int funCallsDone = es.getPopulation().getFunctionCalls()-baseEvals; + pop.SetFunctionCalls(funCallsBefore); return funCallsDone; } @@ -488,42 +501,26 @@ public class PostProcess { Population pop = new Population(1); pop.add(cand); - int evalsDone = processSingleCandidates(PostProcessMethod.nelderMead, pop, hcSteps, initPerturbation, prob); + int evalsDone = processSingleCandidates(PostProcessMethod.nelderMead, pop, hcSteps, initPerturbation, prob, null); - 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); + return new Pair(pop.getBestEAIndividual(), evalsDone); } /** - * Create a subpopulation around an indicated individual from the candidate set. + * Create a sub-population 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. + * + * @see #createPopInSubRange(double, AbstractOptimizationProblem, AbstractEAIndividual) + * @see #NelderMeadSimplex.createNMSPopulation(AbstractEAIndividual, double, double[][], boolean) + * @param method + * @param problem + * @param candidates + * @param index index of the individual for which to produce the sub population + * @param maxPerturbation + * @param includeCand */ - private static Population createLSSupPopulation(PostProcessMethod method, AbstractOptimizationProblem problem, Population candidates, int index, double maxPerturbation, boolean includeCand) { + public static Population createLSSupPopulation(PostProcessMethod method, AbstractOptimizationProblem problem, Population candidates, int index, double maxPerturbation, boolean includeCand) { Population subPop = null; switch (method) { case cmaES: @@ -534,27 +531,78 @@ public class PostProcess { break; case nelderMead: double[][] range = ((InterfaceDataTypeDouble)candidates.getEAIndividual(index)).getDoubleRange(); - double perturb = findNMSPerturn(candidates, index, maxPerturbation); + double perturb = findNMSPerturb(candidates, index, maxPerturbation); if (TRACE) System.out.println("perturb " + index + " is " + perturb); subPop = NelderMeadSimplex.createNMSPopulation(candidates.getEAIndividual(index), perturb, range, false); } +// subPop.setSameParams(candidates); 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. + * Employ hill-climbing directly or NM/CMA on the candidates. The candidate population + * must not be empty and candidates must implement InterfaceDataTypeDouble. + * The given number of steps gives the number of evaluations which may not be hit exactly. + * The population will not be altered for Nelder-Mead or CMA-ES, and the evaluation calls will not be added to + * the candidate population! * + * @see #processWithHC(Population, AbstractOptimizationProblem, InterfaceTerminator, InterfaceMutation) + * @see #processSingleCandidatesNMCMA(PostProcessMethod, Population, InterfaceTerminator, double, AbstractOptimizationProblem) + * @param method * @param candidates - * @param steps + * @param steps number of evaluations to be performed (summed up) * @param maxPerturbation * @param prob - * @return + * @param mute the mutator to use (in case of HC) + * @return the evaluations performed */ - public static int processSingleCandidates(PostProcessMethod method, Population candidates, int steps, double maxPerturbation, AbstractOptimizationProblem prob) { + public static int processSingleCandidates(PostProcessMethod method, Population candidates, int steps, double maxPerturbation, AbstractOptimizationProblem prob, InterfaceMutation mute) { + int dim=((InterfaceDataTypeDouble)candidates.getEAIndividual(0)).getDoubleRange().length; + int candCnt = candidates.size(); + + if (method == PostProcessMethod.hillClimber) { + int evalsOld = candidates.getFunctionCalls(); + processWithHC(candidates, prob, new EvaluationTerminator(evalsOld+steps), mute); + int evalsDone = candidates.getFunctionCalls()-evalsOld; + candidates.SetFunctionCalls(evalsOld); + return evalsDone; + } else { + int stepsPerCand = (steps-(candCnt*(dim-1)))/candCnt; + if (TRACE) System.out.println("employing " + stepsPerCand + " steps per cand."); + if (stepsPerCand < dim) { + System.err.println("Too few steps allowed in processSingleCandidates!"); + System.err.println("Method: " + method + ", cands: " + candidates.size() + ", steps: " + steps); + return 0; + } else { + EvaluationTerminator term = new EvaluationTerminator(stepsPerCand); + return processSingleCandidatesNMCMA(method, candidates, term, maxPerturbation, prob); + } + } + } + + /** + * For each candidate individual, create an own sub-population and optimize it separately. Candidates must have + * been evaluated earlier. The candidates population is not altered. + * The performed evaluation calls for problem dimension n will 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. The given terminator will be applied to each + * candidate sub-population anew. If the terminator is null, 10*n steps will be performed on each candidate. + * + * A double value is added to each solution individual that replaces its ancestor candidate, using the key "PostProcessingMovedBy". + * It indicates the phenotype distance the found solution has moved relatively to the original candidate. + * + * @see #findNMSPerturb(Population, int, double) + * @see #createLSSupPopulation(PostProcessMethod, AbstractOptimizationProblem, Population, int, double, boolean) + * @see #processWithCMA(Population, AbstractOptimizationProblem, InterfaceTerminator, int) + * @see #processWithNMS(Population, AbstractOptimizationProblem, InterfaceTerminator, int) + * @param method NM or CMA is allowed here + * @param candidates + * @param term + * @param maxPerturbation perturbation for the sub population + * @param prob + * @return the number of evaluations performed + */ + public static int processSingleCandidatesNMCMA(PostProcessMethod method, Population candidates, InterfaceTerminator term, double maxPerturbation, AbstractOptimizationProblem prob) { ArrayList nmPops = new ArrayList(); int stepsPerf = 0; Population subPop; @@ -568,31 +616,39 @@ public class PostProcess { nmPops.add(subPop); } - int stepsPerCand = (steps-stepsPerf)/candidates.size(); - if (TRACE) System.out.println("rest is " + (steps-stepsPerf) + ", thats " + stepsPerCand + " per candidate."); - if (stepsPerCand < 1) System.err.println("Too few steps allowed!"); - else { - for (int i=0; i popD = new Pair(pop, 1.); int i=0; int evalCnt = 0; - while (popD.tail() > 0.01) { + while (popD.tail() > 0.001) { i++; // public static PopDoublePair clusterHC(pop, problem, sigmaCluster, funCalls, keepClusterRatio, mute) { - popD = clusterHC(popD.head(), problem, 0.01, 1000 - (evalCnt % 1000), 0.5, new MutateESFixedStepSize(0.02)); + popD = clusterLocalSearch(PostProcessMethod.hillClimber, popD.head(), problem, 0.01, 1500, 0.1, new MutateESFixedStepSize(0.02)); evalCnt += popD.head().getFunctionCalls(); + System.out.println("popsize is " + popD.head().size()); } found = getFoundOptima(popD.head(), mmp.getRealOptima(), 0.05, true); System.out.println("found at " + i + " (" + found.size() + "): " + BeanInspector.toString(found)); @@ -760,11 +817,12 @@ public class PostProcess { } /** - * Cluster a population and reduce it by a certain ratio, then optimize the remaining individuals for a given number of function calls with a HC. - * Return a pair of the optimized population and the improvement in the mean fitness (not normed) that was achieved by the HC run. The returned + * Cluster a population and reduce it by a certain ratio, then optimize the remaining individuals for a given number of function calls with a LS. + * Return a pair of the optimized population and the improvement in the mean fitness (not normed) that was achieved by the LS run. The returned * individuals are deep clones, so the given population is not altered. Of a cluster of individuals, the given * ratio of individuals is kept, more precisely, the best one is kept while the remaining are selected randomly. All loners are kept. * + * @param method the local search method to be used * @param pop the population to work on * @param problem the target problem instance * @param sigmaCluster minimum clustering distance @@ -773,71 +831,33 @@ public class PostProcess { * @param mute the mutation operator to be used by the hill climber * @return a pair of the optimized population and the improvement in the mean fitness (not normed) achieved by the HC run */ - public static Pair clusterHC(Population pop, AbstractOptimizationProblem problem, double sigmaCluster, int funCalls, double keepClusterRatio, InterfaceMutation mute) { + public static Pair clusterLocalSearch(PostProcessMethod method, Population pop, AbstractOptimizationProblem problem, double sigmaCluster, int funCalls, double keepClusterRatio, InterfaceMutation mute) { + int evalsBefore = pop.getFunctionCalls(); + Population clust = (Population)clusterBest(pop, new ClusteringDensityBased(sigmaCluster, 2), keepClusterRatio, KEEP_LONERS, BEST_RAND).clone(); -// System.out.println("keeping " + clust.size() + " for hc...."); + + //clust.addPopulationChangedEventListener() double[] meanFit = clust.getMeanFitness(); - processWithHC(clust, problem, new EvaluationTerminator(pop.getFunctionCalls()+funCalls), mute); + + if (TRACE) System.out.println("BEF: funcalls done: " + pop.getFunctionCalls() + ", now allowed: " + funCalls); + + int evalsDone = processSingleCandidates(method, clust, funCalls, sigmaCluster/2., problem, mute); + + clust.SetFunctionCalls(evalsBefore + evalsDone); + double improvement = PhenotypeMetric.euclidianDistance(meanFit, clust.getMeanFitness()); - if (TRACE) System.out.println("improvement by " + improvement); + if (TRACE) System.out.println("improvement by " + improvement + " funcalls done: " + evalsDone); return new Pair(clust, improvement); } -// /** -// * Do some post processing on a multimodal problem. If the real optima are known, only the number of -// * found optima is printed. Otherwise, the population is clustered and for the population of cluster-representatives, -// * some diversity measures and a fitness histogram are printed. -// * -// * @see Population.getPopulationMeasures() -// * @see createFitNormHistogram -// * @param mmProb the target problem -// * @param pop the solution set -// * @param sigmaCluster the min clustering distance -// * @param out a PrintStream for data output -// * @param minBnd lower fitness bound -// * @param maxBnd upper fitness bound -// * @param bins number of bins for the fitness histogram -// * @return -// */ -// public static Population outputResult(AbstractOptimizationProblem mmProb, Population pop, double sigmaCluster, PrintStream out, double minBnd, double maxBnd, int bins, int hcSteps) { -// ClusteringDensityBased clust = new ClusteringDensityBased(sigmaCluster); -// clust.setMinimumGroupSize(2); -// Population clusteredBest = clusterBest(pop, clust, 0, KEEP_LONERS, BEST_ONLY); -// if (hcSteps > 0) { // HC post process -// Population tmpPop = (Population)clusteredBest.clone(); -// processWithHC(tmpPop, (AbstractOptimizationProblem)mmProb, hcSteps, 0.001); -// clusteredBest = clusterBest(tmpPop, clust, 0, KEEP_LONERS, BEST_ONLY); -// } -// double[] meas = clusteredBest.getPopulationMeasures(); -// int[] sols = createFitNormHistogram(clusteredBest, minBnd, maxBnd, bins); -// out.println("measures: " + BeanInspector.toString(meas)); -// out.println("solution hist.: " + BeanInspector.toString(sols)); -// -// Object[] bestArr = clusteredBest.toArray(); -// for (Object locOpt : bestArr) { -//// out.print((AbstractEAIndividual.getDefaultDataString((IndividualInterface)locOpt))); -// out.println(AbstractEAIndividual.getDefaultStringRepresentation(((AbstractEAIndividual)locOpt))); -// } -// return clusteredBest; -// } - -// public static Population outputResultKnown(InterfaceMultimodalProblemKnown mmProb, Population pop, double sigmaCluster, PrintStream out, double minBnd, double maxBnd, int bins) { -// Population found = getFoundOptima(pop, ((InterfaceMultimodalProblemKnown)mmProb).getRealOptima(), ((InterfaceMultimodalProblemKnown)mmProb).getEpsilon(), true); -// for (double epsilon=0.1; epsilon > 0.00000001; epsilon/=10.) { -// //out.println("no optima found: " + ((InterfaceMultimodalProblemKnown)mmProb).getNumberOfFoundOptima(pop)); -// out.println("found " + getFoundOptima(pop, ((InterfaceMultimodalProblemKnown)mmProb).getRealOptima(), epsilon, true).size() + " for epsilon = " + epsilon); -// } -// out.println("max peak ratio is " + mmProb.getMaximumPeakRatio(found)); -// return found; -// } - /** - * Do some data output for multimodal problems with known optima. The listener may be null, but then the method is - * not really doing much at this state. + * Do some data output for multimodal problems to the listener. + * This may be expensive computationally. */ - public static void procMultiModalKnown(Population solutions, InterfaceMultimodalProblemKnown mmkProb, InterfaceTextListener listener) { -// Population found = getFoundOptima(solutions, mmkProb.getRealOptima(), mmkProb.getEpsilon(), true); - if (listener != null) { + public static void evaluateMultiModal(Population solutions, AbstractOptimizationProblem prob, InterfaceTextListener listener) { + if (listener == null) return; + if (prob instanceof InterfaceMultimodalProblemKnown) { + InterfaceMultimodalProblemKnown mmkProb = (InterfaceMultimodalProblemKnown)prob; listener.println("number of known optima is " + mmkProb.getRealOptima().size()); listener.println("default epsilon is " + mmkProb.getEpsilon()); listener.println("optima found with default epsilon: " + getFoundOptima(solutions, mmkProb.getRealOptima(), mmkProb.getEpsilon(), true).size()); @@ -846,6 +866,21 @@ public class PostProcess { // out.println("no optima found: " + ((InterfaceMultimodalProblemKnown)mmProb).getNumberOfFoundOptima(pop)); listener.println("found " + getFoundOptima(solutions, mmkProb.getRealOptima(), epsilon, true).size() + " for epsilon = " + epsilon + ", maxPeakRatio: " + AbstractMultiModalProblemKnown.getMaximumPeakRatio(mmkProb,solutions, epsilon)); } + } else { + // TODO in this form it may cost a lot of time and cant be stopped, which is bad +// double epsilonPhenoSpace = 0.01, epsilonFitConv = 1e-10, clusterSigma = 0.; +// Population extrOpts; +// for (int k=0; k<3; k++) { +// extrOpts = prob.extractPotentialOptima(solutions, epsilonPhenoSpace, epsilonFitConv, clusterSigma, -1); +// listener.println("estimated number of found optima: " + extrOpts.size() + " with crit. " + epsilonPhenoSpace); +// if (extrOpts.size() > 0) { +// listener.println("fit measures: "); +// int critCnt = extrOpts.getEAIndividual(0).getFitness().length; +// for (int i=0; inBestPop.size()) ? ( "(first " + nBestPop.size() + " of " + outputPop.size() + ")") : "")); //////////// output some individual data if (listener != null) for (int i=0; i0) return Math.min(maxPerturb, minDistNeighbour/3.); else return minDistNeighbour/3.; } + + /** + * Sample a given problem randomly for the number of times specified and calculate the average + * fitness returned after evaluation. This may give a general measure of how good an optimum is + * on an unknown function. Of course its expensive for problems with considerable computational + * cost. + * + * @param steps + * @param prob + * @return an averaged fitness vector + */ + public static double[] calcAvgRandomFunctionValue(int steps, AbstractOptimizationProblem prob) { + int cnt = 0; + int portion = 100; + int curPopSize = Math.min(portion, steps); + double[] portionFitSum = null; + double[] avgFit = null; + Population pop = new Population(portion); + IndividualInterface indy; + prob.initProblem(); + while (cnt < steps) { + pop.clear(); + for (int i=0; i sortedArr = null; transient private ArrayList listeners = null; // transient protected InterfacePopulationChangedEventListener m_Listener = null; @@ -57,6 +55,8 @@ public class Population extends ArrayList implements PopulationInterface, Clonea // remember when the last sorted queue was prepared private int lastQModCount = -1; + // a sorted queue (for efficiency) + transient private ArrayList sortedArr = null; // remember when the last evaluation was performed private Pair evaluationTimeHashes = null; // remember when the last evaluation was performed @@ -513,7 +513,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea * */ public Population getSortedNIndividuals(int n, boolean bBestOrWorst) { - Population result = new Population(n); + Population result = new Population((n > 0) ? n : this.size()); getSortedNIndividuals(n, bBestOrWorst, result); return result; } @@ -557,7 +557,8 @@ public class Population extends ArrayList implements PopulationInterface, Clonea if (sortedArr == null || (super.modCount != lastQModCount)) { PriorityQueue sQueue = new PriorityQueue(super.size(), new AbstractEAIndividualComparator()); for (int i = 0; i < super.size(); i++) { - sQueue.add(getEAIndividual(i)); + AbstractEAIndividual indy = getEAIndividual(i); + if (indy != null) sQueue.add(indy); } lastQModCount = super.modCount; if (sortedArr==null) sortedArr = new ArrayList(this.size()); @@ -794,24 +795,28 @@ public class Population extends ArrayList implements PopulationInterface, Clonea return "A population stores the individuals of a generation."; } - /** This method allows you to set the population size + /** + * This method allows you to set the population size. Be aware that this will not + * directly alter the number of individuals stored. The actual size will be + * adapted on a reinitialization, for example. + * * @param size */ public void setPopulationSize(int size) { this.m_Size = size; -// int rand; -// if (this.size() != 0) { -// while (this.size() < size) { -// rand = RNG.randomInt(0, this.size()-1); -// this.add(((AbstractEAIndividual)this.get(rand)).clone()); -// } -// while (this.size() > size) { -// rand = RNG.randomInt(0, this.size()-1); -// this.remove(rand); -// } -// } -// System.out.println("This.size() = "+this.size() +" this.getSize() = " + this.m_Size); } + + /** + * Convenience method. + * + * @param size + * @return + */ + public Population setPopSize(int size) { + this.m_Size = size; + return this; + } + public int getPopulationSize() { return this.m_Size; } @@ -949,9 +954,51 @@ public class Population extends ArrayList implements PopulationInterface, Clonea if (d > maxDist) maxDist = d; } } - res[0] = meanDist / (this.size() * (this.size()-1) / 2); res[1] = minDist; res[2] = maxDist; + if (this.size() > 1) res[0] = meanDist / (this.size() * (this.size()-1) / 2); + else { // only one indy? + res[1]=0; + res[2]=0; + } + return res; + } + + /** + * Returns the average, minimal and maximal individual fitness and std dev. for the population in the given criterion. + * + * @param fitCrit fitness dimension to be used + * @return the average, minimal, maximal and std dev. of fitness of individuals in an array + */ + public double[] getFitnessMeasures(int fitCrit) { + double d; + double[] res = new double[4]; + + res[0] = 0.; + res[1] = Double.MAX_VALUE; + res[2] = Double.MIN_VALUE; + res[3] = 0; + + for (int i = 0; i < this.size(); i++) { + d = this.getEAIndividual(i).getFitness(fitCrit); + res[0] += d; + if (d < res[1]) res[1] = d; + if (d > res[2]) res[2] = d; + } + + if (size()==0) { + res[0]=res[1]=res[2]=res[3]=Double.NaN; + } else { + // calc standard deviation + res[0] = res[0] / this.size(); + for (int i=0; i< this.size(); i++) { + d = res[0]-this.getEAIndividual(i).getFitness(fitCrit); + res[3]+=d*d; + } + res[3] /= this.size(); + res[3] = Math.sqrt(res[3]); + } + return res; } @@ -1012,6 +1059,80 @@ public class Population extends ArrayList implements PopulationInterface, Clonea return mean; } + /** + * Search for the closest individual which is not equal to the given individual. Return + * its index or -1 if none could be found. + * + * @param indy + * @return closest neighbor (euclidian measure) of the given individual in the given population + */ + public int getNeighborIndex(AbstractEAIndividual indy) { + // get the neighbor... + int index = -1; + double mindist = Double.POSITIVE_INFINITY; + + for (int i = 0; i < size(); ++i){ + AbstractEAIndividual currentindy = getEAIndividual(i); + if (!indy.equals(currentindy)){ // dont compare particle to itself or a copy of itself + double dist = PhenotypeMetric.euclidianDistance(AbstractEAIndividual.getDoublePosition(indy), + AbstractEAIndividual.getDoublePosition(currentindy)); + if (dist < mindist){ + mindist = dist; + index = i; + } + } + } + if (index == -1){ + System.err.println("Pop too small or all individuals in population are equal !?"); + return -1; + } + return index; + } + + /** + * Calculate the average of the distance of each individual to its closest neighbor in the population. + * The boolean parameter switches between range-normalized and simple euclidian distance. If calcVariance + * is true, the variance is calculated and returned as second entry + * + * @param normalizedPhenoMetric + * @return a double array containing the average (or average and variance) of the distance of each individual to its closest neighbor + */ + public double[] getAvgDistToClosestNeighbor(boolean normalizedPhenoMetric, boolean calcVariance){ + PhenotypeMetric metric = new PhenotypeMetric(); + ArrayList distances = null; + if (calcVariance) distances = new ArrayList(size()); + double sum = 0; + double d=0; + for (int i = 0; i < size(); ++i){ + AbstractEAIndividual neighbor, indy = getEAIndividual(i); + int neighborIndex = getNeighborIndex(indy); + if (neighborIndex >= 0) neighbor = getEAIndividual(neighborIndex); + else return null; + if (normalizedPhenoMetric){ + d = metric.distance(indy, neighbor); + } else { + d = PhenotypeMetric.euclidianDistance(AbstractEAIndividual.getDoublePosition(indy), + AbstractEAIndividual.getDoublePosition(neighbor)); + } + if (calcVariance) distances.add(d); + sum += d; + } + double avg = sum/(double)size(); + double[] res; + if (calcVariance) { + res = new double[2]; + double var = 0; + for (int i=0; i 0) return (Population)PostProcess.clusterBest(potOptima, clusterSigma, 0, PostProcess.KEEP_LONERS, PostProcess.BEST_ONLY).clone(); + else return potOptima; } /** @@ -273,6 +287,50 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati else return false; } + /** + * Refine a given individual using Nelder-Mead-Simplex local search. Return true, if the refined result is within a given + * distance from the original individual in phenotype space. The numOfFailures parameter gives the maximum evaluations + * for the local search Using the epsilonFitConv parameter may define a convergence criterion as PhenotypeConvergenceTerminator + * which is combined (using OR) with the evaluation counter. + * If numOfFailures is smaller than zero, 100*dim is used. Be aware that this may cost quite some runtime depending on the target + * function. + * + * @param orig + * @param epsilonPhenoSpace + * @param epsilonFitConv + * @param numOfFailures + * @return + */ + public boolean isPotentialOptimumNMS(AbstractEAIndividual orig, double epsilonPhenoSpace, double epsilonFitConv, int numOfFailures){ + + AbstractEAIndividual indy = (AbstractEAIndividual)orig.clone(); + this.evaluate(indy); // indy may be evaluated in a normalised way... + + InterfaceDistanceMetric metric = new PhenotypeMetric(); + double overallDist = 0; + double initPerturb = -1; + int dim = -1; + if (orig instanceof InterfaceDataTypeDouble) { + initPerturb = epsilonPhenoSpace/(2*(Mathematics.getAvgRange(((InterfaceDataTypeDouble)orig).getDoubleRange()))); + dim=((InterfaceDataTypeDouble)orig).getDoubleRange().length; + if (numOfFailures<0) numOfFailures = 100*AbstractEAIndividual.getDoublePosition(this.m_Template).length; // scales the effort with the number of problem dimensions + } else { + System.err.println("Cannot initialize NMS on non-double valued individuals!"); + return false; + } + + Population pop = new Population(1); + pop.add(orig); + InterfaceTerminator term = new EvaluationTerminator(numOfFailures); + if (epsilonFitConv > 0) term = new CombinedTerminator(new PhenotypeConvergenceTerminator(epsilonFitConv, 10*dim, true, true), term, false); + int evalsPerf = PostProcess.processSingleCandidatesNMCMA(PostProcessMethod.nelderMead, pop, term, initPerturb, this); + overallDist = metric.distance(indy, pop.getBestEAIndividual()); +// System.out.println("aft: " + pop.getBestEAIndividual().toString() + ", evals performed: " + evalsPerf + ", opt moved by " + overallDist); +// System.out.println("terminated because: " + term.lastTerminationMessage()); + if (overallDist < epsilonPhenoSpace) return true; + else return false; + } + /********************************************************************************************************************** * These are for GUI */ diff --git a/src/eva2/server/go/problems/F13Problem.java b/src/eva2/server/go/problems/F13Problem.java index e725ce1e..1091eb1a 100644 --- a/src/eva2/server/go/problems/F13Problem.java +++ b/src/eva2/server/go/problems/F13Problem.java @@ -17,6 +17,10 @@ public class F13Problem extends F1Problem implements InterfaceMultimodalProblem public F13Problem(F13Problem b) { super(b); } + public F13Problem(int dim) { + super(); + setProblemDimension(dim); + } /** This method returns a deep clone of the problem. * @return the clone diff --git a/src/eva2/server/go/problems/F1Problem.java b/src/eva2/server/go/problems/F1Problem.java index 163f8485..8e2e4ca0 100644 --- a/src/eva2/server/go/problems/F1Problem.java +++ b/src/eva2/server/go/problems/F1Problem.java @@ -38,7 +38,17 @@ public class F1Problem extends AbstractProblemDouble implements Interface2DBorde this.m_YOffSet = b.m_YOffSet; this.m_UseTestConstraint = b.m_UseTestConstraint; } - + + public F1Problem(int dim) { + this(); + setProblemDimension(dim); + } + + public F1Problem(int dim, double defRange) { + this(dim); + setDefaultRange(defRange); + } + /** This method returns a deep clone of the problem. * @return the clone */ diff --git a/src/eva2/server/go/problems/PSymbolicRegression.java b/src/eva2/server/go/problems/PSymbolicRegression.java index 10ab5b50..b526528e 100644 --- a/src/eva2/server/go/problems/PSymbolicRegression.java +++ b/src/eva2/server/go/problems/PSymbolicRegression.java @@ -190,7 +190,8 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements evaluatePopulationEnd(population); } - /** This method evaluate a single individual and sets the fitness values + /** + * This method evaluates a single individual and sets the fitness values * @param individual The individual that is to be evalutated */ public void evaluate(AbstractEAIndividual individual) { @@ -203,13 +204,14 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements if ((tmpIndy instanceof GAPIndividualProgramData) && (this.m_UseInnerConst)) this.m_C = ((GAPIndividualProgramData)tmpIndy).getDoubleData(); fitness = 0; - for (double i = 0; i < this.m_NumberOfCheckPoints; i++) { - for (int j = 0; j < this.m_X.length; j++) - this.m_X[j] = this.m_LowerBound +(i*(this.m_UpperBound-this.m_LowerBound)/this.m_NumberOfCheckPoints); - tmpValue = ((Double)program.evaluate(this)).doubleValue(); - fitness += Math.pow((this.m_TargetFunction.evaulateFunction(this.m_X) - ((Double)program.evaluate(this)).doubleValue()), 2); - } + for (int j = 0; j < this.m_NumberOfCheckPoints; j++) + for (int i = 0; i < this.m_X.length; i++) { + this.m_X[i] = this.m_LowerBound +(j*(this.m_UpperBound-this.m_LowerBound)/this.m_NumberOfCheckPoints); + tmpValue = ((Double)program.evaluate(this)).doubleValue(); + fitness += Math.pow((this.m_TargetFunction.evaluateFunction(this.m_X) - ((Double)program.evaluate(this)).doubleValue()), 2); + } + fitness = fitness / (double)this.m_NumberOfCheckPoints; // add noise to the fitness fitness += RNG.gaussianDouble(this.m_Noise); @@ -225,7 +227,7 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements for (int j = 0; j < this.m_X.length; j++) this.m_X[j] = i ; tmpValue = ((Double)program.evaluate(this)).doubleValue(); this.m_Plot.setConnectedPoint(this.m_X[0], tmpValue, 0); - tmpValue = this.m_TargetFunction.evaulateFunction(this.m_X); + tmpValue = this.m_TargetFunction.evaluateFunction(this.m_X); this.m_Plot.setConnectedPoint(this.m_X[0], tmpValue, 1); this.m_Plot.setInfoString(1, program.getStringRepresentation(), 1.0f); } @@ -233,7 +235,7 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements } } - /** This method returns a string describing the optimization problem. + /** This method returns a string describing the optimization problem. * @param opt The Optimizer that is used or had been used. * @return The description. */ diff --git a/src/eva2/server/go/problems/regression/InterfaceRegressionFunction.java b/src/eva2/server/go/problems/regression/InterfaceRegressionFunction.java index c774798e..871394f8 100644 --- a/src/eva2/server/go/problems/regression/InterfaceRegressionFunction.java +++ b/src/eva2/server/go/problems/regression/InterfaceRegressionFunction.java @@ -18,5 +18,5 @@ public interface InterfaceRegressionFunction { * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x); + public double evaluateFunction(double[] x); } diff --git a/src/eva2/server/go/problems/regression/RFKoza_GPI_10_1.java b/src/eva2/server/go/problems/regression/RFKoza_GPI_10_1.java index e74021ca..21322021 100644 --- a/src/eva2/server/go/problems/regression/RFKoza_GPI_10_1.java +++ b/src/eva2/server/go/problems/regression/RFKoza_GPI_10_1.java @@ -25,7 +25,7 @@ public class RFKoza_GPI_10_1 implements InterfaceRegressionFunction, java.io.Ser * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += Math.cos(2*x[i]); return result; diff --git a/src/eva2/server/go/problems/regression/RFKoza_GPI_10_2.java b/src/eva2/server/go/problems/regression/RFKoza_GPI_10_2.java index ff92b885..57d66476 100644 --- a/src/eva2/server/go/problems/regression/RFKoza_GPI_10_2.java +++ b/src/eva2/server/go/problems/regression/RFKoza_GPI_10_2.java @@ -25,7 +25,7 @@ public class RFKoza_GPI_10_2 implements InterfaceRegressionFunction, java.io.Ser * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += 3.1416*x[i] + 2.718 * Math.pow(x[i], 2); return result; diff --git a/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3.java b/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3.java index 43a27c12..8a3ae298 100644 --- a/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3.java +++ b/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3.java @@ -25,7 +25,7 @@ public class RFKoza_GPI_7_3 implements InterfaceRegressionFunction, java.io.Seri * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += Math.pow(x[i], 4) + Math.pow(x[i], 3) + Math.pow(x[i], 2) + Math.pow(x[i], 1); return result; diff --git a/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3_extended.java b/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3_extended.java index 52f23a85..90873e26 100644 --- a/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3_extended.java +++ b/src/eva2/server/go/problems/regression/RFKoza_GPI_7_3_extended.java @@ -25,7 +25,7 @@ public class RFKoza_GPI_7_3_extended implements InterfaceRegressionFunction, jav * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += 0.12345*Math.pow(x[i], 4) + (Math.PI/4)*Math.pow(x[i], 3) + (Math.E/2)*Math.pow(x[i], 2) + 1.23456*Math.pow(x[i], 1); return result; diff --git a/src/eva2/server/go/problems/regression/RFRaidl_F1.java b/src/eva2/server/go/problems/regression/RFRaidl_F1.java index 6dc0d6a0..ac070ecd 100644 --- a/src/eva2/server/go/problems/regression/RFRaidl_F1.java +++ b/src/eva2/server/go/problems/regression/RFRaidl_F1.java @@ -25,7 +25,7 @@ public class RFRaidl_F1 implements InterfaceRegressionFunction, java.io.Serializ * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += Math.sin(x[i]); return result; diff --git a/src/eva2/server/go/problems/regression/RFRaidl_F2.java b/src/eva2/server/go/problems/regression/RFRaidl_F2.java index 4ecb0fde..63051663 100644 --- a/src/eva2/server/go/problems/regression/RFRaidl_F2.java +++ b/src/eva2/server/go/problems/regression/RFRaidl_F2.java @@ -25,7 +25,7 @@ public class RFRaidl_F2 implements InterfaceRegressionFunction, java.io.Serializ * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += Math.exp(x[i]/3)*Math.cos(3*x[i])/2; return result; diff --git a/src/eva2/server/go/problems/regression/RFRaidl_F3.java b/src/eva2/server/go/problems/regression/RFRaidl_F3.java index 96fda405..79ee643d 100644 --- a/src/eva2/server/go/problems/regression/RFRaidl_F3.java +++ b/src/eva2/server/go/problems/regression/RFRaidl_F3.java @@ -25,7 +25,7 @@ public class RFRaidl_F3 implements InterfaceRegressionFunction, java.io.Serializ * @param x Input vector. * @return y the function result. */ - public double evaulateFunction(double[] x) { + public double evaluateFunction(double[] x) { double result = 0; for (int i = 0; i < x.length; i++) result += Math.log(4+2*Math.sin(x[i]*Math.sin(8*x[i])))*Math.exp(Math.cos(3*x[i])); return result; diff --git a/src/eva2/server/go/strategies/ClusteringHillClimbing.java b/src/eva2/server/go/strategies/ClusteringHillClimbing.java index 0bfca02d..782e9be4 100644 --- a/src/eva2/server/go/strategies/ClusteringHillClimbing.java +++ b/src/eva2/server/go/strategies/ClusteringHillClimbing.java @@ -4,6 +4,7 @@ import java.io.Serializable; import eva2.gui.GenericObjectEditor; import eva2.server.go.InterfacePopulationChangedEventListener; +import eva2.server.go.enums.PostProcessMethod; import eva2.server.go.operators.mutation.MutateESFixedStepSize; import eva2.server.go.operators.postprocess.PostProcess; import eva2.server.go.populations.InterfaceSolutionSet; @@ -50,6 +51,7 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi // reduce the step size when there is hardy improvement. private double reduceFactor = 0.2; private MutateESFixedStepSize mutator = new MutateESFixedStepSize(0.1); + private PostProcessMethod localSearchMethod = PostProcessMethod.nelderMead; public ClusteringHillClimbing() { hideHideable(); @@ -143,18 +145,25 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi loopCnt++; m_Population.addPopulationChangedEventListener(this); m_Population.setNotifyEvalInterval(notifyGuiEvery); - Pair popD = PostProcess.clusterHC(m_Population, (AbstractOptimizationProblem)m_Problem, sigmaClust, hcEvalCycle - (m_Population.getFunctionCalls() % hcEvalCycle), 0.5, mutator); + Pair popD; + if (TRACE) System.out.println("evalCycle: " + hcEvalCycle + ", evals now: " + (2*hcEvalCycle - (m_Population.getFunctionCalls() % hcEvalCycle))); + popD = PostProcess.clusterLocalSearch(localSearchMethod, m_Population, (AbstractOptimizationProblem)m_Problem, sigmaClust, 2*hcEvalCycle - (m_Population.getFunctionCalls() % hcEvalCycle), 0.5, mutator); +// (m_Population, (AbstractOptimizationProblem)m_Problem, sigmaClust, hcEvalCycle - (m_Population.getFunctionCalls() % hcEvalCycle), 0.5); improvement = popD.tail(); m_Population = popD.head(); + if (TRACE) System.out.println("num inds after clusterLS: " + m_Population.size()); popD.head().setGenerationTo(m_Population.getGeneration()+1); if (improvement < minImprovement) { if (TRACE) System.out.println("improvement below " + minImprovement); - if (mutator.getSigma() < stepSizeThreshold) { // reinit! + if ((localSearchMethod != PostProcessMethod.hillClimber) || (mutator.getSigma() < stepSizeThreshold)) { // reinit! + // is performed for nm and cma, and if hc has too low sigma if (TRACE) System.out.println("REINIT!!"); - // store results - mutator.setSigma(initialStepSize); + + if (localSearchMethod == PostProcessMethod.hillClimber) mutator.setSigma(initialStepSize); + + // store results archive.SetFunctionCalls(m_Population.getFunctionCalls()); archive.addPopulation(m_Population); @@ -171,7 +180,8 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi m_Population.addPopulation(tmpPop); m_Population.incrFunctionCallsBy(tmpPop.size()); - } else { // decrease step size + } else { // decrease step size for hc + if (localSearchMethod != PostProcessMethod.hillClimber) System.err.println("Invalid case in ClusteringHillClimbing!"); mutator.setSigma(mutator.getSigma()*reduceFactor); if (TRACE) System.out.println("mutation stepsize reduced to " + mutator.getSigma()); } @@ -249,18 +259,18 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi /** * @return the hcEvalCycle */ - public int getHcEvalCycle() { + public int getEvalCycle() { return hcEvalCycle; } /** * @param hcEvalCycle the hcEvalCycle to set */ - public void setHcEvalCycle(int hcEvalCycle) { + public void setEvalCycle(int hcEvalCycle) { this.hcEvalCycle = hcEvalCycle; } - public String hcEvalCycleTipText() { + public String evalCycleTipText() { return "The number of evaluations between two clustering/adaption steps."; } @@ -369,7 +379,19 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi } public String stepSizeInitialTipText() { - return "Initial mutation step size, relative to the problem range."; + return "Initial mutation step size for hill climbing, relative to the problem range."; + } + + public PostProcessMethod getLocalSearchMethod() { + return localSearchMethod; + } + + public void setLocalSearchMethod(PostProcessMethod localSearchMethod) { + this.localSearchMethod = localSearchMethod; + } + + public String localSearchMethodTipText() { + return "Set the method to be used for local search"; } // /** diff --git a/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java index d4072f9b..447e221c 100644 --- a/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java +++ b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java @@ -114,8 +114,8 @@ public class EvolutionStrategyIPOP extends EvolutionStrategies implements Interf * Reinitialize population with increased mu,lambda **/ private void boostPopSize() { - // increase by at least one - int newLambda = Math.max((int)(getLambda()*incPopSizeFact), getLambda() + 1); + // potentially increase pop size, increase by at least one if the factor is > 1. + int newLambda = Math.max((int)(getLambda()*incPopSizeFact), getLambda() + ((incPopSizeFact > 1.) ? 1 : 0)); setLambda(newLambda); checkPopulationConstraints(); // update the stagnation time in the terminator diff --git a/src/eva2/server/go/strategies/NelderMeadSimplex.java b/src/eva2/server/go/strategies/NelderMeadSimplex.java index 5632b751..ce05816b 100644 --- a/src/eva2/server/go/strategies/NelderMeadSimplex.java +++ b/src/eva2/server/go/strategies/NelderMeadSimplex.java @@ -3,6 +3,8 @@ package eva2.server.go.strategies; import java.io.Serializable; import java.util.Vector; +import com.sun.org.apache.bcel.internal.generic.CHECKCAST; + import eva2.OptimizerFactory; import eva2.OptimizerRunnable; import eva2.gui.BeanInspector; @@ -17,10 +19,12 @@ import eva2.server.go.problems.AbstractOptimizationProblem; import eva2.server.go.problems.AbstractProblemDouble; import eva2.server.go.problems.InterfaceOptimizationProblem; import eva2.server.stat.StatsParameter; +import eva2.tools.Mathematics; /** * Nelder-Mead-Simplex does not guarantee an equal number of evaluations within each optimize call * because of the different step types. + * Range check is now available by projection at the bounds. * * @author mkron * @@ -35,6 +39,7 @@ public class NelderMeadSimplex implements InterfaceOptimizer, Serializable, Inte private AbstractOptimizationProblem m_Problem; private transient Vector m_Listener; private String m_Identifier = "NelderMeadSimplex"; + private boolean checkConstraints = true; public NelderMeadSimplex() { setPopulation(new Population(populationSize)); @@ -52,10 +57,8 @@ public class NelderMeadSimplex implements InterfaceOptimizer, Serializable, Inte return new NelderMeadSimplex(this); } - public void SetIdentifier(String name) { m_Identifier = name; - } public void SetProblem(InterfaceOptimizationProblem problem) { @@ -85,31 +88,44 @@ public class NelderMeadSimplex implements InterfaceOptimizer, Serializable, Inte public void freeWilly() {} + protected double[] calcChallengeVect(double[] centroid, double[] refX) { + double[] r = new double[centroid.length]; + 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= 1. || (perturbRatio <= 0.)) { + System.err.println("Warning: perturbation ratio should lie between 0 and 1! (NelderMeadSimplex:createNMSPopulation)"); + } addPerturbedPopulation(perturbRatio, initPop, range, candidate); return initPop; } @@ -362,45 +395,6 @@ public class NelderMeadSimplex implements InterfaceOptimizer, Serializable, Inte } initialPop.setPopulationSize(initialPop.size()); } - -// /** -// * Search for a local optimizer using nelder mead and return the solution found and the number of steps -// * (evaluations) actually performed. -// * -// * @param candidate -// * @param problem -// * @param term -// * @param perturbationRatio -// * @return -// */ -// public static int processWithNMS(Population candidates, AbstractOptimizationProblem problem, InterfaceTerminator term, double perturbationRatio) { -// NelderMeadSimplex nms = new NelderMeadSimplex(); -// nms.setProblemAndPopSize(problem); -// nms.setGenerationCycle(5); -// nms.initByPopulation(candidates, false); -// int funCallsBefore = candidates.getFunctionCalls(); -// candidates.SetFunctionCalls(0); -// -// OptimizerRunnable hcRunnable = new OptimizerRunnable(OptimizerFactory.makeParams(nms, candidates, problem, 0, term), true); -// // as nms creates a new population and has already evaluated them, send a signal to stats -// hcRunnable.getStats().createNextGenerationPerformed(nms.getPopulation(), null); -// hcRunnable.getGOParams().setDoPostProcessing(false); -// hcRunnable.setVerbosityLevel(StatsParameter.VERBOSITY_NONE); -// hcRunnable.run(); -// hcRunnable.getGOParams().setDoPostProcessing(true); -// hcRunnable = null; -// int funCallsDone = candidates.getFunctionCalls(); -// candidates.SetFunctionCalls(funCallsBefore+funCallsDone); -// -// return funCallsDone; -// } - -// /** -// * @return the generationCycle -// */ -// public int getGenerationCycle() { -// return generationCycle; -// } /** * @param generationCycle the generationCycle to set @@ -408,13 +402,17 @@ public class NelderMeadSimplex implements InterfaceOptimizer, Serializable, Inte public void setGenerationCycle(int generationCycle) { this.generationCycle = generationCycle; } + + public boolean isCheckRange() { + return checkConstraints; + } + + public void setCheckRange(boolean checkRange) { + this.checkConstraints = checkRange; + } -// -// public static final GOParameters standardNMS(AbstractOptimizationProblem problem) { -// NelderMeadSimplex nms = NelderMeadSimplex.createNelderMeadSimplex(problem, null); -// Population pop = new Population(); -// pop.setPopulationSize(nms.getPopulationSize()); -// -// return makeParams(nms, pop, problem, randSeed, defaultTerminator()); -// } + public String checkRangeTipText() { + return "Mark to check range constraints by reflection/projection"; + } + } diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java index a6f0502d..cc3d9479 100644 --- a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java @@ -124,7 +124,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se if (a.algType != null) this.algType = (SelectedTag)a.algType.clone(); this.m_Population = (Population)a.m_Population.clone(); - this.m_Problem = (InterfaceOptimizationProblem)a.m_Problem.clone(); + this.m_Problem = a.m_Problem; this.m_Identifier = a.m_Identifier; this.m_InitialVelocity = a.m_InitialVelocity; this.m_SpeedLimit = a.m_SpeedLimit; @@ -169,8 +169,9 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se * Set the initial random velocity vector. * * @param indy the individual to work on + * @param initialV initial velocity relative to the range */ - protected void initIndividualDefaults(AbstractEAIndividual indy) { + public static void initIndividualDefaults(AbstractEAIndividual indy, double initialV) { double[] writeData; // init velocity writeData = new double[((InterfaceDataTypeDouble)indy).getDoubleData().length]; @@ -181,7 +182,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se //sum = Math.sqrt(sum); double relSpeed = getRelativeSpeed(writeData, ((InterfaceDataTypeDouble)indy).getDoubleRange()); for (int j = 0; j < writeData.length; j++) { - writeData[j] = (writeData[j]/relSpeed)*this.m_InitialVelocity; + writeData[j] = (writeData[j]/relSpeed)*initialV; } indy.putData(partTypeKey, defaultType); indy.putData(partVelKey, writeData); @@ -192,7 +193,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se * * @param indy the individual to work on */ - protected void initIndividualMemory(AbstractEAIndividual indy) { + protected static void initIndividualMemory(AbstractEAIndividual indy) { // init best fitness double[] tmpD = indy.getFitness(); double[] writeData = new double[tmpD.length]; @@ -338,6 +339,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se public double[] getPopulationVelocity(Population pop) { return getPopulationVelSpeed(pop, 1); } + /** * Calculates the norm of the velocity vector relative to the problem range. * @@ -345,7 +347,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se * @param range the problem range in each dimension * @return measure of the speed relative to the problem range */ - public double getRelativeSpeed(double[] curSpeed, double[][] range) { + public static double getRelativeSpeed(double[] curSpeed, double[][] range) { double sumV = 0; double sumR = 0; for (int i = 0; i < range.length; i++) { @@ -403,7 +405,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se for (int i = 0; i < pop.size(); i++) { indy = (AbstractEAIndividual) pop.get(i); if (indy instanceof InterfaceDataTypeDouble) { - initIndividualDefaults(indy); + initIndividualDefaults(indy, m_InitialVelocity); } indy.putData(indexKey, i); indy.SetIndividualIndex(i); @@ -470,13 +472,17 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se } protected void resetIndividual(AbstractEAIndividual indy) { + resetIndividual(indy, m_InitialVelocity); + plotIndy(((InterfaceDataTypeDouble)indy).getDoubleData(), null, (Integer)indy.getData(indexKey)); + } + + public static void resetIndividual(AbstractEAIndividual indy, double initialV) { if (indy instanceof InterfaceDataTypeDouble) { indy.setParents(null); indy.defaultInit(); indy.putData(partTypeKey, defaultType); // turn into default type - initIndividualDefaults(indy); + initIndividualDefaults(indy, initialV); initIndividualMemory(indy); - plotIndy(((InterfaceDataTypeDouble)indy).getDoubleData(), null, (Integer)indy.getData(indexKey)); } else System.err.println("error, double valued individuals required for PSO"); } @@ -1432,7 +1438,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se if (indy==null) { System.err.println("Error in PSO.setPopulation!"); } else if (!indy.hasData(partTypeKey)) { - initIndividualDefaults(indy); + initIndividualDefaults(indy, m_InitialVelocity); initIndividualMemory(indy); indy.putData(indexKey, i); indy.SetIndividualIndex(i); @@ -1596,7 +1602,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se public void setGOEShowProperties(Class cls) { GenericObjectEditor.setShowProperty(cls, "topologyRange", (m_Topology.getSelectedTag().getID() < 2) || (m_Topology.getSelectedTag().getID() == 6)); GenericObjectEditor.setShowProperty(cls, "subSwarmRadius", (m_Topology.getSelectedTag().getID() == 3)); - GenericObjectEditor.setShowProperty(cls, "subSwarmSize", (m_Topology.getSelectedTag().getID() == 3)); + GenericObjectEditor.setShowProperty(cls, "maxSubSwarmSize", (m_Topology.getSelectedTag().getID() == 3)); GenericObjectEditor.setShowProperty(cls, "treeStruct", (m_Topology.getSelectedTag().getID() == 4)); GenericObjectEditor.setShowProperty(cls, "treeBranchDegree", (m_Topology.getSelectedTag().getID() == 4) || (m_Topology.getSelectedTag().getID() == 5)); GenericObjectEditor.setShowProperty(cls, "wrapTopology", (m_Topology.getSelectedTag().getID() == 0)); @@ -1718,15 +1724,15 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se return "Define the maximum distance to a swarm leader in the multi-swarm variant"; } - public int getSubSwarmSize() { + public int getMaxSubSwarmSize() { return maxSubSwarmSize; } - public void setSubSwarmSize(int subSize) { + public void setMaxSubSwarmSize(int subSize) { maxSubSwarmSize = subSize; } - public String subSwarmSizeTipText() { + public String maxSubSwarmSizeTipText() { return "Maximum size of a sub swarm. Violating particles will be reinitialized. 0 means no limit to the sub swarm size."; } diff --git a/src/eva2/server/modules/PSOParameters.java b/src/eva2/server/modules/PSOParameters.java index 00bdd9dc..05e3259c 100644 --- a/src/eva2/server/modules/PSOParameters.java +++ b/src/eva2/server/modules/PSOParameters.java @@ -220,14 +220,14 @@ public class PSOParameters extends AbstractGOParameters implements InterfaceGOPa return ((ParticleSwarmOptimization)this.m_Optimizer).subSwarmRadiusTipText(); } - public int getSubSwarmSize() { - return ((ParticleSwarmOptimization)this.m_Optimizer).getSubSwarmSize(); + public int getMaxSubSwarmSize() { + return ((ParticleSwarmOptimization)this.m_Optimizer).getMaxSubSwarmSize(); } - public void setSubSwarmSize(int subSize) { - ((ParticleSwarmOptimization)this.m_Optimizer).setSubSwarmSize(subSize); + public void setMaxSubSwarmSize(int subSize) { + ((ParticleSwarmOptimization)this.m_Optimizer).setMaxSubSwarmSize(subSize); } - public String subSwarmSizeTipText() { - return ((ParticleSwarmOptimization)this.m_Optimizer).subSwarmSizeTipText(); + public String maxSubSwarmSizeTipText() { + return ((ParticleSwarmOptimization)this.m_Optimizer).maxSubSwarmSizeTipText(); } /** diff --git a/src/eva2/server/modules/Processor.java b/src/eva2/server/modules/Processor.java index eca52bc3..def3d933 100644 --- a/src/eva2/server/modules/Processor.java +++ b/src/eva2/server/modules/Processor.java @@ -1,5 +1,9 @@ package eva2.server.modules; +import java.util.Vector; + +import wsi.ra.jproxy.RemoteStateListener; +import wsi.ra.math.RNG; import eva2.gui.BeanInspector; import eva2.server.go.InterfaceGOParameters; import eva2.server.go.InterfacePopulationChangedEventListener; @@ -11,13 +15,12 @@ import eva2.server.go.operators.terminators.EvaluationTerminator; import eva2.server.go.operators.terminators.GenerationTerminator; import eva2.server.go.populations.Population; import eva2.server.go.problems.AbstractOptimizationProblem; -import wsi.ra.math.RNG; +import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; import eva2.server.stat.InterfaceStatistics; import eva2.server.stat.InterfaceTextListener; import eva2.server.stat.StatisticsWithGUI; import eva2.tools.EVAERROR; import eva2.tools.EVAHELP; -import wsi.ra.jproxy.RemoteStateListener; /** * The Processor may run as a thread permanently (GenericModuleAdapter) and is then stopped and started @@ -64,7 +67,7 @@ public class Processor extends Thread implements InterfaceProcessor, InterfacePo m_Statistics = Stat; } - protected boolean isOptRunning() { + public boolean isOptRunning() { return m_optRunning; } @@ -213,6 +216,9 @@ public class Processor extends Thread implements InterfaceProcessor, InterfacePo //////////////// PP or set results without further PP if (isOptRunning()) { resultPop = performPostProcessing(); + if (resultPop==null) { // post processing disabled, so use opt. solutions + resultPop = goParams.getOptimizer().getAllSolutions().getSolutions(); + } } else resultPop = goParams.getOptimizer().getAllSolutions().getSolutions(); } @@ -252,9 +258,13 @@ public class Processor extends Thread implements InterfaceProcessor, InterfacePo */ public void registerPopulationStateChanged(Object source, String name) { if (name.equals(Population.nextGenerationPerformed)) { +// System.out.println(getGOParams().getOptimizer().getPopulation().getFunctionCalls() + " " + getGOParams().getOptimizer().getPopulation().getBestFitness()[0]); + Vector informerList = new Vector(2); + informerList.add(this.goParams.getProblem()); + if (this.goParams.getOptimizer() instanceof InterfaceAdditionalPopulationInformer) informerList.add(this.goParams.getOptimizer()); m_Statistics.createNextGenerationPerformed( (PopulationInterface)this.goParams.getOptimizer().getPopulation(), - this.goParams.getProblem()); + informerList); if (m_ListenerModule != null) { m_ListenerModule.updateProgress( getStatusPercent( diff --git a/src/eva2/server/stat/AbstractStatistics.java b/src/eva2/server/stat/AbstractStatistics.java index ff71c2ed..931ef907 100644 --- a/src/eva2/server/stat/AbstractStatistics.java +++ b/src/eva2/server/stat/AbstractStatistics.java @@ -236,14 +236,20 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter return (resultOut != null) || (textListeners.size()>0); } - protected String getOutputHeader(InterfaceAdditionalPopulationInformer informer, PopulationInterface pop) { + protected String getOutputHeader(List informerList, PopulationInterface pop) { + String headline = "Fit.-calls \t Best \t Mean \t Worst "; - if ((informer == null) || !m_StatsParams.isOutputAdditionalInfo()) { + if ((informerList == null) || !m_StatsParams.isOutputAdditionalInfo()) { return headline; - } else return headline + "\t " + informer.getAdditionalFileStringHeader(pop); + } else { + for (InterfaceAdditionalPopulationInformer informer : informerList) { + headline = headline + "\t " + informer.getAdditionalFileStringHeader(pop); + } + return headline; + } } - protected String getOutputLine(InterfaceAdditionalPopulationInformer informer, PopulationInterface pop) { + protected String getOutputLine(List informerList, PopulationInterface pop) { StringBuffer sbuf = new StringBuffer(Integer.toString(functionCalls)); sbuf.append(" \t "); sbuf.append(BeanInspector.toString(currentBestFit)); @@ -255,9 +261,11 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter sbuf.append(" \t "); sbuf.append(BeanInspector.toString(currentWorstFit)); } else sbuf.append(" # \t"); - if (informer != null && m_StatsParams.isOutputAdditionalInfo()) { - sbuf.append(" \t "); - sbuf.append(informer.getAdditionalFileStringValue(pop)); + if (informerList != null && m_StatsParams.isOutputAdditionalInfo()) { + for (InterfaceAdditionalPopulationInformer informer : informerList) { + sbuf.append(" \t "); + sbuf.append(informer.getAdditionalFileStringValue(pop)); + } } return sbuf.toString(); } @@ -289,7 +297,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter * @param pop * @param informer */ - public abstract void plotSpecificData(PopulationInterface pop, InterfaceAdditionalPopulationInformer informer); + public abstract void plotSpecificData(PopulationInterface pop, List informerList); protected abstract void plotCurrentResults(); @@ -303,16 +311,16 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter * */ public synchronized void createNextGenerationPerformed(PopulationInterface - pop, InterfaceAdditionalPopulationInformer informer) { + pop, List informerList) { if (firstPlot) { initPlots(m_StatsParams.getPlotDescriptions()); // if (doTextOutput()) printToTextListener(getOutputHeader(informer, pop)+'\n'); firstPlot = false; } - if ((runIterCnt==0) && printHeaderByVerbosity()) printToTextListener(getOutputHeader(informer, pop)+'\n'); + if ((runIterCnt==0) && printHeaderByVerbosity()) printToTextListener(getOutputHeader(informerList, pop)+'\n'); if (pop.getSpecificData() != null) { - plotSpecificData(pop, informer); + plotSpecificData(pop, informerList); return; } // by default plotting only the best @@ -361,7 +369,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } // meanCollection.set(pop.getGenerations()-1, means); - if (doTextOutput() && printLineByVerbosity(runIterCnt)) printToTextListener(getOutputLine(informer, pop)+'\n'); + if (doTextOutput() && printLineByVerbosity(runIterCnt)) printToTextListener(getOutputLine(informerList, pop)+'\n'); plotCurrentResults(); runIterCnt++; diff --git a/src/eva2/server/stat/InterfaceStatistics.java b/src/eva2/server/stat/InterfaceStatistics.java index 103b28e1..b071a268 100644 --- a/src/eva2/server/stat/InterfaceStatistics.java +++ b/src/eva2/server/stat/InterfaceStatistics.java @@ -12,8 +12,9 @@ package eva2.server.stat; /*==========================================================================* * IMPORTS *==========================================================================*/ +import java.util.List; + import eva2.server.go.IndividualInterface; -import eva2.server.go.InterfaceGOParameters; import eva2.server.go.PopulationInterface; import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; /*==========================================================================* @@ -34,7 +35,7 @@ public interface InterfaceStatistics { public void addTextListener(InterfaceTextListener listener); public boolean removeTextListener(InterfaceTextListener listener); public void printToTextListener(String s); - public void createNextGenerationPerformed(PopulationInterface Pop, InterfaceAdditionalPopulationInformer informer); + public void createNextGenerationPerformed(PopulationInterface Pop, List informerList); public void createNextGenerationPerformed(double[] bestfit,double[] worstfit,int calls); public InterfaceStatisticsParameter getStatisticsParameter(); // called from moduleadapter public IndividualInterface getBestSolution(); // returns the best overall solution diff --git a/src/eva2/server/stat/StatisticsDummy.java b/src/eva2/server/stat/StatisticsDummy.java index f3da7ae6..6c9f158d 100644 --- a/src/eva2/server/stat/StatisticsDummy.java +++ b/src/eva2/server/stat/StatisticsDummy.java @@ -1,5 +1,7 @@ package eva2.server.stat; +import java.util.List; + import eva2.server.go.IndividualInterface; import eva2.server.go.PopulationInterface; import eva2.server.go.individuals.AbstractEAIndividual; @@ -35,7 +37,7 @@ public class StatisticsDummy implements InterfaceStatistics, InterfaceTextListen } public void createNextGenerationPerformed(PopulationInterface pop, - InterfaceAdditionalPopulationInformer informer) { + List informerList) { bestCurrentIndividual = (AbstractEAIndividual)pop.getBestIndividual(); if ((bestIndividualAllover == null) || (AbstractStatistics.secondIsBetter(bestIndividualAllover, bestCurrentIndividual))) { bestIndividualAllover = bestCurrentIndividual; diff --git a/src/eva2/server/stat/StatisticsStandalone.java b/src/eva2/server/stat/StatisticsStandalone.java index 4f7ddc39..92382edc 100644 --- a/src/eva2/server/stat/StatisticsStandalone.java +++ b/src/eva2/server/stat/StatisticsStandalone.java @@ -90,7 +90,7 @@ public class StatisticsStandalone extends AbstractStatistics implements Interfac ((ArrayList[]) m_Result.get(0))[optRunsPerformed].add(new double[] {functionCalls, currentBestFit[0]}); } - public void plotSpecificData(PopulationInterface pop, InterfaceAdditionalPopulationInformer informer) { + public void plotSpecificData(PopulationInterface pop, List informerList) { if (TRACE) System.out.println(" m_SpecificData !!"); double[] specificData = pop.getSpecificData(); if (specificData != null) { diff --git a/src/eva2/server/stat/StatisticsWithGUI.java b/src/eva2/server/stat/StatisticsWithGUI.java index 6ac79669..6c8e3237 100644 --- a/src/eva2/server/stat/StatisticsWithGUI.java +++ b/src/eva2/server/stat/StatisticsWithGUI.java @@ -241,7 +241,7 @@ public class StatisticsWithGUI extends AbstractStatistics implements Serializabl /** * */ - public void plotSpecificData(PopulationInterface pop, InterfaceAdditionalPopulationInformer informer) { + public void plotSpecificData(PopulationInterface pop, List informer) { double[] specificData = pop.getSpecificData(); int calls = pop.getFunctionCalls(); ArrayList description = new ArrayList(); diff --git a/src/eva2/tools/Mathematics.java b/src/eva2/tools/Mathematics.java index feec7d5c..94498713 100644 --- a/src/eva2/tools/Mathematics.java +++ b/src/eva2/tools/Mathematics.java @@ -727,4 +727,66 @@ public class Mathematics { } return viols; } + + + /** + * Calculate the average length of the range intervals over all dimensions. + * + * @param range + * @return the average length of the range intervals + */ + public static double getAvgRange(double[][] range) { + double sum = 0.; + for (int i=0; i dimLen) d -= dimLen; // avoid violating the other bound immediately + x[i]=range[i][0]+d; + } else if (x[i]>range[i][1]) { + viols++; + d = x[i]-range[i][1]; + while (d>dimLen) d -= dimLen; // avoid violating the other bound immediately + x[i]=range[i][1]-d; + } + } + return viols; + } + + /** + * Simple version of reflection of a value moving by a step and bouncing + * of min and max values like a pool ball. Precondition is min <= val <= max, + * post condition is min <= retVal <= max. + * + * @param val + * @param step + * @param min + * @param max + * @return + */ + public static double reflectValue(double val, double step, double min, double max) { + while (step > (max-min)) step -= (max-min); + if ((val + step) > max) + return (2 * max - val - step); + if ((val + step) < min) + return (2 * min - val - step); + return (val += step); + } } diff --git a/src/eva2/tools/SelectedTag.java b/src/eva2/tools/SelectedTag.java index d9b7fc66..24ea1bc8 100644 --- a/src/eva2/tools/SelectedTag.java +++ b/src/eva2/tools/SelectedTag.java @@ -73,8 +73,9 @@ public class SelectedTag implements java.io.Serializable { * * @param i The new selected tag index */ - public void setSelectedTag(int i) { + public SelectedTag setSelectedTag(int i) { if ((i >= 0) && (i < this.m_Tags.length)) this.m_Selected = i; + return this; } /** @@ -84,14 +85,15 @@ public class SelectedTag implements java.io.Serializable { * * @param str The new selected tag name */ - public void setSelectedTag(String str) { + public SelectedTag setSelectedTag(String str) { for (int i=0; i