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()
30 .size() > 0);
31
32 final Set<OperationFactory> functions = program.functions();
33 return functions.stream()
34 .skip(randomGenerator.nextInt(functions.size()))
35 .findFirst()
36 .get();
37 }
38
39 public <T> OperationFactory pickRandomFunction(final Program program, final Class<T> requiredClass) {
40 Objects.requireNonNull(program);
41 Objects.requireNonNull(requiredClass);
42 Validate.isTrue(program.functions()
43 .size() > 0);
44
45 final Set<OperationFactory> functions = program.functions();
46 @SuppressWarnings("unchecked")
47 final List<OperationFactory> candidates = functions.stream()
48 .filter((operationFactory) -> operationFactory.returnedType()
49 .isAssignableFrom(requiredClass))
50 .collect(Collectors.toList());
51
52 if (candidates == null || candidates.isEmpty()) {
53 throw new IllegalArgumentException("Could not find a suitable function returning a " + requiredClass);
54 }
55
56 return candidates.get(randomGenerator.nextInt(candidates.size()));
57 }
58
59 public <T> OperationFactory pickRandomTerminal(final Program program, final Class<T> requiredClass) {
60 Objects.requireNonNull(program);
61 Objects.requireNonNull(requiredClass);
62
63 final Set<OperationFactory> terminals = program.terminal();
64 @SuppressWarnings("unchecked")
65 final List<OperationFactory> candidates = terminals.stream()
66 .filter((operationFactory) -> operationFactory.returnedType()
67 .isAssignableFrom(requiredClass))
68 .collect(Collectors.toList());
69
70 if (candidates == null || candidates.isEmpty()) {
71 throw new IllegalArgumentException("Could not find a suitable terminal returning a " + requiredClass);
72 }
73
74 return candidates.get(randomGenerator.nextInt(candidates.size()));
75 }
76
77 public OperationFactory pickRandomTerminal(final Program program) {
78 Objects.requireNonNull(program);
79
80 final Set<OperationFactory> terminals = program.terminal();
81 final List<OperationFactory> candidates = terminals.stream()
82 .collect(Collectors.toList());
83
84 return candidates.get(randomGenerator.nextInt(candidates.size()));
85 }
86
87 public OperationFactory pickRandomFunctionOrTerminal(final Program program) {
88 Objects.requireNonNull(program);
89
90 final Set<OperationFactory> terminals = program.terminal();
91 final Set<OperationFactory> functions = program.functions();
92 final int totalNumberCandidates = terminals.size() + functions.size();
93
94 final Stream<OperationFactory> candidates = Stream.concat(terminals.stream(), functions.stream());
95 final int chosenCandidate = randomGenerator.nextInt(totalNumberCandidates);
96
97 return candidates.skip(chosenCandidate)
98 .findFirst()
99 .get();
100 }
101
102 public <T> OperationFactory pickRandomFunctionOrTerminal(final Program program, final Class<T> requiredClass) {
103 Objects.requireNonNull(program);
104 Objects.requireNonNull(requiredClass);
105
106 final Set<OperationFactory> terminals = program.terminal();
107 final Set<OperationFactory> functions = program.functions();
108
109 final Stream<OperationFactory> candidates = Stream.concat(terminals.stream(), functions.stream());
110
111 @SuppressWarnings("unchecked")
112 final List<OperationFactory> filteredCandidates = candidates
113 .filter((operationFactory) -> operationFactory.returnedType()
114 .isAssignableFrom(requiredClass))
115 .collect(Collectors.toList());
116
117 final int filteredCandidatesCount = filteredCandidates.size();
118 if (filteredCandidatesCount == 0) {
119 logger.error("No candidate terminals or functions found that can return an instance of class {}",
120 requiredClass);
121 logger.debug("\tKnown terminals: {}",
122 program.terminal()
123 .stream());
124 logger.debug("\tKnown functions: {}", program.functions());
125
126 throw new IllegalArgumentException(
127 "No candidate terminals or functions found that can return an instance of class " + requiredClass);
128 }
129
130 final int chosenCandidate = randomGenerator.nextInt(filteredCandidates.size());
131
132 return filteredCandidates.get(chosenCandidate);
133 }
134 }