diff --git a/.gitignore b/.gitignore index ff76151c..eb18a21d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ website *.iws .idea/workspace.xml .DS_Store +.idea +target diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 59ccb457..00000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -watchmaker \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml deleted file mode 100644 index 313b0c0c..00000000 --- a/.idea/ant.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index c04517b0..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index 3572571a..00000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 2a99e956..00000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.idea/libraries/Maven__com_beust_jcommander_1_12.xml b/.idea/libraries/Maven__com_beust_jcommander_1_12.xml deleted file mode 100644 index 2b9ea172..00000000 --- a/.idea/libraries/Maven__com_beust_jcommander_1_12.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_google_collections_google_collections_1_0.xml b/.idea/libraries/Maven__com_google_collections_google_collections_1_0.xml deleted file mode 100644 index 7ed5d20e..00000000 --- a/.idea/libraries/Maven__com_google_collections_google_collections_1_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__jfree_jcommon_1_0_12.xml b/.idea/libraries/Maven__jfree_jcommon_1_0_12.xml deleted file mode 100644 index 80156ee8..00000000 --- a/.idea/libraries/Maven__jfree_jcommon_1_0_12.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__jfree_jfreechart_1_0_13.xml b/.idea/libraries/Maven__jfree_jfreechart_1_0_13.xml deleted file mode 100644 index c91b3c02..00000000 --- a/.idea/libraries/Maven__jfree_jfreechart_1_0_13.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__jfree_jfreechart_1_0_8.xml b/.idea/libraries/Maven__jfree_jfreechart_1_0_8.xml deleted file mode 100644 index 4e53d165..00000000 --- a/.idea/libraries/Maven__jfree_jfreechart_1_0_8.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__junit_junit_3_8_1.xml b/.idea/libraries/Maven__junit_junit_3_8_1.xml deleted file mode 100644 index 71b2993d..00000000 --- a/.idea/libraries/Maven__junit_junit_3_8_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__net_jcip_jcip_annotations_1_0.xml b/.idea/libraries/Maven__net_jcip_jcip_annotations_1_0.xml deleted file mode 100644 index d29c82f6..00000000 --- a/.idea/libraries/Maven__net_jcip_jcip_annotations_1_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_beanshell_bsh_2_0b4.xml b/.idea/libraries/Maven__org_beanshell_bsh_2_0b4.xml deleted file mode 100644 index d6f17aa7..00000000 --- a/.idea/libraries/Maven__org_beanshell_bsh_2_0b4.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_easytesting_fest_assert_1_2.xml b/.idea/libraries/Maven__org_easytesting_fest_assert_1_2.xml deleted file mode 100644 index e0eb7e52..00000000 --- a/.idea/libraries/Maven__org_easytesting_fest_assert_1_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_easytesting_fest_reflect_1_2.xml b/.idea/libraries/Maven__org_easytesting_fest_reflect_1_2.xml deleted file mode 100644 index 2d5ea79d..00000000 --- a/.idea/libraries/Maven__org_easytesting_fest_reflect_1_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_easytesting_fest_swing_1_2_1.xml b/.idea/libraries/Maven__org_easytesting_fest_swing_1_2_1.xml deleted file mode 100644 index 8651372b..00000000 --- a/.idea/libraries/Maven__org_easytesting_fest_swing_1_2_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_easytesting_fest_util_1_1_3.xml b/.idea/libraries/Maven__org_easytesting_fest_util_1_1_3.xml deleted file mode 100644 index f54cc10d..00000000 --- a/.idea/libraries/Maven__org_easytesting_fest_util_1_1_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_testng_testng_6_2_1.xml b/.idea/libraries/Maven__org_testng_testng_6_2_1.xml deleted file mode 100644 index 16c6f535..00000000 --- a/.idea/libraries/Maven__org_testng_testng_6_2_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_uncommons_maths_uncommons_maths_1_2_2.xml b/.idea/libraries/Maven__org_uncommons_maths_uncommons_maths_1_2_2.xml deleted file mode 100644 index 38581b9d..00000000 --- a/.idea/libraries/Maven__org_uncommons_maths_uncommons_maths_1_2_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_6.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_6.xml deleted file mode 100644 index 0f8bd198..00000000 --- a/.idea/libraries/Maven__org_yaml_snakeyaml_1_6.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 75e1580d..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index f314de07..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml deleted file mode 100644 index 922003b8..00000000 --- a/.idea/scopes/scope_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index 3b000203..00000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index c80f2198..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/examples/pom.xml b/examples/pom.xml index 773b7d2d..87ca6eef 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -20,9 +20,9 @@ 4.0.0 - org.uncommons.watchmaker + com.decisionlens watchmaker - 0.7.2 + 0.1.1-SNAPSHOT watchmaker-examples diff --git a/examples/src/java/test/org/uncommons/watchmaker/examples/travellingsalesman/ItineraryPanelTest.java b/examples/src/java/test/org/uncommons/watchmaker/examples/travellingsalesman/ItineraryPanelTest.java index 9f2244d1..99c7f578 100644 --- a/examples/src/java/test/org/uncommons/watchmaker/examples/travellingsalesman/ItineraryPanelTest.java +++ b/examples/src/java/test/org/uncommons/watchmaker/examples/travellingsalesman/ItineraryPanelTest.java @@ -17,7 +17,8 @@ import java.awt.BorderLayout; import java.util.Collection; -import javax.swing.JFrame; +import javax.swing.*; + import org.fest.swing.core.BasicRobot; import org.fest.swing.core.Robot; import org.fest.swing.fixture.FrameFixture; @@ -62,7 +63,10 @@ public void testSelectAll() frame.validate(); frame.setVisible(true); assert itineraryPanel.getSelectedCities().isEmpty() : "Should be no cities selected initially."; + robot.waitForIdle(); frameFixture.button("All").click(); + SwingUtilities.updateComponentTreeUI(frame); + robot.waitForIdle(); Collection selectedCities = itineraryPanel.getSelectedCities(); assert selectedCities.size() == CITIES.getKnownCities().size() : "All cities should be selected after button click."; @@ -80,11 +84,15 @@ public void testSelectNone() frame.setSize(100, 300); frame.validate(); frame.setVisible(true); + robot.waitForIdle(); frameFixture.button("All").click(); + SwingUtilities.updateComponentTreeUI(frame); + robot.waitForIdle(); Collection selectedCities = itineraryPanel.getSelectedCities(); assert selectedCities.size() == CITIES.getKnownCities().size() : "All cities should be selected after all button click."; frameFixture.button("None").click(); + SwingUtilities.updateComponentTreeUI(frame); assert itineraryPanel.getSelectedCities().isEmpty() : "No cities should be selected after clear button is clicked."; } diff --git a/framework/framework.iml b/framework/framework.iml index 82c64ca4..f0620494 100644 --- a/framework/framework.iml +++ b/framework/framework.iml @@ -13,7 +13,7 @@ - + diff --git a/framework/pom.xml b/framework/pom.xml index 51ecd7bd..53858e98 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -20,9 +20,9 @@ 4.0.0 - org.uncommons.watchmaker + com.decisionlens watchmaker - 0.7.2 + 0.1.1-SNAPSHOT watchmaker-framework @@ -30,12 +30,13 @@ org.uncommons.maths uncommons-maths - 1.2.2 + 1.2.2a + - com.google.collections - google-collections - 1.0 + com.google.guava + guava + 27.0.1-jre org.testng diff --git a/framework/src/java/main/org/uncommons/watchmaker/framework/GenerationalEvolutionEngine.java b/framework/src/java/main/org/uncommons/watchmaker/framework/GenerationalEvolutionEngine.java index 3e43915f..46c38385 100644 --- a/framework/src/java/main/org/uncommons/watchmaker/framework/GenerationalEvolutionEngine.java +++ b/framework/src/java/main/org/uncommons/watchmaker/framework/GenerationalEvolutionEngine.java @@ -117,6 +117,12 @@ protected List> nextEvolutionStep(List originals = new ArrayList(evaluatedPopulation.size()); + iterator = evaluatedPopulation.iterator(); + while (iterator.hasNext()) { + originals.add(iterator.next().getCandidate()); + } // Then select candidates that will be operated on to create the evolved // portion of the next generation. population.addAll(selectionStrategy.select(evaluatedPopulation, @@ -127,6 +133,14 @@ protected List> nextEvolutionStep(List The type of the objects in this pool (must extend Releasable). It must + * either have an empty constructor, or a constructor with parameter T (to make + * a copy). + */ +public class ReleasablePool { + private Constructor constructorCopy=null; + private Constructor constructorEmpty=null; + private List items = new ArrayList(); + private T prototype; + + /** + * The prototype should be an object of the given type. It is used as the prototype + * when we ask for a new object and there are no released objects available. + * @param prototype + */ + public ReleasablePool(T prototype) { + if (prototype == null) + throw new IllegalArgumentException("Prototype cannot be null"); + this.prototype = prototype; + setupConstructors(); + } + + private void setupConstructors() { + try { + constructorCopy = (Constructor) prototype.getClass().getConstructor(prototype.getClass()); + } catch (NoSuchMethodException e) { + try { + constructorEmpty = (Constructor) prototype.getClass().getConstructor(); + } catch (NoSuchMethodException e1) { + throw new IllegalArgumentException("Prototype had no empty, nor copy constructor"); + } + } + } + + /** + * Adds an item to this pool. Makes sure the item.clearReleased() is called + * @param item + */ + public void add(T item) { + items.add(item); + } + + /** + * Gives the next released item from this pool. If there are no items + * that are released in this pool, create a new one from the prototype. + * @return + */ + public T nextOrCreate() { + if (items.size() > 0) + return items.remove(0); + //We made it here, we have nothing + //We have to create one + + T rval = null; + try { + rval = createItem(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return rval; + } + + /** + * Used internally to create a new object for the pool, assumed there are no + * available items to give. + * @return A newly created item using either the new T(T src) constructor or + * new T() constructor. + */ + private T createItem() { + if (constructorCopy != null) { + try { + return constructorCopy.newInstance(prototype); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } else { + try { + return constructorEmpty.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + + /** + * @return The number of items in this pool. + */ + public int size() { + return items.size(); + } + + /** + * Changes the prototype for this pool. + * @param prototype + */ + public void setProtoype(T prototype) { + this.prototype = prototype; + setupConstructors();; + } +} diff --git a/framework/src/java/main/org/uncommons/watchmaker/framework/termination/ImprovementTermination.java b/framework/src/java/main/org/uncommons/watchmaker/framework/termination/ImprovementTermination.java new file mode 100644 index 00000000..a75c847a --- /dev/null +++ b/framework/src/java/main/org/uncommons/watchmaker/framework/termination/ImprovementTermination.java @@ -0,0 +1,95 @@ +package org.uncommons.watchmaker.framework.termination; + +import org.uncommons.watchmaker.framework.PopulationData; +import org.uncommons.watchmaker.framework.TerminationCondition; + + +/** + * A termination validator that takes into account: + * 1. A minimum generation count, before even considering termination + * 2. A maximum generation count, once reached we consider it terminated + * 3. The history of the fitness function for each generation + * If we are between min/max number of generations, we look at the history + * of fitness function values for timesMustBeClose before the current + * generation. If each successive value is within closeEnough of the + * previous generation for timesMustBeClose, we consider it converged. + */ +public class ImprovementTermination implements TerminationCondition { + final int minGenerationCount; + final int maxGenerationCount; + int genCount=0; + double bestFitness=-1; + double closeEnough=1e-5; + double closeHistory[]; + double fitnessHistory[]; + int timesMustBeClose; + private boolean shouldTerminate=false; + public ImprovementTermination(int minGenCount, int maxGenCount, double closeEnoughPercent, int timesMustBeClose) { + maxGenerationCount=maxGenCount; + minGenerationCount=minGenCount; + this.closeEnough=closeEnoughPercent; + closeHistory=new double[maxGenerationCount]; + fitnessHistory=new double[maxGenerationCount]; + this.timesMustBeClose=timesMustBeClose; + } + + + public boolean shouldTerminate(PopulationData arg0) { + //First see if shouldTerminate flag set + if (shouldTerminate) { + //Yes we should terminate, we are done + return true; + } + //Calculate new percent diff + double newBest=arg0.getBestCandidateFitness(); + double perDiff=percentDiff(bestFitness, newBest); + if (genCount >= maxGenerationCount) { + return true; + } + closeHistory[genCount]=perDiff; + fitnessHistory[genCount]=newBest; + bestFitness=newBest; + genCount++; + if (genCount < minGenerationCount) + return false; + if (genCount >= timesMustBeClose) { + if (closeLongEnough()) { + return true; + } else { + return false; + } + } else { + return false; + } + } + private boolean closeLongEnough() { + for(int i=(genCount-timesMustBeClose); i closeEnough) { + return false; + } + } + return true; + } + + public void setTerminate(boolean b) { + // TODO Auto-generated method stub + this.shouldTerminate=b; + } + + /** + * A standard percent difference calculation where the first + * parameter is assumed to be known. If that parameter is + * zero, then no division by zero occurs. + * @param oldV The "correct value", as used by percent difference calculations. + * @param newV The "incorrect value", as used by percent difference calculations. + * @return absolute value of (newV - oldV)/oldV assuming oldV!=0, or just newV otherwise. + */ + public static double percentDiff(double oldV, double newV) { + double diff=Math.abs(newV-oldV); + if (oldV==0) + return diff; + return (diff/Math.abs(oldV)); + } + + +} diff --git a/framework/src/java/test/org/uncommons/watchmaker/framework/ReleasableTest.java b/framework/src/java/test/org/uncommons/watchmaker/framework/ReleasableTest.java new file mode 100644 index 00000000..cb1d8a5a --- /dev/null +++ b/framework/src/java/test/org/uncommons/watchmaker/framework/ReleasableTest.java @@ -0,0 +1,150 @@ +package org.uncommons.watchmaker.framework; + +import org.testng.annotations.Test; +import org.testng.Assert; +import org.uncommons.watchmaker.framework.factories.AbstractCandidateFactory; +import org.uncommons.watchmaker.framework.selection.RouletteWheelSelection; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Unit tests for the {@link GenerationalEvolutionEngine} class making use of + * {@alink Releasable} objects. + * @author wjladams@gmail.com + */ +public class ReleasableTest { + + /** + * Simple test to verify that Releasable objects are being released. + */ + @Test + public void testReleaseable() { + ReleasablePool pool = new ReleasablePool(new ReleasableInteger(0)); + pool.setProtoype(new ReleasableInteger(pool)); + + GenerationalEvolutionEngine engine2 = new GenerationalEvolutionEngine(new ReleasableStubFactory(pool), + new ReleasableIntegerZeroMaker(pool), + new ReleasableIntegerEvaluator(), + new RouletteWheelSelection(), + FrameworkTestUtils.getRNG()); + TerminationCondition tc = new TerminationCondition() { + int count = 0; + @Override + public boolean shouldTerminate(PopulationData populationData) { + if (count < 20) { + count++; + return false; + } else { + return true; + } + } + }; + int eliteCount=3; + int popSize = 10; + engine2.evolve(popSize, eliteCount, tc); + Assert.assertEquals(pool.size(), popSize - eliteCount); + } + + /** + * Simple evaluator for ReleasableIntegers + * */ + private static final class ReleasableIntegerEvaluator implements FitnessEvaluator { + + @Override + public double getFitness(ReleasableInteger candidate, List population) { + return candidate.value; + } + + @Override + public boolean isNatural() { + return true; + } + } + + /** + * Simple factory to create all 0 ReleasableInteger's + * */ + private static final class ReleasableStubFactory extends AbstractCandidateFactory { + private ReleasablePool pool; + + public ReleasableStubFactory(ReleasablePool pool) { + this.pool = pool; + } + + + @Override + public ReleasableInteger generateRandomCandidate(Random rng) { + ReleasableInteger rval = pool.nextOrCreate(); + if (rval != null) { + return rval; + } else { + rval = new ReleasableInteger(0); + pool.add(rval); + return rval; + } + } + } + /** + * Trivial test operator that mutates all releasable integers into zeroes. + */ + private static final class ReleasableIntegerZeroMaker implements EvolutionaryOperator + { + private final ReleasablePool pool; + + public ReleasableIntegerZeroMaker(ReleasablePool pool) { + this.pool = pool; + } + + public List apply(List selectedCandidates, Random rng) + { + List result = new ArrayList(selectedCandidates.size()); + for (int i = 0; i < selectedCandidates.size(); i++) + { + ReleasableInteger ri = pool.nextOrCreate(); + if (ri != null) { + result.add(ri); + } else { + ri = new ReleasableInteger(0); + pool.add(ri); + result.add(ri); + } + } + return result; + } + } + + /** + * Simple Releasable integer class + */ + private static class ReleasableInteger implements Releasable { + public int value; + private boolean isReleased = false; + private ReleasablePool pool=null; + + public ReleasableInteger(ReleasablePool pool) { + this.pool = pool; + this.value = 0; + } + + public ReleasableInteger(ReleasableInteger src) { + this.pool = src.pool; + this.value = src.value; + this.isReleased = false; + } + + public ReleasableInteger(int val) { + this.value = val; + } + + @Override + public void release() { + if (pool!=null) { + pool.add(this); + } + isReleased = true; + } + + } +} diff --git a/pom.xml b/pom.xml index 6698f38b..17ccdf6c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,9 +6,9 @@ oss-parent 7 - org.uncommons.watchmaker + com.decisionlens watchmaker - 0.7.2 + 0.1.1-SNAPSHOT pom watchmaker Watchmaker Framework - Root Project @@ -30,19 +30,12 @@ - dwdyer - Dan Dyer + wjladams + Dr. William Adams committer - - cowwoc - Gili Tzabari - - contributor - - @@ -51,6 +44,20 @@ examples + + + mvnrepo-releases + Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + + + mvnrepo-snapshots + Maven Snapshot Repository + https://oss.sonatype.org/content/repositories/snapshots + + + @@ -63,15 +70,61 @@ + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + maven-resources-plugin 2.4.3 ${project.build.sourceEncoding} - + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + mvnrepo-releases + https://oss.sonatype.org/ + true + + UTF-8 - \ No newline at end of file + diff --git a/swing/pom.xml b/swing/pom.xml index 690f0dba..c6ca4b2b 100644 --- a/swing/pom.xml +++ b/swing/pom.xml @@ -20,9 +20,9 @@ 4.0.0 - org.uncommons.watchmaker + com.decisionlens watchmaker - 0.7.2 + 0.1.1-SNAPSHOT watchmaker-swing @@ -35,7 +35,7 @@ org.uncommons.maths uncommons-maths - 1.2.2 + 1.2.2a jfree @@ -60,4 +60,4 @@ src/java/main src/java/test - \ No newline at end of file +