diff --git a/src/main/java/jp/kusumotolab/kgenprog/KGenProgMain.java b/src/main/java/jp/kusumotolab/kgenprog/KGenProgMain.java index 9e73ae1c7..07bed5d7f 100644 --- a/src/main/java/jp/kusumotolab/kgenprog/KGenProgMain.java +++ b/src/main/java/jp/kusumotolab/kgenprog/KGenProgMain.java @@ -1,11 +1,13 @@ package jp.kusumotolab.kgenprog; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jp.kusumotolab.kgenprog.fl.FaultLocalization; @@ -100,6 +102,8 @@ public List run() throws RuntimeException { final StopWatch stopwatch = new StopWatch(config.getTimeLimitSeconds()); stopwatch.start(); + ExitStatus exitStatus; + while (true) { // 新しい世代に入ったことをログ出力 @@ -114,25 +118,25 @@ public List run() throws RuntimeException { // 世代別サマリの出力 logGenerationSummary(stopwatch.toString(), variantsByMutation, variantsByCrossover); stopwatch.split(); + variantStore.updateVariantCounts( + Stream.concat(variantsByMutation.stream(), variantsByCrossover.stream()) + .collect(Collectors.toList())); // しきい値以上の completedVariants が生成された場合は,GA を抜ける if (areEnoughCompletedVariants(variantStore.getFoundSolutions())) { - log.info("enough solutions have been found."); - logGAStopped(variantStore.getGenerationNumber()); + exitStatus = ExitStatus.SUCCESS; break; } // 制限時間に達した場合には GA を抜ける if (stopwatch.isTimeout()) { - log.info("GA reached the time limit."); - logGAStopped(variantStore.getGenerationNumber()); + exitStatus = ExitStatus.FAILURE_TIME_LIMIT; break; } // 最大世代数に到達した場合には GA を抜ける if (reachedMaxGeneration(variantStore.getGenerationNumber())) { - log.info("GA reached the maximum generation."); - logGAStopped(variantStore.getGenerationNumber()); + exitStatus = ExitStatus.FAILURE_MAXIMUM_GENERATION; break; } @@ -140,12 +144,15 @@ public List run() throws RuntimeException { variantStore.proceedNextGeneration(); } + log.info("GA stopped."); // 出力処理を行う exporters.exportAll(variantStore); stopwatch.unsplit(); strategies.finish(); - log.info("execution time: " + stopwatch.toString()); + logGAStopped(variantStore.getGenerationNumber(), variantStore.getVariantCount(), + variantStore.getSyntaxValidVariantCount(), variantStore.getBuildSuccessVariantCount(), + stopwatch.toString(), exitStatus); return variantStore.getFoundSolutions(config.getRequiredSolutionsCount()); } @@ -206,6 +213,7 @@ private void logGenerationSummary(final String timeText, final List var variants.addAll(variantsByMutation); variants.addAll(variantsByCrossover); final StringBuilder sb = new StringBuilder(); + final DecimalFormat df = createDecimalFormat(); sb// .append(System.lineSeparator()) .append("----------------------------------------------------------------") @@ -229,7 +237,7 @@ private void logGenerationSummary(final String timeText, final List var .append(", min ") .append(getMinText(variants)) .append(", ave ") - .append(getAverage(variants)) + .append(df.format(getAverage(variants))) .append(System.lineSeparator()) .append("----------------------------------------------------------------") .append(System.lineSeparator()); @@ -249,7 +257,8 @@ private String getMaxText(final List variants) { } final Map.Entry max = Collections.max(frequencies.entrySet(), Map.Entry.comparingByKey()); - return max.getKey() + "(" + max.getValue() + ")"; + final DecimalFormat df = createDecimalFormat(); + return df.format(max.getKey()) + "(" + max.getValue() + ")"; } private String getMinText(final List variants) { @@ -259,7 +268,8 @@ private String getMinText(final List variants) { } final Map.Entry min = Collections.min(frequencies.entrySet(), Map.Entry.comparingByKey()); - return min.getKey() + "(" + min.getValue() + ")"; + final DecimalFormat df = createDecimalFormat(); + return df.format(min.getKey()) + "(" + min.getValue() + ")"; } private double getAverage(final List variants) { @@ -281,12 +291,48 @@ private double getNormalizedFitnessValue(final Variant variant) { .getNormalizedValue(); } - private void logGAStopped(final OrdinalNumber generation) { + private DecimalFormat createDecimalFormat() { + return new DecimalFormat("#.###"); + } + + private void logGAStopped(final OrdinalNumber generation, final int variantCount, + final int syntaxValidCount, final int buildSuccessCount, final String time, + final ExitStatus exitStatus) { final StringBuilder sb = new StringBuilder(); sb// - .append("GA stopped at the era of ") - .append(generation.toString()) - .append(" generation."); + .append("Summary") + .append(System.lineSeparator()) + .append("Reached generation = ") + .append(generation.intValue()) + .append(System.lineSeparator()) + .append("Generated variants = ") + .append(variantCount) + .append(System.lineSeparator()) + .append("Syntax valid variants = ") + .append(syntaxValidCount) + .append(System.lineSeparator()) + .append("Build succeeded variants = ") + .append(buildSuccessCount) + .append(System.lineSeparator()) + .append("Time elapsed = ") + .append(time) + .append(System.lineSeparator()) + .append("Exit status = ") + .append(exitStatus.getCode()); log.info(sb.toString()); } + + private enum ExitStatus { + SUCCESS("SUCCESS"), FAILURE_MAXIMUM_GENERATION( + "FAILURE (maximum generation)"), FAILURE_TIME_LIMIT("FAILURE (time limit)"); + private final String code; + + ExitStatus(String code) { + this.code = code; + } + + String getCode() { + return code; + } + } } diff --git a/src/main/java/jp/kusumotolab/kgenprog/ga/variant/VariantStore.java b/src/main/java/jp/kusumotolab/kgenprog/ga/variant/VariantStore.java index b559ae8c1..2441a6d95 100644 --- a/src/main/java/jp/kusumotolab/kgenprog/ga/variant/VariantStore.java +++ b/src/main/java/jp/kusumotolab/kgenprog/ga/variant/VariantStore.java @@ -36,6 +36,9 @@ public class VariantStore { private final AtomicLong variantCounter; private final Function elementReplacer; private final Consumer variantRecorder; + private int variantCount; + private int syntaxValidVariantCount; + private int buildSuccessVariantCount; /** * @param config 設定 @@ -57,6 +60,9 @@ public VariantStore(final Configuration config, final Strategies strategies) { foundSolutions = new ArrayList<>(); // 最後に次の世代番号に進めておく generation.incrementAndGet(); + variantCount = 0; + syntaxValidVariantCount = 0; + buildSuccessVariantCount = 0; } /** @@ -129,6 +135,27 @@ public List getFoundSolutions(final int maxNumber) { return foundSolutions.subList(0, length); } + /** + * @return 今まで生成した個体数 + */ + public int getVariantCount() { + return variantCount; + } + + /** + * @return 今まで生成した個体のうち、Syntax Valid な個体数 + */ + public int getSyntaxValidVariantCount() { + return syntaxValidVariantCount; + } + + /** + * @return 今まで生成した個体のうち、ビルド成功個体数 + */ + public int getBuildSuccessVariantCount() { + return buildSuccessVariantCount; + } + /** * 引数の要素すべてを次世代のVariantとして追加する * @@ -233,4 +260,19 @@ private Consumer newVariantRecorder(final boolean historyRecord) { public Configuration getConfiguration() { return config; } + + /** + * variantCount, syntaxValidVariantCount, buildSuccessVariantCountを更新する + * + * @param variants 前回の更新以降新たに生成した個体のリスト + */ + public void updateVariantCounts(final List variants) { + variantCount += variants.size(); + syntaxValidVariantCount += variants.stream() + .filter(Variant::isSyntaxValid) + .count(); + buildSuccessVariantCount += variants.stream() + .filter(Variant::isBuildSucceeded) + .count(); + } }