/* Copyright 2009-2016 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.util.weights; import java.util.ArrayList; import java.util.List; import org.apache.commons.math3.primes.Primes; /** * Generates weights according to a uniform design of mixtures using the * Hammersley low-discrepancy sequence generator. Uniform design has several * advantages over {@link NormalBoundaryIntersectionGenerator}, including * avoiding generating many weights on the boundary and avoiding the * combinatorial growth of weights as the number of objectives increases. * Tan et al. first proposed the use of uniform design to generate weights for * an MOEA, but their method becomes computationally prohibitive as the number * of objectives or number of points increases. The use of the more efficient * Hammersley method was proposed by Berenguer and Coello Coello (2015). * <p> * References: * <ol> * <li>Tan Y., Y. Jiao, H. Li, and X. Wang (2013). "MOEA/D + uniform design: * A new version of MOEA/D for optimization problems with many * objectives." Computers & Operations Research, 40, 1648-1660. * <li>Berenguer, J.A.M. and C.A. Coello Coello (2015). "Evolutionary Many- * Objective Optimization Based on Kuhn-Munkres' Algorithm." Evolutionary * Multi-Criterion Optimization: 8th International Conference, pp. 3-17. * </ol> */ public class UniformDesignGenerator implements WeightGenerator { /** * The number of objectives. */ private final int numberOfObjectives; /** * The number of weights to generate. */ private final int numberOfPoints; /** * Constructs a new weight generator based on uniform design. * * @param numberOfObjectives the number of objectives * @param numberOfPoints the number of weights to generate */ public UniformDesignGenerator(int numberOfObjectives, int numberOfPoints) { super(); this.numberOfObjectives = numberOfObjectives; this.numberOfPoints = numberOfPoints; } @Override public int size() { return numberOfPoints; } /** * Returns the first k prime numbers. * * @param k the number of prime numbers to return * @return the first k prime numbers */ protected int[] generateFirstKPrimes(int k) { int[] primes = new int[k]; primes[0] = 2; for (int i = 1; i < k; i++) { primes[i] = Primes.nextPrime(primes[i-1]); } return primes; } @Override public List<double[]> generate() { // generate uniform design using Hammersley method List<double[]> designs = new ArrayList<double[]>(); int[] primes = generateFirstKPrimes(numberOfObjectives-2); for (int i = 0; i < numberOfPoints; i++) { double[] design = new double[numberOfObjectives-1]; design[0] = (2.0*(i+1) - 1.0) / (2.0*numberOfPoints); for (int j = 1; j < numberOfObjectives-1; j++) { double f = 1.0/primes[j-1]; int d = i+1; design[j] = 0.0; while (d > 0) { design[j] += f * (d % primes[j-1]); d = d / primes[j-1]; f = f / primes[j-1]; } } designs.add(design); } // transform designs into weight vectors (sum to 1) List<double[]> weights = new ArrayList<double[]>(); for (double[] design : designs) { double[] weight = new double[numberOfObjectives]; for (int i = 1; i <= numberOfObjectives; i++) { if (i == numberOfObjectives) { weight[i-1] = 1.0; } else { weight[i-1] = 1.0 - Math.pow(design[i-1], 1.0 / (numberOfObjectives-i)); } for (int j = 1; j <= i-1; j++) { weight[i-1] *= Math.pow(design[j-1], 1.0 / (numberOfObjectives-j)); } } weights.add(weight); } return weights; } }