1 package net.bmahe.genetics4j.gp.program;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Set;
6 import java.util.random.RandomGenerator;
7 import java.util.stream.Collectors;
8 import java.util.stream.Stream;
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.gp.OperationFactory;
15
16 public class ProgramHelper {
17 public final static Logger logger = LogManager.getLogger(ProgramHelper.class);
18
19 private final RandomGenerator randomGenerator;
20
21 public ProgramHelper(final RandomGenerator _randomGenerator) {
22 Objects.requireNonNull(_randomGenerator);
23
24 this.randomGenerator = _randomGenerator;
25 }
26
27 public OperationFactory pickRandomFunction(final Program program) {
28 Objects.requireNonNull(program);
29 Validate.isTrue(program.functions().size() > 0);
30
31 final Set<OperationFactory> functions = program.functions();
32 return functions.stream().skip(randomGenerator.nextInt(functions.size())).findFirst().get();
33 }
34
35 public <T> OperationFactory pickRandomFunction(final Program program, final Class<T> requiredClass) {
36 Objects.requireNonNull(program);
37 Objects.requireNonNull(requiredClass);
38 Validate.isTrue(program.functions().size() > 0);
39
40 final Set<OperationFactory> functions = program.functions();
41 @SuppressWarnings("unchecked")
42 final List<OperationFactory> candidates = functions.stream()
43 .filter((operationFactory) -> operationFactory.returnedType().isAssignableFrom(requiredClass))
44 .collect(Collectors.toList());
45
46 if (candidates == null || candidates.isEmpty()) {
47 throw new IllegalArgumentException("Could not find a suitable function returning a " + requiredClass);
48 }
49
50 return candidates.get(randomGenerator.nextInt(candidates.size()));
51 }
52
53 public <T> OperationFactory pickRandomTerminal(final Program program, final Class<T> requiredClass) {
54 Objects.requireNonNull(program);
55 Objects.requireNonNull(requiredClass);
56
57 final Set<OperationFactory> terminals = program.terminal();
58 @SuppressWarnings("unchecked")
59 final List<OperationFactory> candidates = terminals.stream()
60 .filter((operationFactory) -> operationFactory.returnedType().isAssignableFrom(requiredClass))
61 .collect(Collectors.toList());
62
63 if (candidates == null || candidates.isEmpty()) {
64 throw new IllegalArgumentException("Could not find a suitable terminal returning a " + requiredClass);
65 }
66
67 return candidates.get(randomGenerator.nextInt(candidates.size()));
68 }
69
70 public OperationFactory pickRandomTerminal(final Program program) {
71 Objects.requireNonNull(program);
72
73 final Set<OperationFactory> terminals = program.terminal();
74 final List<OperationFactory> candidates = terminals.stream().collect(Collectors.toList());
75
76 return candidates.get(randomGenerator.nextInt(candidates.size()));
77 }
78
79 public OperationFactory pickRandomFunctionOrTerminal(final Program program) {
80 Objects.requireNonNull(program);
81
82 final Set<OperationFactory> terminals = program.terminal();
83 final Set<OperationFactory> functions = program.functions();
84 final int totalNumberCandidates = terminals.size() + functions.size();
85
86 final Stream<OperationFactory> candidates = Stream.concat(terminals.stream(), functions.stream());
87 final int chosenCandidate = randomGenerator.nextInt(totalNumberCandidates);
88
89 return candidates.skip(chosenCandidate).findFirst().get();
90 }
91
92 public <T> OperationFactory pickRandomFunctionOrTerminal(final Program program, final Class<T> requiredClass) {
93 Objects.requireNonNull(program);
94 Objects.requireNonNull(requiredClass);
95
96 final Set<OperationFactory> terminals = program.terminal();
97 final Set<OperationFactory> functions = program.functions();
98
99 final Stream<OperationFactory> candidates = Stream.concat(terminals.stream(), functions.stream());
100
101 @SuppressWarnings("unchecked")
102 final List<OperationFactory> filteredCandidates = candidates
103 .filter((operationFactory) -> operationFactory.returnedType().isAssignableFrom(requiredClass))
104 .collect(Collectors.toList());
105
106 final int filteredCandidatesCount = filteredCandidates.size();
107 if (filteredCandidatesCount == 0) {
108 logger.error(
109 "No candidate terminals or functions found that can return an instance of class {}",
110 requiredClass);
111 logger.debug("\tKnown terminals: {}", program.terminal().stream());
112 logger.debug("\tKnown functions: {}", program.functions());
113
114 throw new IllegalArgumentException(
115 "No candidate terminals or functions found that can return an instance of class " + requiredClass);
116 }
117
118 final int chosenCandidate = randomGenerator.nextInt(filteredCandidates.size());
119
120 return filteredCandidates.get(chosenCandidate);
121 }
122 }