/* Copyright 2009-2015 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.problem.LZ; import java.util.ArrayList; import java.util.List; import org.moeaframework.core.Solution; import org.moeaframework.core.variable.EncodingUtils; import org.moeaframework.core.variable.RealVariable; import org.moeaframework.problem.AbstractProblem; /* * The following source code is modified from the complicated Pareto set test * problem suite by Hui Li and Qingfu Zhang available at * {@link http://dces.essex.ac.uk/staff/qzhang/}. Permission to distributed * these modified source codes under the GNU Lesser General Public License was * obtained via e-mail correspondence with the authors. */ /** * Abstract class for implementing problems from the complicated Pareto sets * test suite by Hui Li and Qingfu Zhang. */ public abstract class LZ extends AbstractProblem { /** * The {@code ptype} code specifying the type of Pareto front. */ private final int pType; /** * The {@code ltype} code specifying the type of Pareto set. */ private final int lType; /** * The {@code dtype} code specifying the type of non-negative function. */ private final int dType; /** * Construcs an LZ problem instance with the specified number of variables, * number of objectives, {@code ptype} code, {@code ltype} code, and * {@code dtype} code. * * @param numberOfVariables the number of variables * @param numberOfObjectives the number of objectives * @param pType the {@code ptype} code specifying the type of Pareto front * @param lType the {@code ltype} code specifying the type of Pareto set * @param dType the {@code dtype} code specifying the type of non-negative * function */ public LZ(int numberOfVariables, int numberOfObjectives, int pType, int lType, int dType) { super(numberOfVariables, numberOfObjectives); this.pType = pType; this.lType = lType; this.dType = dType; validate(); } /** * Returns the {@code ptype} code specifying the type of Pareto front. * * @return the {@code ptype} code specifying the type of Pareto front */ public int getPType() { return pType; } /** * Returns the {@code ltype} code specifying the type of Pareto set. * * @return the {@code ltype} code specifying the type of Pareto set */ public int getLType() { return lType; } /** * Returns the {@code dtype} code specifying the type of non-negative * function. * * @return the {@code dtype} code specifying the type of non-negative * function */ public int getDType() { return dType; } @Override public void evaluate(Solution solution) { solution.setObjectives(evaluate(EncodingUtils.getReal(solution))); } @Override public Solution newSolution() { Solution solution = new Solution(numberOfVariables, numberOfObjectives); for (int i = 0; i < numberOfVariables; i++) { solution.setVariable(i, new RealVariable(0.0, 1.0)); } return solution; } /** * Validates the inputs, throwing an {@link IllegalArgumentException} if any * inputs are invalid. */ private void validate() { if ((numberOfObjectives < 2) || (numberOfObjectives > 3)) { throw new IllegalArgumentException("invalid number of objectives"); } if (numberOfObjectives == 2) { if ((pType < 21) || (pType > 24)) { throw new IllegalArgumentException("invalid ptype"); } } else if (numberOfObjectives == 3) { if ((pType < 31) || (pType > 34)) { throw new IllegalArgumentException("invalid ptype"); } } if ((dType < 1) || (dType > 4)) { throw new IllegalArgumentException("invalid dtype"); } if (numberOfObjectives == 2) { if ((lType < 21) || (lType > 26)) { throw new IllegalArgumentException("invalid ltype"); } } else { if ((lType < 31) || (lType > 32)) { throw new IllegalArgumentException("invalid ltype"); } } } /** * Controls the Pareto front shape. */ private double[] alphafunction(double[] x) { if (numberOfObjectives == 2) { if (pType == 21) { return new double[] { x[0], 1 - Math.sqrt(x[0]) }; } else if (pType == 22) { return new double[] { x[0], 1 - x[0] * x[0] }; } else if (pType == 23) { return new double[] { x[0], 1 - Math.sqrt(x[0]) - x[0] * Math.sin(10 * x[0] * x[0] * Math.PI) }; } else if (pType == 24) { return new double[] { x[0], 1 - x[0] - 0.05 * Math.sin(4 * Math.PI * x[0]) }; } else { throw new IllegalStateException(); } } else if (numberOfObjectives == 3) { if (pType == 31) { return new double[] { Math.cos(x[0] * Math.PI / 2) * Math.cos(x[1] * Math.PI / 2), Math.cos(x[0] * Math.PI / 2) * Math.sin(x[1] * Math.PI / 2), Math.sin(x[0] * Math.PI / 2) }; } else if (pType == 32) { return new double[] { 1 - Math.cos(x[0] * Math.PI / 2) * Math.cos(x[1] * Math.PI / 2), 1 - Math.cos(x[0] * Math.PI / 2) * Math.sin(x[1] * Math.PI / 2), 1 - Math.sin(x[0] * Math.PI / 2) }; } else if (pType == 33) { return new double[] { x[0], x[1], 3 - (Math.sin(3 * Math.PI * x[0]) + Math.sin(3 * Math.PI * x[1])) - 2 * (x[0] + x[1]) }; } else if (pType == 34) { return new double[] { x[0] * x[1], x[0] * (1 - x[1]), (1 - x[0]) }; } else { throw new IllegalStateException(); } } else { throw new IllegalStateException(); } } /** * Controls the distance. */ private double betafunction(double[] x) { int dim = x.length; if (dType == 1) { double beta = 0; for (int i = 0; i < dim; i++) { beta += x[i] * x[i]; } return 2.0 * beta / dim; } else if (dType == 2) { double beta = 0; for (int i = 0; i < dim; i++) { beta += Math.sqrt(i + 1) * x[i] * x[i]; } return 2.0 * beta / dim; } else if (dType == 3) { double sum = 0; double xx; for (int i = 0; i < dim; i++) { xx = 2 * x[i]; sum += (xx * xx - Math.cos(4 * Math.PI * xx) + 1); } return 2.0 * sum / dim; } else if (dType == 4) { double sum = 0; double prod = 1; double xx; for (int i = 0; i < dim; i++) { xx = 2 * x[i]; sum += xx * xx; prod *= Math.cos(10 * Math.PI * xx / Math.sqrt(i + 1)); } return 2.0 * (sum - 2 * prod + 2) / dim; } else { throw new IllegalStateException(); } } /** * Controls the Pareto set shape for 2D instances. */ private double psfunc2(double x, double t1, int dim, int css) { dim = dim + 1; double xy = 2 * (x - 0.5); if (lType == 21) { return xy - Math.pow(t1, 0.5 * (numberOfVariables + 3 * dim - 8) / (numberOfVariables - 2)); } else if (lType == 22) { double theta = 6 * Math.PI * t1 + dim * Math.PI / numberOfVariables; return xy - Math.sin(theta); } else if (lType == 23) { double theta = 6 * Math.PI * t1 + dim * Math.PI / numberOfVariables; double ra = 0.8 * t1; if (css == 1) { return xy - ra * Math.cos(theta); } else { return xy - ra * Math.sin(theta); } } else if (lType == 24) { double theta = 6 * Math.PI * t1 + dim * Math.PI / numberOfVariables; double ra = 0.8 * t1; if (css == 1) { return xy - ra * Math.cos(theta / 3); } else { return xy - ra * Math.sin(theta); } } else if (lType == 25) { double rho = 0.8; double phi = Math.PI * t1; double theta = 6 * Math.PI * t1 + dim * Math.PI / numberOfVariables; if (css == 1) { return xy - rho * Math.sin(phi) * Math.sin(theta); } else if (css == 2) { return xy - rho * Math.sin(phi) * Math.cos(theta); } else { return xy - rho * Math.cos(phi); } } else if (lType == 26) { double theta = 6 * Math.PI * t1 + dim * Math.PI / numberOfVariables; double ra = 0.3 * t1 * (t1 * Math.cos(4 * theta) + 2); if (css == 1) { return xy - ra * Math.cos(theta); } else { return xy - ra * Math.sin(theta); } } else { throw new IllegalStateException(); } } /** * Controls the Pareto set shape for 3D instances. */ private double psfunc3(double x, double t1, double t2, int dim) { dim = dim + 1; double xy = 4 * (x - 0.5); if (lType == 31) { double rate = dim / (double)numberOfVariables; return xy - 4 * (t1 * t1 * rate + t2 * (1.0 - rate)) + 2; } else if (lType == 32) { double theta = 2 * Math.PI * t1 + dim * Math.PI / numberOfVariables; return xy - 2 * t2 * Math.sin(theta); } else { throw new IllegalStateException(); } } /** * Converts a {@code List<Double>} to a {@code double[]}. * * @param list the list to be converted * @return an array of doubles containing the values in the list */ private double[] toArray(List<Double> list) { double[] array = new double[list.size()]; for (int i = 0; i < list.size(); i++) { array[i] = list.get(i); } return array; } /** * Evaluates the decision variables and returns the objectives. */ private double[] evaluate(double[] x_var) { double[] y_obj = new double[numberOfObjectives]; if (numberOfObjectives == 2) { if ((lType == 21) || (lType == 22) || (lType == 23) || (lType == 24) || (lType == 26)) { List<Double> aa = new ArrayList<Double>(); List<Double> bb = new ArrayList<Double>(); for (int n = 1; n < numberOfVariables; n++) { if (n % 2 == 0) { aa.add(psfunc2(x_var[n], x_var[0], n, 1)); } else { bb.add(psfunc2(x_var[n], x_var[0], n, 2)); } } double g = betafunction(toArray(aa)); double h = betafunction(toArray(bb)); double[] alpha = alphafunction(x_var); y_obj[0] = alpha[0] + h; y_obj[1] = alpha[1] + g; } else if (lType == 25) { List<Double> aa = new ArrayList<Double>(); List<Double> bb = new ArrayList<Double>(); for (int n = 1; n < numberOfVariables; n++) { if (n % 3 == 0) { aa.add(psfunc2(x_var[n], x_var[0], n, 1)); } else if (n % 3 == 1) { bb.add(psfunc2(x_var[n], x_var[0], n, 2)); } else { double c = psfunc2(x_var[n], x_var[0], n, 3); if (n % 2 == 0) { aa.add(c); } else { bb.add(c); } } } double g = betafunction(toArray(aa)); double h = betafunction(toArray(bb)); double[] alpha = alphafunction(x_var); y_obj[0] = alpha[0] + h; y_obj[1] = alpha[1] + g; } else { throw new IllegalStateException(); } } else if (numberOfObjectives == 3) { if ((lType == 31) || (lType == 32)) { List<Double> aa = new ArrayList<Double>(); List<Double> bb = new ArrayList<Double>(); List<Double> cc = new ArrayList<Double>(); for (int n = 2; n < numberOfVariables; n++) { double a = psfunc3(x_var[n], x_var[0], x_var[1], n); if (n % 3 == 0) { aa.add(a); } else if (n % 3 == 1) { bb.add(a); } else { cc.add(a); } } double g = betafunction(toArray(aa)); double h = betafunction(toArray(bb)); double e = betafunction(toArray(cc)); double[] alpha = alphafunction(x_var); y_obj[0] = alpha[0] + h; y_obj[1] = alpha[1] + g; y_obj[2] = alpha[2] + e; } else { throw new IllegalStateException(); } } else { throw new IllegalStateException(); } return y_obj; } }