Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StopFirstを実装した #808

Merged
merged 13 commits into from Dec 9, 2020
Merged

StopFirstを実装した #808

merged 13 commits into from Dec 9, 2020

Conversation

YoshikiHigo
Copy link
Member

resolve #434

ある世代Nにおいて,必要な数の修正プログラムを生成した場合の挙動を変更した.
旧:その世代の最後まで引き続き変異プログラムの生成とテスト実行の処理を行う
新:ただちにその世代の処理を終える

@clione-bot
Copy link

clione-bot bot commented Dec 3, 2020

No problem. Good job!

Copy link
Member

@shinsuke-mat shinsuke-mat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

いくつか改善案です.

final List<Variant> variantsByMutation = mutation.exec(variantStore);
final List<Variant> variantsByCrossover = crossover.exec(variantStore);
final List<Variant> variantsByMutation = mutation.exec(variantStore,
config.getRequiredSolutionsCount());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reqCountは Mutatoin#exec に渡すよりも Mutation#new で渡した方が良いと思います.
・可変なパラメタではなく常に単一の値を取るのでコンストラクタが自然
・execで渡すよりもコンストラクタの方が変更波及が小さい

コンストラクタで設定されるmutationGeneratingCountと同じ性質だと思います.

  public Mutation(final int mutationGeneratingCount, final Random random,
      final CandidateSelection candidateSelection) {
    this.random = random;
    this.mutationGeneratingCount = mutationGeneratingCount;
    this.candidateSelection = candidateSelection;
  }

variantStore.addGeneratedVariants(variantsByMutation);
final List<Variant> variantsByCrossover = crossover.exec(variantStore,
config.getRequiredSolutionsCount());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// 新しい修正プログラムが生成された場合,必要数に達しているかを調べる
// 達している場合はこれ以上の変異プログラムは生成しない
if (newVariant.isCompleted() && requiredSolutions <= ++foundSolutions) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらのコードを推したいです.
複合条件if内でのインクリメント演算はバグの元,かつ混乱の元.

      if (newVariant.isCompleted()) {
        foundSolutions++;
      }
      if (foundSolutions >= requiredSolutions) {
        break;
      }

final List<Variant> variantList = simpleMutation.exec(variantStore, 1);

// 変異プログラムを全く生成しないはず
assertThat(variantList).hasSize(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertThat(variantList).isEmpty();

break VARIANT_GENERATION;
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GOTOを避けたいのでメソッドに切り出した方がよさそう

    final List<Variant> variants = generateVariants(variantStore, validVariants);

    // バリアントを作りすぎた場合はそれを除いてリターン
    return generatingCount < variants.size() ? variants.subList(0, generatingCount) : variants;
  }

  private List<Variant> generateVariants(final VariantStore variantStore,
      final List<Variant> validVariants) {
    final List<Variant> generatedVariants = new ArrayList<>();
    int foundSolutions = variantStore.getFoundSolutionsNumber()
        .get();

    // generatingCountを超えるまでバリアントを作りづづける
    while (generatedVariants.size() < generatingCount) {
      try {
        generatedVariants.addAll(makeVariants(validVariants, variantStore));
        foundSolutions += generatedVariants.stream()
            .filter(Variant::isCompleted)
            .count();
        if (requiredSolutions <= foundSolutions) {
          return generatedVariants;
        }
      } catch (final CrossoverInfeasibleException e) {
        log.debug(e.getMessage());
      }
    }
    return generatedVariants;
  }

厳密には元のコードと挙動は違います.
そのため RandomCrossoverTest#testStopFirst02 が落ちます.
詳細は後述

final List<Variant> variants = crossover.exec(testVariants.variantStore, 1);

// 交叉で1つだけ変異プログラムを生成するはず
assertThat(variants).hasSize(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先のテストが落ちる問題の箇所です.

stopFirst=onにすると解発見時に強制的にGAを止める,という点は認識が一致してると思います.
ただ,その際に以下A/Bどちらの振る舞いをするかの認識違いがありそう.

A. 常に「発見した解の数<=期待する解の数」を満たす.
B. 常に「発見した解の数<=期待する解の数」を満たすとは限らない.

Mutationは一つずつ個体を生成するのでAのような挙動でも自然です.

一方,CrossOverは複数個体をまとめて生成します.
当然その中には解個体が複数含まれます.
その際に,せっかく見つけた(コンパイル+評価済みの)解個体を捨ててAを満たすよりは,
Bのように返した方が損がないと思います.

あくまで「stopFirstはGAのプロセスを強制停止して時間を節約する機能」であり,
Aを満たすか否かは別の問題だと思います.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個体の実態はLazyVariantなので,isCompletedが呼び出されたときにテスト実行がされますよね.
Bだと交叉により生成した全ての個体に対してisCompletedが呼び出されます(テストが実行される).
なので,stopFirstにする意義が薄れるように思いますがどうでしょうか?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

遅延評価を忘れてました.
100%agreeです.

以下のstream使ってさらっとやってる部分を手続き的にやるしかないですね.
とりあえず,return使えばgotoは消えると思います.

    while (generatedVariants.size() < generatingCount) {
      try {
        generatedVariants.addAll(makeVariants(validVariants, variantStore));
        foundSolutions += generatedVariants.stream()
            .filter(Variant::isCompleted)
            .count();
        if (requiredSolutions <= foundSolutions) {
          return generatedVariants;
        }
      } catch (final CrossoverInfeasibleException e) {
        log.debug(e.getMessage());
      }
    }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OKです.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビューありがとうございました.
修正したのでもう一度確認お願いします.

Copy link
Member

@shinsuke-mat shinsuke-mat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

いいですね.
1点,lambdaの省略記法だけ修正お願いします.

Comment on lines 84 to 87
when(testVariants.variantStore.createVariant(any(), any())).then(ans -> {
return new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
ans.getArgument(1));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 省略できます.

    when(testVariants.variantStore.createVariant(any(), any())).then(ans ->
        new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
            ans.getArgument(1))
    );

Comment on lines 84 to 87
when(testVariants.variantStore.createVariant(any(), any())).then(ans -> {
return new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
ans.getArgument(1));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return

Comment on lines 84 to 87
when(testVariants.variantStore.createVariant(any(), any())).then(ans -> {
return new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
ans.getArgument(1));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return

Comment on lines 116 to 119
when(variantStore.createVariant(any(), any())).then(ans -> {
return new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
ans.getArgument(1));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return

Comment on lines 447 to 451
// 修正プログラムが必ず生成されるようにモックを設定する
when(testVariants.variantStore.createVariant(any(), any())).then(ans -> {
return new Variant(0, 0, ans.getArgument(0), null, null, new SimpleFitness(1.0), null,
ans.getArgument(1));
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return

@YoshikiHigo
Copy link
Member Author

修正しましたので,再度確認お願いします.

Copy link
Member

@shinsuke-mat shinsuke-mat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よさそう.
お疲れさんです.マージします.

@shinsuke-mat shinsuke-mat merged commit 2bb09a5 into master Dec 9, 2020
@shinsuke-mat shinsuke-mat deleted the introduce-stop-first branch December 9, 2020 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

stopfirstオプションほしい
2 participants