Skip to content

Commit a826e70

Browse files
maibinKevinGilmore
authored andcommitted
Jenetics library (eugenp#1601)
1 parent cc27658 commit a826e70

10 files changed

Lines changed: 388 additions & 0 deletions

File tree

algorithms/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target/

algorithms/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
<version>${lombok.version}</version>
3232
<scope>provided</scope>
3333
</dependency>
34+
<dependency>
35+
<groupId>io.jenetics</groupId>
36+
<artifactId>jenetics</artifactId>
37+
<version>3.7.0</version>
38+
</dependency>
3439
</dependencies>
3540

3641
<build>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import static org.jenetics.engine.EvolutionResult.toBestPhenotype;
4+
import static org.jenetics.engine.limit.bySteadyFitness;
5+
6+
import java.util.stream.Stream;
7+
8+
import org.jenetics.BitChromosome;
9+
import org.jenetics.BitGene;
10+
import org.jenetics.Mutator;
11+
import org.jenetics.Phenotype;
12+
import org.jenetics.RouletteWheelSelector;
13+
import org.jenetics.SinglePointCrossover;
14+
import org.jenetics.TournamentSelector;
15+
import org.jenetics.engine.Engine;
16+
import org.jenetics.engine.EvolutionStatistics;
17+
18+
//The main class.
19+
public class Knapsack {
20+
21+
public static void main(String[] args) {
22+
int nItems = 15;
23+
double ksSize = nItems * 100.0 / 3.0;
24+
25+
KnapsackFF ff = new KnapsackFF(Stream.generate(KnapsackItem::random)
26+
.limit(nItems)
27+
.toArray(KnapsackItem[]::new), ksSize);
28+
29+
Engine<BitGene, Double> engine = Engine.builder(ff, BitChromosome.of(nItems, 0.5))
30+
.populationSize(500)
31+
.survivorsSelector(new TournamentSelector<>(5))
32+
.offspringSelector(new RouletteWheelSelector<>())
33+
.alterers(new Mutator<>(0.115), new SinglePointCrossover<>(0.16))
34+
.build();
35+
36+
EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();
37+
38+
Phenotype<BitGene, Double> best = engine.stream()
39+
.limit(bySteadyFitness(7))
40+
.limit(100)
41+
.peek(statistics)
42+
.collect(toBestPhenotype());
43+
44+
System.out.println(statistics);
45+
System.out.println(best);
46+
}
47+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import java.util.function.Function;
4+
5+
import org.jenetics.BitChromosome;
6+
import org.jenetics.BitGene;
7+
import org.jenetics.Genotype;
8+
9+
public class KnapsackFF implements Function<Genotype<BitGene>, Double> {
10+
private KnapsackItem[] items;
11+
private double size;
12+
13+
public KnapsackFF(KnapsackItem[] items, double size) {
14+
this.items = items;
15+
this.size = size;
16+
}
17+
18+
@Override
19+
public Double apply(Genotype<BitGene> gt) {
20+
KnapsackItem sum = ((BitChromosome) gt.getChromosome()).ones()
21+
.mapToObj(i -> items[i])
22+
.collect(KnapsackItem.toSum());
23+
return sum.size <= this.size ? sum.value : 0;
24+
}
25+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import java.util.Random;
4+
import java.util.stream.Collector;
5+
6+
import org.jenetics.util.RandomRegistry;
7+
8+
public class KnapsackItem {
9+
10+
public double size;
11+
public double value;
12+
13+
public KnapsackItem(double size, double value) {
14+
this.size = size;
15+
this.value = value;
16+
}
17+
18+
protected static KnapsackItem random() {
19+
Random r = RandomRegistry.getRandom();
20+
return new KnapsackItem(r.nextDouble() * 100, r.nextDouble() * 100);
21+
}
22+
23+
protected static Collector<KnapsackItem, ?, KnapsackItem> toSum() {
24+
return Collector.of(() -> new double[2], (a, b) -> {
25+
a[0] += b.size;
26+
a[1] += b.value;
27+
} , (a, b) -> {
28+
a[0] += b[0];
29+
a[1] += b[1];
30+
return a;
31+
} , r -> new KnapsackItem(r[0], r[1]));
32+
}
33+
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import org.jenetics.BitChromosome;
4+
import org.jenetics.BitGene;
5+
import org.jenetics.Genotype;
6+
import org.jenetics.engine.Engine;
7+
import org.jenetics.engine.EvolutionResult;
8+
import org.jenetics.util.Factory;
9+
10+
public class SimpleGeneticAlgorithm {
11+
12+
private static Integer eval(Genotype<BitGene> gt) {
13+
return gt.getChromosome()
14+
.as(BitChromosome.class)
15+
.bitCount();
16+
}
17+
18+
public static void main(String[] args) {
19+
Factory<Genotype<BitGene>> gtf = Genotype.of(BitChromosome.of(10, 0.5));
20+
System.out.println("Before the evolution:\n" + gtf);
21+
22+
Engine<BitGene, Integer> engine = Engine.builder(SimpleGeneticAlgorithm::eval, gtf)
23+
.build();
24+
25+
Genotype<BitGene> result = engine.stream()
26+
.limit(500)
27+
.collect(EvolutionResult.toBestGenotype());
28+
29+
System.out.println("After the evolution:\n" + result);
30+
31+
}
32+
33+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import java.util.function.Function;
6+
import java.util.stream.Collectors;
7+
8+
import org.jenetics.BitGene;
9+
import org.jenetics.engine.Codec;
10+
import org.jenetics.engine.Engine;
11+
import org.jenetics.engine.EvolutionResult;
12+
import org.jenetics.engine.Problem;
13+
import org.jenetics.engine.codecs;
14+
import org.jenetics.util.ISeq;
15+
16+
public class SpringsteenProblem implements Problem<ISeq<SpringsteenRecord>, BitGene, Double> {
17+
18+
private ISeq<SpringsteenRecord> records;
19+
private double maxPricePerUniqueSong;
20+
21+
public SpringsteenProblem(ISeq<SpringsteenRecord> records, double maxPricePerUniqueSong) {
22+
this.records = requireNonNull(records);
23+
this.maxPricePerUniqueSong = maxPricePerUniqueSong;
24+
}
25+
26+
@Override
27+
public Function<ISeq<SpringsteenRecord>, Double> fitness() {
28+
return SpringsteenRecords -> {
29+
double cost = SpringsteenRecords.stream()
30+
.mapToDouble(r -> r.price)
31+
.sum();
32+
33+
int uniqueSongCount = SpringsteenRecords.stream()
34+
.flatMap(r -> r.songs.stream())
35+
.collect(Collectors.toSet())
36+
.size();
37+
38+
double pricePerUniqueSong = cost / uniqueSongCount;
39+
40+
return pricePerUniqueSong <= maxPricePerUniqueSong ? uniqueSongCount : 0.0;
41+
};
42+
}
43+
44+
@Override
45+
public Codec<ISeq<SpringsteenRecord>, BitGene> codec() {
46+
return codecs.ofSubSet(records);
47+
}
48+
49+
public static void main(String[] args) {
50+
double maxPricePerUniqueSong = 2.5;
51+
52+
SpringsteenProblem springsteen = new SpringsteenProblem(
53+
ISeq.of(new SpringsteenRecord("SpringsteenRecord1", 25, ISeq.of("Song1", "Song2", "Song3", "Song4", "Song5", "Song6")), new SpringsteenRecord("SpringsteenRecord2", 15, ISeq.of("Song2", "Song3", "Song4", "Song5", "Song6", "Song7")),
54+
new SpringsteenRecord("SpringsteenRecord3", 35, ISeq.of("Song5", "Song6", "Song7", "Song8", "Song9", "Song10")), new SpringsteenRecord("SpringsteenRecord4", 17, ISeq.of("Song9", "Song10", "Song12", "Song4", "Song13", "Song14")),
55+
new SpringsteenRecord("SpringsteenRecord5", 29, ISeq.of("Song1", "Song2", "Song13", "Song14", "Song15", "Song16")), new SpringsteenRecord("SpringsteenRecord6", 5, ISeq.of("Song18", "Song20", "Song30", "Song40"))),
56+
maxPricePerUniqueSong);
57+
58+
Engine<BitGene, Double> engine = Engine.builder(springsteen)
59+
.build();
60+
61+
ISeq<SpringsteenRecord> result = springsteen.codec()
62+
.decoder()
63+
.apply(engine.stream()
64+
.limit(10)
65+
.collect(EvolutionResult.toBestGenotype()));
66+
67+
double cost = result.stream()
68+
.mapToDouble(r -> r.price)
69+
.sum();
70+
71+
int uniqueSongCount = result.stream()
72+
.flatMap(r -> r.songs.stream())
73+
.collect(Collectors.toSet())
74+
.size();
75+
76+
double pricePerUniqueSong = cost / uniqueSongCount;
77+
78+
System.out.println("Overall cost: " + cost);
79+
System.out.println("Unique songs: " + uniqueSongCount);
80+
System.out.println("Cost per song: " + pricePerUniqueSong);
81+
System.out.println("Records: " + result.map(r -> r.name)
82+
.toString(", "));
83+
84+
}
85+
86+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import org.jenetics.util.ISeq;
6+
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Data
11+
@NoArgsConstructor
12+
public class SpringsteenRecord {
13+
14+
String name;
15+
double price;
16+
ISeq<String> songs;
17+
18+
public SpringsteenRecord(String name, double price, ISeq<String> songs) {
19+
this.name = requireNonNull(name);
20+
this.price = price;
21+
this.songs = requireNonNull(songs);
22+
}
23+
24+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.baeldung.algorithms.ga.jenetics;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import java.util.Random;
6+
import java.util.function.Function;
7+
8+
import org.jenetics.EnumGene;
9+
import org.jenetics.Mutator;
10+
import org.jenetics.PartiallyMatchedCrossover;
11+
import org.jenetics.Phenotype;
12+
import org.jenetics.engine.Codec;
13+
import org.jenetics.engine.Engine;
14+
import org.jenetics.engine.EvolutionResult;
15+
import org.jenetics.engine.Problem;
16+
import org.jenetics.engine.codecs;
17+
import org.jenetics.engine.limit;
18+
import org.jenetics.util.ISeq;
19+
import org.jenetics.util.LCG64ShiftRandom;
20+
21+
public class SubsetSum implements Problem<ISeq<Integer>, EnumGene<Integer>, Integer> {
22+
23+
private ISeq<Integer> basicSet;
24+
private int size;
25+
26+
public SubsetSum(ISeq<Integer> basicSet, int size) {
27+
this.basicSet = requireNonNull(basicSet);
28+
this.size = size;
29+
}
30+
31+
@Override
32+
public Function<ISeq<Integer>, Integer> fitness() {
33+
return subset -> Math.abs(subset.stream()
34+
.mapToInt(Integer::intValue)
35+
.sum());
36+
}
37+
38+
@Override
39+
public Codec<ISeq<Integer>, EnumGene<Integer>> codec() {
40+
return codecs.ofSubSet(basicSet, size);
41+
}
42+
43+
public static SubsetSum of(int n, int k, Random random) {
44+
return new SubsetSum(random.doubles()
45+
.limit(n)
46+
.mapToObj(d -> (int) ((d - 0.5) * n))
47+
.collect(ISeq.toISeq()), k);
48+
}
49+
50+
public static void main(String[] args) {
51+
SubsetSum problem = of(500, 15, new LCG64ShiftRandom(101010));
52+
53+
Engine<EnumGene<Integer>, Integer> engine = Engine.builder(problem)
54+
.minimizing()
55+
.maximalPhenotypeAge(5)
56+
.alterers(new PartiallyMatchedCrossover<>(0.4), new Mutator<>(0.3))
57+
.build();
58+
59+
Phenotype<EnumGene<Integer>, Integer> result = engine.stream()
60+
.limit(limit.bySteadyFitness(55))
61+
.collect(EvolutionResult.toBestPhenotype());
62+
63+
System.out.print(result);
64+
}
65+
66+
}

0 commit comments

Comments
 (0)