diff --git a/src/eva2/OptimizerFactory.java b/src/eva2/OptimizerFactory.java index 987aaf8b..a74e470b 100644 --- a/src/eva2/OptimizerFactory.java +++ b/src/eva2/OptimizerFactory.java @@ -649,6 +649,18 @@ public class OptimizerFactory { return opt; } + /** + * Produce a runnable optimizer from a GOParameters instance. Output is written to a file if the + * prefix String is given. + * + * @param params + * @param outputFilePrefix + * @return a runnable optimizer + */ + public static OptimizerRunnable getOptRunnable(GOParameters params, String outputFilePrefix) { + return new OptimizerRunnable(params, outputFilePrefix); + } + // /////////////////////////// constructing a default OptimizerRunnable /** * Produce a runnable optimizer from a strategy identifier, a problem instance and with the current @@ -708,7 +720,19 @@ public class OptimizerFactory { public static GOParameters makeParams(InterfaceOptimizer opt, int popSize, AbstractOptimizationProblem problem) { return makeParams(opt, popSize, problem, randSeed, makeDefaultTerminator()); } - + + /** + * Use default random seed and the population size of the optimizer. + * + * @see #makeParams(InterfaceOptimizer, int, AbstractOptimizationProblem, long, InterfaceTerminator) + * @param opt + * @param popSize + * @param problem + * @return + */ + public static GOParameters makeParams(InterfaceOptimizer opt, AbstractOptimizationProblem problem, InterfaceTerminator term) { + return makeParams(opt, opt.getPopulation().getPopulationSize(), problem, randSeed, term); + } /** * Set the population size, initialize the population and return a parameter structure containing all * given parts. diff --git a/src/eva2/OptimizerRunnable.java b/src/eva2/OptimizerRunnable.java index db285844..de4ed785 100644 --- a/src/eva2/OptimizerRunnable.java +++ b/src/eva2/OptimizerRunnable.java @@ -57,9 +57,7 @@ public class OptimizerRunnable implements Runnable { * @param restart */ public OptimizerRunnable(GOParameters params, boolean restart) { - proc = new Processor(new StatisticsDummy(), null, params); - if (proc.getStatistics() instanceof AbstractStatistics) ((AbstractStatistics)proc.getStatistics()).setSaveParams(false); - doRestart = restart; + this(params, new StatisticsDummy(), restart); } /** @@ -72,7 +70,19 @@ public class OptimizerRunnable implements Runnable { * @param restart */ public OptimizerRunnable(GOParameters params, String outputFilePrefix, boolean restart) { - proc = new Processor(new StatisticsStandalone(outputFilePrefix), null, params); + this(params, new StatisticsStandalone(outputFilePrefix), restart); + } + + /** + * Construct an OptimizerRunnable with given parameters and statistics instance with optional restart. + * If restart is true, the processor will not reinitialize the population allowing search on predefined populations. + * + * @param params + * @param outputFilePrefix + * @param restart + */ + public OptimizerRunnable(GOParameters params, InterfaceStatistics stats, boolean restart) { + proc = new Processor(stats, null, params); if (proc.getStatistics() instanceof AbstractStatistics) ((AbstractStatistics)proc.getStatistics()).setSaveParams(false); doRestart = restart; } @@ -85,6 +95,13 @@ public class OptimizerRunnable implements Runnable { return proc.getStatistics(); } + public void setStats(InterfaceStatistics stats) { + if (proc.isOptRunning()) throw new RuntimeException("Error - cannot change statistics instance during optimization."); + InterfaceGOParameters params = proc.getGOParams(); + proc = new Processor(stats, null, params); + if (proc.getStatistics() instanceof AbstractStatistics) ((AbstractStatistics)proc.getStatistics()).setSaveParams(false); + } + public void setTextListener(InterfaceTextListener lsnr) { proc.getStatistics().removeTextListener(listener); this.listener = lsnr; diff --git a/src/eva2/gui/GOEPanel.java b/src/eva2/gui/GOEPanel.java index de69f16c..72ad52a2 100644 --- a/src/eva2/gui/GOEPanel.java +++ b/src/eva2/gui/GOEPanel.java @@ -373,7 +373,7 @@ public class GOEPanel extends JPanel implements ItemListener { JOptionPane.showMessageDialog(this, "Could not create an example of\n" + className + "\n" - + "from the current classpath. Is it abstract? Is the default constructor missing?", + + "from the current classpath. Is the resource folder at the right place?\nIs the class abstract or the default constructor missing?", "GenericObjectEditor", JOptionPane.ERROR_MESSAGE); EVAHELP.getSystemPropertyString(); diff --git a/src/eva2/server/go/individuals/AbstractEAIndividual.java b/src/eva2/server/go/individuals/AbstractEAIndividual.java index 76a35592..665aadc0 100644 --- a/src/eva2/server/go/individuals/AbstractEAIndividual.java +++ b/src/eva2/server/go/individuals/AbstractEAIndividual.java @@ -160,6 +160,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. * @return boolean if equal true else false */ public boolean equals(Object obj) { + if (this==obj) return true; if (obj instanceof AbstractEAIndividual) { AbstractEAIndividual indy = (AbstractEAIndividual) obj; @@ -607,13 +608,18 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. boolean result = true; int i=0; while (result && (i < fit1.length) && (i < fit2.length)) { - if (fit1[i] > fit2[i]) result = false; + if (firstIsFiniteAndLarger(fit1[i], fit2[i])) result = false; i++; } return result; } - /** + private static boolean firstIsFiniteAndLarger(double a, double b) { + if (Double.isNaN(a) || Double.isInfinite(a)) return false; + else return (a > b); + } + + /** * Returns true if the first fitness vector truly dominates the second one in every component. * * @param fit1 first fitness vector to look at @@ -863,6 +869,8 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. sb.append(", fitness: "); sb.append(BeanInspector.toString(individual.getFitness())); + if (individual.isMarkedPenalized() || individual.violatesConstraint()) + sb.append(", X"); sb.append(", ID: "); sb.append(individual.getIndyID()); if (individual.getParentIDs()!=null) { @@ -882,7 +890,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. public static String getDefaultDataString(IndividualInterface individual) { // Note that changing this method might change the hashcode of an individual // which might interfere with some functionality. - return getDefaultDataString(individual, "; "); + return getDefaultDataString(individual, ", "); } /** @@ -897,8 +905,8 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java. // which might interfere with some functionality. if (individual == null) return "null"; StringBuffer sb = new StringBuffer(""); - char left = '['; - char right = ']'; + char left = '{'; + char right = '}'; sb.append(left); if (individual instanceof InterfaceDataTypeBinary) { BitSet b = ((InterfaceDataTypeBinary)individual).getBinaryData(); diff --git a/src/eva2/server/go/individuals/ESIndividualDoubleData.java b/src/eva2/server/go/individuals/ESIndividualDoubleData.java index 34604850..796eed66 100644 --- a/src/eva2/server/go/individuals/ESIndividualDoubleData.java +++ b/src/eva2/server/go/individuals/ESIndividualDoubleData.java @@ -6,6 +6,8 @@ import eva2.server.go.operators.crossover.CrossoverESDefault; import eva2.server.go.operators.mutation.InterfaceMutation; import eva2.server.go.operators.mutation.MutateESGlobal; import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.tools.EVAERROR; +import eva2.tools.Mathematics; /** This individual uses a real-valued genotype to code for double values. * Created by IntelliJ IDEA. @@ -162,8 +164,9 @@ public class ESIndividualDoubleData extends AbstractEAIndividual implements Inte return this.m_Phenotype; } - /** This method allows you to read the double data without - * an update from the genotype + /** + * This method allows you to read the double data without + * an update from the genotype. * @return double[] representing the double data. */ public double[] getDoubleDataWithoutUpdate() { @@ -198,6 +201,8 @@ public class ESIndividualDoubleData extends AbstractEAIndividual implements Inte this.defaultInit(); this.m_MutationOperator.init(this, opt); this.m_CrossoverOperator.init(this, opt); + // evil operators may not respect the range, so at least give some hint + if (!Mathematics.isInRange(m_Genotype, m_Range)) EVAERROR.errorMsgOnce("Warning: Individual out of range after initialization (and potential initial crossover/mutation)!"); } /** This method will init the individual with a given value for the diff --git a/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java b/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java index 30fe22d4..b8a6aec1 100644 --- a/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java +++ b/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java @@ -6,7 +6,9 @@ import java.util.Vector; import eva2.gui.BeanInspector; import eva2.gui.GenericObjectEditor; +import eva2.server.go.problems.GPFunctionProblem; import eva2.server.go.problems.InterfaceProgramProblem; +import eva2.tools.Mathematics; import eva2.tools.Pair; @@ -73,7 +75,8 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial public abstract String getOpIdentifier(); /** - * Small parser for GP nodes from a String. Format must be (nearly) equivalent to what makeStringRepresentation produces. + * Small parser for GP nodes from a String. Format must be (nearly) equivalent to what + * makeStringRepresentation produces. * This mainly means prefix notation with braces and commata, such as in: * AbstractGPNode node = AbstractGPNode.parseFromString("+(2.0,cos(*(pi,pi)))"); * System.out.println("Parsed GPNode: " + node.getStringRepresentation()); @@ -84,15 +87,7 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial */ public static Pair parseFromString(String str, Vector nodeTypes) { if (nodeTypes == null) { - ArrayListcls = GenericObjectEditor.getClassesFromClassPath(AbstractGPNode.class.getCanonicalName()); - nodeTypes = new Vector(cls.size()); - for (int i=0; i0) { Vector matchSet=AbstractGPNode.match(nodeTypes, str, true, true); @@ -116,10 +111,10 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial if (currentNode instanceof GPNodeInput) { Pair nextState=readDouble(restStr, false); if (nextState!=null) { - ((GPNodeInput)currentNode).setIdentifier("X"+((int)nextState.head().doubleValue())); + ((GPNodeInput)currentNode).setIdentifier(currentNode.getOpIdentifier()+((int)nextState.head().doubleValue())); restStr = nextState.tail(); } else { - ((GPNodeInput)currentNode).setIdentifier("X"); + ((GPNodeInput)currentNode).setIdentifier(currentNode.getOpIdentifier()); } } return new Pair(currentNode,restStr); @@ -129,7 +124,13 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial for (int i=0; i nextState = parseFromString(restStr, nodeTypes); currentNode.m_Nodes[i]=nextState.head(); - restStr=nextState.tail().substring(1).trim(); // cut comma or brace + try { + restStr=nextState.tail().substring(1).trim(); // cut comma or brace + } catch (StringIndexOutOfBoundsException e) { + System.err.println("Error: parsing failed for node " + currentNode.getOpIdentifier() + "/" + currentNode.getArity() + ", depth " + currentNode.getDepth()); + System.err.println("String was " + str); + e.printStackTrace(); + } } if (TRACE) System.out.println("read " + currentNode.getName() + ", rest: " + restStr); return new Pair(currentNode, restStr); @@ -137,6 +138,27 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial } } return null; } + + /** + * Return all available node types as AbstractGPNode list. + * Using getOpIdentifier on all elements gives an overview of the operators + * that can be used. + * + * @return a list of available AbstractGPNode implementations + */ + public static Vector getNodeTypes() { + ArrayListcls = GenericObjectEditor.getClassesFromClassPath(AbstractGPNode.class.getCanonicalName()); + Vector nodeTypes = new Vector(cls.size()); + for (int i=0; i readDouble(String str, boolean expect) { String firstArg; @@ -193,14 +215,19 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial if (matching.size()>1 && firstLongestOnly) { // allow only the longest match (or first longest) int maxLen = matching.get(0).getOpIdentifier().length(); AbstractGPNode longest=matching.get(0); + Vector longestList = new Vector(); + longestList.add(longest); for (int i=1; imaxLen) { longest = matching.get(i); maxLen = longest.getOpIdentifier().length(); - } + longestList.clear(); + longestList.add(longest); + } else if (matching.get(i).getOpIdentifier().length()==maxLen) longestList.add(matching.get(i)); } matching.clear(); - matching.add(longest); + matching.addAll(longestList); + // TODO test if arities are different! } return matching; } @@ -214,14 +241,46 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial public static void main(String[] args) { // Double d = Double.parseDouble("2.58923 + 3"); // AbstractGPNode node = AbstractGPNode.parseFromString("-23421"); - AbstractGPNode node = AbstractGPNode.parseFromString("+(-23421,cOs(*(pI,x1)))"); + AbstractGPNode node = AbstractGPNode.parseFromString("+(-23421,cOs(*(pI,x)))"); AbstractGPNode.parseFromString("+(+(85.334407,*(0.0056858,*(x1,x4))), +(*(0.00026,*(x0,x3)),*(-0.0022053,*(x2,x4))))"); AbstractGPNode.parseFromString("+(+(80.51249,*(0.0071317,*(x1,x4))), +(*(0.0029955,*(x0,x1)),*(0.0021813,*(x2,x2))))"); AbstractGPNode.parseFromString("+(+(9.300961,*(0.0047026,*(x2,x4))), +(*(0.0012547,*(x0,x2)),*(0.0019085,*(x2,x3))))"); System.out.println("Parsed GPNode: " + node.getStringRepresentation()); node = AbstractGPNode.parseFromString(node.getStringRepresentation()); + + double[] sol= new double[]{4.755837346122817, 0.0, 1.618818602745894, 7.941611605461133, 7.949805645271173, 7.9567145687445695, 4.8033535294211225, 7.96718976492528, 1.641971622483205, 7.973813526015599, 7.980394418430633, 7.98301197251176, 7.98590997257042, 1.6493767411801206, 7.994756424330215, 7.994983501150322, 7.9971658558418035, 8.00273733683876, 8.00492865462689, 8.006601147955184}; + double[] sol2={7.897269942114308, 0.0, 7.939346674715275, 1.6272963933436047, 7.952303730484389, 7.960893192129872, 4.804987144876599, 7.9682843963405805, 7.977546251710085, 7.981109017707746, 1.642081396353059, 7.985246784301232, 4.827113167927753, 1.6448751122424057, 7.997468593784776, 8.00165633007073, 8.000613763831703, 8.003920903217887, 8.005789437120203, 8.012425280944097}; + double[] sol3={4.705970234231343, 4.71343334004773, 7.845971927185614, 4.708648989456629, 4.723918978896874, 7.864710619970946, 1.5776948341096448, 7.854961967305262, 7.858760422458277, 1.5743212019457036, 7.8488102514506, 1.5637070804731334, 1.5778078319616269, 1.5757833862993071, 4.711995406637344, 4.715448624806491, 7.8434193487088155, 4.7036514083601535, 7.848371610694223, 7.856489370257257}; + test("-(0.75,prod(x))", sol3); + test("-(sum(x),*(7.5,n))", sol3); +// test("+(*(1000,+(sin(-(-0.25,x2)),sin(-(-0.25,x3)))), -(894.8,x0))", new double[]{1.,2,0,0,}); + double[] solG5lit = new double[]{679.9453, 1026.067, 0.1188764, -0.3962336}; + double[] solG5 = new double[] {891.702675571982, 808.9201991846442, -0.028381806025171354, -0.4684444512076402}; + test("-(x2,+(x3,0.55))", solG5); + test("-(x3,+(x2,0.55))", solG5); + test("+(*(1000,+(sin(-(-0.25,x2)),sin(-(-0.25,x3)))), -(894.8,x0))", solG5); + test("+(*(1000,+(sin(+(-0.25,x2)),sin(-(x2,+(x3,0.25))))), -(894.8,x1))", solG5); + test("+(*(1000,+(sin(+(-0.25,x3)),sin(-(x3,+(x2,0.25))))), 1294.8)", solG5); + + double[] solG13lit = new double[] {-1.717143,1.595709,1.827247,-0.7636413,-0.763645}; +// double[] solG13 = new double[] {-0.999977165120676, -0.03949641197962931, 2.9901909235593664, 0.11170038214968671, -0.21164083835675082}; +//NMS: double[] solG13 = new double[] {-1.20317028354022, 0.9052295512320271, 2.580255691052748, 0.5210663754783309, 0.8965551458319728}; + double[] solG13 = {-1.717136209326236, 1.5957142570821299, -1.8272614459011625, -0.7636708932891901, 0.7636501970281446}; + test("-(+(+(pow2(x0),pow2(x1)),+(pow2(x2),+(pow2(x3),pow2(x4)))),10)", solG13); + test("-(*(x1,x2),*(5,*(x3,x4)))", solG13); + test("+(pow3(x0),+(pow3(x1),1))", solG13); + System.out.println("" + Math.exp(Mathematics.product(solG13))); + + test("-(sum(x),*(7.5,n))", solG5); } + + public static void test(String constr, double[] pos) { + AbstractGPNode node = AbstractGPNode.parseFromString(constr); + GPFunctionProblem func = new GPFunctionProblem(node, null, pos.length, 0., 0.); + double[] ret = func.eval(pos); + System.out.println("testing " + constr + " evaluated to " + BeanInspector.toString(ret)); + } /** This method returns the depth of the current node * @return The depth. diff --git a/src/eva2/server/go/individuals/codings/gp/GPNodeMult.java b/src/eva2/server/go/individuals/codings/gp/GPNodeMult.java index 5a28a922..8efade81 100644 --- a/src/eva2/server/go/individuals/codings/gp/GPNodeMult.java +++ b/src/eva2/server/go/individuals/codings/gp/GPNodeMult.java @@ -3,7 +3,7 @@ package eva2.server.go.individuals.codings.gp; import eva2.server.go.problems.InterfaceProgramProblem; -/** A multiplicator node taking to arguments. +/** A multiplicator node taking two arguments. * Created by IntelliJ IDEA. * User: streiche * Date: 04.04.2003 @@ -70,6 +70,7 @@ public class GPNodeMult extends AbstractGPNode implements java.io.Serializable { for (int i = 0; i < this.m_Nodes.length; i++) { tmpObj = this.m_Nodes[i].evaluate(environment); if (tmpObj instanceof Double) result = result * ((Double)tmpObj).doubleValue(); + else System.err.println("Unexpected type returned in evaluate for "+this.getClass().getSimpleName()); } return new Double(result); } diff --git a/src/eva2/server/go/individuals/codings/gp/GPNodeNeg.java b/src/eva2/server/go/individuals/codings/gp/GPNodeNeg.java new file mode 100644 index 00000000..f7f38fbd --- /dev/null +++ b/src/eva2/server/go/individuals/codings/gp/GPNodeNeg.java @@ -0,0 +1,89 @@ +package eva2.server.go.individuals.codings.gp; + +import eva2.server.go.problems.InterfaceProgramProblem; + + +/** A substraction node using two arguments. + * Created by IntelliJ IDEA. + * User: streiche + * Date: 04.04.2003 + * Time: 15:49:47 + * To change this template use Options | File Templates. + */ +public class GPNodeNeg extends AbstractGPNode implements java.io.Serializable { + + public GPNodeNeg() { + } + public GPNodeNeg(GPNodeNeg node) { + this.m_Depth = node.m_Depth; + this.m_Parent = node.m_Parent; + this.m_Nodes = new AbstractGPNode[node.m_Nodes.length]; + for (int i = 0; i < node.m_Nodes.length; i++) this.m_Nodes[i] = (AbstractGPNode) node.m_Nodes[i].clone(); + } + + /** This method allows you to determine wehter or not two subtrees + * are actually the same. + * @param obj The other subtree. + * @return boolean if equal true else false. + */ + public boolean equals(Object obj) { + if (obj instanceof GPNodeNeg) { + GPNodeNeg node = (GPNodeNeg)obj; + if (this.m_Nodes.length != node.m_Nodes.length) return false; + for (int i = 0; i < this.m_Nodes.length; i++) { + if (!this.m_Nodes[i].equals(node.m_Nodes[i])) return false; + } + return true; + } else { + return false; + } + } + + /** This method will be used to identify the node in the GPAreaEditor + * @return The name. + */ + public String getName() { + return "Neg"; + } + + /** This method allows you to clone the Nodes + * @return the clone + */ + public Object clone() { + return (Object) new GPNodeNeg(this); + } + + /** This method will return the current arity + * @return Arity. + */ + public int getArity() { + return 1; + } + + /** This method will evaluate a given node + * @param environment + */ + public Object evaluate(InterfaceProgramProblem environment) { + Object tmpObj; + double result = 0; + + tmpObj = this.m_Nodes[0].evaluate(environment); + if (tmpObj instanceof Double) result += ((Double)tmpObj).doubleValue(); + for (int i = 1; i < this.m_Nodes.length; i++) { + tmpObj = this.m_Nodes[i].evaluate(environment); + if (tmpObj instanceof Double) result -= ((Double)tmpObj).doubleValue(); + } + return new Double(result); + } + + @Override + public String getOpIdentifier() { + return "neg"; + } +// /** This method returns a string representation +// * @return string +// */ +// public String getStringRepresentation() { +// return AbstractGPNode.makeStringRepresentation(m_Nodes, "-"); +// } +} diff --git a/src/eva2/server/go/individuals/codings/gp/GPNodeProd.java b/src/eva2/server/go/individuals/codings/gp/GPNodeProd.java new file mode 100644 index 00000000..4302e8f6 --- /dev/null +++ b/src/eva2/server/go/individuals/codings/gp/GPNodeProd.java @@ -0,0 +1,75 @@ +package eva2.server.go.individuals.codings.gp; + + +import eva2.server.go.problems.InterfaceProgramProblem; +import eva2.tools.Mathematics; + +/** + * A simple product node with a single, possibly vectorial (array), argument. + * + */ +public class GPNodeProd extends AbstractGPNode implements java.io.Serializable { + + public GPNodeProd() { + } + + public GPNodeProd(GPNodeProd node) { + this.m_Depth = node.m_Depth; + this.m_Parent = node.m_Parent; + this.m_Nodes = new AbstractGPNode[node.m_Nodes.length]; + for (int i = 0; i < node.m_Nodes.length; i++) this.m_Nodes[i] = (AbstractGPNode) node.m_Nodes[i].clone(); + } + + /** This method allows you to determine wehter or not two subtrees + * are actually the same. + * @param obj The other subtree. + * @return boolean if equal true else false. + */ + public boolean equals(Object obj) { + if (obj instanceof GPNodeProd) { + GPNodeProd node = (GPNodeProd)obj; + if (this.m_Nodes.length != node.m_Nodes.length) return false; + for (int i = 0; i < this.m_Nodes.length; i++) { + if (!this.m_Nodes[i].equals(node.m_Nodes[i])) return false; + } + return true; + } else { + return false; + } + } + + /** This method will be used to identify the node in the GPAreaEditor + * @return The name. + */ + public String getName() { + return "Prod"; + } + + public Object clone() { + return (Object) new GPNodeProd(this); + } + + public int getArity() { + return 1; + } + + public Object evaluate(InterfaceProgramProblem environment) { + Object tmpObj; + double result = 1; + + for (int i = 0; i < this.m_Nodes.length; i++) { + tmpObj = this.m_Nodes[i].evaluate(environment); + if (tmpObj instanceof double[]) result*=Mathematics.product((double[])tmpObj); + else if (tmpObj instanceof Double[]) { + Double[] vals = (Double[])tmpObj; + for (int j=0; j0) { + indy.SetMarkPenalized(true); + for (int i=0; i0) { + indy.SetMarkPenalized(true); + for (int i=0; i0) indy.addConstraintViolation(v); + break; + } + } + + private double getViolationConsideringRelation(double val) { +// System.out.println("Penalty is " + penaltyFactor); + val *= penaltyFactor; + switch (relation) { +// case linearLessEqZero: + case lessEqZero: + return (val <= 0.) ? 0 : val; + case eqZero: + val = Math.abs(val); + if (val<=equalityEpsilon) return 0.; + else return val; + case greaterEqZero: + return (val >= 0.) ? 0. : -val; + } + System.err.println("Unknown relation!"); + return 0.; + } + + public boolean isViolated(double[] pos) { + return (getViolation(pos)>0); + } + + public boolean isSatisfied(double[] pos) { + return (getViolation(pos)==0.); + } + + public ConstraintRelationEnum getRelation() { + return relation; + } + + public void setRelation(ConstraintRelationEnum relation) { + this.relation = relation; + GenericObjectEditor.setShowProperty(this.getClass(), "equalityEpsilon", relation==ConstraintRelationEnum.eqZero); + } + + public ParamAdaption getPenaltyFactControl() { + return paramCtrl.getSingleAdapters()[0]; + } + + public void setPenaltyFactControl(ParamAdaption penaltyAdaption) { +// this.penaltyFactAdaption = penaltyFact; + if (!(penaltyAdaption instanceof NoParamAdaption)) { + if (penaltyAdaption instanceof GenericParamAdaption) { + ((GenericParamAdaption)penaltyAdaption).setControlledParam(penaltyPropName); + } else { + if (!penaltyPropName.equals(penaltyAdaption.getControlledParam())) System.err.println("Warning: penalty factor control may have different target"); + } + } + paramCtrl.setSingleAdapters(new ParamAdaption[]{penaltyAdaption}); + } + + public String penaltyFactControlTipText() { + return "Adaptive penalty may used. For generic adaption mechanisms, the target string will be set automatically."; + } + + public double getPenaltyFactor() { + return penaltyFactor; + } + + public void setPenaltyFactor(double penaltyFactor) { + if (penaltyFactor<0) { + EVAERROR.errorMsgOnce("Error: a negative penalty factor is not allowed!"); + } else this.penaltyFactor = penaltyFactor; + } + + public String penaltyFactorTipText() { + return "Penalty factor by which a constraint violation is multiplied."; + } + + public ConstraintHandlingEnum getHandlingMethod() { + return handling; + } + + public void setHandlingMethod(ConstraintHandlingEnum handling) { + this.handling = handling; + } + + public String handlingMethodTipText() { + return "Select the method the constraint is handled."; + } + + public double getEqualityEpsilon() { + return equalityEpsilon; + } + + public void setEqualityEpsilon(double equalityEpsilon) { + this.equalityEpsilon = equalityEpsilon; + } + + public String equalityEpsilonTipText() { + return "The threshold below which equality constraints are said to be satisfied."; + } +} diff --git a/src/eva2/server/go/operators/constraint/ConstraintCollection.java b/src/eva2/server/go/operators/constraint/ConstraintCollection.java new file mode 100644 index 00000000..f03df6d9 --- /dev/null +++ b/src/eva2/server/go/operators/constraint/ConstraintCollection.java @@ -0,0 +1,75 @@ +package eva2.server.go.operators.constraint; + +import eva2.server.go.individuals.AbstractEAIndividual; + +/** + * To handle a set of constraints with a single parameter adaption mechanism. + * Single constraints are + * + * @author mkron + * + */ +public class ConstraintCollection extends AbstractConstraint { + private AbstractConstraint[] constraintArray = new AbstractConstraint[]{}; + + public ConstraintCollection() { + super(); + constraintArray = new AbstractConstraint[]{}; + } + + public ConstraintCollection(AbstractConstraint[] constrArr) { + super(); + constraintArray = constrArr; + } + + public ConstraintCollection(AbstractConstraint[] constrArr, ConstraintHandlingEnum handling, double penaltyFact) { + this(constrArr); + setHandlingMethod(handling); + setPenaltyFactor(penaltyFact); + } + + public ConstraintCollection(ConstraintCollection o) { + super(o); + constraintArray = o.constraintArray.clone(); + for (int i=0; i=indyX.length) { + System.err.println("Error in ImplicitConstraint!"); + return 0.; + } + return indyX[index]; + } + + public String getName() { + return "ImplicitCnstr-"+index; + } + + public String globalInfo() { + return "Similar to a multi-objective translation into fitness, this class allows to interpret fitness criteria as constraints."; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + if (index>0) this.index = index; + else System.err.println("Error, invalid index (<=0) in ImplicitConstraint."); + } + + public String indexTipText() { + return "Set the index of the fitness criterion to be translated into a constraint, must be > 0"; + } +} diff --git a/src/eva2/server/go/operators/constraint/InterfaceDoubleConstraint.java b/src/eva2/server/go/operators/constraint/InterfaceDoubleConstraint.java new file mode 100644 index 00000000..4ea88e1c --- /dev/null +++ b/src/eva2/server/go/operators/constraint/InterfaceDoubleConstraint.java @@ -0,0 +1,33 @@ +package eva2.server.go.operators.constraint; + +import eva2.server.go.individuals.AbstractEAIndividual; + +/** + * A constraint delivering a double valued degree of violation. + */ +public interface InterfaceDoubleConstraint { + /** + * This method allows you to make a deep clone of + * the object + * @return the deep clone + */ + public Object clone(); + + /** + * Returns the boolean information whether the constraint is satisfied. + * + * @param indy + * @return + */ + public boolean isSatisfied(double[] indyX); + + /** + * Return the absolute (positive) degree of violation or zero if the constraint + * is fulfilled. + * + * @param indy The individual to check. + * @param indyX possibly the decoded individual position + * @return true if valid false else. + */ + public double getViolation(double[] indyX); +} diff --git a/src/eva2/server/go/operators/constraint/IntervalConstraint.java b/src/eva2/server/go/operators/constraint/IntervalConstraint.java new file mode 100644 index 00000000..437c1501 --- /dev/null +++ b/src/eva2/server/go/operators/constraint/IntervalConstraint.java @@ -0,0 +1,123 @@ +package eva2.server.go.operators.constraint; + +import java.io.Serializable; + +import eva2.gui.GenericObjectEditor; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.tools.EVAERROR; +import eva2.tools.Mathematics; + +/** + * A constraint for a parameter or a generic function to lie within certain bounds. + * @author mkron + * + */ +public class IntervalConstraint extends AbstractConstraint implements InterfaceDoubleConstraint, Serializable{ + double lower=0; + double upper=1; + int index = 0; + GenericConstraint genericConstr = null; + + public IntervalConstraint() { + this(0,0.,1.); + genericConstr = null; + } + + public void hideHideable() { + GenericObjectEditor.setHideProperty(this.getClass(), "relation", true); + } + + public IntervalConstraint(int index, double lowerBnd, double upperBnd) { + this.index=index; + this.lower=lowerBnd; + this.upper=upperBnd; + setRelation(ConstraintRelationEnum.lessEqZero); + genericConstr = null; + } + + public IntervalConstraint(String genericFunctionString, double lowerBnd, double upperBnd) { + this(0, lowerBnd, upperBnd); + setGenericFunction(genericFunctionString); + } + + public IntervalConstraint(IntervalConstraint o) { + this(o.index, o.lower, o.upper); + genericConstr = o.genericConstr; + } + + @Override + public Object clone() { + return new IntervalConstraint(this); + } + + @Override + protected double getRawViolationValue(double[] indyX) { + if (genericConstr!=null) { + double constrFuncValue = genericConstr.getRawViolationValue(indyX); + return distanceToInterval(constrFuncValue); + } else { + if (index<0) { + double violSum=0; + for (int i=0;i=indyX.length) { + EVAERROR.errorMsgOnce("Error, invalid index for " + this.getClass().getSimpleName()); + return 0.; + } else { + return violInDim(index, indyX); + } + } + } + } + + public String getName() { + String clsName=this.getClass().getSimpleName(); + if (genericConstr!=null) return clsName+"/"+genericConstr.getConstraintString()+ " in ["+lower+","+upper+"]"; + else { + if (index<0) return clsName+"/x_i in ["+lower+","+upper+"]"; + else return clsName+"/x_" + index + " in ["+lower+","+upper+"]"; + } + } + + /** + * Return zero if the position respects the range, else the positive distance. + * + * @param i + * @param pos + * @return + */ + private double violInDim(int i, double[] pos) { + return distanceToInterval(pos[i]); + } + + /** + * Return zero if the position respects the range, else the positive distance. + * + * @param i + * @param pos + * @return + */ + private double distanceToInterval(double v) { + double tmp=Mathematics.projectValue(v, lower, upper); + return Math.abs(tmp-v); + } + + public void setGenericFunction(String str) { + if (str!=null && (str.length()>0)) { + genericConstr = new GenericConstraint(str); + if (!genericConstr.checkValid()) genericConstr=null; + } else genericConstr=null; + } + + public String getGenericFunction() { + if (genericConstr==null) return ""; + else return genericConstr.getConstraintString(); + } + + public String genericConstrTipText() { + return "A generic function can be used as in GenericConstraint - it has priority."; + } +} diff --git a/src/eva2/server/go/operators/paramcontrol/NoParamAdaption.java b/src/eva2/server/go/operators/paramcontrol/NoParamAdaption.java new file mode 100644 index 00000000..12daebbf --- /dev/null +++ b/src/eva2/server/go/operators/paramcontrol/NoParamAdaption.java @@ -0,0 +1,34 @@ +package eva2.server.go.operators.paramcontrol; + +import java.io.Serializable; + +import eva2.server.go.populations.Population; + +/** + * A dummy implementation which does not do any adaption. + * + * @author mkron + * + */ +public class NoParamAdaption implements ParamAdaption, Serializable { + + public Object clone() { + return new NoParamAdaption(); + } + + public Object calcValue(Object obj, Population pop, int iteration, int maxIteration) { + return null; + } + + public String getControlledParam() { + return null; + } + + public String globalInfo() { + return "A dummy implementation which will not change parameters."; + } + + public void finish(Object obj, Population pop) {} + + public void init(Object obj, Population pop, Object[] initialValues) {} +} diff --git a/src/eva2/server/go/problems/AbstractOptimizationProblem.java b/src/eva2/server/go/problems/AbstractOptimizationProblem.java index 4d43072d..c8a61f02 100644 --- a/src/eva2/server/go/problems/AbstractOptimizationProblem.java +++ b/src/eva2/server/go/problems/AbstractOptimizationProblem.java @@ -1,6 +1,7 @@ package eva2.server.go.problems; import java.awt.BorderLayout; +import java.io.Serializable; import javax.swing.JComponent; import javax.swing.JPanel; @@ -32,9 +33,9 @@ import eva2.tools.Mathematics; * Time: 13:40:12 * To change this template use Options | File Templates. */ -public abstract class AbstractOptimizationProblem implements InterfaceOptimizationProblem, java.io.Serializable { - +public abstract class AbstractOptimizationProblem implements InterfaceOptimizationProblem /*, InterfaceParamControllable*/, Serializable { protected AbstractEAIndividual m_Template; +// private transient ArrayList changeListeners = null; /** This method returns a deep clone of the problem. * @return the clone @@ -61,8 +62,10 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati evaluatePopulationStart(population); for (int i = 0; i < population.size(); i++) { tmpIndy = (AbstractEAIndividual) population.get(i); - tmpIndy.resetConstraintViolation(); - this.evaluate(tmpIndy); + synchronized (tmpIndy) { + tmpIndy.resetConstraintViolation(); + this.evaluate(tmpIndy); + } population.incrFunctionCalls(); } evaluatePopulationEnd(population); @@ -335,6 +338,28 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati else return false; } +// /********************************************************************************************************************** +// * These are for InterfaceParamControllable +// */ +// public Object[] getParamControl() { +// return null; +// } +// +// public void notifyParamChanged(String member, Object oldVal, Object newVal) { +// if (changeListeners != null) for (ParamChangeListener l : changeListeners) { +// l.notifyChange(this, oldVal, newVal, null); +// } +// } +// +// public void addChangeListener(ParamChangeListener l) { +// if (changeListeners==null) changeListeners = new ArrayList(); +// if (!changeListeners.contains(l)) changeListeners.add(l); +// } +// +// public void removeChangeListener(ParamChangeListener l) { +// if (changeListeners!=null) changeListeners.remove(l); +// } + /********************************************************************************************************************** * These are for GUI */ diff --git a/src/eva2/server/go/problems/AbstractProblemDouble.java b/src/eva2/server/go/problems/AbstractProblemDouble.java index 0bbf9572..af91e0c8 100644 --- a/src/eva2/server/go/problems/AbstractProblemDouble.java +++ b/src/eva2/server/go/problems/AbstractProblemDouble.java @@ -1,12 +1,16 @@ package eva2.server.go.problems; +import wsi.ra.math.RNG; +import eva2.gui.GenericObjectEditor; +import eva2.server.go.PopulationInterface; import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.individuals.ESIndividualDoubleData; import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.operators.constraint.AbstractConstraint; +import eva2.server.go.operators.constraint.GenericConstraint; import eva2.server.go.populations.Population; import eva2.server.go.strategies.InterfaceOptimizer; -import wsi.ra.math.RNG; -import eva2.server.go.problems.Interface2DBorderProblem; +import eva2.tools.Pair; /** * For a double valued problem, there are two main methods to implement: {@link #getProblemDimension()} @@ -29,17 +33,21 @@ import eva2.server.go.problems.Interface2DBorderProblem; * @author mkron * */ -public abstract class AbstractProblemDouble extends AbstractOptimizationProblem implements InterfaceProblemDouble, Interface2DBorderProblem { +public abstract class AbstractProblemDouble extends AbstractOptimizationProblem implements InterfaceProblemDouble, Interface2DBorderProblem/*, InterfaceParamControllable */{ private double m_DefaultRange = 10; private double m_Noise = 0; +// PropertySelectableList constraintList = new PropertySelectableList(new AbstractConstraint[]{new GenericConstraint()}); + private AbstractConstraint[] constraintArray = new AbstractConstraint[]{new GenericConstraint()}; + private boolean withConstraints = false; + public AbstractProblemDouble() { initTemplate(); } -// public AbstractProblemDouble(AbstractProblemDouble o) { -// cloneObjects(o); -// } + public AbstractProblemDouble(AbstractProblemDouble o) { + cloneObjects(o); + } protected void initTemplate() { if (m_Template == null) m_Template = new ESIndividualDoubleData(); @@ -49,16 +57,25 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem } } - public void hideHideable() {} + public void hideHideable() { + setWithConstraints(isWithConstraints()); + } protected void cloneObjects(AbstractProblemDouble o) { this.m_DefaultRange = o.m_DefaultRange; this.m_Noise = o.m_Noise; if (o.m_Template != null) this.m_Template = (AbstractEAIndividual)o.m_Template.clone(); + if (o.constraintArray!=null) { + this.constraintArray=o.constraintArray.clone(); + for (int i=0; i getConstraints() { +// return constraintList; +// } +// +// public void setConstraints(PropertySelectableList constraintArray) { +// this.constraintList = constraintArray; +// } + + public AbstractConstraint[] getConstraints() { + return constraintArray; + } + + public void setConstraints(AbstractConstraint[] constrArray) { + this.constraintArray = constrArray; + } + + public String constraintsTipText() { + return "Add constraints to the problem."; + } + + public boolean isWithConstraints() { + return withConstraints; + } + + public void setWithConstraints(boolean withConstraints) { + this.withConstraints = withConstraints; + GenericObjectEditor.setShowProperty(this.getClass(), "constraints", withConstraints); + } + + public String withConstraintsTipText() { + return "(De-)Activate constraints for the problem."; + } + + @Override + public String getAdditionalFileStringHeader(PopulationInterface pop) { + String superHeader = super.getAdditionalFileStringHeader(pop); + if (isWithConstraints()) return superHeader + " \tNum.Viol. \t Sum.Viol."; + else return superHeader; + } + + @Override + public String getAdditionalFileStringValue(PopulationInterface pop) { + String superVal = super.getAdditionalFileStringValue(pop); + if (isWithConstraints()) { + Pair violation= getConstraintViolation((AbstractEAIndividual)pop.getBestIndividual()); + return superVal + " \t" + violation.head() + " \t" + violation.tail(); + } else return superVal; + } + + protected Pair getConstraintViolation(AbstractEAIndividual indy) { + double sum=0; + int numViol=0; + for (AbstractConstraint constr : constraintArray) { + double v= constr.getViolation(getEvalArray(indy)); + if (v>0) numViol++; + sum += v; + } + return new Pair(numViol, sum); + } } diff --git a/src/eva2/server/go/problems/ConstrHimmelblauProblem.java b/src/eva2/server/go/problems/ConstrHimmelblauProblem.java new file mode 100644 index 00000000..86ff99d3 --- /dev/null +++ b/src/eva2/server/go/problems/ConstrHimmelblauProblem.java @@ -0,0 +1,83 @@ +package eva2.server.go.problems; + +import java.io.Serializable; +import java.util.Vector; + +import eva2.server.go.operators.constraint.AbstractConstraint; +import eva2.server.go.operators.constraint.ConstraintCollection; +import eva2.server.go.operators.constraint.IntervalConstraint; + +public class ConstrHimmelblauProblem extends AbstractProblemDouble implements Serializable { + private static double yOffset = 31025.5602425; // moving the optimum close to zero + private boolean useYOffset = true; + + public ConstrHimmelblauProblem() { + setWithConstraints(true); + setDefaultRange(100); + setConstraints(new AbstractConstraint[]{new ConstraintCollection(makeDefaultConstraints())}); + } + + public ConstrHimmelblauProblem( + ConstrHimmelblauProblem o) { + super(); + super.cloneObjects(o); + useYOffset=o.useYOffset; + } + + @Override + public Object clone() { + return new ConstrHimmelblauProblem(this); + } + +// @Override +// public void initProblem() { +// super.initProblem(); +// setConstraints(new AbstractConstraint[]{new ConstraintCollection(makeDefaultConstraints())}); +// } + + public static AbstractConstraint[] makeDefaultConstraints() { + Vector constraints = new Vector(); + constraints.add(new IntervalConstraint("+(+(85.334407,*(0.0056858,*(x1,x4))), +(*(0.00026,*(x0,x3)),*(-0.0022053,*(x2,x4))))", 0, 92)); + constraints.add(new IntervalConstraint("+(+(80.51249,*(0.0071317,*(x1,x4))), +(*(0.0029955,*(x0,x1)),*(0.0021813,*(x2,x2))))", 90, 110)); + constraints.add(new IntervalConstraint("+(+(9.300961,*(0.0047026,*(x2,x4))), +(*(0.0012547,*(x0,x2)),*(0.0019085,*(x2,x3))))", 20, 25)); + + constraints.add(new IntervalConstraint(0, 78, 102)); + constraints.add(new IntervalConstraint(1, 33, 45)); + constraints.add(new IntervalConstraint(2, 27, 45)); + constraints.add(new IntervalConstraint(3, 27, 45)); + constraints.add(new IntervalConstraint(4, 27, 45)); + return constraints.toArray(new AbstractConstraint[constraints.size()]); + } + + @Override + public double[] eval(double[] x) { + double v=5.3578547*x[2]*x[2]+0.8356891*x[0]*x[4]+37.293239*x[0]-40792.141; + if (useYOffset) v+=yOffset; + return new double[]{v}; + } + + @Override + public int getProblemDimension() { + return 5; + } + + public String getName() { + return "Constrained Himmelblau Problem"; + } + + public String globalInfo() { + return "Himmelblau's nonlinear optimization problem with 5 simple boundary constraints and 3 nonlinear boundary constraints."; + } + + public boolean isUseYOffset() { + return useYOffset; + } + + public void setUseYOffset(boolean useYOffset) { + this.useYOffset = useYOffset; + } + + public String useYOffsetTipText() { + return "Activate offset moving the optimum (close) to zero."; + } +} diff --git a/src/eva2/server/go/problems/ConstrPressureVessel.java b/src/eva2/server/go/problems/ConstrPressureVessel.java new file mode 100644 index 00000000..0fc2942b --- /dev/null +++ b/src/eva2/server/go/problems/ConstrPressureVessel.java @@ -0,0 +1,142 @@ +package eva2.server.go.problems; + +import java.util.Iterator; +import java.util.Vector; + +import eva2.gui.GenericObjectEditor; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.operators.constraint.AbstractConstraint; +import eva2.server.go.operators.constraint.ConstraintCollection; +import eva2.server.go.operators.constraint.ConstraintHandlingEnum; +import eva2.server.go.operators.constraint.ConstraintRelationEnum; +import eva2.server.go.operators.constraint.GenericConstraint; + +public class ConstrPressureVessel extends AbstractProblemDouble { + private boolean discreteThickness = true; + private double minThickness=0.0625; + private double maxThickness=2; + private double minRad=10, maxRad=300; + private double minLen=10, maxLen=300; +// L=200; +// R=40.3239; +// thickS=0.8125; +// thickH=0.4375; + + public ConstrPressureVessel() { + setWithConstraints(true); + setConstraints(new AbstractConstraint[]{new ConstraintCollection(makeDefaultConstraints(), ConstraintHandlingEnum.penaltyAdditive, 1000)}); +// setConstraints(makeDefaultConstraints()); + } + + public ConstrPressureVessel(ConstrPressureVessel o) { + super(); + super.cloneObjects(o); + } + + public static AbstractConstraint[] makeDefaultConstraints() { + Vector constraints = new Vector(); +// constraints.add(new IntervalConstraint("+(+(85.334407,*(0.0056858,*(x1,x4))), +(*(0.00026,*(x0,x3)),*(-0.0022053,*(x2,x4))))", 0, 92)); + constraints.add(new GenericConstraint("-(*(0.0193,x2),x0)", ConstraintRelationEnum.lessEqZero)); + constraints.add(new GenericConstraint("-(*(0.00954,x2),x1)", ConstraintRelationEnum.lessEqZero)); + constraints.add(new GenericConstraint("-(1296000, +(*(pi, *(pow2(x2),x3)),*(/(4,3),*(pi,pow3(x2))))))", ConstraintRelationEnum.lessEqZero)); + constraints.add(new GenericConstraint("-(x3,240)", ConstraintRelationEnum.lessEqZero)); + +// for (Iterator iterator = constraints.iterator(); iterator.hasNext();) { +// AbstractConstraint constr = iterator.next(); +// constr.setHandlingMethod(ConstraintHandlingEnum.penaltyAdditive); +// constr.setPenaltyFactor(10000); +// } + return constraints.toArray(new AbstractConstraint[constraints.size()]); + } + + @Override + protected double[] getEvalArray(AbstractEAIndividual individual) { + double[] x = super.getEvalArray(individual); + if (discreteThickness) {// integer multiple of minimal thickness + int n=(int)(x[0]/minThickness); + x[0]=n*minThickness; + n=(int)(x[1]/minThickness); + x[1]=n*minThickness; + } + //double thickS=x[0], thickH=x[1], R=x[2], L=x[3]; +// x[0]=0.8125; //thickS=0.8125; +// x[1]=0.4375; //thickH=0.4375; +// x[2]=40.3239; //R=40.3239; +// x[3]=200; //L=200; + return x; + } + + @Override + public double[] eval(double[] x) { + double v, thickS=x[0], thickH=x[1], R=x[2], L=x[3]; + + v = 0.6224*thickS*R*L+1.7781*thickH*R*R+3.1661*thickS*thickS*L+19.84*thickS*thickS*R; +// v = 0.6224*x(0)*x(2)*x(3)+1.7781*x(1)*x(2)*x(2)+3.1661*x(0)*x(0)*x(3)+19.84*x(0)*x(0)*x(2); + return new double[]{v}; + } + + @Override + public int getProblemDimension() { + return 4; + } + + @Override + public Object clone() { + return new ConstrPressureVessel(this); + } + + @Override + protected double getRangeLowerBound(int dim) { + switch (dim) { + case 0: + case 1: return minThickness/2; + case 2: return minRad; + case 3: return minLen; + } + System.err.println("Invalid dimension for lower bound (ConstrPressureVessel)"); + return 0.; +// if (dim<=1) return minThickness/2; +// else return minLen; + } + + @Override + protected double getRangeUpperBound(int dim) { + switch (dim) { + case 0: + case 1: return maxThickness; + case 2: return maxRad; + case 3: return maxLen; + } + System.err.println("Invalid dimension for upper bound (ConstrPressureVessel)"); + return 100.; +// if (dim<=1) { +// return maxThickness; +// } else if (dim==2) return maxRad; +// else return maxLen; + } + + @Override + public String getName() { + return "Constrained-Pressure-Vessel"; + } + + @Override + public String globalInfo() { + return "Minimize the material cost of a pressure vessel"; + } + + @Override + public void hideHideable() { + super.hideHideable(); + GenericObjectEditor.setHideProperty(this.getClass(), "defaultRange", true); + } + + public boolean isDiscreteThickness() { + return discreteThickness; + } + + public void setDiscreteThickness(boolean discreteThickness) { + this.discreteThickness = discreteThickness; + } + +} diff --git a/src/eva2/server/go/problems/F13Problem.java b/src/eva2/server/go/problems/F13Problem.java index d884d72e..18feef80 100644 --- a/src/eva2/server/go/problems/F13Problem.java +++ b/src/eva2/server/go/problems/F13Problem.java @@ -1,9 +1,6 @@ package eva2.server.go.problems; -import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.individuals.ESIndividualDoubleData; -import eva2.server.go.individuals.InterfaceDataTypeDouble; -import eva2.server.go.populations.Population; /** * Schwefels sine root function (1981) with a minimum at 420.9687^n of value 0. diff --git a/src/eva2/server/go/problems/F1Problem.java b/src/eva2/server/go/problems/F1Problem.java index 8e2e4ca0..fe34622b 100644 --- a/src/eva2/server/go/problems/F1Problem.java +++ b/src/eva2/server/go/problems/F1Problem.java @@ -1,9 +1,7 @@ package eva2.server.go.problems; -import wsi.ra.math.RNG; import eva2.server.go.individuals.AbstractEAIndividual; -import eva2.server.go.individuals.InterfaceDataTypeDouble; -import eva2.server.go.populations.Population; +import eva2.server.go.operators.constraint.GenericConstraint; import eva2.server.go.strategies.InterfaceOptimizer; /** @@ -23,7 +21,7 @@ public class F1Problem extends AbstractProblemDouble implements Interface2DBorde protected int m_ProblemDimension = 10; protected double m_XOffSet = 0.0; protected double m_YOffSet = 0.0; - protected boolean m_UseTestConstraint = false; +// protected boolean m_UseTestConstraint = false; public F1Problem() { super(); @@ -36,7 +34,7 @@ public class F1Problem extends AbstractProblemDouble implements Interface2DBorde this.m_ProblemDimension = b.m_ProblemDimension; this.m_XOffSet = b.m_XOffSet; this.m_YOffSet = b.m_YOffSet; - this.m_UseTestConstraint = b.m_UseTestConstraint; +// this.m_UseTestConstraint = b.m_UseTestConstraint; } public F1Problem(int dim) { @@ -55,32 +53,7 @@ public class F1Problem extends AbstractProblemDouble implements Interface2DBorde public Object clone() { return (Object) new F1Problem(this); } - -// @Override -// public void initPopulation(Population population) { -// AbstractEAIndividual tmpIndy; -// population.clear(); -// initTemplate(); -// -// for (int i = 0; i < population.getPopulationSize(); i++) { -// tmpIndy = (AbstractEAIndividual)((AbstractEAIndividual)this.m_Template).clone(); -// tmpIndy.init(this); -// if (tmpIndy instanceof InterfaceDataTypeDouble) { -// double[] v = ((InterfaceDataTypeDouble)tmpIndy).getDoubleData(); -// for (int j=0; j individual.getFitness(0))) { -// this.m_OverallBest = (AbstractEAIndividual)individual.clone(); -// } - } - /** Ths method allows you to evaluate a simple bit string to determine the fitness * @param x The n-dimensional input vector * @return The m-dimensional output vector. */ public double[] eval(double[] x) { double[] result = new double[1]; - result[0] = 0; + result[0] = m_YOffSet; + // add an offset in solution space for (int i = 0; i < x.length; i++) { - result[0] += Math.pow(x[i], 2); + result[0] += Math.pow(x[i] - this.m_XOffSet, 2); } return result; } @@ -189,18 +146,18 @@ public class F1Problem extends AbstractProblemDouble implements Interface2DBorde return this.m_ProblemDimension; } public String problemDimensionTipText() { - return "Length of the x vector at is to be optimized."; - } - /** This method allows you to toggle the application of a simple test constraint. - * @param b The mode for the test constraint - */ - public void setUseTestConstraint(boolean b) { - this.m_UseTestConstraint = b; - } - public boolean getUseTestConstraint() { - return this.m_UseTestConstraint; - } - public String useTestConstraintTipText() { - return "Just a simple test constraint of x[0] >= 1."; + return "Length of the x vector to be optimized."; } +// /** This method allows you to toggle the application of a simple test constraint. +// * @param b The mode for the test constraint +// */ +// public void setUseTestConstraint(boolean b) { +// this.m_UseTestConstraint = b; +// } +// public boolean getUseTestConstraint() { +// return this.m_UseTestConstraint; +// } +// public String useTestConstraintTipText() { +// return "Just a simple test constraint of x[0] >= 1."; +// } } diff --git a/src/eva2/server/go/problems/F7Problem.java b/src/eva2/server/go/problems/F7Problem.java index 2dbe5a46..b7100198 100644 --- a/src/eva2/server/go/problems/F7Problem.java +++ b/src/eva2/server/go/problems/F7Problem.java @@ -65,40 +65,13 @@ public class F7Problem extends F1Problem implements java.io.Serializable { evaluatePopulationEnd(population); } - /** This method evaluate a single individual and sets the fitness values - * @param individual The individual that is to be evalutated - */ - public void evaluate(AbstractEAIndividual individual) { - double[] x; - double[] fitness; - - x = new double[((InterfaceDataTypeDouble) individual).getDoubleData().length]; - System.arraycopy(((InterfaceDataTypeDouble) individual).getDoubleData(), 0, x, 0, x.length); - - for (int i = 0; i < x.length; i++) x[i] = x[i] - this.m_XOffSet; - fitness = this.eval(x); - for (int i = 0; i < fitness.length; i++) { - // add noise to the fitness - fitness[i] += RNG.gaussianDouble(this.getNoise()); - fitness[i] += this.m_YOffSet; - // set the fitness of the individual - individual.SetFitness(i, fitness[i]); - } - if (this.m_UseTestConstraint) { - if (x[0] < 1) individual.addConstraintViolation(1-x[0]); - } -// if ((this.m_OverallBest == null) || (this.m_OverallBest.getFitness(0) > individual.getFitness(0))) { -// this.m_OverallBest = (AbstractEAIndividual)individual.clone(); -// } - } - /** Ths method allows you to evaluate a double[] to determine the fitness * @param x The n-dimensional input vector * @return The m-dimensional output vector. */ public double[] eval(double[] x) { double[] result = new double[1]; - result[0] = 0; + result[0] = m_YOffSet; if ((Math.floor(this.m_CurrentTimeStamp / this.m_t)%2) == 0) { for (int i = 0; i < x.length-1; i++) { result[0] += Math.pow(x[i], 2); diff --git a/src/eva2/server/go/problems/GPFunctionProblem.java b/src/eva2/server/go/problems/GPFunctionProblem.java new file mode 100644 index 00000000..54bedd2c --- /dev/null +++ b/src/eva2/server/go/problems/GPFunctionProblem.java @@ -0,0 +1,139 @@ +package eva2.server.go.problems; + +import eva2.server.go.individuals.ESIndividualDoubleData; +import eva2.server.go.individuals.codings.gp.GPArea; +import eva2.server.go.individuals.codings.gp.InterfaceProgram; +import eva2.server.go.strategies.InterfaceOptimizer; +import eva2.tools.EVAERROR; + +/** + * A helper problem class which takes a GP program as argument and serves as target function + * for evaluating the GP function in optimization. A scaling option is implemented to flatten the + * function by scaling it logarithmically. This avoids ugly functions in GP. To activate scaling, + * set the scStart and scLimit parameters to positive values. Function values y with |y|>scStart + * will be rescaled to values below scLimit. + * + * @author mkron + * + */ +public class GPFunctionProblem extends AbstractProblemDouble implements InterfaceProgramProblem { + InterfaceProgram gpProblem = null; + GPArea gpArea = new GPArea(); + double[] pos = null; + int dim = 2; + double scalingStart=10.; + double scalingLimit=20.; + + public static boolean hideFromGOE = true; + + /** + * Initialize a default GP function problem in 2D with scaling. + * @param gpProb + * @param area + */ + public GPFunctionProblem(InterfaceProgram gpProb, GPArea area) { + this(gpProb, area, 0., 0.); + } + + /** + * By default, a 2-D problem is initialized with given scaling bounds. Set the scaling limit to 0 to + * deactivate scaling. + * + * @param gpProb + * @param area + * @param scStart + * @param scLim + */ + public GPFunctionProblem(InterfaceProgram gpProb, GPArea area, double scStart, double scLim) { + this(gpProb, area, 2, scStart, scLim); + } + + /** + * A GP function problem is initialized with given scaling bounds. Set the scaling limit to 0 to + * deactivate scaling. + * + * @param gpProb + * @param area + * @param scStart + * @param scLim + */ + public GPFunctionProblem(InterfaceProgram gpProb, GPArea area, int pDim, double scStart, double scLim) { + dim = pDim; + ((ESIndividualDoubleData)m_Template).setDoubleDataLength(dim); + gpProblem = gpProb; + gpArea = area; + scalingStart=scStart; + scalingLimit=scLim; + } + + public GPFunctionProblem(GPFunctionProblem functionProblem) { + dim = functionProblem.dim; + if (functionProblem.pos != null) { + pos = new double[dim]; + System.arraycopy(functionProblem.pos, 0, pos, 0, dim); + } + gpArea = (GPArea) functionProblem.gpArea.clone(); + gpProblem = functionProblem.gpProblem; + } + + @Override + public Object clone() { + return new GPFunctionProblem(this); + } + + @Override + public double[] eval(double[] x) { + if (x.length != dim) EVAERROR.errorMsgOnce("mismatching dimension of GPFunctionProblem!"); + pos = x; + Double res = (Double) gpProblem.evaluate(this); + double[] fit = new double[1]; + fit[0] = scaleFit(res.doubleValue()); + return fit; + } + + /** + * Scale the allover fitness value. + * + * @param doubleValue + * @return + */ + public double scaleFit(double v) { + if (scalingLimit==0.) return v; + else { + double aV = Math.abs(v); + if (aV > scalingStart) { + double logVal=Math.log(aV)/Math.log(scalingStart); + double tmp=1./(logVal); + return (scalingLimit - tmp)*Math.signum(v); + } else return v; + } + } + +// public static void main(String[] args) { +// for (double x=1.; x<100000000; x*=10.) { +// System.out.println("x: " + -x + " sc: " + scaleFit(-x)); +// } +// } + + @Override + public int getProblemDimension() { + return dim; + } + + public String getStringRepresentationForProblem(InterfaceOptimizer opt) { + return "GP find a function problem"; + } + + public Object getSensorValue(String sensor) { + return PSymbolicRegression.getSensorValue(sensor, pos, null); + } + + public void setActuatorValue(String actuator, Object parameter) { + // nothing to do here + } + + public GPArea getArea() { + return gpArea; + } + +} diff --git a/src/eva2/server/go/problems/PSymbolicRegression.java b/src/eva2/server/go/problems/PSymbolicRegression.java index 47edbaa1..aadabacd 100644 --- a/src/eva2/server/go/problems/PSymbolicRegression.java +++ b/src/eva2/server/go/problems/PSymbolicRegression.java @@ -280,6 +280,8 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements * This method allows a GP program to sense the environment, e.g. * input values, current time etc. Specialized to constants and variables * in arrays whose identifiers have the form "Xi" and "Ci". + * For an identifier X only, the full vars array is returned. For an + * identifier N only, the array dimension is returned. * * @param sensor The identifier for the sensor. * @param vars array of x_i @@ -288,11 +290,17 @@ public class PSymbolicRegression extends AbstractOptimizationProblem implements */ public static Object getSensorValue(String sensor, double[] vars, double[] consts) { if (sensor.charAt(0)=='X') { - int index=Integer.parseInt(sensor.substring(1)); - return new Double(vars[index]); + try { + int index=Integer.parseInt(sensor.substring(1)); + return new Double(vars[index]); + } catch(Exception e) { + return vars; + } } else if (sensor.charAt(0)=='C') { int index=Integer.parseInt(sensor.substring(1)); return new Double(consts[index]); + } else if (sensor.charAt(0)=='N') { + return (double)vars.length; } else return new Double(0); // for (int i = 0; i < this.m_X.length; i++) if (sensor.equalsIgnoreCase("X"+i)) return new Double(this.m_X[i]); // for (int i = 0; i < this.m_C.length; i++) if (sensor.equalsIgnoreCase("C"+i)) return new Double(this.m_C[i]); diff --git a/src/eva2/server/go/tools/AbstractObjectEditor.java b/src/eva2/server/go/tools/AbstractObjectEditor.java index 95015014..6591f0dd 100644 --- a/src/eva2/server/go/tools/AbstractObjectEditor.java +++ b/src/eva2/server/go/tools/AbstractObjectEditor.java @@ -245,6 +245,9 @@ public abstract class AbstractObjectEditor implements PropertyEditor, java.beans return result; } } + if (result==null) { + System.err.println("Warning: unknown property or unable to create editor for property " + prop + ", object " + this.getClass().getName()); + } return result; } diff --git a/src/eva2/server/stat/AbstractStatistics.java b/src/eva2/server/stat/AbstractStatistics.java index ff325c2f..257429e4 100644 --- a/src/eva2/server/stat/AbstractStatistics.java +++ b/src/eva2/server/stat/AbstractStatistics.java @@ -4,7 +4,9 @@ import java.io.FileOutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; +import java.util.Iterator; import java.util.List; import eva2.gui.BeanInspector; @@ -41,6 +43,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter private boolean refineMultiRuns = true; private ArrayList meanCollection; + // say whether the object should be written to a file every time private boolean saveParams = true; private boolean firstPlot = true; @@ -58,14 +61,17 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter protected int optRunsPerformed; protected double[] currentBestFit; protected double[] currentBestFeasibleFit; - protected double[] meanBestFeasibleFit; +// protected double[] meanBestFeasibleFit; protected double[] meanFitness; protected double[] currentWorstFit; - protected double[] meanBestOfRunFitness; +// protected double[] meanBestOfRunFitness; protected double avgPopDist; protected double maxPopDist; - protected IndividualInterface bestCurrentIndividual, bestRunIndividual, bestRunFeasibleIndy, bestIndividualAllover; + protected IndividualInterface bestCurrentIndividual, bestRunIndividual, bestRunFeasibleIndy, bestFeasibleAllover, bestIndividualAllover; + // collect feasible results of a run + private ArrayList runBestFeasibleList; + private ArrayList runBestFitList; private ArrayList textListeners; @@ -96,7 +102,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter SimpleDateFormat formatter = new SimpleDateFormat("E'_'yyyy.MM.dd'_at_'hh.mm.ss"); String startDate = formatter.format(new Date()); // open the result file: - if ((m_StatsParams.getOutputTo().getSelectedTagID()!=1) // not "text only" + if (doFileOutput() // not "text-window only" && (m_StatsParams.getOutputVerbosity().getSelectedTagID() > StatsParameter.VERBOSITY_NONE)) { // verbosity accordingly high //!resFName.equalsIgnoreCase("none") && !resFName.equals("")) { String fname = makeOutputFileName(m_StatsParams.getResultFilePrefix(), infoString, startDate); @@ -112,6 +118,10 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } else resultOut = null; } + protected boolean doFileOutput() { + return (m_StatsParams.getOutputTo().getSelectedTagID()!=1); // not "text-window only" + } + private String makeOutputFileName(String prefix, String infoString, String startDate) { return (prefix + "_" + infoString).replace(' ', '_') + "_" + startDate + ".txt"; } @@ -126,7 +136,11 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } public void startOptPerformed(String infoString, int runNumber, Object params) { - if (TRACE) System.out.println("AbstractStatistics.startOptPerformed " + runNumber); + if (TRACE) { + System.out.println("AbstractStatistics.startOptPerformed " + runNumber); + System.out.println("Statsparams were " + BeanInspector.toString(m_StatsParams)); + } + if (runNumber == 0) { functionCallSum = 0; firstPlot = true; @@ -135,8 +149,11 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter if (saveParams) m_StatsParams.saveInstance(); initOutput(infoString); bestIndividualAllover = null; - meanBestOfRunFitness = null; - meanBestFeasibleFit = null; + bestFeasibleAllover = null; +// meanBestOfRunFitness = null; +// meanBestFeasibleFit = null; + runBestFeasibleList = new ArrayList(); + runBestFitList = new ArrayList(); if (refineMultiRuns) meanCollection = new ArrayList(); else meanCollection = null; feasibleFoundAfterSum=-1; @@ -174,17 +191,14 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter if (Mathematics.norm(bestCurrentIndividual.getFitness()) < this.m_StatsParams.getConvergenceRateThreshold()) { convergenceCnt++; } - if (printRunStoppedVerbosity()) printToTextListener(" Last best individual : " + BeanInspector.toString(bestCurrentIndividual) + "\n"); - if (printRunStoppedVerbosity()) printToTextListener(" Last solution data : " + AbstractEAIndividual.getDefaultDataString(bestCurrentIndividual) + "\n"); - if (printRunStoppedVerbosity()) printToTextListener(" Last solution fit : " + BeanInspector.toString(bestCurrentIndividual.getFitness()) + "\n"); + if (printRunStoppedVerbosity()) printIndy("Last best", bestCurrentIndividual); } if (bestRunIndividual != null) { - if (printRunStoppedVerbosity()) printToTextListener(" Run best individual : " + BeanInspector.toString(bestRunIndividual) + "\n"); - if (printRunStoppedVerbosity()) printToTextListener(" Run solution data : " + AbstractEAIndividual.getDefaultDataString(bestRunIndividual) + "\n"); - if (printRunStoppedVerbosity()) printToTextListener(" Run solution fit : " + BeanInspector.toString(bestRunIndividual.getFitness()) + "\n"); - if (meanBestOfRunFitness==null) { - meanBestOfRunFitness=bestRunIndividual.getFitness().clone(); - } else addMean(meanBestOfRunFitness, bestRunIndividual.getFitness()); + runBestFitList.add(bestRunIndividual); + if (printRunStoppedVerbosity()) printIndy("Run best", bestRunIndividual); +// if (meanBestOfRunFitness==null) { +// meanBestOfRunFitness=bestRunIndividual.getFitness().clone(); +// } else addSecond(meanBestOfRunFitness, bestRunIndividual.getFitness()); } if (feasibleFoundAfter>0) { if (printRunStoppedVerbosity()) printToTextListener(" Feasible ind. found after " + feasibleFoundAfter + " evaluations.\n"); @@ -192,23 +206,21 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter if (printRunStoppedVerbosity()) printToTextListener(" NO feasible individual found.\n"); } if (bestRunFeasibleIndy != null) { - if (meanBestFeasibleFit==null) { - meanBestFeasibleFit=currentBestFeasibleFit.clone(); - } else addMean(meanBestFeasibleFit, currentBestFeasibleFit); + runBestFeasibleList.add(bestRunFeasibleIndy); +// if (meanBestFeasibleFit==null) { +// meanBestFeasibleFit=bestRunFeasibleIndy.getFitness().clone(); +// } else addSecond(meanBestFeasibleFit, bestRunFeasibleIndy.getFitness()); if (printRunStoppedVerbosity()) { if ((bestRunFeasibleIndy instanceof AbstractEAIndividual) && ((AbstractEAIndividual)bestRunFeasibleIndy).equalGenotypes((AbstractEAIndividual)bestRunIndividual)) { - printToTextListener(" Run best feasible individual equals best individual.\n"); + printToTextListener("* Run best feasible individual equals best individual.\n"); } else { - if (bestRunFeasibleIndy instanceof AbstractEAIndividual) { + if (bestRunIndividual instanceof AbstractEAIndividual) { if (((AbstractEAIndividual)bestRunIndividual).violatesConstraint()) printToTextListener(" Run best individual violates constraints by " + ((AbstractEAIndividual)bestRunIndividual).getConstraintViolation() + "\n"); if (((AbstractEAIndividual)bestRunIndividual).isMarkedPenalized()) printToTextListener(" Run best individual is penalized.\n"); } - - printToTextListener(" Run best feasible ind.: " + BeanInspector.toString(bestRunFeasibleIndy) + "\n"); - printToTextListener(" Feas. solution data : " + AbstractEAIndividual.getDefaultDataString(bestRunFeasibleIndy) + "\n"); - printToTextListener(" Feas. solution fit : " + BeanInspector.toString(bestRunFeasibleIndy.getFitness()) + "\n"); + printIndy("Run best feasible", bestRunFeasibleIndy); } } } @@ -218,6 +230,18 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter if (optRunsPerformed == m_StatsParams.getMultiRuns()) finalizeOutput(); } + private void printIndy(String prefix, IndividualInterface indy) { + printToTextListener("* " + prefix + " ind.: " + BeanInspector.toString(indy) + '\n'); + printToTextListener(" solution data : " + AbstractEAIndividual.getDefaultDataString(indy) + '\n'); + printToTextListener(" solution fit : " + BeanInspector.toString(indy.getFitness())); + if (!(indy instanceof AbstractEAIndividual)) printToTextListener(" - feasibility unknown\n"); + else { + if (((AbstractEAIndividual)indy).isMarkedPenalized() || ((AbstractEAIndividual)indy).violatesConstraint()) printToTextListener(" - infeasible\n"); + else printToTextListener("\n"); + } + + } + protected void finalizeOutput() { if (printFinalVerbosity()) printToTextListener("*******\n Runs performed: " + optRunsPerformed + ", reached target " + convergenceCnt + " times with threshold " + m_StatsParams.getConvergenceRateThreshold() + ", rate " + convergenceCnt/(double)m_StatsParams.getMultiRuns() + '\n'); if (printFinalVerbosity()) printToTextListener(" Average function calls: " + (functionCallSum/optRunsPerformed) + "\n"); @@ -227,20 +251,25 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter printToTextListener(" Average evaluations until feasible ind. was found in " + numOfRunsFeasibleFound + " runs: " + feasibleFoundAfterSum/numOfRunsFeasibleFound + " evaluations\n"); } - if (printFinalVerbosity() && (bestIndividualAllover != null)) printToTextListener(" Overall best individual: " + BeanInspector.toString(bestIndividualAllover) + '\n'); - if (printFinalVerbosity() && (bestIndividualAllover != null)) printToTextListener(" Overall solution data : " + AbstractEAIndividual.getDefaultDataString(bestIndividualAllover) + '\n'); - if (printFinalVerbosity() && (bestIndividualAllover != null)) printToTextListener(" Overall solution fit : " + BeanInspector.toString(bestIndividualAllover.getFitness()) + '\n'); + if (printFinalVerbosity() && (bestIndividualAllover != null)) printIndy("Overall best", bestIndividualAllover); if (optRunsPerformed>1) { - if (meanBestOfRunFitness!=null) { - Mathematics.svDiv((double)optRunsPerformed, meanBestOfRunFitness, meanBestOfRunFitness); + if (runBestFitList.size()>0) { +// Mathematics.svDiv((double)optRunsPerformed, meanBestOfRunFitness, meanBestOfRunFitness); if (printFinalVerbosity()) { - printToTextListener(" Average best fitness per run: " + BeanInspector.toString(meanBestOfRunFitness)+"\n"); + double[] meanBestFit=calcMeanFit(runBestFitList); + printToTextListener(" MultiRun stats: Mean best fitness: " + BeanInspector.toString(meanBestFit)+"\n"); + if (meanBestFit.length==1) printToTextListener(" MultiRun stats: Variance/Std.Dev.: " + BeanInspector.toString(calcStdDevVar(runBestFitList, meanBestFit[0])) + "\n"); + printToTextListener(" MultiRun stats: Median best fitn.: " + BeanInspector.toString(calcMedianFit(runBestFitList))+"\n"); } } - if (meanBestFeasibleFit!=null) { - Mathematics.svDiv((double)numOfRunsFeasibleFound, meanBestFeasibleFit, meanBestFeasibleFit); + if (printFinalVerbosity() && (bestFeasibleAllover != null)) printIndy("Overall best feasible", bestFeasibleAllover); +// if ((runBestFeasibleList.size()>0) && (!equalLists(runBestFeasibleList, runBestFitList))) { // is there a difference between best feasibles and best fit? + if (runBestFeasibleList.size()>0) { // always output feasible stats even if theyre equal if (printFinalVerbosity()) { - printToTextListener(" Average best feasible fitness in " + numOfRunsFeasibleFound + " runs: " + BeanInspector.toString(meanBestFeasibleFit)+"\n"); + double[] meanBestFeasibleFit=calcMeanFit(runBestFeasibleList); + printToTextListener(" MultiRun stats: Mean best feasible fitness (" + numOfRunsFeasibleFound + " runs): " + BeanInspector.toString(meanBestFeasibleFit)+"\n"); + if (meanBestFeasibleFit.length==1) printToTextListener(" MultiRun stats: Variance/Std.Dev.: " + BeanInspector.toString(calcStdDevVar(runBestFeasibleList, meanBestFeasibleFit[0])) + "\n"); + printToTextListener(" MultiRun stats: Median best feasible fitn. (: " + numOfRunsFeasibleFound + " runs): " + BeanInspector.toString(calcMedianFit(runBestFeasibleList))+"\n"); } } if (refineMultiRuns && (meanCollection != null)) { @@ -261,7 +290,59 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } } - public static String refineToText(ArrayList result, int iterationsToShow) { + /** + * Perform a deep equals test on the fitness vectors of both individual lists. + * @param l1 + * @param l2 + * @return + */ + private boolean equalLists( + ArrayList l1, + ArrayList l2) { + boolean equal = true; + Iterator iter1=l1.iterator(); + Iterator iter2=l2.iterator(); + IndividualInterface indy1, indy2; + if (l1.size()!=l2.size()) return false; + else while (equal && (iter1.hasNext() && iter2.hasNext())) { + equal = Arrays.equals(iter1.next().getFitness(), iter2.next().getFitness()); + } + return equal; + } + + private double[] calcStdDevVar(ArrayList list, double meanFit) { + double tmp=0, sum=0; + for (Iterator iter = list.iterator(); iter.hasNext();) { + IndividualInterface indy = (IndividualInterface) iter.next(); + tmp=indy.getFitness()[0]-meanFit; + sum+=(tmp*tmp); + } + double[] res = new double[2]; + res[0]=sum/list.size(); + res[1]=Math.sqrt(res[0]); + return res; + } + + /** + * Calculate the mean fitness of a list of individuals. + * @param list + * @return + */ + public static double[] calcMeanFit(List list) { + double[] sumFit = list.get(0).getFitness().clone(); + for (int i=1; i list) { + ArrayList dblAList = new ArrayList(list.size()); + for (int i=0; i result, int iterationsToShow) { double[][] mean; StringBuffer sbuf = new StringBuffer("Iteration\tFun.Calls\tBest\tMean\tWorst\n"); double step = result.size()/(iterationsToShow-1.); @@ -350,7 +431,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } /** - * + * @deprecated The method {@link #createNextGenerationPerformed(PopulationInterface, List)} should be used instead. */ public synchronized void createNextGenerationPerformed(double[] bestfit, double[] worstfit, int calls) { @@ -424,7 +505,6 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } if (pop instanceof Population) { AbstractEAIndividual curBestFeasible = ((Population)pop).getBestFeasibleIndividual(-1); - if (curBestFeasible!=null) { // a feasible ind. was found! if (currentBestFeasibleFit==null) { // feasible indy found for the first time numOfRunsFeasibleFound++; @@ -434,10 +514,14 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } currentBestFeasibleFit = curBestFeasible.getFitness().clone(); if ((bestRunFeasibleIndy==null) || (secondIsBetter(bestRunFeasibleIndy, curBestFeasible))) { - bestRunFeasibleIndy=curBestFeasible; + bestRunFeasibleIndy=(AbstractEAIndividual)curBestFeasible.clone(); +// System.out.println("New best feasible: " + AbstractEAIndividual.getDefaultStringRepresentation((AbstractEAIndividual)bestRunFeasibleIndy)); } - } - } + if ((bestFeasibleAllover == null) || (secondIsBetter(bestFeasibleAllover, bestRunFeasibleIndy))) { + bestFeasibleAllover = bestRunFeasibleIndy; + } + } + } else System.err.println("INVALID POPULATION (AbstractStatistics)"); meanFitness = pop.getMeanFitness().clone(); currentWorstFit = pop.getWorstIndividual().getFitness().clone(); @@ -504,9 +588,9 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter private void updateMeans(double[][] means, double funCalls, double[] bestFit, double[] meanFit, double[] worstFit) { means[0][0]+=funCalls; - addMean(means[1], bestFit); - addMean(means[2], meanFit); - addMean(means[3], worstFit); + addSecond(means[1], bestFit); + addSecond(means[2], meanFit); + addSecond(means[3], worstFit); } private static void divideMean(double[][] mean, double d) { @@ -515,7 +599,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } } - private void addMean(double[] mean, double[] fit) { + public static void addSecond(double[] mean, double[] fit) { for (int i=0; i