Skip to content

Commit b6847ab

Browse files
authored
Merge pull request #793 from kusumotolab/fix-crossover-bug
crossoverのバグを修正
2 parents 5ea0d10 + 9599224 commit b6847ab

File tree

13 files changed

+695
-154
lines changed

13 files changed

+695
-154
lines changed
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public class Foo {
2+
public void a(int n) {
3+
if (n) {
4+
n = 0; // loc0
5+
} else {
6+
n = 1; // loc1
7+
}
8+
n = 2; // loc2
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package example;
2+
3+
import static org.junit.Assert.assertTrue;
4+
import org.junit.Test;
5+
6+
public class FooTest {
7+
8+
@Test
9+
public void test01() {
10+
assertEquals(1, 2); // always fail
11+
}
12+
13+
}

src/main/java/jp/kusumotolab/kgenprog/ga/codegeneration/DefaultSourceCodeGeneration.java

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public GeneratedSourceCode exec(final VariantStore variantStore, final Gene gene
5151
for (final Base base : gene.getBases()) {
5252
final Operation operation = base.getOperation();
5353
generatedSourceCode = operation.apply(generatedSourceCode, base.getTargetLocation());
54+
55+
// immediately return failed source code if operation#apply was failed
56+
if (!generatedSourceCode.isGenerationSuccess()) {
57+
return generatedSourceCode;
58+
}
5459
}
5560

5661
if (sourceCodeMap.containsKey((generatedSourceCode.getMessageDigest()))) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package jp.kusumotolab.kgenprog.ga.crossover;
2+
3+
import java.util.Arrays;
4+
import java.util.Collection;
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
import java.util.stream.Stream;
8+
import jp.kusumotolab.kgenprog.ga.variant.Base;
9+
import jp.kusumotolab.kgenprog.ga.variant.CascadeCrossoverHistoricalElement;
10+
import jp.kusumotolab.kgenprog.ga.variant.Gene;
11+
import jp.kusumotolab.kgenprog.ga.variant.HistoricalElement;
12+
import jp.kusumotolab.kgenprog.ga.variant.Variant;
13+
import jp.kusumotolab.kgenprog.ga.variant.VariantStore;
14+
15+
/**
16+
* 直列的な交叉を行うクラス.
17+
*
18+
* @author shinsuke
19+
*/
20+
public class CascadeCrossover extends CrossoverAdaptor {
21+
22+
/**
23+
* @param firstStrategy 1つ目の親を選ぶためのアルゴリズム
24+
* @param secondStrategy 2つ目の親を選ぶためのアルゴリズム
25+
*/
26+
public CascadeCrossover(final FirstVariantSelectionStrategy firstStrategy,
27+
final SecondVariantSelectionStrategy secondStrategy) {
28+
super(firstStrategy, secondStrategy, 2);
29+
}
30+
31+
32+
@Override
33+
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
34+
throws CrossoverInfeasibleException {
35+
final Variant v1 = getFirstVariantSelectionStrategy().exec(variants);
36+
final Variant v2 = getSecondVariantSelectionStrategy().exec(variants, v1);
37+
final HistoricalElement histElement = new CascadeCrossoverHistoricalElement(v1, v2);
38+
39+
// create two variants from cascaded genes
40+
final Gene cascadeGene1 = createCascadeGene(v1, v2);
41+
final Gene cascadeGene2 = createCascadeGene(v2, v1); // NOSONAR: it's intentional.
42+
final Variant newVariant1 = store.createVariant(cascadeGene1, histElement);
43+
final Variant newVariant2 = store.createVariant(cascadeGene2, histElement);
44+
45+
return Arrays.asList(newVariant1, newVariant2);
46+
}
47+
48+
@Override
49+
protected List<Variant> filter(final List<Variant> variants) {
50+
return variants; // no filter necessary
51+
}
52+
53+
private Gene createCascadeGene(final Variant v1, final Variant v2) {
54+
final List<Base> cascadeBases = Stream.of(v1, v2)
55+
.map(Variant::getGene)
56+
.map(Gene::getBases)
57+
.flatMap(Collection::stream)
58+
.distinct() // remove shared genes meaning these two variants have blood relation
59+
.collect(Collectors.toList());
60+
return new Gene(cascadeBases);
61+
}
62+
63+
}

src/main/java/jp/kusumotolab/kgenprog/ga/crossover/CrossoverAdaptor.java

+8-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919
public abstract class CrossoverAdaptor implements Crossover {
2020

21-
private static Logger log = LoggerFactory.getLogger(CrossoverAdaptor.class);
21+
private static final Logger log = LoggerFactory.getLogger(CrossoverAdaptor.class);
2222

2323
private final FirstVariantSelectionStrategy firstVariantSelectionStrategy;
2424
private final SecondVariantSelectionStrategy secondVariantSelectionStrategy;
@@ -30,7 +30,6 @@ public abstract class CrossoverAdaptor implements Crossover {
3030
* @param firstVariantSelectionStrategy 1つ目の親を選ぶためのアルゴリズム
3131
* @param secondVariantSelectionStrategy 2つ目の親を選ぶためのアルゴリズム
3232
* @param generatingCount 一世代の交叉処理で生成する個体の数
33-
* @return 交叉を行うインスタンス
3433
*/
3534
public CrossoverAdaptor(final FirstVariantSelectionStrategy firstVariantSelectionStrategy,
3635
final SecondVariantSelectionStrategy secondVariantSelectionStrategy,
@@ -69,25 +68,19 @@ public SecondVariantSelectionStrategy getSecondVariantSelectionStrategy() {
6968
* @return 交叉により生成された個体群
7069
*/
7170
@Override
72-
public final List<Variant> exec(final VariantStore variantStore) {
73-
74-
final List<Variant> filteredVariants = variantStore.getCurrentVariants()
75-
.stream()
76-
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
77-
.getBases()
78-
.size())
79-
.collect(Collectors.toList());
71+
public List<Variant> exec(final VariantStore variantStore) {
72+
final List<Variant> validVariants = filter(variantStore.getCurrentVariants());
73+
final List<Variant> variants = new ArrayList<>();
8074

8175
// filteredVariantsの要素数が2に満たない場合は交叉しない
82-
if (filteredVariants.size() < 2) {
76+
if (validVariants.size() < 2) {
8377
return Collections.emptyList();
8478
}
8579

86-
final List<Variant> variants = new ArrayList<>();
8780
try {
8881
// generatingCountを超えるまでバリアントを作りづづける
8982
while (variants.size() < generatingCount) {
90-
final List<Variant> newVariants = makeVariants(filteredVariants, variantStore);
83+
final List<Variant> newVariants = makeVariants(validVariants, variantStore);
9184
variants.addAll(newVariants);
9285
}
9386
} catch (final CrossoverInfeasibleException e) {
@@ -100,4 +93,6 @@ public final List<Variant> exec(final VariantStore variantStore) {
10093

10194
protected abstract List<Variant> makeVariants(List<Variant> variants, VariantStore variantStore)
10295
throws CrossoverInfeasibleException;
96+
97+
protected abstract List<Variant> filter(List<Variant> variants);
10398
}

src/main/java/jp/kusumotolab/kgenprog/ga/crossover/RandomCrossover.java

+9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ public RandomCrossover(final Random random,
3939
this.random = random;
4040
}
4141

42+
@Override
43+
protected List<Variant> filter(final List<Variant> variants) {
44+
return variants.stream()
45+
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
46+
.getBases()
47+
.size())
48+
.collect(Collectors.toList());
49+
}
50+
4251
@Override
4352
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
4453
throws CrossoverInfeasibleException {

src/main/java/jp/kusumotolab/kgenprog/ga/crossover/SinglePointCrossover.java

+9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ public SinglePointCrossover(final Random random,
3838
this.random = random;
3939
}
4040

41+
@Override
42+
protected List<Variant> filter(final List<Variant> variants) {
43+
return variants.stream()
44+
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
45+
.getBases()
46+
.size())
47+
.collect(Collectors.toList());
48+
}
49+
4150
@Override
4251
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
4352
throws CrossoverInfeasibleException {

src/main/java/jp/kusumotolab/kgenprog/ga/crossover/UniformCrossover.java

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Arrays;
55
import java.util.List;
66
import java.util.Random;
7+
import java.util.stream.Collectors;
78
import jp.kusumotolab.kgenprog.ga.variant.Base;
89
import jp.kusumotolab.kgenprog.ga.variant.Gene;
910
import jp.kusumotolab.kgenprog.ga.variant.HistoricalElement;
@@ -37,6 +38,15 @@ public UniformCrossover(final Random random,
3738
this.random = random;
3839
}
3940

41+
@Override
42+
protected List<Variant> filter(final List<Variant> variants) {
43+
return variants.stream()
44+
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
45+
.getBases()
46+
.size())
47+
.collect(Collectors.toList());
48+
}
49+
4050
@Override
4151
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
4252
throws CrossoverInfeasibleException {

src/main/java/jp/kusumotolab/kgenprog/ga/variant/Base.java

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package jp.kusumotolab.kgenprog.ga.variant;
22

3+
import java.util.Objects;
34
import jp.kusumotolab.kgenprog.project.ASTLocation;
45
import jp.kusumotolab.kgenprog.project.Operation;
56

@@ -31,5 +32,21 @@ public Operation getOperation() {
3132
return operation;
3233
}
3334

35+
@Override
36+
public boolean equals(final Object o) {
37+
if (this == o) {
38+
return true;
39+
}
40+
if (o == null || getClass() != o.getClass()) {
41+
return false;
42+
}
43+
final Base base = (Base) o;
44+
return Objects.equals(getTargetLocation(), base.getTargetLocation()) &&
45+
Objects.equals(getOperation(), base.getOperation());
46+
}
3447

48+
@Override
49+
public int hashCode() {
50+
return Objects.hash(getTargetLocation(), getOperation());
51+
}
3552
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package jp.kusumotolab.kgenprog.ga.variant;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
/**
7+
* cascade交叉の記録をするクラス
8+
*/
9+
public class CascadeCrossoverHistoricalElement implements HistoricalElement {
10+
11+
private final Variant parentA;
12+
private final Variant parentB;
13+
14+
/**
15+
* @param parentA 交叉した片方の親
16+
* @param parentB もう片方の親
17+
*/
18+
public CascadeCrossoverHistoricalElement(final Variant parentA, final Variant parentB) {
19+
this.parentA = parentA;
20+
this.parentB = parentB;
21+
}
22+
23+
/**
24+
* @return 親のリスト
25+
*/
26+
@Override
27+
public List<Variant> getParents() {
28+
return Arrays.asList(parentA, parentB);
29+
}
30+
31+
/**
32+
* @return 適用した操作の名前
33+
*/
34+
@Override
35+
public String getOperationName() {
36+
return "cascade-crossover";
37+
}
38+
}

0 commit comments

Comments
 (0)