From b21e1134317858a733c8b7a56dae670b18b06eb0 Mon Sep 17 00:00:00 2001 From: Mauro J Giamberardino Date: Tue, 13 Dec 2016 20:00:18 -0300 Subject: [PATCH] In this commit the solution has evolved to improve the interface: - Added the evolution class - Added some methods to allow easly building of populations - Added methods to allow calculating the population fitness - Added support for selection crossers, selectos and mutators on the Evolution --- pom.xml | 22 +++-- .../java/com/mgiamberardino/jnetic/App.java | 13 --- .../jnetic/population/Evolution.java | 53 ++++++++++++ .../jnetic/population/Population.java | 64 +++++++++++++- .../jnetic/population/Populations.java | 21 ----- .../jnetic/population/EvolutionTest.java | 67 +++++++++++++++ .../jnetic/population/PopulationsTest.java | 85 +++++++++++++++---- 7 files changed, 266 insertions(+), 59 deletions(-) delete mode 100644 src/main/java/com/mgiamberardino/jnetic/App.java create mode 100644 src/main/java/com/mgiamberardino/jnetic/population/Evolution.java delete mode 100644 src/main/java/com/mgiamberardino/jnetic/population/Populations.java create mode 100644 src/test/java/com/mgiamberardino/jnetic/population/EvolutionTest.java diff --git a/pom.xml b/pom.xml index a266520..fbcc833 100644 --- a/pom.xml +++ b/pom.xml @@ -16,10 +16,22 @@ - junit - junit - 3.8.1 - test - + junit + junit + 4.11 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + diff --git a/src/main/java/com/mgiamberardino/jnetic/App.java b/src/main/java/com/mgiamberardino/jnetic/App.java deleted file mode 100644 index 37dbea8..0000000 --- a/src/main/java/com/mgiamberardino/jnetic/App.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.mgiamberardino.jnetic; - -/** - * Hello world! - * - */ -public class App -{ - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); - } -} diff --git a/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java b/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java new file mode 100644 index 0000000..fe049a6 --- /dev/null +++ b/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java @@ -0,0 +1,53 @@ +package com.mgiamberardino.jnetic.population; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class Evolution { + + private Population population; + private BiFunction> crosser; + private Function, List> selector; + private Function mutator; + + public static Evolution of(Population population) { + return new Evolution(population); + } + + Evolution(Population population){ + this.population = population; + } + + public Population evolve() { + return Population.of(population); + } + + public Evolution crosser(BiFunction> crosser) { + this.crosser = crosser; + return this; + } + + public BiFunction> crosser() { + return crosser; + } + + public Evolution selector(Function, List> selector) { + this.selector = selector; + return this; + } + + public Function, List> selector() { + return selector; + } + + public Evolution mutator(Function mutator) { + this.mutator = mutator; + return this; + } + + public Function mutator() { + return mutator; + } + +} diff --git a/src/main/java/com/mgiamberardino/jnetic/population/Population.java b/src/main/java/com/mgiamberardino/jnetic/population/Population.java index da2da29..39d02ef 100644 --- a/src/main/java/com/mgiamberardino/jnetic/population/Population.java +++ b/src/main/java/com/mgiamberardino/jnetic/population/Population.java @@ -1,14 +1,35 @@ package com.mgiamberardino.jnetic.population; +import java.util.ArrayList; import java.util.List; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.Stream; -public class Population { +public class Population { private List members; + private Function aptitudeFunction; + public static Population of(List members, Function aptitudeFunction) { + return new Population(members); + } + + public static Population generate(Supplier generator, Integer size) { + return new Population( + Stream.generate(generator) + .limit(size) + .collect(Collectors.toList())); + } + + public static Population of(Population population) { + return new Population(population.members()).aptitudeFunction(population.aptitudeFunction()); + } + Population(List members){ - this.members = members; + this.members = new ArrayList(members); } public Integer size() { @@ -16,11 +37,48 @@ public Integer size() { } public Stream stream() { - return (Stream) Stream.of(members.toArray()); + return members.stream(); } public void evolve(Integer iterations) { } + public U calculateFitness(Function, U> fitnessFunction, Function aptitudeFunction) { + if (null == aptitudeFunction){ + throw new IllegalArgumentException("Aptitude function can't be null."); + } + if (null == fitnessFunction){ + throw new IllegalArgumentException("Fitness function can't be null."); + } + return fitnessFunction.apply( + members.stream() + .map(aptitudeFunction)); + } + + public U calculateFitness(Function, U> fitnessFunction) { + if (null == aptitudeFunction){ + throw new IllegalStateException("You need to define the aptitude function to run this method."); + } + return fitnessFunction.apply( + members.stream() + .map(aptitudeFunction)); + } + + public Evolution evolution() { + return new Evolution(this); + } + + public Population aptitudeFunction(Function aptitudeFunction) { + this.aptitudeFunction = aptitudeFunction; + return this; + } + + public Function aptitudeFunction() { + return aptitudeFunction; + } + + private List members() { + return members; + } } diff --git a/src/main/java/com/mgiamberardino/jnetic/population/Populations.java b/src/main/java/com/mgiamberardino/jnetic/population/Populations.java deleted file mode 100644 index 12608c9..0000000 --- a/src/main/java/com/mgiamberardino/jnetic/population/Populations.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.mgiamberardino.jnetic.population; - -import java.util.List; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class Populations { - - public static Population of(List members) { - return new Population(members); - } - - public static Population generate(Supplier generator, Integer size) { - return new Population<>(IntStream.range(0, size) - .boxed() - .map( position -> generator.get()) - .collect(Collectors.toList())); - } - -} diff --git a/src/test/java/com/mgiamberardino/jnetic/population/EvolutionTest.java b/src/test/java/com/mgiamberardino/jnetic/population/EvolutionTest.java new file mode 100644 index 0000000..7764a58 --- /dev/null +++ b/src/test/java/com/mgiamberardino/jnetic/population/EvolutionTest.java @@ -0,0 +1,67 @@ +package com.mgiamberardino.jnetic.population; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.junit.Test; + +public class EvolutionTest { + private static BiFunction> CROSSER = (i1, i2) -> Arrays.asList(i1, i2); + private static Function, List> SELECTOR = (list) -> new ArrayList<>(list); + private static Function MUTATOR = (i1) -> i1; + + @Test + public void testEvolutionCreation() { + Evolution ev = Evolution.of(Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()),Function.identity())); + assertNotNull(ev); + } + + @Test + public void testEvolutionEvolve(){ + Evolution ev = Evolution.of(Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()),Function.identity())); + assertNotNull(ev.evolve()); + } + + @Test + public void testSetCrosser(){ + assertEquals(CROSSER, Evolution.of(Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()),Function.identity())) + .crosser(CROSSER) + .crosser()); + } + + @Test + public void testSetSelector(){ + assertEquals(SELECTOR, Evolution.of(Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()),Function.identity())) + .selector(SELECTOR) + .selector()); + } + + @Test + public void testSetMutator(){ + assertEquals(MUTATOR, Evolution.of(Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()),Function.identity())) + .mutator(MUTATOR) + .mutator()); + } + + @Test + public void testSetFunctions(){ + Evolution ev = Evolution.of( + Population.of( + IntStream.range(0,10) + .boxed() + .collect(Collectors.toList()) + ,Function.identity())) + .crosser(CROSSER) + .selector(SELECTOR) + .mutator(MUTATOR); + } + +} diff --git a/src/test/java/com/mgiamberardino/jnetic/population/PopulationsTest.java b/src/test/java/com/mgiamberardino/jnetic/population/PopulationsTest.java index b6d2cbb..f8ed427 100644 --- a/src/test/java/com/mgiamberardino/jnetic/population/PopulationsTest.java +++ b/src/test/java/com/mgiamberardino/jnetic/population/PopulationsTest.java @@ -1,33 +1,53 @@ package com.mgiamberardino.jnetic.population; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + import java.util.ArrayList; +import java.util.Random; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; -import com.mgiamberardino.jnetic.population.Population; -import com.mgiamberardino.jnetic.population.Populations; - -import junit.framework.TestCase; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; -public class PopulationsTest extends TestCase { +public class PopulationsTest{ + private static Random random = new Random(System.currentTimeMillis()); + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test public void testCreateEmptyPopulation() { - Population pop = Populations.of(new ArrayList()); + Population pop = Population.of(new ArrayList(), Function.identity()); assertEquals(Integer.valueOf(0), pop.size()); } - + + @Test + public void testSetAptitudeFunction() { + Population pop = Population.of(new ArrayList(), Function.identity()) + .aptitudeFunction(Function.identity()); + assertEquals(Function.identity(), pop.aptitudeFunction()); + } + + @Test public void testCreatePopulationWithSomeMembers() { - Population pop = Populations.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList())); + Population pop = Population.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList()), Function.identity()); assertEquals(Integer.valueOf(4), pop.size()); } - + + @Test public void testPopulationGenerator() { - Population pop = Populations.generate(() -> new Integer(0), 10); + Population pop = Population.generate(() -> new Integer(0), 10); assertEquals(Integer.valueOf(10), pop.size()); } - + + @Test public void testPopulationGenerateIndivuals() { - Population> pop = Populations.generate(PopulationsTest::individualGenerator, 10); + Population, Integer> pop = Population.generate(PopulationsTest::individualGenerator, 10); assertEquals(Integer.valueOf(10), pop.size()); if (! pop.stream().allMatch(i -> null != i)){ fail(); @@ -35,13 +55,44 @@ public void testPopulationGenerateIndivuals() { } private static ArrayList individualGenerator() { - return IntStream.range(0, 10) - .boxed() + return getRandomStream(10,0,100) + .boxed() .collect(Collectors.toCollection(ArrayList::new)); } + + private static IntStream getRandomStream(int size, int from, int to) { + return random.ints(size, from, to); + } + + @Test + public void testSummarizing(){ + Population pop = Population.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList()), Function.identity()); + Integer result = pop.calculateFitness((members) -> members.mapToInt(Integer::intValue).sum(), Function.identity()); + assertEquals(new Integer(10), result); + } + + @Test(expected=IllegalArgumentException.class) + public void testFitnessParametersFitnessFunctionNull(){ + Population pop = Population.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList()), Function.identity()); + pop.calculateFitness(null, Function.identity()); + } + + @Test(expected=IllegalArgumentException.class) + public void testFitnessParametersAptitudeFunctionNull(){ + Population pop = Population.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList()), Function.identity()); + pop.calculateFitness((members) -> members.mapToInt(Integer::intValue).sum(), null); + } - public void testEvolvingPopulation(){ - Population> pop = Populations.generate(PopulationsTest::individualGenerator, 10); - pop.evolve(1); + @Test(expected=IllegalStateException.class) + public void testSummarizingThrowingError(){ + Population pop = Population.of(IntStream.of(1, 2, 3, 4).boxed().collect(Collectors.toList()), Function.identity()); + pop.calculateFitness((members) -> members.mapToInt(Integer::intValue).sum()); } + + @Test + public void testEvolutionFromPopulation(){ + Evolution ev = Population.of(IntStream.range(0,10).boxed().collect(Collectors.toList()), Function.identity()).evolution(); + assertNotNull(ev); + } + }