View Javadoc
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 }