aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/modules/problem/Problem.java
blob: 453e3a1518c0dbd0bb3104e931f499bf16962c37 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package jcgp.backend.modules.problem;

import java.io.File;

import jcgp.backend.function.FunctionSet;
import jcgp.backend.modules.Module;
import jcgp.backend.parameters.DoubleParameter;
import jcgp.backend.parameters.monitors.DoubleMonitor;
import jcgp.backend.population.Population;
import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;

/**
 * Defines the general behaviour of a CGP problem. The primary function of {@code Problem} 
 * is to evaluate a population and assign a fitness value to each chromosome. 
 * <br>
 * Problems are free to define whether better fitness means a higher or lower fitness value.
 * In some problem types, it is more convenient to treat fitness 0 as the best possible value.
 * This can be done by changing the fitness orientation to {@code BestFitness.HIGH} or {@code BestFitness.LOW} as appropriate.
 * Fitness orientation is set to high by default.
 * <br><br>
 * When extending this class, the constructor should call a few methods in order to
 * properly construct the problem type: {@code setFunctionSet()}, {@code setFileExtension()} and {@code setFitnessOrientation()},
 * with the respective arguments. As with all subclasses of {@code Module}, {@code setName()} and
 * {@code registerParameters()} should be used where appropriate as well.
 * <br><br>
 * It is advisable to use {@code Resources.reportln()} and {@code Resources.report()}
 * to print any relevant information. Note that reportln() and report() are affected
 * by the report interval base parameter. Use {@code Resources.println()} and
 * {@code Resources.print()} to print information regardless of the current generation.
 * See {@link Resources} for more information.
 * 
 * @see Module
 * @author Eduardo Pedroni
 *
 */
public abstract class Problem extends Module {

	private FunctionSet functionSet;
	private String fileExtension = ".*";
	
	private BestFitness fitnessOrientation = BestFitness.HIGH;
	
	protected DoubleParameter maxFitness, bestFitness;
	
	/**
	 * Initialises the two problem-wide parameters, maxFitness and bestFitness.
	 *
	 * @param resources a reference to the experiment's resources.
	 */
	protected Problem(Resources resources) {
		super(resources);
		
		maxFitness = new DoubleMonitor(0, "Max fitness");
		bestFitness = new DoubleMonitor(0, "Best fitness");
		registerParameters(maxFitness, bestFitness);
	}
	
	/**
	 * The most important method of the problem type. This is called once
	 * per generation, when the new population has been generated.
	 * <br><br>
	 * The basic functionality of this method is to loop through all chromosomes
	 * in the population and decode them according to the problem type. The
	 * fitness of each chromosome is then calculated using the problem data
	 * or otherwise (subjective problem types such as art generation might
	 * leave fitness evaluations up to the user) and assigned to the appropriate
	 * chromosome. 
	 * <br><br>
	 * In addition, realisations of this method should update the value of 
	 * bestFitness as appropriate, since the value of this parameter is displayed
	 * if a GUI is in use.
	 * 
	 * @param population the population to be evaluated.
	 */
	public abstract void evaluate(Population population);
	
	/**
	 * Used to assert whether a given population contains a perfect solution
	 * to the problem. It is up to the problem to define what qualifies
	 * a perfect solution, as some problems (subject ones such as music and
	 * art evolution, for example) might not have perfect solutions at all.
	 * 
	 * @param population the population to search through for a perfect chromosome.
	 * @return the perfect solution index, if one exits, -1 if no perfect solution was found.
	 */
	public abstract int hasPerfectSolution(Population population);
	
	/**
	 * Used to assert whether a given population has a chromosome that is an improvement over 
	 * the current best chromosome. A typical implementation of this method
	 * will simply compare chromosome fitness values, though the problem type
	 * is free to implement this in any way.
	 * 
	 * @param population the population potentially containing a fitter chromosome.
	 * @return the index of the first chromosome in the population that is an improvement, -1 if none is found.
	 */
	public abstract int hasImprovement(Population population);
	
	/**
	 * Parses the specified file and uses the parsed data to
	 * set up the problem type instance appropriately. Any necessary
	 * resource changes can be performed using the provided {@code ModifiableResources}
	 * instance.
	 * <br><br>
	 * In addition, realisations of this method should update the value of
	 * maxFitness where appropriate, as this may be displayed to the user
	 * if a GUI is in use.
	 * 
	 * @param file the data file to parse.
	 * @param resources a modifiable reference to the experiment's resources.
	 */
	public abstract void parseProblemData(File file, ModifiableResources resources);
	
	/**
	 * For internal use in subclass constructor, sets the functions to be
	 * used for this problem type. See {@link FunctionSet} for more details.
	 * 
	 * @param newFunctionSet the function set to use.
	 */
	protected void setFunctionSet(FunctionSet newFunctionSet) {
		this.functionSet = newFunctionSet;
	}
	
	/**
	 * @return the FunctionSet object used by this problem type.
	 */
	public FunctionSet getFunctionSet() {
		return functionSet;
	}
	
	/**
	 * For internal use in subclass constructors, sets the file extension accepted
	 * by this problem type's parser. This is used by the GUI to filter loaded files
	 * by extension in a file chooser. File extensions should be set in the form ".*", 
	 * so for plain text files, ".txt" would be used.
	 * 
	 * @param fileExtension the accepted file extension.
	 */
	protected void setFileExtension(String fileExtension) {
		this.fileExtension = fileExtension;
	}
	
	/**
	 * @return the file extension accepted by this problem type for problem data files.
	 */
	public String getFileExtension() {
		return fileExtension;
	}
	
	/**
	 * @param newOrientation the new fitness orientation to set.
	 */
	protected void setFitnessOrientation(BestFitness newOrientation) {
		this.fitnessOrientation = newOrientation;
	}
	
	/**
	 * @return the fitness orientation of this particular problem.
	 */
	public BestFitness getFitnessOrientation() {
		return fitnessOrientation;
	}
	
	/**
	 * @return the current best fitness, in other words, the fitness
	 * value of the fittest chromosome in the current generation.
	 */
	public double getBestFitness() {
		return bestFitness.get();
	}
	
	/**
	 * Resets the bestFitness parameter.
	 */
	public void reset() {
		bestFitness.set(0);
	}
}