1 package net.bmahe.genetics4j.core.evaluation;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.concurrent.CompletableFuture;
7 import java.util.concurrent.ExecutorService;
8 import java.util.concurrent.Executors;
9
10 import org.apache.commons.lang3.Validate;
11 import org.apache.logging.log4j.LogManager;
12 import org.apache.logging.log4j.Logger;
13
14 import net.bmahe.genetics4j.core.Fitness;
15 import net.bmahe.genetics4j.core.Genotype;
16 import net.bmahe.genetics4j.core.spec.EAConfiguration;
17 import net.bmahe.genetics4j.core.spec.EAExecutionContext;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class FitnessEvaluatorVirtualThread<T extends Comparable<T>> implements FitnessEvaluator<T> {
58 public static final Logger logger = LogManager.getLogger(FitnessEvaluatorVirtualThread.class);
59
60 private final EAExecutionContext<T> eaExecutionContext;
61 private final EAConfiguration<T> eaConfiguration;
62 private final ExecutorService virtualThreadExecutor;
63
64 public FitnessEvaluatorVirtualThread(final EAExecutionContext<T> _eaExecutionContext,
65 final EAConfiguration<T> _eaConfiguration) {
66 Objects.requireNonNull(_eaExecutionContext);
67 Objects.requireNonNull(_eaConfiguration);
68
69 this.eaExecutionContext = _eaExecutionContext;
70 this.eaConfiguration = _eaConfiguration;
71 this.virtualThreadExecutor = Executors.newVirtualThreadPerTaskExecutor();
72 }
73
74 @Override
75 public void preEvaluation() {
76 logger.debug("Pre-evaluation setup for virtual thread fitness evaluator");
77 }
78
79 @Override
80 public void postEvaluation() {
81 logger.debug("Post-evaluation cleanup for virtual thread fitness evaluator");
82 }
83
84 @Override
85 public List<T> evaluate(final long generation, final List<Genotype> population) {
86 Validate.isTrue(generation >= 0);
87 Objects.requireNonNull(population);
88
89 if (population.isEmpty()) {
90 return new ArrayList<>();
91 }
92
93 logger.debug("Evaluating {} individuals using virtual threads", population.size());
94
95 final Fitness<T> fitness = eaConfiguration.fitness();
96 final List<CompletableFuture<T>> evaluationTasks = new ArrayList<>(population.size());
97
98
99 for (final Genotype genotype : population) {
100 final CompletableFuture<T> evaluationTask = CompletableFuture.supplyAsync(() -> {
101 return fitness.compute(genotype);
102 }, virtualThreadExecutor);
103
104 evaluationTasks.add(evaluationTask);
105 }
106
107
108 final List<T> fitnessScores = new ArrayList<>(population.size());
109 for (final CompletableFuture<T> task : evaluationTasks) {
110 fitnessScores.add(task.join());
111 }
112
113 logger.debug("Completed evaluation of {} individuals", population.size());
114 return fitnessScores;
115 }
116 }