io.github.ericmedvet.jgea.problem.synthetic.KLandscapes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jgea.problem Show documentation
Show all versions of jgea.problem Show documentation
Problem (benchmarks and templates) for jgea.
The newest version!
/*-
* ========================LICENSE_START=================================
* jgea-problem
* %%
* Copyright (C) 2018 - 2024 Eric Medvet
* %%
* 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.
* =========================LICENSE_END==================================
*/
package io.github.ericmedvet.jgea.problem.synthetic;
import io.github.ericmedvet.jgea.core.problem.ComparableQualityBasedProblem;
import io.github.ericmedvet.jgea.core.representation.grammar.string.GrammarBasedProblem;
import io.github.ericmedvet.jgea.core.representation.grammar.string.StringGrammar;
import io.github.ericmedvet.jgea.core.representation.tree.Tree;
import io.github.ericmedvet.jnb.datastructure.DoubleRange;
import io.github.ericmedvet.jnb.datastructure.Pair;
import java.util.*;
import java.util.function.Function;
public class KLandscapes
implements GrammarBasedProblem>, ComparableQualityBasedProblem, Double> {
private static final int ARITY = 2;
private static final DoubleRange V_RANGE = DoubleRange.SYMMETRIC_UNIT;
private static final DoubleRange W_RANGE = DoubleRange.UNIT;
private static final int N_TERMINALS = 4;
private static final int N_NON_TERMINALS = 2;
private final int k;
private final StringGrammar grammar;
private final int arity;
private final DoubleRange vRange;
private final DoubleRange wRange;
private final int nTerminals;
private final int nNonTerminals;
private final Function, Double> fitnessFunction;
private final Function, Tree> solutionMapper;
public KLandscapes(int k) {
this(k, ARITY, V_RANGE, W_RANGE, N_TERMINALS, N_NON_TERMINALS);
}
public KLandscapes(int k, int arity, DoubleRange vRange, DoubleRange wRange, int nTerminals, int nNonTerminals) {
this.k = k;
this.arity = arity;
this.vRange = vRange;
this.wRange = wRange;
this.nTerminals = nTerminals;
this.nNonTerminals = nNonTerminals;
grammar = buildGrammar(nTerminals, nNonTerminals, arity);
fitnessFunction = buildFitnessFunction();
solutionMapper = buildSolutionMapper();
}
private static StringGrammar buildGrammar(int nTerminals, int nNonTerminals, int arity) {
StringGrammar grammar = new StringGrammar<>();
grammar.setStartingSymbol("N");
grammar.rules().put("N", l(c(l("n"), r(arity, "N")), l("t")));
List> nonTerminalConstOptions = new ArrayList<>();
for (int i = 0; i < nNonTerminals; i++) {
nonTerminalConstOptions.add(l("n" + i));
}
grammar.rules().put("n", nonTerminalConstOptions);
List> terminalConstOptions = new ArrayList<>();
for (int i = 0; i < nTerminals; i++) {
terminalConstOptions.add(l("t" + i));
}
grammar.rules().put("t", terminalConstOptions);
return grammar;
}
private static Function, Tree> buildSolutionMapper() {
return KLandscapes::convertTree;
}
@SafeVarargs
private static List c(List... tss) {
List list = new ArrayList<>();
for (List ts : tss) {
list.addAll(ts);
}
return list;
}
private static Tree convertTree(Tree original) {
if (original == null) {
return null;
}
Tree tree = Tree.of(original.child(0).child(0).content());
if (original.height() > 1) {
// is a non terminal node
for (Tree orginalChild : original) {
if (orginalChild.content().equals("N")) {
tree.addChild(convertTree(orginalChild));
}
}
}
return tree;
}
protected static double f(Tree tree, int k, Map v, Map, Double> w) {
return 1d / (1d + (double) Math.abs(k - tree.height())) * maxFK(tree, k, v, w);
}
protected static double fK(Tree tree, int k, Map v, Map, Double> w) {
if (k == 0) {
return v.get(tree.content());
}
double sum = v.get(tree.content());
for (Tree child : tree) {
final double weight = w.get(new Pair<>(tree.content(), child.content()));
final double innerFK = fK(child, k - 1, v, w);
sum = sum + (1 + weight) * innerFK;
}
return sum;
}
@SafeVarargs
private static List l(T... ts) {
return Arrays.asList(ts);
}
protected static Tree levelEqualTree(int[] indexes, int arity) {
if (indexes.length == 1) {
return Tree.of("t" + indexes[0]);
}
Tree tree = Tree.of("n" + indexes[0]);
for (int i = 0; i < arity; i++) {
tree.addChild(levelEqualTree(Arrays.copyOfRange(indexes, 1, indexes.length), arity));
}
return tree;
}
protected static double maxFK(
Tree tree, int k, Map v, Map, Double> w) {
double max = fK(tree, k, v, w);
for (Tree child : tree) {
max = Math.max(max, maxFK(child, k, v, w));
}
return max;
}
protected static Tree optimum(
int k,
int nTerminals,
int nNonTerminals,
int arity,
Map v,
Map, Double> w) {
Tree optimum = null;
double maxFitness = Double.NEGATIVE_INFINITY;
for (int d = 1; d <= k + 1; d++) {
int[] indexes = new int[d]; // indexes of the (non)Terminals to be used. terminal is the last index.
while (true) {
Tree tree = levelEqualTree(indexes, arity);
double fitness = f(tree, k, v, w);
if ((optimum == null) || (fitness > maxFitness)) {
optimum = tree;
maxFitness = fitness;
}
indexes[indexes.length - 1] = indexes[indexes.length - 1] + 1;
for (int j = indexes.length - 1; j > 0; j--) {
int threshold = (j == (indexes.length - 1)) ? nTerminals : nNonTerminals;
if (indexes[j] == threshold) {
indexes[j] = 0;
indexes[j - 1] = indexes[j - 1] + 1;
}
}
if (indexes[0] == nNonTerminals) {
break;
}
}
}
return optimum;
}
@SafeVarargs
private static List r(int n, T... ts) {
List list = new ArrayList<>(n * ts.length);
for (int i = 0; i < n; i++) {
list.addAll(l(ts));
}
return list;
}
private Function, Double> buildFitnessFunction() {
Random random = new Random(1L);
final Map v = new LinkedHashMap<>();
final Map, Double> w = new LinkedHashMap<>();
// fill v map
for (int i = 0; i < nTerminals; i++) {
v.put("t" + i, vRange.denormalize(random.nextDouble()));
}
for (int i = 0; i < nNonTerminals; i++) {
v.put("n" + i, vRange.denormalize(random.nextDouble()));
}
// fill w map
for (int j = 0; j < nNonTerminals; j++) {
for (int i = 0; i < nTerminals; i++) {
w.put(new Pair<>("n" + j, "t" + i), wRange.denormalize(random.nextDouble()));
}
for (int i = 0; i < nNonTerminals; i++) {
w.put(new Pair<>("n" + j, "n" + i), wRange.denormalize(random.nextDouble()));
}
}
// prepare fitness
final double optimumFitness = f(optimum(k, nTerminals, nNonTerminals, arity, v, w), k, v, w);
// build function
return t -> (1d - f(t, k, v, w) / optimumFitness);
}
@Override
public StringGrammar getGrammar() {
return grammar;
}
@Override
public Function, Tree> getSolutionMapper() {
return solutionMapper;
}
@Override
public Function, Double> qualityFunction() {
return fitnessFunction;
}
}