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 }