/* 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.CEC2009;
import org.junit.Assert;
import org.junit.Test;
import org.moeaframework.TestThresholds;
import org.moeaframework.core.Solution;
import org.moeaframework.core.operator.RandomInitialization;
import org.moeaframework.core.variable.EncodingUtils;
/**
* Tests if the {@link UF13} class (which is now an alias to {@code WFG1})
* matches the test function defined in the CEC2009 code.
*/
public class UF13Test {
@Test
public void test() {
UF13 uf13 = new UF13();
RandomInitialization initialization = new RandomInitialization(uf13,
TestThresholds.SAMPLES);
for (Solution solution : initialization.initialize()) {
double[] x = EncodingUtils.getReal(solution);
double[] f = new double[uf13.getNumberOfObjectives()];
WFG1_M5(x, f, uf13.getNumberOfVariables(),
uf13.getNumberOfObjectives());
uf13.evaluate(solution);
Assert.assertArrayEquals(f, solution.getObjectives(),
TestThresholds.SOLUTION_EPS);
}
}
/*
* The following source code is modified from the CEC 2009 test problem
* suite available at {@link http://dces.essex.ac.uk/staff/qzhang/}.
* Permission to distribute these modified source codes under the GNU
* Lesser General Public License was obtained via e-mail correspondence
* with the original authors.
*/
private static final double PI = 3.1415926535897932384626433832795;
private static final double EPSILON = 1.0e-10;
/**
* Evaluates the UF13 problem. This is the version of the code provided in
* the CEC2009 test suite.
*
* @param x the decision variables
* @param f the objective function output
* @param nx the number of decision variables
* @param M the number of objectives
*/
private static void WFG1_M5(double[] z, double[] f, int nx, int M) {
double[] y = new double[30];
double[] t1 = new double[30];
double[] t2 = new double[30];
double[] t3 = new double[30];
double[] t4 = new double[5];
int k = M == 2 ? 4 : 2 * (M - 1);
for (int i = 0; i < nx; i++) {
y[i] = z[i] / (2.0 * (i + 1));
}
for (int i = 0; i < k; i++) {
t1[i] = y[i];
}
for (int i = k; i < nx; i++) {
t1[i] = s_linear(y[i], 0.35);
}
for (int i = 0; i < k; i++) {
t2[i] = t1[i];
}
for (int i = k; i < nx; i++) {
t2[i] = b_flat(t1[i], 0.8, 0.75, 0.85);
}
for (int i = 0; i < nx; i++) {
t3[i] = b_poly(t2[i], 0.02);
}
double[] w = new double[30];
double[] y_sub = new double[30];
double[] w_sub = new double[30];
double[] y_sub2 = new double[30];
double[] w_sub2 = new double[30];
for (int i = 1; i <= nx; i++) {
w[i - 1] = 2.0 * i;
}
for (int i = 1; i <= M - 1; i++) {
int head = (i - 1) * k / (M - 1);
int tail = i * k / (M - 1);
for (int j = head; j < tail; j++) {
y_sub[j - head] = t3[j];
w_sub[j - head] = w[j];
}
t4[i - 1] = r_sum(y_sub, w_sub, tail - head);
}
for (int j = k; j < nx; j++) {
y_sub2[j - k] = t3[j];
w_sub2[j - k] = w[j];
}
t4[M - 1] = r_sum(y_sub2, w_sub2, nx - k);
int[] A = new int[5];
double[] x = new double[5];
double[] h = new double[5];
double[] S = new double[5];
A[0] = 1;
for (int i = 1; i < M - 1; i++) {
A[i] = 1;
}
for (int i = 0; i < M - 1; i++) {
double tmp1 = t4[M - 1];
if (A[i] > tmp1) {
tmp1 = A[i];
}
x[i] = tmp1 * (t4[i] - 0.5) + 0.5;
}
x[M - 1] = t4[M - 1];
for (int m = 1; m <= M - 1; m++) {
h[m - 1] = convex(x, m, M);
}
h[M - 1] = mixed(x, 5, 1.0);
for (int m = 1; m <= M; m++) {
S[m - 1] = m * 2.0;
}
for (int i = 0; i < M; i++) {
f[i] = 1.0 * x[M - 1] + S[i] * h[i];
}
}
private static double correct_to_01(double aa, double epsilon) {
double min = 0.0;
double max = 1.0;
double min_epsilon = min - epsilon;
double max_epsilon = max + epsilon;
if (aa <= min && aa >= min_epsilon) {
return min;
} else if (aa >= max && aa <= max_epsilon) {
return max;
} else {
return aa;
}
}
private static double convex(double[] x, int m, int M) {
double result = 1.0;
for (int i = 1; i <= M - m; i++) {
result *= 1.0 - Math.cos(x[i - 1] * PI / 2.0);
}
if (m != 1) {
result *= 1.0 - Math.sin(x[M - m] * PI / 2.0);
}
return correct_to_01(result, EPSILON);
}
private static double mixed(double[] x, int A, double alpha) {
double tmp = 2.0 * A * PI;
return correct_to_01(Math.pow(1.0 - x[0]
- Math.cos(tmp * x[0] + PI / 2.0) / tmp, alpha), EPSILON);
}
private static double min_double(double aa, double bb) {
return aa < bb ? aa : bb;
}
private static double b_poly(double y, double alpha) {
return correct_to_01(Math.pow(y, alpha), EPSILON);
}
private static double b_flat(double y, double A, double B, double C) {
double tmp1 = min_double(0.0, Math.floor(y - B)) * A * (B - y) / B;
double tmp2 = min_double(0.0, Math.floor(C - y)) * (1.0 - A) * (y - C)
/ (1.0 - C);
return correct_to_01(A + tmp1 - tmp2, EPSILON);
}
private static double s_linear(double y, double A) {
return correct_to_01(Math.abs(y - A) / Math.abs(Math.floor(A - y) + A),
EPSILON);
}
private static double r_sum(double[] y, double[] w, int ny) {
double numerator = 0.0;
double denominator = 0.0;
for (int i = 0; i < ny; i++) {
numerator += w[i] * y[i];
denominator += w[i];
}
return correct_to_01(numerator / denominator, EPSILON);
}
}