Skip to content

Commit

Permalink
Merge pull request #793 from kusumotolab/fix-crossover-bug
Browse files Browse the repository at this point in the history
crossoverのバグを修正
  • Loading branch information
hrtwt authored Oct 12, 2020
2 parents 5ea0d10 + 9599224 commit b6847ab
Show file tree
Hide file tree
Showing 13 changed files with 695 additions and 154 deletions.
10 changes: 10 additions & 0 deletions example/Crossover01/src/example/Foo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public class Foo {
public void a(int n) {
if (n) {
n = 0; // loc0
} else {
n = 1; // loc1
}
n = 2; // loc2
}
}
13 changes: 13 additions & 0 deletions example/Crossover01/test/example/FooTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package example;

import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class FooTest {

@Test
public void test01() {
assertEquals(1, 2); // always fail
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public GeneratedSourceCode exec(final VariantStore variantStore, final Gene gene
for (final Base base : gene.getBases()) {
final Operation operation = base.getOperation();
generatedSourceCode = operation.apply(generatedSourceCode, base.getTargetLocation());

// immediately return failed source code if operation#apply was failed
if (!generatedSourceCode.isGenerationSuccess()) {
return generatedSourceCode;
}
}

if (sourceCodeMap.containsKey((generatedSourceCode.getMessageDigest()))) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package jp.kusumotolab.kgenprog.ga.crossover;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jp.kusumotolab.kgenprog.ga.variant.Base;
import jp.kusumotolab.kgenprog.ga.variant.CascadeCrossoverHistoricalElement;
import jp.kusumotolab.kgenprog.ga.variant.Gene;
import jp.kusumotolab.kgenprog.ga.variant.HistoricalElement;
import jp.kusumotolab.kgenprog.ga.variant.Variant;
import jp.kusumotolab.kgenprog.ga.variant.VariantStore;

/**
* 直列的な交叉を行うクラス.
*
* @author shinsuke
*/
public class CascadeCrossover extends CrossoverAdaptor {

/**
* @param firstStrategy 1つ目の親を選ぶためのアルゴリズム
* @param secondStrategy 2つ目の親を選ぶためのアルゴリズム
*/
public CascadeCrossover(final FirstVariantSelectionStrategy firstStrategy,
final SecondVariantSelectionStrategy secondStrategy) {
super(firstStrategy, secondStrategy, 2);
}


@Override
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
throws CrossoverInfeasibleException {
final Variant v1 = getFirstVariantSelectionStrategy().exec(variants);
final Variant v2 = getSecondVariantSelectionStrategy().exec(variants, v1);
final HistoricalElement histElement = new CascadeCrossoverHistoricalElement(v1, v2);

// create two variants from cascaded genes
final Gene cascadeGene1 = createCascadeGene(v1, v2);
final Gene cascadeGene2 = createCascadeGene(v2, v1); // NOSONAR: it's intentional.
final Variant newVariant1 = store.createVariant(cascadeGene1, histElement);
final Variant newVariant2 = store.createVariant(cascadeGene2, histElement);

return Arrays.asList(newVariant1, newVariant2);
}

@Override
protected List<Variant> filter(final List<Variant> variants) {
return variants; // no filter necessary
}

private Gene createCascadeGene(final Variant v1, final Variant v2) {
final List<Base> cascadeBases = Stream.of(v1, v2)
.map(Variant::getGene)
.map(Gene::getBases)
.flatMap(Collection::stream)
.distinct() // remove shared genes meaning these two variants have blood relation
.collect(Collectors.toList());
return new Gene(cascadeBases);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
public abstract class CrossoverAdaptor implements Crossover {

private static Logger log = LoggerFactory.getLogger(CrossoverAdaptor.class);
private static final Logger log = LoggerFactory.getLogger(CrossoverAdaptor.class);

private final FirstVariantSelectionStrategy firstVariantSelectionStrategy;
private final SecondVariantSelectionStrategy secondVariantSelectionStrategy;
Expand All @@ -30,7 +30,6 @@ public abstract class CrossoverAdaptor implements Crossover {
* @param firstVariantSelectionStrategy 1つ目の親を選ぶためのアルゴリズム
* @param secondVariantSelectionStrategy 2つ目の親を選ぶためのアルゴリズム
* @param generatingCount 一世代の交叉処理で生成する個体の数
* @return 交叉を行うインスタンス
*/
public CrossoverAdaptor(final FirstVariantSelectionStrategy firstVariantSelectionStrategy,
final SecondVariantSelectionStrategy secondVariantSelectionStrategy,
Expand Down Expand Up @@ -69,25 +68,19 @@ public SecondVariantSelectionStrategy getSecondVariantSelectionStrategy() {
* @return 交叉により生成された個体群
*/
@Override
public final List<Variant> exec(final VariantStore variantStore) {

final List<Variant> filteredVariants = variantStore.getCurrentVariants()
.stream()
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
.getBases()
.size())
.collect(Collectors.toList());
public List<Variant> exec(final VariantStore variantStore) {
final List<Variant> validVariants = filter(variantStore.getCurrentVariants());
final List<Variant> variants = new ArrayList<>();

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

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

protected abstract List<Variant> makeVariants(List<Variant> variants, VariantStore variantStore)
throws CrossoverInfeasibleException;

protected abstract List<Variant> filter(List<Variant> variants);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ public RandomCrossover(final Random random,
this.random = random;
}

@Override
protected List<Variant> filter(final List<Variant> variants) {
return variants.stream()
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
.getBases()
.size())
.collect(Collectors.toList());
}

@Override
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
throws CrossoverInfeasibleException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ public SinglePointCrossover(final Random random,
this.random = random;
}

@Override
protected List<Variant> filter(final List<Variant> variants) {
return variants.stream()
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
.getBases()
.size())
.collect(Collectors.toList());
}

@Override
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
throws CrossoverInfeasibleException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import jp.kusumotolab.kgenprog.ga.variant.Base;
import jp.kusumotolab.kgenprog.ga.variant.Gene;
import jp.kusumotolab.kgenprog.ga.variant.HistoricalElement;
Expand Down Expand Up @@ -37,6 +38,15 @@ public UniformCrossover(final Random random,
this.random = random;
}

@Override
protected List<Variant> filter(final List<Variant> variants) {
return variants.stream()
.filter(e -> 1 < e.getGene() // 遺伝子の長さが2に満たないバリアントは交叉に使えない
.getBases()
.size())
.collect(Collectors.toList());
}

@Override
protected List<Variant> makeVariants(final List<Variant> variants, final VariantStore store)
throws CrossoverInfeasibleException {
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/jp/kusumotolab/kgenprog/ga/variant/Base.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package jp.kusumotolab.kgenprog.ga.variant;

import java.util.Objects;
import jp.kusumotolab.kgenprog.project.ASTLocation;
import jp.kusumotolab.kgenprog.project.Operation;

Expand Down Expand Up @@ -31,5 +32,21 @@ public Operation getOperation() {
return operation;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Base base = (Base) o;
return Objects.equals(getTargetLocation(), base.getTargetLocation()) &&
Objects.equals(getOperation(), base.getOperation());
}

@Override
public int hashCode() {
return Objects.hash(getTargetLocation(), getOperation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package jp.kusumotolab.kgenprog.ga.variant;

import java.util.Arrays;
import java.util.List;

/**
* cascade交叉の記録をするクラス
*/
public class CascadeCrossoverHistoricalElement implements HistoricalElement {

private final Variant parentA;
private final Variant parentB;

/**
* @param parentA 交叉した片方の親
* @param parentB もう片方の親
*/
public CascadeCrossoverHistoricalElement(final Variant parentA, final Variant parentB) {
this.parentA = parentA;
this.parentB = parentB;
}

/**
* @return 親のリスト
*/
@Override
public List<Variant> getParents() {
return Arrays.asList(parentA, parentB);
}

/**
* @return 適用した操作の名前
*/
@Override
public String getOperationName() {
return "cascade-crossover";
}
}
Loading

0 comments on commit b6847ab

Please sign in to comment.