// WFGHV.java // // Authors: // Antonio J. Nebro <antonio@lcc.uma.es> // Juan J. Durillo <durillo@lcc.uma.es> // // Copyright (c) 2013 Antonio J. Nebro, Juan J. Durillo // // This program 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. // // This program 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 this program. If not, see <http://www.gnu.org/licenses/>. // // CREDIT // This class is based on the code of the WFG group (http://www.wfg.csse.uwa.edu.au/hypervolume/) // Copyright (C) 2010 Lyndon While, Lucas Bradstreet. package jmetal.qualityIndicator.fastHypervolume.wfg; import jmetal.core.Solution; import jmetal.core.SolutionSet; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; /** * Created with IntelliJ IDEA. * User: Antonio J. Nebro * Date: 25/07/13 * Time: 17:50 * To change this template use File | Settings | File Templates. */ public class WFGHV { Front [] fs_ ; Point referencePoint_ ; boolean maximizing_ ; int currentDeep_ ; int currentDimension_ ; int maxNumberOfPoints_ ; int maxNumberOfObjectives_ ; final int OPT = 2 ; Comparator pointComparator_; public WFGHV(int dimension, int maxNumberOfPoints) { referencePoint_ = null ; maximizing_ = false ; currentDeep_ = 0 ; currentDimension_ = dimension ; maxNumberOfPoints_ = maxNumberOfPoints ; maxNumberOfObjectives_ = dimension ; pointComparator_ = new PointComparator(true) ; int maxd = maxNumberOfPoints_ - (OPT /2 + 1) ; fs_ = new Front[maxd] ; for (int i = 0; i < maxd; i++) { fs_[i] = new Front(maxNumberOfPoints, dimension) ; } } public WFGHV(int dimension, int maxNumberOfPoints, Solution referencePoint) { referencePoint_ = new Point(referencePoint) ; maximizing_ = false ; currentDeep_ = 0 ; currentDimension_ = dimension ; maxNumberOfPoints_ = maxNumberOfPoints ; maxNumberOfObjectives_ = dimension ; pointComparator_ = new PointComparator(true) ; int maxd = maxNumberOfPoints_ - (OPT /2 + 1) ; fs_ = new Front[maxd] ; for (int i = 0; i < maxd; i++) { fs_[i] = new Front(maxNumberOfPoints, dimension) ; } } public WFGHV(int dimension, int maxNumberOfPoints, Point referencePoint) { referencePoint_ = referencePoint ; maximizing_ = false ; currentDeep_ = 0 ; currentDimension_ = dimension ; maxNumberOfPoints_ = maxNumberOfPoints ; maxNumberOfObjectives_ = dimension ; pointComparator_ = new PointComparator(true) ; int maxd = maxNumberOfPoints_ - (OPT /2 + 1) ; fs_ = new Front[maxd] ; for (int i = 0; i < maxd; i++) { fs_[i] = new Front(maxNumberOfPoints, dimension) ; } } public int getLessContributorHV(SolutionSet set) { Front wholeFront = new Front(); wholeFront.loadFront(set, -1); int index= 0; double contribution = Double.POSITIVE_INFINITY; for (int i = 0; i < set.size(); i++) { double [] v = new double[set.get(i).getNumberOfObjectives()]; for (int j = 0; j < v.length; j++){ v[j] = set.get(i).getObjective(j); } Point p = new Point(v); double aux = this.getExclusiveHV(wholeFront, i); if ((aux) < contribution) { index = i; contribution = aux; } set.get(i).setCrowdingDistance(aux); } return index; } public double getHV(Front front, Solution referencePoint) { referencePoint_ = new Point(referencePoint) ; double volume = 0.0 ; sort(front) ; if (currentDimension_ == 2) volume = get2DHV(front) ; else { volume = 0.0 ; currentDimension_ -- ; for (int i = front.nPoints_-1; i >= 0; i--) { volume += Math.abs(front.getPoint(i).objectives_[currentDimension_] - referencePoint_.objectives_[currentDimension_])* this.getExclusiveHV(front, i) ; } currentDimension_ ++ ; } return volume ; } public double getHV(Front front) { double volume = 0.0 ; sort(front) ; if (currentDimension_ == 2) volume = get2DHV(front) ; else { volume = 0.0 ; currentDimension_ -- ; for (int i = front.nPoints_-1; i >= 0; i--) { volume += Math.abs(front.getPoint(i).objectives_[currentDimension_] - referencePoint_.objectives_[currentDimension_])* this.getExclusiveHV(front, i) ; } currentDimension_ ++ ; } return volume ; } public double get2DHV(Front front) { double hv = 0.0 ; hv = Math.abs((front.getPoint(0).getObjectives()[0] - referencePoint_.objectives_[0]) * (front.getPoint(0).getObjectives()[1] - referencePoint_.objectives_[1])) ; for (int i = 1; i < front.nPoints_; i++) { hv += Math.abs((front.getPoint(i).getObjectives()[0] - referencePoint_.objectives_[0]) * (front.getPoint(i).getObjectives()[1] - front.getPoint(i-1).getObjectives()[1])) ; } return hv ; } public double getInclusiveHV(Point p) { double volume = 1 ; for (int i = 0; i < currentDimension_; i++) { volume *= Math.abs(p.objectives_[i] - referencePoint_.objectives_[i]) ; } return volume ; } public double getExclusiveHV(Front front, int point) { double volume ; volume = getInclusiveHV(front.getPoint(point)) ; if (front.nPoints_ > point + 1) { makeDominatedBit(front, point); double v = getHV(fs_[currentDeep_-1]) ; volume -= v ; currentDeep_ -- ; } return volume ; } public void makeDominatedBit(Front front, int p) { int z = front.nPoints_ - 1 - p ; for (int i = 0 ; i < z ; i++) for (int j = 0 ; j < currentDimension_; j++) { fs_[currentDeep_].getPoint(i).objectives_[j] = worse(front.points_[p].objectives_[j], front.points_[p+1+i].objectives_[j], false) ; } Point t ; fs_[currentDeep_].nPoints_ = 1 ; for (int i = 1; i < z; i++) { int j = 0 ; boolean keep = true ; while (j < fs_[currentDeep_].nPoints_ && keep) { switch (dominates2way(fs_[currentDeep_].points_[i], fs_[currentDeep_].points_[j])) { case -1: t = fs_[currentDeep_].points_[j] ; fs_[currentDeep_].nPoints_--; fs_[currentDeep_].points_[j] = fs_[currentDeep_].points_[fs_[currentDeep_].nPoints_]; fs_[currentDeep_].points_[fs_[currentDeep_].nPoints_] = t; break; case 0: j++; break; // case 2: printf("Identical points!\n"); default: keep = false; } } if (keep) {t = fs_[currentDeep_].points_[fs_[currentDeep_].nPoints_]; fs_[currentDeep_].points_[fs_[currentDeep_].nPoints_] = fs_[currentDeep_].points_[i]; fs_[currentDeep_].points_[i] = t; fs_[currentDeep_].nPoints_++; } } currentDeep_++ ; } private double worse (double x, double y, boolean maximizing) { double result ; if (maximizing) { if (x > y) result = y ; else result = x ; } else { if (x > y) result = x ; else result = y ; } return result ; } int dominates2way(Point p, Point q) // returns -1 if p dominates q, 1 if q dominates p, 2 if p == q, 0 otherwise // ASSUMING MINIMIZATION { // domination could be checked in either order for (int i = currentDimension_ - 1; i >= 0; i--) if (p.objectives_[i] < q.objectives_[i]){ for (int j = i - 1; j >= 0; j--) if (q.objectives_[j] < p.objectives_[j]) return 0; return -1; } else if (q.objectives_[i] < p.objectives_[i]){ for (int j = i - 1; j >= 0; j--) if (p.objectives_[j] < q.objectives_[j]) return 0; return 1; } return 2; } public void sort(Front front) { Arrays.sort(front.points_, 0, front.nPoints_, pointComparator_); } public static void main(String args[]) throws IOException { Front front = new Front() ; if (args.length == 0) { System.out.println("Usage: WFGHV front [reference point]") ; System.exit(-1) ; } if (args.length > 0) { front.readFront(args[0]); } int dimensions = front.getNumberOfObjectives() ; Point referencePoint ; double [] points = new double[dimensions] ; if (args.length == (dimensions + 1)) { for (int i = 1; i <= dimensions; i++) points[i-1] = Double.parseDouble(args[i]) ; } else { for (int i = 1; i <= dimensions; i++) points[i-1] = 0.0 ; } referencePoint = new Point(points) ; System.out.println("Using reference point: " + referencePoint) ; WFGHV wfghv = new WFGHV(referencePoint.getNumberOfObjectives(), front.getNumberOfPoints(), referencePoint) ; System.out.println("hv = " + wfghv.getHV(front)) ; } }