aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
blob: e2f17c3ec0f7285c38ddbb4efabe5b83e00e41ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package jcgp.backend.modules.problem;

import jcgp.backend.function.DigitalCircuitFunctions;
import jcgp.backend.function.UnsignedInteger;
import jcgp.backend.population.Population;
import jcgp.backend.resources.Resources;

/**
 * Digital circuit problem
 * <br><br>
 * Using this problem type, digital logic circuits can be evolved.
 * {@code parseData()} must be used to load the desired circuit
 * truth table in the standard CGP .plu format. 
 * 
 * @see DigitalCircuitFunctions
 * @author Eduardo Pedroni
 *
 */
public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {

	/**
	 * Construct a new instance of DigitalCircuitProblem.
	 * 
	 * @param resources a reference to the experiment's resources.
	 */
	public DigitalCircuitProblem(Resources resources) {
		super(resources);
		setFunctionSet(new DigitalCircuitFunctions());
		setName("Digital circuit");
		setFileExtension(".plu");
	}

	@Override
	public void evaluate(Population population, Resources resources) {
		// for every chromosome in the population
		for (int i = 0; i < resources.populationSize(); i++) {
			// assume an initial fitness of 0
			int fitness = 0;

			// iterate over every test case
			for (int t = 0; t < testCases.size(); t++) {
				population.get(i).setInputs((Object[]) testCases.get(t).getInputs());
				// check each output
				for (int o = 0; o < resources.outputs(); o++) {
					Integer output = ((UnsignedInteger) population.get(i).getOutput(o).calculate()).get();
					Integer matches = ~(output ^ testCases.get(t).getOutput(o).get());
					// check only the relevant bits
					int bits;
					if (resources.inputs() < 5) {
						bits = (int) Math.pow(2.0, (double) resources.inputs());
					} else {
						bits = 32;
					}
					for (int b = 0; b < bits; b++) {
						fitness += (matches >>> b) & 1;
					}
				}
			}
			// assign the resulting fitness to the respective individual
			population.get(i).setFitness(fitness);
		}
	}

	@Override
	protected double getMaxFitness() {
		// calculate the fitness by looking at inputs, not number of test cases
		double maxFitness = Math.pow(2.0, (double) getResources().inputs()) * getResources().outputs();
		return maxFitness;
	}

	@Override
	public TestCase<UnsignedInteger> parseTestCase(String[] inputs, String[] outputs) {
		// cast the test case values to UnsignedInteger
		UnsignedInteger[] inputCases = new UnsignedInteger[inputs.length];
		UnsignedInteger[] outputCases = new UnsignedInteger[outputs.length];
		for (int i = 0; i < inputCases.length; i++) {
			inputCases[i] = new UnsignedInteger(inputs[i]);
		}
		for (int o = 0; o < outputCases.length; o++) {
			outputCases[o] = new UnsignedInteger(outputs[o]);
		}

		return new TestCase<UnsignedInteger>(inputCases, outputCases);
	}

	@Override
	public int hasPerfectSolution(Population population) {
		// higher fitness is better
		for (int i = 0; i < getResources().populationSize(); i++) {
			if (population.get(i).getFitness() >= maxFitness.get()) {
				return i;
			}
		}
		return -1;
	}
}