/* * Copyright 2015 S. Webber * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.oakgp.examples.simple; import static org.oakgp.Assignments.createAssignments; import static org.oakgp.TestUtils.createArguments; import static org.oakgp.Type.booleanType; import static org.oakgp.Type.integerArrayType; import static org.oakgp.Type.integerToBooleanFunctionType; import static org.oakgp.Type.integerType; import static org.oakgp.rank.fitness.TestDataFitnessFunction.createIntegerTestDataFitnessFunction; import static org.oakgp.util.Utils.createIntegerConstants; import static org.oakgp.util.Utils.createIntegerTypeArray; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.junit.Test; import org.oakgp.Arguments; import org.oakgp.Assignments; import org.oakgp.Type; import org.oakgp.function.Function; import org.oakgp.function.choice.If; import org.oakgp.function.classify.IsNegative; import org.oakgp.function.classify.IsPositive; import org.oakgp.function.classify.IsZero; import org.oakgp.function.coll.Count; import org.oakgp.function.compare.Equal; import org.oakgp.function.compare.GreaterThan; import org.oakgp.function.compare.GreaterThanOrEqual; import org.oakgp.function.compare.LessThan; import org.oakgp.function.compare.LessThanOrEqual; import org.oakgp.function.compare.NotEqual; import org.oakgp.function.hof.Filter; import org.oakgp.function.math.IntegerUtils; import org.oakgp.node.ConstantNode; import org.oakgp.rank.fitness.FitnessFunction; import org.oakgp.util.RunBuilder; /** * Performs full genetic programming runs without relying on any mock objects. * <p> * Would be better to have in a separate "system-test" directory under the "src" directory - or in a completely separate Git project (that has this project as a * dependency). Leaving here for the moment as it provides a convenient mechanism to perform a full test of the process. * </p> */ public class FitnessFunctionSystemTest { private static final int NUM_GENERATIONS = 50; private static final int INITIAL_POPULATION_SIZE = 50; private static final int INITIAL_POPULATION_MAX_DEPTH = 4; private static final Function[] ARITHMETIC_FUNCTIONS = { IntegerUtils.INTEGER_UTILS.getAdd(), IntegerUtils.INTEGER_UTILS.getSubtract(), IntegerUtils.INTEGER_UTILS.getMultiply() }; @Test public void testSymbolicRegressionExample() { SymbolicRegressionExample.main(null); } @Test public void testTwoVariableArithmeticExpression() { ConstantNode[] constants = createIntegerConstants(0, 11); Type[] variableTypes = createIntegerTypeArray(2); FitnessFunction fitnessFunction = createIntegerTestDataFitnessFunction(createTests(variableTypes.length, a -> { int x = (int) a.get(0); int y = (int) a.get(1); return (x * x) + 2 * y + 3 * x + 5; })); new RunBuilder().setReturnType(integerType()).setConstants(constants).setVariables(variableTypes).setFunctions(ARITHMETIC_FUNCTIONS) .setFitnessFunction(fitnessFunction).setInitialPopulationSize(INITIAL_POPULATION_SIZE).setTreeDepth(INITIAL_POPULATION_MAX_DEPTH) .setMaxGenerations(NUM_GENERATIONS).process(); } @Test public void testThreeVariableArithmeticExpression() { ConstantNode[] constants = createIntegerConstants(0, 11); Type[] variableTypes = createIntegerTypeArray(3); FitnessFunction fitnessFunction = createIntegerTestDataFitnessFunction(createTests(variableTypes.length, a -> { int x = (int) a.get(0); int y = (int) a.get(1); int z = (int) a.get(2); return (x * -3) + (y * 5) - z; })); new RunBuilder().setReturnType(integerType()).setConstants(constants).setVariables(variableTypes).setFunctions(ARITHMETIC_FUNCTIONS) .setFitnessFunction(fitnessFunction).setInitialPopulationSize(INITIAL_POPULATION_SIZE).setTreeDepth(INITIAL_POPULATION_MAX_DEPTH) .setMaxGenerations(NUM_GENERATIONS).process(); } @Test public void testTwoVariableBooleanLogicExpression() { ConstantNode[] constants = createIntegerConstants(0, 5); Type[] variableTypes = createIntegerTypeArray(2); Function[] functions = { IntegerUtils.INTEGER_UTILS.getAdd(), IntegerUtils.INTEGER_UTILS.getSubtract(), IntegerUtils.INTEGER_UTILS.getMultiply(), LessThan.create(integerType()), LessThanOrEqual.create(integerType()), new GreaterThan(integerType()), new GreaterThanOrEqual(integerType()), new Equal(integerType()), new NotEqual(integerType()), new If(integerType()) }; FitnessFunction fitnessFunction = createIntegerTestDataFitnessFunction(createTests(variableTypes.length, a -> { int x = (int) a.get(0); int y = (int) a.get(1); return x > 20 ? x : y; })); new RunBuilder().setReturnType(integerType()).setConstants(constants).setVariables(variableTypes).setFunctions(functions) .setFitnessFunction(fitnessFunction).setInitialPopulationSize(INITIAL_POPULATION_SIZE).setTreeDepth(INITIAL_POPULATION_MAX_DEPTH) .setMaxGenerations(NUM_GENERATIONS).process(); } @Test public void testIsCountOfZerosGreater() { IsPositive isPositive = new IsPositive(); IsNegative isNegative = new IsNegative(); IsZero isZero = new IsZero(); ConstantNode[] constants = { new ConstantNode(Boolean.TRUE, booleanType()), new ConstantNode(Boolean.FALSE, booleanType()), new ConstantNode(isPositive, integerToBooleanFunctionType()), new ConstantNode(isNegative, integerToBooleanFunctionType()), new ConstantNode(isZero, integerToBooleanFunctionType()), new ConstantNode(Arguments.createArguments(), integerArrayType()), new ConstantNode(0, integerType()) }; Type[] variableTypes = { integerArrayType() }; List<Function> functions = new ArrayList<>(); Collections.addAll(functions, ARITHMETIC_FUNCTIONS); Collections.addAll(functions, new Function[] { new Filter(integerType()), isPositive, isNegative, isZero, new Count(integerType()) }); Map<Assignments, Integer> testData = new HashMap<>(); testData.put(createAssignments(createArguments("0", "0", "0", "0", "0", "0", "0", "0")), 8); testData.put(createAssignments(createArguments("6", "3", "4", "0", "2", "4", "1", "3")), 1); testData.put(createAssignments(createArguments("0", "0", "4", "0", "0", "0", "1", "0")), 6); testData.put(createAssignments(createArguments("1", "-1", "2", "5", "4", "-2")), 0); testData.put(createAssignments(createArguments("1", "0", "2", "5", "4", "-2")), 1); testData.put(createAssignments(createArguments("1", "0", "2", "5", "4", "0")), 2); testData.put(createAssignments(createArguments("-2", "0", "8", "7", "0", "-3", "0")), 3); testData.put(createAssignments(createArguments("0", "0", "0")), 3); FitnessFunction fitnessFunction = createIntegerTestDataFitnessFunction(testData); new RunBuilder().setReturnType(integerType()).setConstants(constants).setVariables(variableTypes).setFunctions(functions) .setFitnessFunction(fitnessFunction).setInitialPopulationSize(INITIAL_POPULATION_SIZE).setTreeDepth(INITIAL_POPULATION_MAX_DEPTH) .setMaxGenerations(NUM_GENERATIONS).process(); } private static Map<Assignments, Integer> createTests(int numVariables, java.util.function.Function<Assignments, Integer> f) { Map<Assignments, Integer> tests = new HashMap<>(); for (int i = 0; i < 200; i++) { Object[] inputs = createInputs(numVariables); Assignments assignments = createAssignments(inputs); tests.put(assignments, f.apply(assignments)); } return tests; } private static Object[] createInputs(int numVariables) { Random random = new Random(); Object[] variables = new Object[numVariables]; for (int i = 0; i < numVariables; i++) { variables[i] = random.nextInt(40); } return variables; } }