diff --git a/src/main/java/com/mgiamberardino/jnetic/operators/Condition.java b/src/main/java/com/mgiamberardino/jnetic/operators/Condition.java deleted file mode 100644 index 6e2e689..0000000 --- a/src/main/java/com/mgiamberardino/jnetic/operators/Condition.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.mgiamberardino.jnetic.operators; - -import java.util.function.Function; - -import com.mgiamberardino.jnetic.population.Population; - -@FunctionalInterface -public interface Condition extends Function, Boolean> { - - default Condition or(Condition condition){ - return (t) -> (apply(t) || condition.apply(t)); - } - -} diff --git a/src/main/java/com/mgiamberardino/jnetic/operators/Selector.java b/src/main/java/com/mgiamberardino/jnetic/operators/Selector.java index 502157c..66abbfa 100644 --- a/src/main/java/com/mgiamberardino/jnetic/operators/Selector.java +++ b/src/main/java/com/mgiamberardino/jnetic/operators/Selector.java @@ -9,6 +9,6 @@ @FunctionalInterface public interface Selector> { - public List select(Population population, Function aptitudeFunction); + public List select(Population population, Function aptitudeFunction, Double elitePortion); } diff --git a/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java b/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java index 85a0d4b..fa776fd 100644 --- a/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java +++ b/src/main/java/com/mgiamberardino/jnetic/population/Evolution.java @@ -2,20 +2,17 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.mgiamberardino.jnetic.operators.Condition; import com.mgiamberardino.jnetic.operators.Selector; import com.mgiamberardino.jnetic.population.Population.Parents; +import com.mgiamberardino.jnetic.util.Selectors; public class Evolution> { @@ -26,18 +23,21 @@ public class Evolution> { private Function aptitudeFunction; private Function, Supplier>> parentSupplierBuilder = Evolution::defaultSupplier; private Predicate validator = o -> true; + private Double elitePortion; - public static > Evolution of(Population population, Function aptitudeFunction) { - return new Evolution(population, aptitudeFunction); + public static > Evolution of(Population population, Function aptitudeFunction, double elitePortion) { + return new Evolution(population, aptitudeFunction,elitePortion); } - Evolution(Population population, Function aptitudeFunction){ + Evolution(Population population, Function aptitudeFunction, Double elitePortion){ this.population = population; this.aptitudeFunction = aptitudeFunction; + this.elitePortion = elitePortion; + this.selector = Selectors.binaryTournament(this ,0.25, 0.75); } public Evolution evolve() { - List parents = selector.select(population, aptitudeFunction); + List parents = selector.select(population, aptitudeFunction, elitePortion); Map aptitudes = parents.stream() .collect(Collectors.toMap(Function.identity(), aptitudeFunction, (s1, s2) -> s1)); List sons = Stream.generate(parentSupplierBuilder.apply(aptitudes)) @@ -52,9 +52,9 @@ public Evolution evolve() { return this; } - public Evolution evolveUntil(Condition condition){ + public Evolution evolveUntil(Predicate> condition){ Integer i = 0; - while(! condition.apply(population)){ + while(! condition.test(population)){ evolve(); System.out.println("Generacion " + i + ":"); System.out.println(population.stream().collect(Collectors.toList())); diff --git a/src/main/java/com/mgiamberardino/jnetic/population/Population.java b/src/main/java/com/mgiamberardino/jnetic/population/Population.java index 2db4faf..e1a8336 100644 --- a/src/main/java/com/mgiamberardino/jnetic/population/Population.java +++ b/src/main/java/com/mgiamberardino/jnetic/population/Population.java @@ -61,8 +61,8 @@ public Stream stream() { return members.stream(); } - public > Evolution evolution(Function aptitudeFunction) { - return new Evolution(this, aptitudeFunction); + public > Evolution evolution(Function aptitudeFunction, double elitePortion) { + return new Evolution(this, aptitudeFunction, elitePortion); } private List members() { diff --git a/src/main/java/com/mgiamberardino/jnetic/util/Conditions.java b/src/main/java/com/mgiamberardino/jnetic/util/Conditions.java index 442eb21..9bb01c9 100644 --- a/src/main/java/com/mgiamberardino/jnetic/util/Conditions.java +++ b/src/main/java/com/mgiamberardino/jnetic/util/Conditions.java @@ -1,23 +1,23 @@ package com.mgiamberardino.jnetic.util; import java.util.function.Function; +import java.util.function.Predicate; -import com.mgiamberardino.jnetic.operators.Condition; import com.mgiamberardino.jnetic.population.Population; public class Conditions { - public static Condition after(int iterations){ + public static Predicate> after(int iterations){ return (population) -> population.getGeneration() == iterations; } - public static Condition converge(Double difference, Function, Double> avgFunction){ - return new Condition() { + public static Predicate> converge(Double difference, Function, Double> avgFunction){ + return new Predicate>() { private Double lastAvg = 0.0; private int times = 0; @Override - public Boolean apply(Population population) { + public boolean test(Population population) { Double avg = avgFunction.apply(population); Double diff = Math.abs(lastAvg - avg); System.out.println("Last: " + lastAvg + " New: " + avg + "Dif: " + diff); @@ -33,14 +33,10 @@ public Boolean apply(Population population) { }; } - public static Condition contains(T value){ - return new Condition() { - - @Override - public Boolean apply(Population population) { + public static Predicate> contains(T value){ + return (Population population) -> { return population.stream().anyMatch(t -> t.equals(value)); - } - }; + }; } } diff --git a/src/main/java/com/mgiamberardino/jnetic/util/Crossers.java b/src/main/java/com/mgiamberardino/jnetic/util/Crossers.java new file mode 100644 index 0000000..55a0a92 --- /dev/null +++ b/src/main/java/com/mgiamberardino/jnetic/util/Crossers.java @@ -0,0 +1,7 @@ +package com.mgiamberardino.jnetic.util; + +public class Crossers { + + + +} diff --git a/src/main/java/com/mgiamberardino/jnetic/util/Selectors.java b/src/main/java/com/mgiamberardino/jnetic/util/Selectors.java index 04a5731..6d9aaa0 100644 --- a/src/main/java/com/mgiamberardino/jnetic/util/Selectors.java +++ b/src/main/java/com/mgiamberardino/jnetic/util/Selectors.java @@ -3,31 +3,84 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; import com.mgiamberardino.jnetic.operators.Selector; +import com.mgiamberardino.jnetic.population.Evolution; import com.mgiamberardino.jnetic.population.Population; public class Selectors { public static > Selector truncatedSelection(Double portion){ - return (population, aptitudeFunction) -> { + return (population, aptitudeFunction, elitePortion) -> { List result = population.stream().collect(Collectors.toList()); Collections.sort(result , Collections.reverseOrder(Population.comparator(aptitudeFunction))); - return result.stream().limit((long) (population.size() * portion)).collect(Collectors.toList()); + Double calculatedPortion = portion > elitePortion + ? portion + : elitePortion; + return result.stream().limit((long) (population.size() * calculatedPortion)).collect(Collectors.toList()); }; } public static Selector rouletteStochasticAcceptance(Double portion){ - return (population, aptitudeFunction) -> { - List result = population.stream().collect(Collectors.toList()); - Double max = result.stream().map(aptitudeFunction).sorted().reduce((act, last) -> last).orElse(null); - Collections.shuffle(result); - return result.stream() + return (population, aptitudeFunction, elitePortion) -> { + long toSelect = Math.round(population.size() * portion); + List result = getElite(population, elitePortion, toSelect, aptitudeFunction); + if (result.size() >= toSelect){ + return result; + } + List individuals = population.stream().collect(Collectors.toList()); + Double max = population.stream().map(aptitudeFunction).sorted().reduce((act, last) -> last).orElse(null); + Collections.shuffle(individuals); + population.stream() .filter(t -> new Random(System.currentTimeMillis()).nextDouble() < (aptitudeFunction.apply(t)/max)) - .limit((long) (population.size() * portion)) - .collect(Collectors.toList()); + .limit(toSelect - result.size()) + .forEach(result::add); + return result; }; } + public static Selector deterministicBinaryTournament(Double portion){ + return binaryTournament(portion, 1.0); + } + + public static > Selector binaryTournament(Evolution e, Double portion, Double probability){ + return binaryTournament(portion, probability); + } + + public static > Selector binaryTournament(Double portion, Double probability){ + return (population, aptitudeFunction, elitePortion) -> { + long toSelect = Math.round(population.size() * portion); + List individuals = population.stream().collect(Collectors.toList()); + List result = getElite(population, elitePortion, toSelect, aptitudeFunction); + if (result.size() >= toSelect){ + return result; + } + Stream.generate(() -> selectForTournament(individuals, 2, aptitudeFunction, probability)) + .limit(toSelect - result.size()) + .forEach(result::add); + return result; + }; + } + + private static > T selectForTournament(List population, int size, Function aptitudeFunction, double probability){ + Random r = new Random(System.currentTimeMillis()); + return IntStream.generate(() -> r.nextInt(population.size())) + .limit(size) + .mapToObj(population::get) + .sorted(Population.comparator(aptitudeFunction)) + .reduce((i1, i2) -> r.nextDouble() <= probability ? i2 : i1) + .get(); + } + + private static > List getElite(Population population, double elitePortion, long toSelect, Function aptitudeFunction) { + long eliteToSelect = Math.round(population.size() * elitePortion); + long eliteRealTotal = eliteToSelect < toSelect ? eliteToSelect : toSelect; + List sorted = population.stream().sorted(Collections.reverseOrder(Population.comparator(aptitudeFunction))).collect(Collectors.toList()); + return sorted.stream().limit(eliteRealTotal).collect(Collectors.toList()); + } + } diff --git a/src/test/java/com/mgiamberardino/jnetic/population/ToBeOrNotToBe.java b/src/test/java/com/mgiamberardino/jnetic/population/ToBeOrNotToBe.java index bc1c092..5cf63b2 100644 --- a/src/test/java/com/mgiamberardino/jnetic/population/ToBeOrNotToBe.java +++ b/src/test/java/com/mgiamberardino/jnetic/population/ToBeOrNotToBe.java @@ -1,7 +1,9 @@ package com.mgiamberardino.jnetic.population; import java.util.List; +import java.util.Stack; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import org.apache.commons.lang3.RandomStringUtils; @@ -14,13 +16,16 @@ public class ToBeOrNotToBe { private static final String SEARCHED_STRING = "To be or not to be"; + private static interface A { + + } public static void main(String[] args) { System.out.println( Evolution.of( - Population.generate(ToBeOrNotToBe::generatePhrase, 10), - ToBeOrNotToBe::aptitudeMeter) - .selector(Selectors.truncatedSelection(0.50)) + Population.generate(ToBeOrNotToBe::generatePhrase, 200), + ToBeOrNotToBe::aptitudeMeter, + 0.005) .crosser(ToBeOrNotToBe::crosser) .mutator(ToBeOrNotToBe::mutator) .evolveUntil(