aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/modules/problem/Problem.java
blob: 721b9b3761874ebab6b764a0ea3eaa740a66f423 (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
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.Chromosome;
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 Problem 
 * is to evaluate a population and assign a fitness value to each chromosome. 
 * <br>
 * By convention, the population should be sorted into ascending order of fitness. The
 * reason for this is because high fitness is not necessarily better - some problem types
 * might treat 0 as the best fitness. In order for the evolutionary strategy to be able to
 * pick chromosomes by fitness, the safest way is to sort them such that the last chromosome
 * is the fittest.
 * <br><br>
 * When extending this class, the constructor should call a couple methods in order to
 * properly construct the problem type: {@code setFunctionSet()} and {@code setFileExtension()},
 * 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 = ".*";
	
	protected DoubleParameter maxFitness, bestFitness;
	
	/**
	 * Initialises the two problem-wide parameters, maxFitness and bestFitness.
	 */
	public Problem() {
		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.
	 * @param resources parameters and utilities for optional reference.
	 */
	public abstract void evaluate(Population population, Resources resources);
	
	/**
	 * Used to assert whether a given chromosome is 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.
	 * <br><br>
	 * Note that if this method returns true, the experiment will move on
	 * to the next run, or finish if no more runs are left.
	 * 
	 * @param candidate the potentially perfect chromosome.
	 * @return true if the argument is a perfect solution.
	 */
	public abstract boolean isPerfectSolution(Chromosome candidate);
	
	/**
	 * Used to assert whether a given chromosome 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 candidate the potentially fitter chromosome.
	 * @return true if the argument is fitter than the currently fittest chromosome.
	 */
	public abstract boolean isImprovement(Chromosome candidate);
	
	/**
	 * 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;
	}
	
	/**
	 * @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);
	}
}