aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/function/FunctionSet.java
blob: abc9eb46b55d9e32c1dcce0be061e107b4df6c28 (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
package jcgp.backend.function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

/**
 * FunctionSet encapsulates a group of functions. This is done to
 * simplify the implementation of problem types.
 * <br><br>
 * FunctionSet contains a variety of useful methods for acquiring general
 * information, such as the maximum arity across all functions and the total
 * number of functions.
 * <br><br>
 * In addition, FunctionSet offers the ability to enable and disable functions.
 * Accessing the functions through {@code getAllowedFunction()} will return
 * allowed functions only, providing an easy way to control which functions
 * can be used in mutations.
 * <br><br>
 * An implementation of FunctionSet must simply use its constructor to set
 * the name field and use {@code registerFunctions()} to add the required
 * functions. 
 * 
 * @author Eduardo Pedroni
 *
 */
public abstract class FunctionSet {
		private ArrayList<Function> functionList = new ArrayList<Function>();
		private ArrayList<Integer> allowedFunctions = new ArrayList<Integer>();
		
		/**
		 * @return the number of currently allowed functions.
		 */
		public int getAllowedFunctionCount() {
			return allowedFunctions.size();
		}
		
		/**
		 * @return the total number of functions, including disabled ones.
		 */
		public int getTotalFunctionCount() {
			return functionList.size();
		}
		
		/**
		 * Returns an allowed function. This throws an
		 * ArrayIndexOutOfBoundsException if the supplied 
		 * index is beyond the count of allowed functions.
		 * 
		 * @param index the allowed function index.
		 * @return the allowed function object.
		 */
		public Function getAllowedFunction(int index) {
			return functionList.get(allowedFunctions.get(index));
		}
		
		/**
		 * Returns a function from the complete collection,
		 * enabled or disabled alike. This throws an
		 * ArrayIndexOutOfBoundsException if the supplied 
		 * index is beyond the count of allowed functions.
		 * 
		 * @param index the function index.
		 * @return the function object.
		 */
		public Function getFunction(int index) {
			return functionList.get(index);
		}
		
		/**
		 * Computes and returns the maximum arity out of
		 * all enabled functions.
		 * 
		 * @return the problem's current maximum arity.
		 */
		public int getMaxArity(){
			int arity = 0;
			for (Integer function : allowedFunctions) {
				// if a higher arity is found, store it
				if (functionList.get(function).getArity() > arity) {
					arity = functionList.get(function).getArity();
				}
			}
			return arity;
		}
		
		/**
		 * Disables the indexed function. If the function
		 * is already disabled, this does nothing.
		 * 
		 * @param index the function to disable.
		 */
		public void disableFunction(int index) {
			/*
			 * allowedFunctions is a list of the indices of all allowed functions, 
			 * as addressed in functionList. This method iterates through the whole
			 * list of allowed functions and removes any elements which are equal
			 * to the specified index.
			 */
			if (index < functionList.size()) {
				for (Iterator<Integer> iterator = allowedFunctions.iterator(); iterator.hasNext();) {
					int function = iterator.next();
					if (function == index) {
						iterator.remove();
					}
				}
			} else {
				throw new ArrayIndexOutOfBoundsException("Function " + index + " does not exist, the set only has " + functionList.size() + " functions.");
			}
		}
		
		/**
		 * Disables the indexed function. If the function is
		 * already enabled, this does nothing. 
		 * 
		 * @param index the function to disable.
		 */
		public void enableFunction(int index) {
			// add the specified index to the list of allowed indices
			if (!allowedFunctions.contains(index)) {
				allowedFunctions.add(index);
				Collections.sort(allowedFunctions);
			}
		}
		
		/**
		 * Checks if a specified function is enabled. If the function
		 * does not belong in the FunctionSet, this returns false.
		 * 
		 * @param function the function to check.
		 * @return true if the function is enabled.
		 */
		public boolean isEnabled(Function function) {
			for (int i = 0; i < allowedFunctions.size(); i++) {
				if (functionList.get(allowedFunctions.get(i)) == function) {
					return true;
				}
			}
			return false;
		}
		
		/**
		 * For internal use in subclass constructors. This method
		 * adds the specified functions and enables them. The same
		 * function cannot be added more than once.
		 * 
		 * @param functions the functions to register in the function set.
		 */
		protected void registerFunctions(Function... functions) {
			for (int i = 0; i < functions.length; i++) {
				if (!alreadyHave(functions[i])) {
					functionList.add(functions[i]);
					enableFunction(functionList.size() - 1);
				}
			}
		}
		
		/**
		 * For internal use only, this checks whether a function
		 * is already present in the function set.
		 * 
		 * @param function the function to look for.
		 * @return true if the function is already in the function set.
		 */
		private boolean alreadyHave(Function function) {
			for (int i = 0; i < functionList.size(); i++) {
				if (functionList.get(i).getClass() == function.getClass()) {
					return true;
				}
			}
			return false;
		}
	}