├── .github └── workflows │ └── ci.yml ├── .gitignore ├── HOY ├── hoy.cpp └── makefile ├── HV ├── Hypervolume_MEX.c ├── LICENSE ├── Makefile ├── Makefile.lib ├── README ├── getrusage.c ├── hv.c ├── hv.h ├── io.c ├── io.h ├── main-hv.c ├── mk │ ├── Darwin_i386_cc.mk │ ├── Darwin_i386_gcc-4.2.mk │ ├── Linux_x86_64_icc.mk │ ├── Linux_x86_64_pathcc.mk │ ├── Linux_x86_64_pgcc.mk │ ├── Linux_x86_64_suncc.mk │ ├── README │ ├── cc.mk │ ├── gcc.mk │ ├── icc.mk │ ├── pgcc.mk │ └── suncc.mk ├── resource.h ├── svn_version ├── timer.c └── timer.h ├── README.md └── WFG ├── CHANGELOG.TXT ├── LICENSE ├── README.TXT ├── avl.c ├── avl.h ├── makefile ├── read.c ├── wfg.c └── wfg.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, workflow_dispatch] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up JDK 17 13 | uses: actions/setup-java@v4 14 | with: 15 | java-version: 17 16 | distribution: zulu 17 | - name: Compile HOY 18 | run: | 19 | cd HOY 20 | make 21 | - name: Compile WFG 22 | run: | 23 | cd WFG 24 | make 25 | - name: Compile HV 26 | run: | 27 | pushd HV 28 | make 29 | - name: Download and setup MOEA Framework 30 | run: | 31 | # ** Use the following to setup the latest release version ** 32 | VERSION=$(curl https://api.github.com/repos/MOEAFramework/MOEAFramework/releases/latest | jq '.tag_name' | grep -oEi '[0-9]+\.[0-9]+(\.[0-9]+)?') 33 | wget https://github.com/MOEAFramework/MOEAFramework/releases/download/v${VERSION}/MOEAFramework-${VERSION}.tar.gz 34 | tar -xzf MOEAFramework-${VERSION}.tar.gz 35 | mv MOEAFramework-${VERSION} MOEAFramework-Latest 36 | 37 | # ** Use the following to setup the latest master version ** 38 | #git clone http://github.com/MOEAFramework/MOEAFramework 39 | #cd MOEAFramework 40 | #VERSION=$(cat META-INF/build.properties | awk '{split($0,a,"="); if (a[1]=="version") print tolower(a[2])}' | tr -d '[:space:]') 41 | #ant package-binary 42 | #cd dist 43 | #tar -xzf MOEAFramework-${VERSION}.tar.gz 44 | #mv MOEAFramework-${VERSION} ../../MOEAFramework-Latest 45 | - name: Setup executables 46 | run: | 47 | mv WFG/wfg2 MOEAFramework-Latest 48 | mv HOY/hoy MOEAFramework-Latest 49 | mv HV/hv MOEAFramework-Latest 50 | - name: Run timings 51 | run: | 52 | cd MOEAFramework-Latest 53 | 54 | trials=1 55 | inputs=(DTLZ2.2D.pf DTLZ2.3D.pf DTLZ2.4D.pf DTLZ2.6D.pf DTLZ2.8D.pf) 56 | 57 | function test() { 58 | ts=$(date +%s%N) 59 | eps=0.01 60 | 61 | if echo "$input" | grep ".4D." > /dev/null; then 62 | eps=0.05 63 | elif echo "$input" | grep ".6D." > /dev/null; then 64 | eps=0.1 65 | elif echo "$input" | grep ".8D." > /dev/null; then 66 | eps=0.25 67 | fi 68 | 69 | for i in $(seq 1 $trials) 70 | do 71 | hv=$(java -cp ".:lib/*" org.moeaframework.analysis.tools.SetHypervolume -e "$eps" "./pf/$1") 72 | done 73 | 74 | et=$((($(date +%s%N) - $ts)/1000000)) 75 | echo " $hv ($et ms)" 76 | } 77 | 78 | function test_all() { 79 | for input in ${inputs[@]} 80 | do 81 | test "$input" 82 | done 83 | } 84 | 85 | echo "Built-in (WFG)..." 86 | printf "" > moeaframework.properties 87 | test_all 88 | 89 | #echo "" 90 | #echo "Built-in (PISA)..." 91 | #printf "org.moeaframework.core.indicator.hypervolume = PISAHypervolume" > moeaframework.properties 92 | #test_all 93 | 94 | echo "" 95 | echo "WFG (Variant 2)..." 96 | printf "org.moeaframework.core.indicator.hypervolume = ./wfg2 {2}\norg.moeaframework.core.indicator.hypervolume_inverted = true" > moeaframework.properties 97 | test_all 98 | 99 | # Need to investigate, this is taking really long and something might have broke... 100 | #echo "" 101 | #echo "HOY..." 102 | #printf "org.moeaframework.core.indicator.hypervolume = ./hoy {0} {1} {2} {3}\norg.moeaframework.core.indicator.hypervolume_inverted = false" > moeaframework.properties 103 | #test_all 104 | 105 | echo "" 106 | echo "HV..." 107 | printf "org.moeaframework.core.indicator.hypervolume = ./hv {2}\norg.moeaframework.core.indicator.hypervolume_inverted = true" > moeaframework.properties 108 | test_all 109 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.exe 3 | wfg0 4 | wfg1 5 | wfg2 6 | wfg3 7 | hoy 8 | -------------------------------------------------------------------------------- /HOY/hoy.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------- 2 | 3 | Copyright (c) 2006 4 | Nicola Beume 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | 19 | --------------------------------------------------------------------- 20 | 21 | This program calculates the dominated hypervolume or S-metric of a 22 | set of d-dimensional points (d>=3). Please refer to the following 23 | publication for a description of the algorithm: 24 | 25 | Nicola Beume and Guenter Rudolph. 26 | Faster S-Metric Calculation by Considering Dominated Hypervolume 27 | as Klee's Measure Problem. 28 | In: B. Kovalerchuk (ed.): Proceedings of the Second IASTED 29 | Conference on Computational Intelligence (CI 2006), pp. 231-236. 30 | ACTA Press: Anaheim, 2006. 31 | 32 | Extended version published as: 33 | Technical Report of the Collaborative Research Centre 531 34 | 'Computational Intelligence', CI-216/06, ISSN 1433-3325. 35 | University of Dortmund, July 2006. 36 | 37 | -------------------------------------------------------------------*/ 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include // for calculation of trellis 47 | #include 48 | 49 | using namespace std; 50 | 51 | 52 | 53 | /* function invoked by main */ 54 | void stream(double regLow[], double regUp[], const vector& cubs, int lev, double cov); 55 | bool cmp(double* a, double* b); 56 | /* function invoked by stream */ 57 | /* 58 | inline bool cmp(double* a, double* b); 59 | inline bool covers(const double* cub, const double regLow[]); 60 | inline bool partCovers(const double* cub, const double regUp[]); 61 | inline int containsBoundary(const double* cub, const double regLow[], const int split); 62 | inline double getMeasure(const double regLow[], const double regUp[]); 63 | inline int isPile(const double* cub, const double regLow[], const double regUp[]); 64 | inline double computeTrellis(const double regLow[], const double regUp[], const double trellis[]); 65 | inline double getMedian(vector& bounds); 66 | */ 67 | 68 | 69 | /* global variables */ 70 | static int dataNumber; 71 | static int dimension; 72 | static double dSqrtDataNumber; 73 | static double volume; 74 | 75 | 76 | int main(int argc, char *argv[]) 77 | { 78 | /* 79 | * arguments are: 80 | * dimension of input data points 81 | * number of input data points 82 | * file name of input data 83 | * file name of reference point 84 | */ 85 | 86 | int i,j; 87 | 88 | /* check parameters */ 89 | if (argc < 4) { 90 | fprintf(stderr, "usage: hoy \n"); 91 | exit(1); 92 | } 93 | sscanf(argv[1], "%d", &dimension); 94 | if (dimension < 3) { 95 | fprintf(stderr, "invalid argument\n"); 96 | exit(1); 97 | } 98 | sscanf(argv[2], "%d", &dataNumber); 99 | char *filenameData = argv[3]; 100 | char *filenameRef = argv[4]; 101 | 102 | /* read in data */ 103 | char word[30]; 104 | 105 | // read in data file 106 | ifstream fileData; 107 | fileData.open(filenameData, ios::in); 108 | if (!fileData.good()){ 109 | printf("data file not found \n"); 110 | exit(0); 111 | } 112 | 113 | static vector pointsInitial(dataNumber); 114 | for (int n=0; n> word; 118 | pointsInitial[n][i] = atof(word); 119 | } 120 | } 121 | fileData.close(); 122 | 123 | // read in reference point 124 | static double* refPoint = new double[dimension]; 125 | ifstream fileRef; 126 | fileRef.open(filenameRef, ios::in); 127 | if (!fileRef.good()){ 128 | printf("reference point file not found \n"); 129 | exit(0); 130 | } 131 | for (i=0; i> word; 133 | refPoint[i] = atof(word); 134 | } 135 | fileRef.close(); 136 | 137 | // initialize volume 138 | volume = 0.0; 139 | // sqrt of dataNumber 140 | dSqrtDataNumber = sqrt((double)dataNumber); 141 | 142 | // initialize region 143 | double* regionLow = new double[dimension-1]; 144 | double* regionUp = new double[dimension-1]; 145 | for (j=0; j regLow[i]) { 180 | return false; 181 | } 182 | } 183 | return true; 184 | } 185 | 186 | 187 | inline bool partCovers(const double* cub, const double regUp[]) { 188 | static int i; 189 | for (i=0; i= regUp[i]) { 191 | return false; 192 | } 193 | } 194 | return true; 195 | } 196 | 197 | 198 | inline int containsBoundary(const double* cub, const double regLow[], const int split) { 199 | // condition only checked for split>0 200 | if (regLow[split] >= cub[split]){ 201 | // boundary in dimension split not contained in region, thus 202 | // boundary is no candidate for the splitting line 203 | return -1; 204 | } 205 | else { 206 | static int j; 207 | for (j=0; j regLow[k]) { 239 | if (pile != dimension) { 240 | // second dimension occured that is not completely covered 241 | // ==> cuboid is no pile 242 | return -1; 243 | } 244 | pile = k; 245 | } 246 | } 247 | // if pile == this.dimension then 248 | // cuboid completely covers region 249 | // case is not possible since covering cuboids have been removed before 250 | 251 | // region in only one dimenison not completly covered 252 | // ==> cuboid is a pile 253 | return pile; 254 | } 255 | 256 | 257 | 258 | inline double computeTrellis(const double regLow[], const double regUp[], const double trellis[]) { 259 | 260 | static int i,j; 261 | static double vol; 262 | static int numberSummands; 263 | static double summand; 264 | static bitset<16> bitvector; 265 | 266 | vol= 0.0; 267 | summand = 0.0; 268 | numberSummands = 0; 269 | 270 | // calculate number of summands 271 | static bitset<16> nSummands; 272 | for (i=0; i& bounds) { 349 | // do not filter duplicates 350 | static unsigned int i; 351 | if (bounds.size()==1) { 352 | return bounds[0]; 353 | } 354 | else if (bounds.size()==2) { 355 | return bounds[1]; 356 | } 357 | vector::iterator median; 358 | median = bounds.begin(); 359 | for(i=0;i<=bounds.size()/2;i++){ 360 | median++; 361 | } 362 | partial_sort(bounds.begin(),median,bounds.end()); 363 | return bounds[bounds.size()/2]; 364 | } 365 | 366 | 367 | 368 | // recursive calculation of hypervolume 369 | inline void stream(double regionLow[], double regionUp[], const vector& points, int split, double cover) { 370 | 371 | //--- init --------------------------------------------------------------// 372 | 373 | static double coverOld; 374 | coverOld = cover; 375 | unsigned int coverIndex = 0; 376 | static int c; 377 | 378 | //--- cover -------------------------------------------------------------// 379 | 380 | // identify first covering cuboid 381 | double dMeasure = getMeasure(regionLow, regionUp); 382 | while (cover == coverOld && coverIndex < points.size()) { 383 | if ( covers(points[coverIndex], regionLow) ) { 384 | // new cover value 385 | cover = points[coverIndex][dimension-1]; 386 | volume += dMeasure * (coverOld - cover); 387 | } 388 | else coverIndex++; 389 | } 390 | 391 | /* coverIndex shall be the index of the first point in points which 392 | * is ignored in the remaining process 393 | * 394 | * It may occur that that some points in front of coverIndex have the same 395 | * d-th coordinate as the point at coverIndex. This points must be discarded 396 | * and therefore the following for-loop checks for this points and reduces 397 | * coverIndex if necessary. 398 | */ 399 | for (c=coverIndex; c>0; c--) { 400 | if (points[c-1][dimension-1] == cover) { 401 | coverIndex--; 402 | } 403 | } 404 | 405 | // abort if points is empty 406 | if (coverIndex == 0) { 407 | return; 408 | } 409 | // Note: in the remainder points is only considered to index coverIndex 410 | 411 | 412 | 413 | //--- allPiles ---------------------------------------------------------// 414 | 415 | bool allPiles = true; 416 | unsigned int i; 417 | 418 | static int* piles = new int[coverIndex]; 419 | for (i = 0; i boundaries; 472 | vector noBoundaries; 473 | 474 | do { 475 | for (i=0; i 0) { 485 | bound = getMedian(boundaries); 486 | //bound = getRandom(boundaries); 487 | } 488 | else if (noBoundaries.size() > dSqrtDataNumber) { 489 | bound = getMedian(noBoundaries); 490 | //bound = getRandom(noBoundaries); 491 | } 492 | else { 493 | split++; 494 | } 495 | } while (bound == -1.0); 496 | 497 | double dLast; 498 | vector pointsChild; 499 | pointsChild.reserve(coverIndex); 500 | 501 | // left child 502 | // reduce maxPoint 503 | dLast = regionUp[split]; 504 | regionUp[split] = bound; 505 | for (i=0; i 122 | #include 123 | #include 124 | 125 | # include "hv.h" 126 | #include "mex.h" 127 | 128 | #if !defined(TRUE) || !defined(FALSE) 129 | #define TRUE 1 130 | #define FALSE 0 131 | #endif 132 | 133 | 134 | #define MALLOC mxMalloc 135 | 136 | /*#define DEBUG*/ 137 | 138 | void version(void) 139 | { 140 | printf( 141 | "\nCopyright (C) 2009" 142 | "\nMEX Interface created by Guillaume Jacquenot" 143 | "\n(guillaume.jacquenot@gmail.com)" 144 | "\n" 145 | "\nbased on previous hypervolume software" 146 | "\n" 147 | "\nCopyright (C) 2006" 148 | "\nCarlos M. Fonseca, Manuel Lopez-Ibanez and Luis Paquete\n" 149 | "\n" 150 | "This is free software, and you are welcome to redistribute it under certain\n" 151 | "conditions. See the GNU General Public License for details. There is NO \n" 152 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" 153 | "\n" ); 154 | } 155 | 156 | 157 | 158 | void description(void) 159 | { 160 | printf( 161 | "\nThis program implements a recursive, dimension-sweep algorithm for " 162 | "\ncomputing the hypervolume indicator of the quality of a set of n " 163 | "\nnon-dominated points in d dimensions. It also incorporates a " 164 | "\nrecent result for the three-dimensional special case. The proposed " 165 | "\nalgorithm achieves O(n^{d-2} log n) time and linear space complexity " 166 | "\nin the worst-case, but experimental results show that the pruning " 167 | "\ntechniques used may reduce the time complexity even further. " 168 | "\n " 169 | "\nRelevant literature: " 170 | "\n " 171 | "\n[1] Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An " 172 | "\n improved dimension-sweep algorithm for the hypervolume " 173 | "\n indicator. In IEEE Congress on Evolutionary Computation, pages " 174 | "\n 1157-1163, Vancouver, Canada, July 2006. " 175 | "\n[2] Nicola Beume, Carlos M. Fonseca, Manuel Lopez-Ibanez, Luis " 176 | "\n Paquete, and J. Vahrenhold. On the complexity of computing the " 177 | "\n hypervolume indicator. IEEE Transactions on Evolutionary " 178 | "\n Computation, 13(5):1075–1082, 2009. " 179 | "\n" 180 | "\n" 181 | "\n\n\n "); 182 | } 183 | 184 | 185 | void help(void) 186 | { 187 | mexPrintf("\nHypervolume computation"); 188 | mexPrintf("\nThis function computes the hypervolume value for a set of points in d-dimension."); 189 | mexPrintf("\nAll objectives are considered to be minimized."); 190 | mexPrintf("\nPoints don't have to non-dominated points."); 191 | mexPrintf("\nThis function takes two arguments, the second is optional"); 192 | mexPrintf("\n\tThe first one is the matrix of points"); 193 | mexPrintf("\n\t\tIt contains n rows for the different points"); 194 | mexPrintf("\n\t\tand m columns for the dimension of the points."); 195 | mexPrintf("\n\tThe second argument is a m-dimension vector containing "); 196 | mexPrintf("\n\tthe coordinate of the reference point"); 197 | mexPrintf("\n\tIf not provided, the evaluated Nadir point taken as the maximum"); 198 | mexPrintf("\n\tvalue on all objectives is considered as the reference point."); 199 | mexPrintf("\nThe function is called like this:"); 200 | mexPrintf("\n\tHV = Hypervolume_MEX(Objectives);"); 201 | mexPrintf("\n\tHV = Hypervolume_MEX(Objectives,Reference_point);"); 202 | mexPrintf("\n\n"); 203 | description(); 204 | version(); 205 | mexPrintf("%%2D Example;\n"); 206 | mexPrintf("\tn = 200;\n"); 207 | mexPrintf("\ttheta = linspace(-3*pi/2,-pi,n)';\n"); 208 | mexPrintf("\tFP = [1+cos(theta) 1-sin(theta)];\n"); 209 | mexPrintf("\tRes = Hypervolume_MEX(FP,[1 1])\n"); 210 | mexPrintf("\tdisp('This result tends to pi/4=0.7854 when n goes to infinity');\n\n"); 211 | mexPrintf("%%3D Example;\n"); 212 | mexPrintf("\tn = 50;\n"); 213 | mexPrintf("\t[X,Y] = meshgrid([0:1/n:1]);\n"); 214 | mexPrintf("\tX=X(:);Y=Y(:);\n"); 215 | mexPrintf("\tR = X.^2+Y.^2;\n"); 216 | mexPrintf("\tInd = R<=1;\n"); 217 | mexPrintf("\tXX=X(Ind);\n"); 218 | mexPrintf("\tYY=Y(Ind);\n"); 219 | mexPrintf("\tZZ=sqrt(1-R(Ind));\n"); 220 | mexPrintf("\tRes = Hypervolume_MEX([XX,YY,ZZ],[1 1 1])\n"); 221 | mexPrintf("\tdisp('This result tends to 1-pi/6=0.4764 when n goes to infinity');\n"); 222 | mexPrintf("\tscatter3(XX,YY,ZZ);\n"); 223 | } 224 | 225 | double * data_maximum(double *data, int nobj, int rows) 226 | { 227 | double *vector; 228 | int n, r, k; 229 | 230 | vector = MALLOC(nobj*sizeof(double)); 231 | 232 | for (k = 0; k < nobj; k++) 233 | vector[k] = data[k]; 234 | 235 | for (r = 1 ; r < rows; r++) { 236 | for (n = 0; n < nobj; n++, k++) { 237 | if (vector[n] < data[k] ) 238 | vector[n] = data[k]; 239 | } 240 | } 241 | return vector; 242 | } 243 | 244 | 245 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 246 | { 247 | int nobj; /* Number of objectives */ 248 | int popsize; /* Number of solutions */ 249 | 250 | double *MatLab_Obj; /* Pointer to the objective matrix */ 251 | 252 | double *reference; /* Reference vector*/ 253 | double *data; /* Reshaped vector of MatLab_Obj */ 254 | double *volume = 0; /* Hypervolume computation */ 255 | 256 | int i,j,k; 257 | if ((nrhs==0)||mxIsChar(prhs[0])) 258 | { 259 | help(); 260 | return; 261 | } 262 | if (!mxIsNumeric(prhs[0])) 263 | mexErrMsgTxt("Data points must be a numeric matrix."); 264 | nobj = mxGetN(prhs[0]); 265 | popsize = mxGetM(prhs[0]); 266 | #ifdef DEBUG 267 | mexPrintf("nobj=%d\n",nobj); 268 | mexPrintf("popsize=%d\n",popsize); 269 | #endif 270 | MatLab_Obj = mxGetPr(prhs[0]); 271 | 272 | /* Transpose the objective matrice*/ 273 | data = MALLOC(nobj*popsize*sizeof(double)); 274 | k = 0; 275 | for (i=0;i 10 | # Manuel Lopez-Ibanez 11 | # Luis Paquete 12 | # 13 | # This program is free software (software libre); you can redistribute 14 | # it and/or modify it under the terms of the GNU General Public 15 | # License as published by the Free Software Foundation; either 16 | # version 2 of the License, or (at your option) any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, but 19 | # WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | # General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License 24 | # along with this program; if not, you can obtain a copy of the GNU 25 | # General Public License at: 26 | # http://www.gnu.org/copyleft/gpl.html 27 | # or by writing to: 28 | # Free Software Foundation, Inc., 59 Temple Place, 29 | # Suite 330, Boston, MA 02111-1307 USA 30 | # 31 | #----------------------------------------------------------------------- 32 | 33 | ## Default to no debugging info 34 | DEBUG ?= 0 35 | S= 36 | 37 | ## Quiet / verbose output: 38 | ifneq ($(findstring $(MAKEFLAGS),s),s) 39 | ifdef S 40 | QUIET_CC = @echo ' ' CC $@; 41 | QUIET_AR = @echo ' ' AR $@; 42 | QUIET_LINK = @echo ' ' LINK $@; 43 | QUIET_RM = @echo ' ' RM $@; 44 | ECHO = 45 | else 46 | ECHO = @echo "$(1)" 47 | endif 48 | endif 49 | 50 | uname_S := $(shell gcc -dumpmachine 2>&1) 51 | uname_S := $(subst MINGW,mingw,$(uname_S)) 52 | ifneq (,$(findstring mingw,$(uname_S))) 53 | RM=-del /Q 54 | CC=gcc 55 | uname_S :=mingw 56 | else 57 | ## Detect system and machine type: 58 | uname_S :=$(shell uname -s || echo unknown) 59 | uname_M :=$(shell uname -m || echo unknown) 60 | 61 | ## Do we have svnversion? 62 | ifeq ($(shell sh -c 'which svnversion 1> /dev/null 2>&1 && echo y'),y) 63 | ## Is this a working copy? 64 | ifneq ($(shell sh -c 'LC_ALL=C svnversion -n .'),exported) 65 | $(shell sh -c 'svnversion -n . > svn_version') 66 | endif 67 | endif 68 | ## Set version information: 69 | SVN_REV = $(shell sh -c 'cat svn_version 2> /dev/null') 70 | endif 71 | 72 | 73 | ## Define source files 74 | SRCS = main-hv.c io.c timer.c 75 | HDRS = io.h timer.h 76 | OBJS = $(SRCS:.c=.o) 77 | 78 | DIST_SRC_FILES = Makefile Makefile.lib mk/README mk/*.mk \ 79 | README LICENSE \ 80 | Hypervolume_MEX.c svn_version \ 81 | getrusage.c resource.h $(SRCS) $(HDRS) \ 82 | $(HV_SRCS) $(HV_HDRS) 83 | 84 | DIST_SRC = hv-$(VERSION)-src 85 | 86 | ################################################################################ 87 | ## Configure the compiler / linker: 88 | 89 | ## Global list of CPP flags 90 | CPPFLAGS = -D DEBUG=$(DEBUG) -D VERSION='"$(VERSION)"' 91 | 92 | ifneq ($(DEBUG), 0) 93 | CPPFLAGS += -DMALLOC_CHECK_=3 94 | endif 95 | ifneq ($(uname_S),Cygwin) 96 | CPPFLAGS += -D_GNU_SOURCE 97 | else 98 | CPPFLAGS += -U_GNU_SOURCE 99 | endif 100 | 101 | ifdef march 102 | MARCH=$(march) 103 | endif 104 | 105 | ## Matlab extension compiler 106 | MEX=mex 107 | 108 | ## Define optimizing CFLAGS based on compiler and operating system 109 | ifndef OPT_CFLAGS 110 | -include mk/$(uname_S)_$(uname_M)_$(CC).mk 111 | ## Include failed or could not find optimizing CFLAGS, try compiler include 112 | ifndef OPT_CFLAGS 113 | -include mk/$(CC).mk 114 | ## Still no OPT_CFLAGS, see if gcc variant 115 | ifndef OPT_CFLAGS 116 | ifneq ($(findstring gcc,$(CC)),) 117 | $(warning Unknown C compiler. Assuming a GCC variant.) 118 | -include mk/gcc.mk 119 | endif 120 | endif 121 | endif 122 | endif 123 | 124 | ifeq ($(uname_S),mingw) 125 | SRCS += getrusage.c 126 | HDRS += resource.h 127 | endif 128 | 129 | 130 | ## With DEBUG > 0, OPT_CFLAGS may indeed be undefined. 131 | ifeq ($(DEBUG),0) 132 | ifndef OPT_CFLAGS 133 | $(error No optimizing CFLAGS set. Please manually specify OPT_CFLAGS. \ 134 | Alternatively you can create a file named 'mk/$(uname_S)_$(uname_M)_$(CC).mk' \ 135 | and place all compiler flag configuration directives in this file) 136 | endif 137 | endif 138 | 139 | ifdef ARCH 140 | CPPFLAGS += -DARCH='"$(ARCH)"' 141 | endif 142 | 143 | ## Collect all flags for compiler in one variable 144 | ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) $(OPT_CFLAGS) 145 | ALL_LDFLAGS = $(LDFLAGS) $(OPT_LDFLAGS) 146 | 147 | #---------------------------------------------------------------------- 148 | .PHONY: all clean dist test default mex 149 | .NOTPARALLEL: 150 | #---------------------------------------------------------------------- 151 | default: hv 152 | 153 | all: clean hv 154 | 155 | clean: 156 | $(call ECHO,---> Removing hv <---) 157 | @$(RM) hv 158 | $(call ECHO,---> Removing object files <---) 159 | @$(RM) $(OBJS) $(HV_OBJS) 160 | $(call ECHO,---> Removing $(HV_LIB) <---) 161 | @$(RM) $(HV_LIB) 162 | $(call ECHO,---> Removing backup files <---) 163 | @$(RM) *~ 164 | 165 | dist : DEBUG=0 166 | dist : CDEBUG= 167 | dist : all 168 | @(rm -f ../$(DIST_SRC).tar.gz && mkdir -p ../$(DIST_SRC) \ 169 | && rsync -rlpC --relative --exclude=.svn $(DIST_SRC_FILES) ../$(DIST_SRC)/ \ 170 | && cd .. \ 171 | && tar cf - $(DIST_SRC) | gzip -f9 > $(DIST_SRC).tar.gz \ 172 | && rm -rf ./$(DIST_SRC)/* && rmdir ./$(DIST_SRC)/ \ 173 | && echo "$(DIST_SRC).tar.gz created." && cd $(PWD) ) 174 | 175 | test: all 176 | @if test -d ../test; then \ 177 | cd ../test/ && ./regtest.pl $(PWD)/hv && cd $(PWD); \ 178 | else \ 179 | echo "Error: Testsuite not found in $(PWD)/../test/";\ 180 | exit 1; \ 181 | fi 182 | 183 | #---------------------------------------------------------------------- 184 | # Include actual HV code: 185 | include Makefile.lib 186 | 187 | #---------------------------------------------------------------------- 188 | # Targets: 189 | hv: $(OBJS) $(HV_LIB) 190 | $(call ECHO,---> Building $@ version $(VERSION) <---) 191 | $(QUIET_LINK)$(CC) $(ALL_LDFLAGS) -o $@ $^ 192 | 193 | hv.ps: hv.c 194 | a2ps -E -g -o hv.ps hv.c 195 | 196 | #---------------------------------------------------------------------- 197 | # Rules: 198 | %.o: %.c 199 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< 200 | 201 | 202 | #---------------------------------------------------------------------- 203 | # Dependencies: 204 | main-hv.o: $(HV_HDRS) timer.h io.h 205 | timer.o: timer.h 206 | io.o: io.h 207 | 208 | mex: Hypervolume_MEX.c $(HV_SRCS) 209 | $(MEX) $(MEXFLAGS) -DVARIANT=$(VARIANT) $^ 210 | -------------------------------------------------------------------------------- /HV/Makefile.lib: -------------------------------------------------------------------------------- 1 | # -*- Makefile-gmake -*- 2 | VARIANT ?= 4 3 | 4 | HV_SRCS = hv.c 5 | HV_HDRS = hv.h 6 | HV_OBJS = $(HV_SRCS:.c=.o) 7 | HV_LIB = fpli_hv.a 8 | 9 | $(HV_LIB): $(HV_OBJS) 10 | @$(RM) $@ 11 | $(QUIET_AR)$(AR) rcs $@ $^ 12 | 13 | ## Augment CFLAGS for hv.[co] objects 14 | hv.o: CPPFLAGS += -D VARIANT=$(VARIANT) 15 | 16 | ## Dependencies: 17 | $(HV_OBJS): $(HV_HDRS) 18 | -------------------------------------------------------------------------------- /HV/README: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------- 2 | Computation of the Hypervolume 3 | 4 | Carlos M. Fonseca, Manuel López-Ibáñez, Luís Paquete 5 | and Andreia P. Guerreiro. 6 | ----------------------------------------------------------------- 7 | 8 | Contents 9 | 10 | * Introduction 11 | * Usage 12 | * Embedding 13 | * License 14 | * Download 15 | * Changelog 16 | 17 | 18 | ------------ 19 | Introduction 20 | ------------ 21 | 22 | This program implements a recursive, dimension-sweep algorithm for 23 | computing the hypervolume indicator of the quality of a set of n 24 | non-dominated points in d dimensions. It also incorporates a 25 | recent result for the three-dimensional special case. The proposed 26 | algorithm achieves O(n^{d-2} log n) time and linear space complexity 27 | in the worst-case, but experimental results show that the pruning 28 | techniques used may reduce the time complexity even further. 29 | 30 | Relevant literature: 31 | 32 | [1] Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An 33 | improved dimension-sweep algorithm for the hypervolume 34 | indicator. In IEEE Congress on Evolutionary Computation, pages 35 | 1157-1163, Vancouver, Canada, July 2006. 36 | 37 | [2] Nicola Beume, Carlos M. Fonseca, Manuel López-Ibáñez, Luís 38 | Paquete, and J. Vahrenhold. On the complexity of computing the 39 | hypervolume indicator. IEEE Transactions on Evolutionary 40 | Computation, 13(5):1075-1082, 2009. 41 | 42 | 43 | ------------ 44 | Building 45 | ------------ 46 | 47 | In GNU/Linux, the program can be compiled from source by invoking 48 | 49 | make 50 | 51 | We recommend that you compile it specifically for your 52 | architecture. Depending on the compiler and version of the compiler 53 | you use there are different ways to achieve this. For recent GCC 54 | versions, make will pick a suitable -march argument based on the 55 | processor of the build machine. This can be overridden by passing a 56 | MARCH= argument to make. Similarly if you use the Intel C compiler, it 57 | will pick a sensible default architecture (-xHOST) for you. If you 58 | want to override this, pass XARCH= to make. So to build for an Intel 59 | Core2 you would use 60 | 61 | make MARCH=core2 62 | 63 | if you are using the GCC compiler and 64 | 65 | make XARCH=SSSE3 66 | 67 | for the Intel C compiler. Generally make will try to pick good flags 68 | for you, but if you need to, you can override them by passing a 69 | OPT_CFLAGS argument to make. To build an unoptimized version of hv you 70 | could run: 71 | 72 | make OPT_CFLAGS="-O0 -g" 73 | 74 | Finally, if you do not want to see the command line of each compiler 75 | invocation, pass S=1 to make. 76 | 77 | 78 | ------------ 79 | Usage 80 | ------------ 81 | 82 | The program reads sets of points provided by filenames in the command 83 | line: 84 | 85 | hv data 86 | 87 | or standard input: 88 | 89 | cat data | hv 90 | 91 | In the input files, each point is given in a separate line, and each 92 | coordinate within a line is separated by whitespace. An empty line 93 | denotes a separate set. (See also the --union option). The program 94 | assumes that all objectives must be minimized. Maximization objectives 95 | may be multiplied by -1 to convert them to minimization. 96 | 97 | A reference point can be given by the option -r. 98 | 99 | hv -r "10 10 10" data 100 | 101 | If no reference point is given, the default is the maximum value for each 102 | coordinate from the union of all input points. 103 | 104 | For the remainder options available, check the output of hv --help. 105 | 106 | 107 | ------------ 108 | Embedding 109 | ------------ 110 | 111 | If you want to embed the hypervolume function into your own C/C++ 112 | code, the main function for computing the hypervolume (fpli_hv) is 113 | self-contained in the file hv.c. A simple way to add it to your own 114 | code is to include Makefile.lib into your Makefile and link against 115 | fpli_hv.a. The exported function is: 116 | 117 | double fpli_hv(double *front, int d, int n, double *ref); 118 | 119 | You might want to add $(HV_OBJS) and fpli_hv.a to your Makefile's 120 | clean target to remove object files created during the build. 121 | 122 | 123 | ------------ 124 | License 125 | ------------ 126 | 127 | This software is Copyright (C) 2006-2011 128 | Carlos M. Fonseca, Manuel López-Ibáñez, Luís Paquete and Andreia P. Guerreiro. 129 | 130 | This program is free software (software libre); you can redistribute 131 | it and/or modify it under the terms of the GNU General Public License 132 | as published by the Free Software Foundation; either version 2 of the 133 | License, or (at your option) any later version. As a particular 134 | exception, the files hv.c and hv.h may also be redistributed and/or 135 | modified under the terms of the GNU Lesser General Public License 136 | (LGPL) as published by the Free Software Foundation; either version 3 137 | of the License, or (at your option) any later version. 138 | 139 | This program is distributed in the hope that it will be useful, but 140 | WITHOUT ANY WARRANTY; without even the implied warranty of 141 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 142 | General Public License for more details. 143 | 144 | IMPORTANT NOTE: Please be aware that the fact that this program is 145 | released as Free Software does not excuse you from scientific 146 | propriety, which obligates you to give appropriate credit! If you 147 | write a scientific paper describing research that made substantive use 148 | of this program, it is your obligation as a scientist to (a) mention 149 | the fashion in which this software was used in the Methods section; 150 | (b) mention the algorithm in the References section. The appropriate 151 | citation is: 152 | 153 | Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An improved 154 | dimension-sweep algorithm for the hypervolume indicator. In IEEE 155 | Congress on Evolutionary Computation, pages 1157-1163, Vancouver, 156 | Canada, July 2006. 157 | 158 | Moreover, as a personal note, I would appreciate it if you would email 159 | manuel.lopez-ibanez@ulb.ac.be with citations of papers referencing this 160 | work so I can mention them to my funding agent and tenure committee. 161 | 162 | 163 | ------------ 164 | Download 165 | ------------ 166 | 167 | The latest version can be downloaded from: 168 | 169 | http://iridia.ulb.ac.be/~manuel/hypervolume 170 | 171 | 172 | ------------ 173 | Changelog 174 | ------------ 175 | 176 | Version 2.0 (Release Candidate 2) 177 | 178 | * The files hv.c and hv.h are now also licensed under the GNU 179 | LGPL, which allows calling to the function that computes the 180 | hypervolume (See section "Embedding") from other software that 181 | uses a license incompatible with the GNU GPL. 182 | 183 | Version 2.0 (Release Candidate 1) 184 | 185 | * This is a BETA release for testing. Please be sure to compare 186 | your results with the stable 1.3 version and report to us any 187 | differences. 188 | 189 | * Andreia P. Guerreiro has improved the integration of the 3D case 190 | with the rest of the algorithm, which leads to significant 191 | reduction of computation time. She has also enhanced the 192 | numerical stability of the algorithm by avoiding floating-point 193 | comparisons of partial hypervolumes. 194 | 195 | * The command-line tool can now be compiled in Windows with the GCC 196 | version provided by MINGW (http://www.mingw.org/wiki/Getting_Started). 197 | The function that computes the hypervolume is ANSI C and it is 198 | self-contained in the file hv.c, See section "Embedding" in the 199 | README file for how to use it in your applications. 200 | 201 | 202 | Version 1.3 203 | 204 | * The hypervolume is now calculated separately for each input set. 205 | Reading from standard input when using the option --union 206 | emulates the previous behaviour. 207 | 208 | * Fix bug caused by uninitialized memory. Thanks to Andreia P. Guerreiro 209 | for reporting this. 210 | 211 | * Warn about discarding points that do not strictly dominate the 212 | reference point. Previous versions did not discard such points 213 | and may compute a wrong value. 214 | 215 | * New options: 216 | 217 | -u, --union treat all input sets within a FILE as a single set. 218 | 219 | -s, --suffix=STRING Create an output file for each input file by 220 | appending this suffix. This is ignored when 221 | reading from stdin. If missing, output is 222 | sent to stdout. 223 | 224 | * Guillaume Jacquenot contributed a MEX interface for MATLAB 225 | (Hypervolume_MEX.c). Use `make mex` to compile it. 226 | 227 | * Olaf Mersmann contributed a new build system that should work in 228 | Windows, Linux, Darwin (OS X), and using GCC, ICC, Sun C 229 | compiler and other compilers, as long as GNU Make is 230 | available. See section "Building" in the README file. 231 | 232 | * The function that computes the hypervolume is now called 233 | fpli_hv() and it is compiled into a separate library fpli_hv.a 234 | that can be linked with other C/C++ applications. See section 235 | "Embedding" in the README file. Thanks to Olaf Mersmann for 236 | this suggestion. 237 | 238 | 239 | Version 1.2 240 | 241 | * Fix off-by-one error in loop iteration caused by repeated 242 | coordinates and producing inconsistent results. (Thanks to Yuji 243 | Sakane for reporting this). 244 | 245 | 246 | Version 1.1 247 | 248 | * Warn for empty input files. 249 | 250 | * Compute hypervolume for two-dimensional data using 2D algorithm 251 | even if recursion is set to stop in dimension 3. 252 | 253 | Version 1.0 254 | 255 | * Basic compilation: make march=pentium 256 | 257 | * Select one of the variants (1, 2, 3, or 4) described in the 258 | paper [1]: make march=pentium VARIANT=4 259 | 260 | * Usage: hv [OPTIONS] [FILE...] 261 | 262 | Calculate the hypervolume of the union set of all input FILEs. 263 | With no FILE, or when FILE is -, read standard input. 264 | 265 | Options: 266 | -h, --help print this summary and exit. 267 | --version print version number and exit. 268 | -v, --verbose print some information (time, input points, output 269 | points, etc). Default is --quiet. 270 | -q, --quiet print just the hypervolume (as opposed to --verbose). 271 | -r, --reference=POINT use POINT as reference point. POINT must be within 272 | quotes, e.g., "10 10 10". If no reference point is 273 | given, it is taken as the maximum value for each 274 | coordinate from the input points. 275 | -1, --stop-on-1D stop recursion in dimension 1 276 | -2, --stop-on-2D stop recursion in dimension 2 277 | -3, --stop-on-3D stop recursion in dimension 3 (default) 278 | 279 | -------------------------------------------------------------------------------- /HV/getrusage.c: -------------------------------------------------------------------------------- 1 | /* 2 | getrusage 3 | Implementation according to: 4 | The Open Group Base Specifications Issue 6 5 | IEEE Std 1003.1, 2004 Edition 6 | 7 | THIS SOFTWARE IS NOT COPYRIGHTED 8 | 9 | This source code is offered for use in the public domain. You may 10 | use, modify or distribute it freely. 11 | 12 | This code is distributed in the hope that it will be useful but 13 | WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY 14 | DISCLAIMED. This includes but is not limited to warranties of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 | 17 | Contributed by: 18 | Ramiro Polla 19 | 20 | Modified by: 21 | 22 | Manuel Lopez-Ibanez 23 | * Remove dependency with 24 | 25 | **************************************************************************/ 26 | 27 | /* Include only the minimum from windows.h */ 28 | #define WIN32_LEAN_AND_MEAN 29 | #include "resource.h" 30 | #include 31 | #include 32 | #include 33 | 34 | static inline 35 | void FILETIME_to_timeval (struct timeval *tv, FILETIME *ft) 36 | { 37 | int64_t fulltime = ((((int64_t) ft->dwHighDateTime) << 32) 38 | | ((int64_t) ft->dwLowDateTime)); 39 | fulltime /= 10LL; /* 100-ns -> us */ 40 | 41 | tv->tv_sec = fulltime / 1000000L; 42 | tv->tv_usec = fulltime % 1000000L; 43 | } 44 | 45 | int __cdecl 46 | getrusage(int who, struct rusage *r_usage) 47 | { 48 | FILETIME starttime; 49 | FILETIME exittime; 50 | FILETIME kerneltime; 51 | FILETIME usertime; 52 | 53 | if (!r_usage) { 54 | errno = EFAULT; 55 | return -1; 56 | } 57 | 58 | if (who != RUSAGE_SELF) { 59 | errno = EINVAL; 60 | return -1; 61 | } 62 | 63 | if (GetProcessTimes (GetCurrentProcess (), 64 | &starttime, &exittime, 65 | &kerneltime, &usertime) == 0) { 66 | return -1; 67 | } 68 | FILETIME_to_timeval (&r_usage->ru_stime, &kerneltime); 69 | FILETIME_to_timeval (&r_usage->ru_utime, &usertime); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /HV/hv.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | hypervolume computation 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2010 8 | Carlos M. Fonseca 9 | Manuel Lopez-Ibanez 10 | Luis Paquete 11 | Andreia P. Guerreiro 12 | 13 | This program is free software (software libre); you can redistribute 14 | it and/or modify it under the terms of the GNU General Public License 15 | as published by the Free Software Foundation; either version 2 of the 16 | License, or (at your option) any later version. As a particular 17 | exception, the contents of this file (hv.c) may also be redistributed 18 | and/or modified under the terms of the GNU Lesser General Public 19 | License (LGPL) as published by the Free Software Foundation; either 20 | version 3 of the License, or (at your option) any later version. 21 | 22 | This program is distributed in the hope that it will be useful, but 23 | WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 | General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with this program; if not, you can obtain a copy of the GNU 29 | General Public License at: 30 | http://www.gnu.org/copyleft/gpl.html 31 | or by writing to: 32 | Free Software Foundation, Inc., 59 Temple Place, 33 | Suite 330, Boston, MA 02111-1307 USA 34 | 35 | ---------------------------------------------------------------------- 36 | 37 | Relevant literature: 38 | 39 | [1] C. M. Fonseca, L. Paquete, and M. Lopez-Ibanez. An 40 | improved dimension-sweep algorithm for the hypervolume 41 | indicator. In IEEE Congress on Evolutionary Computation, 42 | pages 1157-1163, Vancouver, Canada, July 2006. 43 | 44 | [2] Nicola Beume, Carlos M. Fonseca, Manuel López-Ibáñez, Luís 45 | Paquete, and J. Vahrenhold. On the complexity of computing the 46 | hypervolume indicator. IEEE Transactions on Evolutionary 47 | Computation, 13(5):1075-1082, 2009. 48 | 49 | *************************************************************************/ 50 | 51 | #include "hv.h" 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | 59 | static int compare_tree_asc(const void *p1, const void *p2); 60 | 61 | /*----------------------------------------------------------------------------- 62 | 63 | The following is a reduced version of the AVL-tree library used here 64 | according to the terms of the GPL. See the copyright notice below. 65 | 66 | */ 67 | #define AVL_DEPTH 68 | 69 | /***************************************************************************** 70 | 71 | avl.h - Source code for the AVL-tree library. 72 | 73 | Copyright (C) 1998 Michael H. Buselli 74 | Copyright (C) 2000-2002 Wessel Dankers 75 | 76 | This library is free software; you can redistribute it and/or 77 | modify it under the terms of the GNU Lesser General Public 78 | License as published by the Free Software Foundation; either 79 | version 2.1 of the License, or (at your option) any later version. 80 | 81 | This library is distributed in the hope that it will be useful, 82 | but WITHOUT ANY WARRANTY; without even the implied warranty of 83 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 84 | Lesser General Public License for more details. 85 | 86 | You should have received a copy of the GNU Lesser General Public 87 | License along with this library; if not, write to the Free Software 88 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 89 | 90 | Augmented AVL-tree. Original by Michael H. Buselli . 91 | 92 | Modified by Wessel Dankers to add a bunch of bloat to 93 | the sourcecode, change the interface and squash a few bugs. 94 | Mail him if you find new bugs. 95 | 96 | *****************************************************************************/ 97 | 98 | /* User supplied function to compare two items like strcmp() does. 99 | * For example: cmp(a,b) will return: 100 | * -1 if a < b 101 | * 0 if a = b 102 | * 1 if a > b 103 | */ 104 | typedef int (*avl_compare_t)(const void *, const void *); 105 | 106 | /* User supplied function to delete an item when a node is free()d. 107 | * If NULL, the item is not free()d. 108 | */ 109 | typedef void (*avl_freeitem_t)(void *); 110 | 111 | typedef struct avl_node_t { 112 | struct avl_node_t *next; 113 | struct avl_node_t *prev; 114 | struct avl_node_t *parent; 115 | struct avl_node_t *left; 116 | struct avl_node_t *right; 117 | void *item; 118 | double domr; 119 | #ifdef AVL_DEPTH 120 | unsigned char depth; 121 | #endif 122 | } avl_node_t; 123 | 124 | typedef struct avl_tree_t { 125 | avl_node_t *head; 126 | avl_node_t *tail; 127 | avl_node_t *top; 128 | avl_compare_t cmp; 129 | avl_freeitem_t freeitem; 130 | } avl_tree_t; 131 | 132 | 133 | /***************************************************************************** 134 | 135 | avl.c - Source code for the AVL-tree library. 136 | 137 | *****************************************************************************/ 138 | 139 | static void avl_rebalance(avl_tree_t *, avl_node_t *); 140 | 141 | #ifdef AVL_DEPTH 142 | #define NODE_DEPTH(n) ((n) ? (n)->depth : 0) 143 | #define L_DEPTH(n) (NODE_DEPTH((n)->left)) 144 | #define R_DEPTH(n) (NODE_DEPTH((n)->right)) 145 | #define CALC_DEPTH(n) ((L_DEPTH(n)>R_DEPTH(n)?L_DEPTH(n):R_DEPTH(n)) + 1) 146 | #endif 147 | 148 | static int avl_check_balance(avl_node_t *avlnode) { 149 | #ifdef AVL_DEPTH 150 | int d; 151 | d = R_DEPTH(avlnode) - L_DEPTH(avlnode); 152 | return d<-1?-1:d>1?1:0; 153 | #endif 154 | } 155 | 156 | static int 157 | avl_search_closest(const avl_tree_t *avltree, const void *item, avl_node_t **avlnode) { 158 | avl_node_t *node; 159 | int c; 160 | 161 | if(!avlnode) 162 | avlnode = &node; 163 | 164 | node = avltree->top; 165 | 166 | if(!node) 167 | return *avlnode = NULL, 0; 168 | 169 | 170 | for(;;) { 171 | c = compare_tree_asc(item, node->item); 172 | 173 | if(c < 0) { 174 | if(node->left) 175 | node = node->left; 176 | else 177 | return *avlnode = node, -1; 178 | } else if(c > 0) { 179 | if(node->right) 180 | node = node->right; 181 | else 182 | return *avlnode = node, 1; 183 | } else { 184 | return *avlnode = node, 0; 185 | } 186 | } 187 | } 188 | 189 | static avl_tree_t * 190 | avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) { 191 | if(rc) { 192 | rc->head = NULL; 193 | rc->tail = NULL; 194 | rc->top = NULL; 195 | rc->cmp = cmp; 196 | rc->freeitem = freeitem; 197 | } 198 | return rc; 199 | } 200 | 201 | static avl_tree_t * 202 | avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) { 203 | return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem); 204 | } 205 | 206 | static void 207 | avl_clear_tree(avl_tree_t *avltree) { 208 | avltree->top = avltree->head = avltree->tail = NULL; 209 | } 210 | 211 | static void 212 | avl_clear_node(avl_node_t *newnode) { 213 | newnode->left = newnode->right = NULL; 214 | #ifdef AVL_COUNT 215 | newnode->count = 1; 216 | #endif 217 | #ifdef AVL_DEPTH 218 | newnode->depth = 1; 219 | #endif 220 | } 221 | 222 | static avl_node_t * 223 | avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) { 224 | avl_clear_node(newnode); 225 | newnode->prev = newnode->next = newnode->parent = NULL; 226 | avltree->head = avltree->tail = avltree->top = newnode; 227 | return newnode; 228 | } 229 | 230 | static avl_node_t * 231 | avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { 232 | /* if(!node) 233 | return avltree->tail 234 | ? avl_insert_after(avltree, avltree->tail, newnode) 235 | : avl_insert_top(avltree, newnode); 236 | 237 | if(node->left) 238 | return avl_insert_after(avltree, node->prev, newnode); 239 | */ 240 | assert (node); 241 | assert (!node->left); 242 | 243 | avl_clear_node(newnode); 244 | 245 | newnode->next = node; 246 | newnode->parent = node; 247 | 248 | newnode->prev = node->prev; 249 | if(node->prev) 250 | node->prev->next = newnode; 251 | else 252 | avltree->head = newnode; 253 | node->prev = newnode; 254 | 255 | node->left = newnode; 256 | avl_rebalance(avltree, node); 257 | return newnode; 258 | } 259 | 260 | static avl_node_t * 261 | avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { 262 | /* if(!node) 263 | return avltree->head 264 | ? avl_insert_before(avltree, avltree->head, newnode) 265 | : avl_insert_top(avltree, newnode); 266 | 267 | if(node->right) 268 | return avl_insert_before(avltree, node->next, newnode); 269 | */ 270 | assert (node); 271 | assert (!node->right); 272 | 273 | avl_clear_node(newnode); 274 | 275 | newnode->prev = node; 276 | newnode->parent = node; 277 | 278 | newnode->next = node->next; 279 | if(node->next) 280 | node->next->prev = newnode; 281 | else 282 | avltree->tail = newnode; 283 | node->next = newnode; 284 | 285 | node->right = newnode; 286 | avl_rebalance(avltree, node); 287 | return newnode; 288 | } 289 | 290 | /* 291 | * avl_unlink_node: 292 | * Removes the given node. Does not delete the item at that node. 293 | * The item of the node may be freed before calling avl_unlink_node. 294 | * (In other words, it is not referenced by this function.) 295 | */ 296 | static void 297 | avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) { 298 | avl_node_t *parent; 299 | avl_node_t **superparent; 300 | avl_node_t *subst, *left, *right; 301 | avl_node_t *balnode; 302 | 303 | if(avlnode->prev) 304 | avlnode->prev->next = avlnode->next; 305 | else 306 | avltree->head = avlnode->next; 307 | 308 | if(avlnode->next) 309 | avlnode->next->prev = avlnode->prev; 310 | else 311 | avltree->tail = avlnode->prev; 312 | 313 | parent = avlnode->parent; 314 | 315 | superparent = parent 316 | ? avlnode == parent->left ? &parent->left : &parent->right 317 | : &avltree->top; 318 | 319 | left = avlnode->left; 320 | right = avlnode->right; 321 | if(!left) { 322 | *superparent = right; 323 | if(right) 324 | right->parent = parent; 325 | balnode = parent; 326 | } else if(!right) { 327 | *superparent = left; 328 | left->parent = parent; 329 | balnode = parent; 330 | } else { 331 | subst = avlnode->prev; 332 | if(subst == left) { 333 | balnode = subst; 334 | } else { 335 | balnode = subst->parent; 336 | balnode->right = subst->left; 337 | if(balnode->right) 338 | balnode->right->parent = balnode; 339 | subst->left = left; 340 | left->parent = subst; 341 | } 342 | subst->right = right; 343 | subst->parent = parent; 344 | right->parent = subst; 345 | *superparent = subst; 346 | } 347 | 348 | avl_rebalance(avltree, balnode); 349 | } 350 | 351 | /* 352 | * avl_rebalance: 353 | * Rebalances the tree if one side becomes too heavy. This function 354 | * assumes that both subtrees are AVL-trees with consistant data. The 355 | * function has the additional side effect of recalculating the count of 356 | * the tree at this node. It should be noted that at the return of this 357 | * function, if a rebalance takes place, the top of this subtree is no 358 | * longer going to be the same node. 359 | */ 360 | static void 361 | avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) { 362 | avl_node_t *child; 363 | avl_node_t *gchild; 364 | avl_node_t *parent; 365 | avl_node_t **superparent; 366 | 367 | parent = avlnode; 368 | 369 | while(avlnode) { 370 | parent = avlnode->parent; 371 | 372 | superparent = parent 373 | ? avlnode == parent->left ? &parent->left : &parent->right 374 | : &avltree->top; 375 | 376 | switch(avl_check_balance(avlnode)) { 377 | case -1: 378 | child = avlnode->left; 379 | #ifdef AVL_DEPTH 380 | if(L_DEPTH(child) >= R_DEPTH(child)) { 381 | #else 382 | #ifdef AVL_COUNT 383 | if(L_COUNT(child) >= R_COUNT(child)) { 384 | #else 385 | #error No balancing possible. 386 | #endif 387 | #endif 388 | avlnode->left = child->right; 389 | if(avlnode->left) 390 | avlnode->left->parent = avlnode; 391 | child->right = avlnode; 392 | avlnode->parent = child; 393 | *superparent = child; 394 | child->parent = parent; 395 | #ifdef AVL_COUNT 396 | avlnode->count = CALC_COUNT(avlnode); 397 | child->count = CALC_COUNT(child); 398 | #endif 399 | #ifdef AVL_DEPTH 400 | avlnode->depth = CALC_DEPTH(avlnode); 401 | child->depth = CALC_DEPTH(child); 402 | #endif 403 | } else { 404 | gchild = child->right; 405 | avlnode->left = gchild->right; 406 | if(avlnode->left) 407 | avlnode->left->parent = avlnode; 408 | child->right = gchild->left; 409 | if(child->right) 410 | child->right->parent = child; 411 | gchild->right = avlnode; 412 | if(gchild->right) 413 | gchild->right->parent = gchild; 414 | gchild->left = child; 415 | if(gchild->left) 416 | gchild->left->parent = gchild; 417 | *superparent = gchild; 418 | gchild->parent = parent; 419 | #ifdef AVL_COUNT 420 | avlnode->count = CALC_COUNT(avlnode); 421 | child->count = CALC_COUNT(child); 422 | gchild->count = CALC_COUNT(gchild); 423 | #endif 424 | #ifdef AVL_DEPTH 425 | avlnode->depth = CALC_DEPTH(avlnode); 426 | child->depth = CALC_DEPTH(child); 427 | gchild->depth = CALC_DEPTH(gchild); 428 | #endif 429 | } 430 | break; 431 | case 1: 432 | child = avlnode->right; 433 | #ifdef AVL_DEPTH 434 | if(R_DEPTH(child) >= L_DEPTH(child)) { 435 | #else 436 | #ifdef AVL_COUNT 437 | if(R_COUNT(child) >= L_COUNT(child)) { 438 | #else 439 | #error No balancing possible. 440 | #endif 441 | #endif 442 | avlnode->right = child->left; 443 | if(avlnode->right) 444 | avlnode->right->parent = avlnode; 445 | child->left = avlnode; 446 | avlnode->parent = child; 447 | *superparent = child; 448 | child->parent = parent; 449 | #ifdef AVL_COUNT 450 | avlnode->count = CALC_COUNT(avlnode); 451 | child->count = CALC_COUNT(child); 452 | #endif 453 | #ifdef AVL_DEPTH 454 | avlnode->depth = CALC_DEPTH(avlnode); 455 | child->depth = CALC_DEPTH(child); 456 | #endif 457 | } else { 458 | gchild = child->left; 459 | avlnode->right = gchild->left; 460 | if(avlnode->right) 461 | avlnode->right->parent = avlnode; 462 | child->left = gchild->right; 463 | if(child->left) 464 | child->left->parent = child; 465 | gchild->left = avlnode; 466 | if(gchild->left) 467 | gchild->left->parent = gchild; 468 | gchild->right = child; 469 | if(gchild->right) 470 | gchild->right->parent = gchild; 471 | *superparent = gchild; 472 | gchild->parent = parent; 473 | #ifdef AVL_COUNT 474 | avlnode->count = CALC_COUNT(avlnode); 475 | child->count = CALC_COUNT(child); 476 | gchild->count = CALC_COUNT(gchild); 477 | #endif 478 | #ifdef AVL_DEPTH 479 | avlnode->depth = CALC_DEPTH(avlnode); 480 | child->depth = CALC_DEPTH(child); 481 | gchild->depth = CALC_DEPTH(gchild); 482 | #endif 483 | } 484 | break; 485 | default: 486 | #ifdef AVL_COUNT 487 | avlnode->count = CALC_COUNT(avlnode); 488 | #endif 489 | #ifdef AVL_DEPTH 490 | avlnode->depth = CALC_DEPTH(avlnode); 491 | #endif 492 | } 493 | avlnode = parent; 494 | } 495 | } 496 | 497 | /*------------------------------------------------------------------------------ 498 | end of functions from AVL-tree library. 499 | *******************************************************************************/ 500 | 501 | #if !defined(VARIANT) || VARIANT < 1 || VARIANT > 4 502 | #error VARIANT must be either 1, 2, 3 or 4, e.g., 'make VARIANT=4' 503 | #endif 504 | 505 | #if __GNUC__ >= 3 506 | # define __hv_unused __attribute__ ((unused)) 507 | #else 508 | # define __hv_unused /* no 'unused' attribute available */ 509 | #endif 510 | 511 | #if VARIANT < 3 512 | # define __variant3_only __hv_unused 513 | #else 514 | # define __variant3_only 515 | #endif 516 | 517 | #if VARIANT < 2 518 | # define __variant2_only __hv_unused 519 | #else 520 | # define __variant2_only 521 | #endif 522 | 523 | typedef struct dlnode { 524 | double *x; /* The data vector */ 525 | struct dlnode **next; /* Next-node vector */ 526 | struct dlnode **prev; /* Previous-node vector */ 527 | struct avl_node_t * tnode; 528 | int ignore; 529 | int ignore_best; //used in define_order 530 | #if VARIANT >= 2 531 | double *area; /* Area */ 532 | #endif 533 | #if VARIANT >= 3 534 | double *vol; /* Volume */ 535 | #endif 536 | } dlnode_t; 537 | 538 | static avl_tree_t *tree; 539 | #if VARIANT < 4 540 | int stop_dimension = 1; /* default: stop on dimension 2 */ 541 | #else 542 | int stop_dimension = 2; /* default: stop on dimension 3 */ 543 | #endif 544 | 545 | static int compare_node(const void *p1, const void* p2) 546 | { 547 | const double x1 = *((*(const dlnode_t **)p1)->x); 548 | const double x2 = *((*(const dlnode_t **)p2)->x); 549 | 550 | return (x1 < x2) ? -1 : (x1 > x2) ? 1 : 0; 551 | } 552 | 553 | static int compare_tree_asc(const void *p1, const void *p2) 554 | { 555 | const double *x1 = (const double *)p1; 556 | const double *x2 = (const double *)p2; 557 | 558 | return (x1[1] > x2[1]) ? -1 : (x1[1] < x2[1]) ? 1 559 | : (x1[0] >= x2[0]) ? -1 : 1; 560 | } 561 | 562 | /* 563 | * Setup circular double-linked list in each dimension 564 | */ 565 | 566 | static dlnode_t * 567 | setup_cdllist(double *data, int d, int n) 568 | { 569 | dlnode_t *head; 570 | dlnode_t **scratch; 571 | int i, j; 572 | 573 | head = malloc ((n+1) * sizeof(dlnode_t)); 574 | 575 | head->x = data; 576 | head->ignore = 0; /* should never get used */ 577 | head->next = malloc( d * (n+1) * sizeof(dlnode_t*)); 578 | head->prev = malloc( d * (n+1) * sizeof(dlnode_t*)); 579 | head->tnode = malloc ((n+1) * sizeof(avl_node_t)); 580 | 581 | #if VARIANT >= 2 582 | head->area = malloc(d * (n+1) * sizeof(double)); 583 | #endif 584 | #if VARIANT >= 3 585 | head->vol = malloc(d * (n+1) * sizeof(double)); 586 | #endif 587 | 588 | for (i = 1; i <= n; i++) { 589 | head[i].x = head[i-1].x + d;/* this will be fixed a few lines below... */ 590 | head[i].ignore = 0; 591 | head[i].next = head[i-1].next + d; 592 | head[i].prev = head[i-1].prev + d; 593 | head[i].tnode = head[i-1].tnode + 1; 594 | #if VARIANT >= 2 595 | head[i].area = head[i-1].area + d; 596 | #endif 597 | #if VARIANT >= 3 598 | head[i].vol = head[i-1].vol + d; 599 | #endif 600 | } 601 | head->x = NULL; /* head contains no data */ 602 | 603 | scratch = malloc(n * sizeof(dlnode_t*)); 604 | for (i = 0; i < n; i++) 605 | scratch[i] = head + i + 1; 606 | 607 | for (j = d-1; j >= 0; j--) { 608 | for (i = 0; i < n; i++) 609 | scratch[i]->x--; 610 | qsort(scratch, n, sizeof(dlnode_t*), compare_node); 611 | head->next[j] = scratch[0]; 612 | scratch[0]->prev[j] = head; 613 | for (i = 1; i < n; i++) { 614 | scratch[i-1]->next[j] = scratch[i]; 615 | scratch[i]->prev[j] = scratch[i-1]; 616 | } 617 | scratch[n-1]->next[j] = head; 618 | head->prev[j] = scratch[n-1]; 619 | } 620 | 621 | free(scratch); 622 | 623 | for (i = 1; i <= n; i++) { 624 | (head[i].tnode)->item = head[i].x; 625 | } 626 | 627 | return head; 628 | } 629 | 630 | static void free_cdllist(dlnode_t * head) 631 | { 632 | free(head->tnode); /* Frees _all_ nodes. */ 633 | free(head->next); 634 | free(head->prev); 635 | #if VARIANT >= 2 636 | free(head->area); 637 | #endif 638 | #if VARIANT >= 3 639 | free(head->vol); 640 | #endif 641 | free(head); 642 | } 643 | 644 | static void delete (dlnode_t *nodep, int dim, double * bound __variant3_only) 645 | { 646 | int i; 647 | 648 | for (i = stop_dimension; i < dim; i++) { 649 | nodep->prev[i]->next[i] = nodep->next[i]; 650 | nodep->next[i]->prev[i] = nodep->prev[i]; 651 | #if VARIANT >= 3 652 | if (bound[i] > nodep->x[i]) 653 | bound[i] = nodep->x[i]; 654 | #endif 655 | } 656 | } 657 | 658 | #if VARIANT >= 2 659 | static void delete_dom (dlnode_t *nodep, int dim) 660 | { 661 | int i; 662 | 663 | for (i = stop_dimension; i < dim; i++) { 664 | nodep->prev[i]->next[i] = nodep->next[i]; 665 | nodep->next[i]->prev[i] = nodep->prev[i]; 666 | } 667 | } 668 | #endif 669 | 670 | static void reinsert (dlnode_t *nodep, int dim, double * bound __variant3_only) 671 | { 672 | int i; 673 | 674 | for (i = stop_dimension; i < dim; i++) { 675 | nodep->prev[i]->next[i] = nodep; 676 | nodep->next[i]->prev[i] = nodep; 677 | #if VARIANT >= 3 678 | if (bound[i] > nodep->x[i]) 679 | bound[i] = nodep->x[i]; 680 | #endif 681 | } 682 | } 683 | 684 | #if VARIANT >= 2 685 | static void reinsert_dom (dlnode_t *nodep, int dim) 686 | { 687 | int i; 688 | for (i = stop_dimension; i < dim; i++) { 689 | dlnode_t *p = nodep->prev[i]; 690 | p->next[i] = nodep; 691 | nodep->next[i]->prev[i] = nodep; 692 | nodep->area[i] = p->area[i]; 693 | 694 | #if VARIANT >= 3 695 | nodep->vol[i] = p->vol[i] + p->area[i] * (nodep->x[i] - p->x[i]); 696 | #endif 697 | } 698 | } 699 | #endif 700 | 701 | static double 702 | hv_recursive(dlnode_t *list, int dim, int c, const double * ref, 703 | double * bound) 704 | { 705 | /* ------------------------------------------------------ 706 | General case for dimensions higher than stop_dimension 707 | ------------------------------------------------------ */ 708 | if ( dim > stop_dimension ) { 709 | dlnode_t *p0 = list; 710 | dlnode_t *p1 = list->prev[dim]; 711 | double hyperv = 0; 712 | #if VARIANT == 1 713 | double hypera; 714 | #endif 715 | #if VARIANT >= 2 716 | dlnode_t *pp; 717 | for (pp = p1; pp->x; pp = pp->prev[dim]) { 718 | if (pp->ignore < dim) 719 | pp->ignore = 0; 720 | } 721 | #endif 722 | while (c > 1 723 | #if VARIANT >= 3 724 | /* We delete all points x[dim] > bound[dim]. In case of 725 | repeated coordinates, we also delete all points 726 | x[dim] == bound[dim] except one. */ 727 | && (p1->x[dim] > bound[dim] 728 | || p1->prev[dim]->x[dim] >= bound[dim]) 729 | #endif 730 | ) { 731 | p0 = p1; 732 | #if VARIANT >=2 733 | if (p0->ignore >= dim) 734 | delete_dom(p0, dim); 735 | else 736 | delete(p0, dim, bound); 737 | #else 738 | delete(p0, dim, bound); 739 | #endif 740 | p1 = p0->prev[dim]; 741 | c--; 742 | } 743 | 744 | #if VARIANT == 1 745 | hypera = hv_recursive(list, dim-1, c, ref, bound); 746 | 747 | #elif VARIANT == 2 748 | int i; 749 | p1->area[0] = 1; 750 | for (i = 1; i <= dim; i++) 751 | p1->area[i] = p1->area[i-1] * (ref[i-1] - p1->x[i-1]); 752 | 753 | #elif VARIANT >= 3 754 | if (c > 1) { 755 | hyperv = p1->prev[dim]->vol[dim] + p1->prev[dim]->area[dim] 756 | * (p1->x[dim] - p1->prev[dim]->x[dim]); 757 | 758 | if (p1->ignore >= dim) 759 | p1->area[dim] = p1->prev[dim]->area[dim]; 760 | else { 761 | p1->area[dim] = hv_recursive(list, dim - 1, c, ref, bound); 762 | /* At this point, p1 is the point with the highest value in 763 | dimension dim in the list, so if it is dominated in 764 | dimension dim-1, so it is also dominated in dimension 765 | dim. */ 766 | if (p1->ignore == (dim - 1)) 767 | p1->ignore = dim; 768 | } 769 | } else { 770 | int i; 771 | p1->area[0] = 1; 772 | for (i = 1; i <= dim; i++) 773 | p1->area[i] = p1->area[i-1] * (ref[i-1] - p1->x[i-1]); 774 | } 775 | p1->vol[dim] = hyperv; 776 | #endif 777 | 778 | while (p0->x != NULL) { 779 | 780 | #if VARIANT == 1 781 | hyperv += hypera * (p0->x[dim] - p1->x[dim]); 782 | #else 783 | hyperv += p1->area[dim] * (p0->x[dim] - p1->x[dim]); 784 | #endif 785 | c++; 786 | #if VARIANT >= 2 787 | if (p0->ignore >= dim) { 788 | reinsert_dom (p0, dim); 789 | p0->area[dim] = p1->area[dim]; 790 | } else { 791 | #endif 792 | reinsert (p0, dim, bound); 793 | #if VARIANT >= 2 794 | p0->area[dim] = hv_recursive (list, dim-1, c, ref, bound); 795 | if (p0->ignore == (dim - 1)) 796 | p0->ignore = dim; 797 | } 798 | #elif VARIANT == 1 799 | hypera = hv_recursive (list, dim-1, c, ref, NULL); 800 | #endif 801 | p1 = p0; 802 | p0 = p0->next[dim]; 803 | #if VARIANT >= 3 804 | p1->vol[dim] = hyperv; 805 | #endif 806 | } 807 | #if VARIANT >= 3 808 | bound[dim] = p1->x[dim]; 809 | #endif 810 | 811 | #if VARIANT == 1 812 | hyperv += hypera * (ref[dim] - p1->x[dim]); 813 | #else 814 | hyperv += p1->area[dim] * (ref[dim] - p1->x[dim]); 815 | #endif 816 | return hyperv; 817 | } 818 | 819 | 820 | /* --------------------------- 821 | special case of dimension 3 822 | --------------------------- */ 823 | else if (dim == 2) { 824 | double hyperv; 825 | double hypera; 826 | double height; 827 | 828 | #if VARIANT >= 3 829 | dlnode_t *pp = list->prev[2]; 830 | avl_node_t *tnode; 831 | 832 | /* All the points that have value of x[2] lower than bound[2] are points 833 | that were previously processed, so there's no need to process them 834 | again. In this case, every point was processed before, so the 835 | volume is known. */ 836 | if (pp->x[2] < bound[2]) 837 | return pp->vol[2] + pp->area[2] * (ref[2] - pp->x[2]); 838 | 839 | pp = list->next[2]; 840 | 841 | /* In this case, every point has to be processed. */ 842 | if (pp->x[2] >= bound[2]) { 843 | pp->tnode->domr = ref[2]; 844 | pp->area[2] = (ref[0] - pp->x[0]) * (ref[1] - pp->x[1]); 845 | pp->vol[2] = 0; 846 | pp->ignore = 0; 847 | } else { 848 | /* Otherwise, we look for the first point that has to be in the 849 | tree, by searching for the first point that isn't dominated or 850 | that is dominated by a point with value of x[2] higher or equal 851 | than bound[2] (domr keeps the value of the x[2] of the point 852 | that dominates pp, or ref[2] if it isn't dominated). */ 853 | while (pp->tnode->domr < bound[2]) { 854 | pp = pp->next[2]; 855 | } 856 | } 857 | 858 | pp->ignore = 0; 859 | avl_insert_top(tree,pp->tnode); 860 | pp->tnode->domr = ref[2]; 861 | 862 | /* Connect all points that aren't dominated or that are dominated and 863 | the point that dominates it has value x[2] (pp->tnode->domr) equal 864 | or higher than bound[2]. */ 865 | for (pp = pp->next[2]; pp->x[2] < bound[2]; pp = pp->next[2]) { 866 | if (pp->tnode->domr >= bound[2]) { 867 | avl_node_t *tnodeaux = pp->tnode; 868 | tnodeaux->domr = ref[2]; 869 | if (avl_search_closest(tree, pp->x, &tnode) <= 0) 870 | avl_insert_before(tree, tnode, tnodeaux); 871 | else 872 | avl_insert_after(tree, tnode, tnodeaux); 873 | } 874 | } 875 | pp = pp->prev[2]; 876 | hyperv = pp->vol[2]; 877 | hypera = pp->area[2]; 878 | 879 | height = (pp->next[2]->x) 880 | ? pp->next[2]->x[2] - pp->x[2] 881 | : ref[2] - pp->x[2]; 882 | 883 | bound[2] = list->prev[2]->x[2]; 884 | #else 885 | /* VARIANT <= 2 */ 886 | dlnode_t *pp = list->next[2]; 887 | hyperv = 0; 888 | 889 | hypera = (ref[0] - pp->x[0])*(ref[1] - pp->x[1]); 890 | height = (c == 1) 891 | ? ref[2] - pp->x[2] 892 | : pp->next[2]->x[2] - pp->x[2]; 893 | 894 | avl_insert_top(tree,pp->tnode); 895 | #endif 896 | hyperv += hypera * height; 897 | for (pp = pp->next[2]; pp->x != NULL; pp = pp->next[2]) { 898 | const double * prv_ip, * nxt_ip; 899 | avl_node_t *tnode; 900 | int cmp; 901 | 902 | #if VARIANT >= 3 903 | pp->vol[2] = hyperv; 904 | #endif 905 | height = (pp == list->prev[2]) 906 | ? ref[2] - pp->x[2] 907 | : pp->next[2]->x[2] - pp->x[2]; 908 | #if VARIANT >= 2 909 | if (pp->ignore >= 2) { 910 | hyperv += hypera * height; 911 | #if VARIANT >= 3 912 | pp->area[2] = hypera; 913 | #endif 914 | continue; 915 | } 916 | #endif 917 | cmp = avl_search_closest(tree, pp->x, &tnode); 918 | if (cmp <= 0) { 919 | nxt_ip = (double *)(tnode->item); 920 | } else { 921 | nxt_ip = (tnode->next != NULL) 922 | ? (double *)(tnode->next->item) 923 | : ref; 924 | } 925 | if (nxt_ip[0] <= pp->x[0]) { 926 | pp->ignore = 2; 927 | #if VARIANT >= 3 928 | pp->tnode->domr = pp->x[2]; 929 | pp->area[2] = hypera; 930 | #endif 931 | if (height > 0) 932 | hyperv += hypera * height; 933 | continue; 934 | } 935 | if (cmp <= 0) { 936 | avl_insert_before(tree, tnode, pp->tnode); 937 | tnode = pp->tnode->prev; 938 | } else { 939 | avl_insert_after(tree, tnode, pp->tnode); 940 | } 941 | #if VARIANT >= 3 942 | pp->tnode->domr = ref[2]; 943 | #endif 944 | if (tnode != NULL) { 945 | prv_ip = (double *)(tnode->item); 946 | if (prv_ip[0] >= pp->x[0]) { 947 | const double * cur_ip; 948 | 949 | tnode = pp->tnode->prev; 950 | /* cur_ip = point dominated by pp with highest 951 | [0]-coordinate. */ 952 | cur_ip = (double *)(tnode->item); 953 | while (tnode->prev) { 954 | prv_ip = (double *)(tnode->prev->item); 955 | hypera -= (prv_ip[1] - cur_ip[1]) * (nxt_ip[0] - cur_ip[0]); 956 | if (prv_ip[0] < pp->x[0]) 957 | break; /* prv is not dominated by pp */ 958 | cur_ip = prv_ip; 959 | avl_unlink_node(tree,tnode); 960 | #if VARIANT >= 3 961 | /* saves the value of x[2] of the point that 962 | dominates tnode. */ 963 | tnode->domr = pp->x[2]; 964 | #endif 965 | tnode = tnode->prev; 966 | } 967 | 968 | avl_unlink_node(tree, tnode); 969 | #if VARIANT >= 3 970 | tnode->domr = pp->x[2]; 971 | #endif 972 | if (!tnode->prev) { 973 | hypera -= (ref[1] - cur_ip[1]) * (nxt_ip[0] - cur_ip[0]); 974 | prv_ip = ref; 975 | } 976 | } 977 | } else 978 | prv_ip = ref; 979 | 980 | hypera += (prv_ip[1] - pp->x[1]) * (nxt_ip[0] - pp->x[0]); 981 | 982 | if (height > 0) 983 | hyperv += hypera * height; 984 | #if VARIANT >= 3 985 | pp->area[2] = hypera; 986 | #endif 987 | } 988 | avl_clear_tree(tree); 989 | return hyperv; 990 | } 991 | 992 | /* special case of dimension 2 */ 993 | else if (dim == 1) { 994 | const dlnode_t *p1 = list->next[1]; 995 | double hypera = p1->x[0]; 996 | double hyperv = 0; 997 | dlnode_t *p0; 998 | 999 | while ((p0 = p1->next[1])->x) { 1000 | hyperv += (ref[0] - hypera) * (p0->x[1] - p1->x[1]); 1001 | if (p0->x[0] < hypera) 1002 | hypera = p0->x[0]; 1003 | else if (p0->ignore == 0) 1004 | p0->ignore = 1; 1005 | p1 = p0; 1006 | } 1007 | hyperv += (ref[0] - hypera) * (ref[1] - p1->x[1]); 1008 | return hyperv; 1009 | } 1010 | 1011 | /* special case of dimension 1 */ 1012 | else if (dim == 0) { 1013 | list->next[0]->ignore = -1; 1014 | return (ref[0] - list->next[0]->x[0]); 1015 | } 1016 | else { 1017 | fprintf(stderr, "%s:%d: unreachable condition! \n" 1018 | "This is a bug, please report it to " 1019 | "manuel.lopez-ibanez@ulb.ac.be\n", __FILE__, __LINE__); 1020 | exit(EXIT_FAILURE); 1021 | } 1022 | } 1023 | 1024 | /* 1025 | Removes the point from the circular double-linked list, but it 1026 | doesn't remove the data. 1027 | */ 1028 | static void 1029 | filter_delete_node(dlnode_t *node, int d) 1030 | { 1031 | int i; 1032 | 1033 | for (i = 0; i < d; i++) { 1034 | node->next[i]->prev[i] = node->prev[i]; 1035 | node->prev[i]->next[i] = node->next[i]; 1036 | } 1037 | } 1038 | 1039 | /* 1040 | Filters those points that do not strictly dominate the reference 1041 | point. This is needed to assure that the points left are only those 1042 | that are needed to calculate the hypervolume. 1043 | */ 1044 | static int 1045 | filter(dlnode_t *list, int d, int n, const double *ref) 1046 | { 1047 | int i, j; 1048 | 1049 | /* fprintf (stderr, "%d points initially\n", n); */ 1050 | for (i = 0; i < d; i++) { 1051 | dlnode_t *aux = list->prev[i]; 1052 | int np = n; 1053 | for (j = 0; j < np; j++) { 1054 | if (aux->x[i] < ref[i]) 1055 | break; 1056 | filter_delete_node (aux, d); 1057 | aux = aux->prev[i]; 1058 | n--; 1059 | } 1060 | } 1061 | /* fprintf (stderr, "%d points remain\n", n); */ 1062 | return n; 1063 | } 1064 | 1065 | 1066 | #ifdef EXPERIMENTAL 1067 | /* 1068 | Verifies up to which dimension k, domr dominates p and returns k 1069 | (it is assumed that domr doesn't dominate p in dimensions higher than dim). 1070 | */ 1071 | static int 1072 | test_domr(dlnode_t *p, dlnode_t *domr, int dim, int *order) 1073 | { 1074 | int i; 1075 | for(i = 1; i <= dim; i++){ 1076 | if (p->x[order[i]] < domr->x[order[i]]) 1077 | return i - 1; 1078 | } 1079 | return dim; 1080 | } 1081 | 1082 | /* 1083 | Verifies up to which dimension k the point pp is dominated and 1084 | returns k. This functions is called only to verify points that 1085 | aren't dominated for more than dim dimensions, so k will always be 1086 | lower or equal to dim. 1087 | */ 1088 | static int 1089 | test_dom(dlnode_t *list, dlnode_t *pp, int dim, int *order) 1090 | { 1091 | dlnode_t *p0; 1092 | int r, r_b = 0; 1093 | int i = order[0]; 1094 | 1095 | p0 = list->next[i]; 1096 | 1097 | /* In every iteration, it is verified if p0 dominates pp and 1098 | up to which dimension. The goal is to find the point that 1099 | dominates pp in more dimension, starting in dimension 0. 1100 | 1101 | Points are processed in ascending order of the first 1102 | dimension. This means that if a point p0 is dominated in 1103 | the first k dimensions, where k >=dim, then the point that 1104 | dominates it (in the first k dimensions) was already 1105 | processed, so p0 won't dominate pp in more dimensions that 1106 | the point that dominates p0 (because pp can be dominated, 1107 | at most, up to dim dimensions, and so if p0 dominates pp in 1108 | the first y dimensions (y < dim), the point that dominates 1109 | p0 also dominates pp in the first y dimensions or more, and 1110 | this informations is already stored in r_b), so p0 is 1111 | skipped. */ 1112 | while (p0 != pp) { 1113 | if (p0->ignore < dim) { 1114 | r = test_domr (pp, p0, dim, order); 1115 | /* if pp is dominated in the first dim + 1 dimensions, 1116 | it is not necessary to verify other points that 1117 | might dominate pp, because pp won't be dominated in 1118 | more that dim+1 dimensions. */ 1119 | if (r == dim) return r; 1120 | else if (r > r_b) r_b = r; 1121 | } 1122 | p0 = p0->next[i]; 1123 | } 1124 | return r_b; 1125 | } 1126 | 1127 | /* 1128 | Determines the number of dominated points from dimension 0 to k, 1129 | where k <= dim. 1130 | */ 1131 | static void determine_ndom(dlnode_t *list, int dim, int *order, int *count) 1132 | { 1133 | dlnode_t *p1; 1134 | int i, dom; 1135 | int ord = order[0]; 1136 | 1137 | for (i = 0; i <= dim; i++) 1138 | count[i] = 0; 1139 | 1140 | p1 = list->next[ord]; 1141 | p1->ignore = 0; 1142 | 1143 | p1 = list->next[ord]; 1144 | 1145 | while (p1 != list) { 1146 | if (p1->ignore <= dim) { 1147 | dom = test_dom(list, p1, dim, order); 1148 | count[dom]++; 1149 | p1->ignore = dom; 1150 | } 1151 | p1 = p1->next[ord]; 1152 | } 1153 | } 1154 | 1155 | static void delete_dominated(dlnode_t *nodep, int dim) 1156 | { 1157 | int i; 1158 | for (i = 0; i <= dim; i++) { 1159 | nodep->prev[i]->next[i] = nodep->next[i]; 1160 | nodep->next[i]->prev[i] = nodep->prev[i]; 1161 | } 1162 | } 1163 | 1164 | 1165 | /* 1166 | Determines the number of dominated points from dimension 0 to k, 1167 | where k <= dim, for the original order of objectives. Also defines 1168 | that this order is the best order so far, so every point has the 1169 | information up to which dimension it is dominated (ignore) and it is 1170 | considered the highest number of dimensions in which it is dominated 1171 | (so ignore_best is also updated). 1172 | 1173 | If there is any point dominated in every dimension, seen that it 1174 | doesn't contribute to the hypervolume, it is removed as soon as 1175 | possible, this way there's no waste of time with these points. 1176 | Returns the number of total points. */ 1177 | static int 1178 | determine_ndomf(dlnode_t *list, int dim, int c, int *order, int *count) 1179 | { 1180 | dlnode_t *p1; 1181 | int i, dom; 1182 | int ord = order[0]; 1183 | 1184 | for(i = 0; i <= dim; i++) 1185 | count[i] = 0; 1186 | 1187 | p1 = list->next[ord]; 1188 | p1->ignore = p1->ignore_best = 0; 1189 | 1190 | p1 = list->next[ord]; 1191 | 1192 | /* Determines up to which dimension each point is dominated and 1193 | uses this information to count the number of dominated points 1194 | from dimension 0 to k, where k <= dim. 1195 | 1196 | Points that are dominated in more than the first 'dim' 1197 | dimensions will continue to be dominated in those dimensions, 1198 | and so they're skipped, it's not necessary to find out again up 1199 | to which dimension they're dominated. */ 1200 | while (p1 != list){ 1201 | if (p1->ignore <= dim) { 1202 | dom = test_dom(list, p1, dim, order); 1203 | count[dom]++; 1204 | p1->ignore = p1->ignore_best = dom; 1205 | } 1206 | p1 = p1->next[ord]; 1207 | } 1208 | 1209 | /* If there is any point dominated in every dimension, it is removed and 1210 | the number of total points is updated. */ 1211 | if (count[dim] > 0) { 1212 | p1 = list->prev[0]; 1213 | while (p1->x) { 1214 | if (p1->ignore == dim) { 1215 | delete_dominated(p1, dim); 1216 | c--; 1217 | } 1218 | p1 = p1->prev[0]; 1219 | } 1220 | } 1221 | return c; 1222 | } 1223 | 1224 | 1225 | /* 1226 | This funtion implements the iterative version of MDP heuristic described in 1227 | L. While, L. Bradstreet, L. Barone, and P. Hingston, "Heuristics for optimising 1228 | the calculation of hypervolume for multi-objective optimisation problems", in 1229 | Congress on Evolutionary Computation, B. McKay, Ed. IEEE, 2005, pp. 2225-2232 1230 | 1231 | Tries to find a good order to process the objectives. 1232 | 1233 | This algorithm tries to maximize the number of dominated points 1234 | dominated in more dimensions. For example, for a problem with d 1235 | dimensions, an order with 20 points dominated from dimension 0 to 1236 | dimension d-1 is prefered to an order of objectives in which the 1237 | number of points dominated from dimension 0 to d-1 is 10. An order 1238 | with the same number of points dominated up to dimension d-1 as a 1239 | second order is prefered if it has more points dominated up to 1240 | dimension d-2 than the second order. */ 1241 | static int define_order(dlnode_t *list, int dim, int c, int *order) 1242 | { 1243 | dlnode_t *p; 1244 | 1245 | // order - keeps the current order of objectives 1246 | 1247 | /* best_order - keeps the current best order for the 1248 | objectives. At the end, this array (and the array order) will 1249 | have the best order found, to process the objectives. 1250 | 1251 | This array keeps the indexes of the objectives, where 1252 | best_order[0] keeps the index of the first objective, 1253 | best_order[1] keeps the index of the second objective and so on. */ 1254 | int *best_order = malloc(dim * sizeof(int)); 1255 | 1256 | /* count - keeps the counting of the dominated points 1257 | corresponding to the order of objectives in 'order'. 1258 | 1259 | When it's found that a point is dominated at most, for the 1260 | first four dimensions, then count[3] is incremented. So, 1261 | count[i] is incremented every time it's found a point that is 1262 | dominated from dimension 0 to i, but not in dimension i+1. */ 1263 | int *count = malloc(dim * sizeof(int)); 1264 | 1265 | /* keeps the best counting of the dominated points (that is 1266 | obtained using the order in best_order). */ 1267 | int *best_count = malloc(dim * sizeof(int)); 1268 | 1269 | int i, j, k; 1270 | 1271 | for (i = 0; i < dim; i++) { 1272 | best_order[i] = order[i] = i; 1273 | best_count[i] = count[i] = 0; 1274 | } 1275 | 1276 | // determines the number of dominated points in the original order. 1277 | // c - total number of points excluding points totally dominated 1278 | c = determine_ndomf(list, dim-1, c, order, count); 1279 | 1280 | /* the best order so far is the original order, so it's necessary 1281 | to register the number of points dominated in the best 1282 | order. */ 1283 | for (i = 0; i < dim; i++) { 1284 | best_count[i] = count[i]; 1285 | } 1286 | 1287 | /* Objectives are chosen from highest to lowest. So we start 1288 | defining which is the objective in position dim-1 and then 1289 | which is the objective in position dim, and so on. The 1290 | objective chosen to be in position i is chosen in a way to 1291 | maximize the number of dominated points from dimension 0 to 1292 | i-1. So, this cycle, selects a position i, and then we find 1293 | the objective (from the remaining objectives that haven't a 1294 | position yet, the objectives that are in positions lower or 1295 | equal to i) that by being in position i maximizes the number of 1296 | points dominated from dimension 0 to i-1. */ 1297 | for (i = dim - 1; i > 2; i--) { 1298 | /* This cycle, in every iteration, assigns a different 1299 | objective to position i. It's important to notice 1300 | that if we want to maximize the number of dominated 1301 | points from dimension 0 to i-1, when we want to now if 1302 | an objective k in position i is the one that maximizes 1303 | it, it doesn't matter the order of the objectives in 1304 | positions lower than i, the number of dominated points 1305 | from dimension 0 to i-1 will always be the same, so 1306 | it's not necessary to worry about the order of those 1307 | objectives. 1308 | 1309 | When this cycle starts, 'order' has the original order and 1310 | so 'count' has the number of points dominated from 0 1311 | to every k, where k < dim or 'order' has the last 1312 | order of objectives used to calculate the best 1313 | objective to put in position i+1 that maximizes the 1314 | number of dominated points from dimension 0 to i and 1315 | so 'count' has the number of points dominated from 1316 | dimension 0 to every k, where k < dim, that was 1317 | calculated previously. 1318 | 1319 | There on, it is not necessary to calculate the number of 1320 | dominated points from dimension 0 to i-1 with the actual 1321 | objective in position i (order[i]), because this value was 1322 | previously calculated and so it is only necessary to 1323 | calculate the number of dominated points when the current 1324 | objectives in order[k], where k < i, are in position i. */ 1325 | for (j = 0; j < i; j++) { 1326 | int aux = order[i]; 1327 | order[i] = order[j]; 1328 | order[j] = aux; 1329 | 1330 | /* Determine the number of dominated points from dimension 1331 | 0 to k, where k < i (the number of points dominated 1332 | from dimension 0 to t, where t >= i, is already known 1333 | from previous calculations) with a different objective 1334 | in position i. */ 1335 | determine_ndom(list, i-1, order, count); 1336 | 1337 | /* If the order in 'order' is better than the previously 1338 | best order, than the actual order is now the best. An 1339 | order is better than another if the number of dominated 1340 | points from dimension 0 to i-1 is higher. If this 1341 | number is equal, then the best is the one that has the 1342 | most dominated points from dimension 0 to i-2. If this 1343 | number is equal, than the last order considered the 1344 | best, still remains the best order so far. */ 1345 | if (best_count[i-1] < count[i-1] 1346 | || (best_count[i-1] == count[i-1] 1347 | && best_count[i-2] < count[i-2])) { 1348 | for (k = 0; k <= i; k++) { 1349 | best_count[k] = count[k]; 1350 | best_order[k] = order[k]; 1351 | } 1352 | p = list->prev[0]; 1353 | while (p != list) { 1354 | p->ignore_best = p->ignore; 1355 | p = p->prev[0]; 1356 | } 1357 | } 1358 | } 1359 | 1360 | /* 1361 | If necessary, update 'order' with the best order so far and 1362 | the corresponding number of dominated points. In this way, 1363 | in the next iteration it is not necessary to recalculate the 1364 | number of dominated points from dimension 0 to i-2, when in 1365 | position i-1 is the objective that is currently in position 1366 | i-1, in the best order so far (best_order[i-1]). 1367 | */ 1368 | if (order[i] != best_order[i]) { 1369 | for (j = 0; j <= i; j++) { 1370 | count[j] = best_count[j]; 1371 | order[j] = best_order[j]; 1372 | } 1373 | p = list->prev[0]; 1374 | /* 1375 | The information about a point being dominated is updated 1376 | because, this way, in some cases it is not necessary to 1377 | find out (again) if a point is dominated. 1378 | */ 1379 | while (p != list) { 1380 | p->ignore = p->ignore_best; 1381 | p = p->prev[0]; 1382 | } 1383 | } 1384 | 1385 | } 1386 | 1387 | free(count); 1388 | free(best_count); 1389 | free(best_order); 1390 | return c; 1391 | } 1392 | 1393 | /* 1394 | Reorders the reference point's objectives according to an order 'order'. 1395 | */ 1396 | static void reorder_reference(double *reference, int d, int *order) 1397 | { 1398 | int j; 1399 | double *tmp = (double *) malloc(d * sizeof(double)); 1400 | for (j = 0; j < d; j++) { 1401 | tmp[j] = reference[j]; 1402 | } 1403 | for (j = 0; j < d; j++) { 1404 | reference[j] = tmp[order[j]]; 1405 | } 1406 | free(tmp); 1407 | } 1408 | 1409 | /* 1410 | Reorders the dimensions for every point according to an order. 1411 | */ 1412 | void reorder_list(dlnode_t *list, int d, int *order) 1413 | { 1414 | int j; 1415 | double *x; 1416 | double *tmp = (double *) malloc(d * sizeof(double)); 1417 | dlnode_t **prev = (dlnode_t **) malloc(d * sizeof(dlnode_t *)); 1418 | dlnode_t **next = (dlnode_t **) malloc(d * sizeof(dlnode_t *)); 1419 | dlnode_t *p; 1420 | 1421 | for(j = 0; j < d; j++) { 1422 | prev[j] = list->prev[j]; 1423 | next[j] = list->next[j]; 1424 | } 1425 | 1426 | for(j = 0; j < d; j++) { 1427 | list->prev[j] = prev[order[j]]; 1428 | list->next[j] = next[order[j]]; 1429 | } 1430 | p = list->next[0]; 1431 | 1432 | while (p != list) { 1433 | p->ignore = 0; 1434 | x = p->x; 1435 | for(j = 0; j < d; j++) { 1436 | tmp[j] = x[j]; 1437 | prev[j] = p->prev[j]; 1438 | next[j] = p->next[j]; 1439 | } 1440 | 1441 | for(j = 0; j < d; j++) { 1442 | x[j] = tmp[order[j]]; 1443 | p->prev[j] = prev[order[j]]; 1444 | p->next[j] = next[order[j]]; 1445 | } 1446 | p = p->next[0]; 1447 | } 1448 | free(tmp); 1449 | free(prev); 1450 | free(next); 1451 | } 1452 | #endif 1453 | 1454 | double fpli_hv(double *data, int d, int n, const double *ref) 1455 | { 1456 | dlnode_t *list; 1457 | double hyperv; 1458 | double * bound = NULL; 1459 | int i; 1460 | 1461 | #if VARIANT >= 3 1462 | bound = malloc (d * sizeof(double)); 1463 | for (i = 0; i < d; i++) bound[i] = -DBL_MAX; 1464 | #endif 1465 | 1466 | tree = avl_alloc_tree ((avl_compare_t) compare_tree_asc, 1467 | (avl_freeitem_t) NULL); 1468 | 1469 | list = setup_cdllist(data, d, n); 1470 | 1471 | n = filter(list, d, n, ref); 1472 | if (n == 0) { 1473 | hyperv = 0.0; 1474 | } else if (n == 1) { 1475 | dlnode_t * p = list->next[0]; 1476 | hyperv = 1; 1477 | for (i = 0; i < d; i++) 1478 | hyperv *= ref[i] - p->x[i]; 1479 | } else { 1480 | hyperv = hv_recursive(list, d-1, n, ref, bound); 1481 | } 1482 | /* Clean up. */ 1483 | free_cdllist (list); 1484 | free (tree); /* The nodes are freed by free_cdllist (). */ 1485 | free (bound); 1486 | 1487 | return hyperv; 1488 | } 1489 | 1490 | #ifdef EXPERIMENTAL 1491 | 1492 | #include "timer.h" /* FIXME: Avoid calling Timer functions here. */ 1493 | double fpli_hv_order(double *data, int d, int n, const double *ref, int *order, 1494 | double *order_time, double *hv_time) 1495 | { 1496 | dlnode_t *list; 1497 | double hyperv; 1498 | double * bound = NULL; 1499 | double * ref_ord = (double *) malloc(d * sizeof(double)); 1500 | 1501 | #if VARIANT >= 3 1502 | int i; 1503 | 1504 | bound = malloc (d * sizeof(double)); 1505 | for (i = 0; i < d; i++) bound[i] = -DBL_MAX; 1506 | #endif 1507 | 1508 | tree = avl_alloc_tree ((avl_compare_t) compare_tree_asc, 1509 | (avl_freeitem_t) NULL); 1510 | 1511 | list = setup_cdllist(data, d, n); 1512 | 1513 | if (d > 3) { 1514 | n = define_order(list, d, n, order); 1515 | reorder_list(list, d, order); 1516 | 1517 | // copy reference so it will be unchanged for the next data sets. 1518 | for (i = 0; i < d; i++) 1519 | ref_ord[i] = ref[i]; 1520 | 1521 | reorder_reference(ref_ord, d, order); 1522 | 1523 | } else { 1524 | for(i = 0; i < d; i++) 1525 | ref_ord[i] = ref[i]; 1526 | } 1527 | 1528 | *order_time = Timer_elapsed_virtual (); 1529 | Timer_start(); 1530 | 1531 | n = filter(list, d, n, ref_ord); 1532 | if (n == 0) { 1533 | hyperv = 0.0; 1534 | } else if (n == 1) { 1535 | hyperv = 1; 1536 | dlnode_t * p = list->next[0]; 1537 | for (i = 0; i < d; i++) 1538 | hyperv *= ref[i] - p->x[i]; 1539 | } else { 1540 | hyperv = hv_recursive(list, d-1, n, ref, bound); 1541 | } 1542 | /* Clean up. */ 1543 | free_cdllist (list); 1544 | free (tree); /* The nodes are freed by free_cdllist (). */ 1545 | free (bound); 1546 | free (ref_ord); 1547 | 1548 | *hv_time = Timer_elapsed_virtual (); 1549 | 1550 | return hyperv; 1551 | } 1552 | #endif 1553 | -------------------------------------------------------------------------------- /HV/hv.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | hv.h 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2010 8 | Carlos M. Fonseca 9 | Manuel Lopez-Ibanez 10 | Luis Paquete 11 | Andreia P. Guerreiro 12 | 13 | This program is free software (software libre); you can redistribute 14 | it and/or modify it under the terms of the GNU General Public License 15 | as published by the Free Software Foundation; either version 2 of the 16 | License, or (at your option) any later version. As a particular 17 | exception, the contents of this file (hv.h) may also be redistributed 18 | and/or modified under the terms of the GNU Lesser General Public 19 | License (LGPL) as published by the Free Software Foundation; either 20 | version 3 of the License, or (at your option) any later version. 21 | 22 | This program is distributed in the hope that it will be useful, but 23 | WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 | General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with this program; if not, you can obtain a copy of the GNU 29 | General Public License at: 30 | http://www.gnu.org/copyleft/gpl.html 31 | or by writing to: 32 | Free Software Foundation, Inc., 59 Temple Place, 33 | Suite 330, Boston, MA 02111-1307 USA 34 | 35 | ---------------------------------------------------------------------- 36 | 37 | 38 | *************************************************************************/ 39 | #ifndef HV_H_ 40 | #define HV_H_ 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | extern int stop_dimension; 47 | double fpli_hv(double *data, int d, int n, const double *ref); 48 | 49 | #ifdef EXPERIMENTAL 50 | double fpli_hv_order(double *data, int d, int n, const double *ref, int *order, 51 | double *order_time, double *hv_time); 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /HV/io.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | I/O functions 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2005, 2006 8 | Carlos M. Fonseca 9 | Manuel Lopez-Ibanez 10 | Luis Paquete 11 | 12 | This program is free software (software libre); you can redistribute 13 | it and/or modify it under the terms of the GNU General Public License 14 | as published by the Free Software Foundation; either version 2 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, but 18 | WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this program; if not, you can obtain a copy of the GNU 24 | General Public License at: 25 | http://www.gnu.org/copyleft/gpl.html 26 | or by writing to: 27 | Free Software Foundation, Inc., 59 Temple Place, 28 | Suite 330, Boston, MA 02111-1307 USA 29 | 30 | ---------------------------------------------------------------------- 31 | 32 | *************************************************************************/ 33 | 34 | #include "io.h" 35 | #include "string.h" /* strerror */ 36 | #include "errno.h" /* errno */ 37 | 38 | #define PAGE_SIZE 4096 /* allocate one page at a time */ 39 | #define DATA_INC (PAGE_SIZE/sizeof(double)) 40 | 41 | int 42 | read_data (const char *filename, double **data_p, 43 | int *nobjs_p, int **cumsizes_p, int *nsets_p) 44 | { 45 | FILE *instream; 46 | 47 | int nobjs = *nobjs_p; /* number of objectives (and columns). */ 48 | int *cumsizes = *cumsizes_p; /* cumulative sizes of data sets. */ 49 | int nsets = *nsets_p; /* number of data sets. */ 50 | double *data = *data_p; 51 | 52 | double number; 53 | 54 | int retval; /* return value for fscanf */ 55 | char newline[2]; 56 | int ntotal; /* the current element of (*datap) */ 57 | 58 | int column, line; 59 | 60 | int datasize; 61 | int sizessize; 62 | 63 | int error = 0; 64 | 65 | if (filename == NULL) { 66 | instream = stdin; 67 | filename = ""; /* used to diagnose errors. */ 68 | } 69 | else if (NULL == (instream = fopen (filename,"r"))) { 70 | errprintf ("%s: %s\n", filename, strerror (errno)); 71 | exit (EXIT_FAILURE); 72 | } 73 | 74 | if (nsets == 0) { 75 | ntotal = 0; 76 | sizessize = 0; 77 | datasize = 0; 78 | } else { 79 | ntotal = nobjs * cumsizes[nsets - 1]; 80 | sizessize = ((nsets - 1) / DATA_INC + 1) * DATA_INC; 81 | datasize = ((ntotal - 1) / DATA_INC + 1) * DATA_INC; 82 | } 83 | 84 | /* if size is equal to zero, this is equivalent to free(). 85 | That is, reinitialize the data structures. */ 86 | cumsizes = realloc (cumsizes, sizessize * sizeof(int)); 87 | data = realloc (data, datasize * sizeof(double)); 88 | 89 | column = 0; 90 | line = 0; 91 | 92 | /* skip over leading whitespace, comments and empty lines. */ 93 | do { 94 | line++; 95 | /* skip full lines starting with # */ 96 | if (!fscanf (instream, "%1[#]%*[^\n\r]", newline)) 97 | /* and whitespace */ 98 | fscanf (instream, "%*[ \t]"); 99 | retval = fscanf (instream, "%1[\r\n]", newline); 100 | } while (retval == 1); 101 | 102 | if (retval == EOF) { /* faster than !feof() */ 103 | error = READ_INPUT_FILE_EMPTY; 104 | goto read_data_finish; 105 | } 106 | 107 | do { 108 | /* beginning of data set */ 109 | if (nsets == sizessize) { 110 | sizessize += DATA_INC; 111 | cumsizes = realloc (cumsizes, sizessize * sizeof(int)); 112 | } 113 | 114 | cumsizes[nsets] = (nsets == 0) ? 0 : cumsizes[nsets - 1]; 115 | 116 | do { 117 | /* beginning of row */ 118 | column = 0; 119 | 120 | do { 121 | /* new column */ 122 | column++; 123 | 124 | if (fscanf (instream, "%lf", &number) != 1) { 125 | char buffer[64]; 126 | fscanf (instream, "%60[^ \t\r\n]", buffer); 127 | errprintf ("%s: line %d column %d: " 128 | "could not convert string `%s' to double", 129 | filename, line, column, buffer); 130 | exit (EXIT_FAILURE); 131 | } 132 | 133 | if (ntotal == datasize) { 134 | datasize += DATA_INC; 135 | data = realloc (data, datasize * sizeof(double)); 136 | } 137 | data[ntotal] = number; 138 | ntotal++; 139 | 140 | #if DEBUG > 1 141 | fprintf (stderr, "%s:%d:%d(%d) %d (set %d) = " 142 | point_printf_format "\n", 143 | filename, line, column, nobjs, 144 | cumsizes[nsets], nsets, (double)number); 145 | #endif 146 | /* skip possible trailing whitespace */ 147 | fscanf (instream, "%*[ \t]"); 148 | retval = fscanf (instream, "%1[\r\n]", newline); 149 | /* We do not consider that '\r\n' starts a new set. */ 150 | if (retval == 1 && newline[0] == '\r') 151 | fscanf (instream, "%*[\n]"); 152 | } while (retval == 0); 153 | 154 | if (!nobjs) 155 | nobjs = column; 156 | else if (column == nobjs) 157 | ; /* OK */ 158 | else if (cumsizes[0] == 0) { /* just finished first row. */ 159 | errprintf ("%s: line %d: input has dimension %d" 160 | " while reference point has dimension %d", 161 | filename, line, column, nobjs); 162 | error = READ_INPUT_WRONG_INITIAL_DIM; 163 | goto read_data_finish; 164 | } else { 165 | errprintf ("%s: line %d has different number of columns (%d)" 166 | " from first row (%d)\n", 167 | filename, line, column, nobjs); 168 | exit (EXIT_FAILURE); 169 | } 170 | cumsizes[nsets]++; 171 | 172 | /* look for an empty line */ 173 | line++; 174 | if (!fscanf (instream, "%1[#]%*[^\n\r]", newline)) 175 | fscanf (instream, "%*[ \t]"); 176 | retval = fscanf (instream, "%1[\r\n]", newline); 177 | 178 | } while (retval == 0); 179 | 180 | nsets++; /* new data set */ 181 | 182 | #if DEBUG > 1 183 | fprintf (stderr, "%s: set %d, read %d rows\n", 184 | filename, nsets, cumsizes[nsets - 1]); 185 | #endif 186 | /* skip over successive empty lines */ 187 | do { 188 | line++; 189 | if (!fscanf (instream, "%1[#]%*[^\n\r]", newline)) 190 | fscanf (instream, "%*[ \t]"); 191 | retval = fscanf (instream, "%1[\r\n]", newline); 192 | } while (retval == 1); 193 | 194 | } while (retval != EOF); /* faster than !feof() */ 195 | 196 | /* adjust to real size (saves memory but probably slower). */ 197 | cumsizes = realloc (cumsizes, nsets * sizeof(int)); 198 | data = realloc (data, ntotal * sizeof(double)); 199 | 200 | read_data_finish: 201 | 202 | *nobjs_p = nobjs; 203 | *nsets_p = nsets; 204 | *cumsizes_p = cumsizes; 205 | *data_p = data; 206 | 207 | if (instream != stdin) 208 | fclose (instream); 209 | 210 | return error; 211 | } 212 | 213 | /* From: 214 | 215 | Edition 0.10, last updated 2001-07-06, of `The GNU C Library 216 | Reference Manual', for Version 2.3.x. 217 | 218 | Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 219 | 2003 Free Software Foundation, Inc. 220 | */ 221 | void errprintf(const char *template,...) 222 | { 223 | extern char *program_invocation_short_name; 224 | va_list ap; 225 | 226 | fprintf(stderr, "%s: error: ", program_invocation_short_name); 227 | va_start(ap,template); 228 | vfprintf(stderr, template, ap); 229 | va_end(ap); 230 | fprintf(stderr, "\n"); 231 | 232 | exit(EXIT_FAILURE); 233 | } 234 | /* End of copyright The GNU C Library Reference Manual */ 235 | 236 | void warnprintf(const char *template,...) 237 | { 238 | extern char *program_invocation_short_name; 239 | va_list ap; 240 | 241 | fprintf(stderr, "%s: warning: ", program_invocation_short_name); 242 | va_start(ap,template); 243 | vfprintf(stderr, template, ap); 244 | va_end(ap); 245 | fprintf(stderr, "\n"); 246 | 247 | } 248 | -------------------------------------------------------------------------------- /HV/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _HV_IO_H_ 2 | #define _HV_IO_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define point_printf_format "%-16.15g" 9 | 10 | /* If we're not using GNU C, elide __attribute__ */ 11 | #ifndef __GNUC__ 12 | # define __attribute__(x) /* NOTHING */ 13 | #endif 14 | 15 | void 16 | errprintf(const char * template,...) 17 | /* enables the compiler to check the format string against the 18 | parameters */ __attribute__ ((format(printf, 1, 2))); 19 | 20 | void warnprintf(const char *template,...) 21 | /* enables the compiler to check the format string against the 22 | parameters */ __attribute__ ((format(printf, 1, 2))); 23 | 24 | /* Error codes for read_data. */ 25 | #define READ_INPUT_FILE_EMPTY -1 26 | #define READ_INPUT_WRONG_INITIAL_DIM -2 27 | 28 | int 29 | read_data (const char *filename, double **data_p, 30 | int *nobjs_p, int **cumsizes_p, int *nsets_p); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /HV/main-hv.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | hv: main program 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2010 8 | Carlos M. Fonseca 9 | Manuel Lopez-Ibanez 10 | Luis Paquete 11 | Andreia Prospero Guerreiro 12 | 13 | This program is free software (software libre); you can redistribute 14 | it and/or modify it under the terms of the GNU General Public License 15 | as published by the Free Software Foundation; either version 2 of the 16 | License, or (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, but 19 | WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | General Public License for more details. 22 | 23 | You should have received a copy of the GNU General Public License 24 | along with this program; if not, you can obtain a copy of the GNU 25 | General Public License at: 26 | http://www.gnu.org/copyleft/gpl.html 27 | or by writing to: 28 | Free Software Foundation, Inc., 59 Temple Place, 29 | Suite 330, Boston, MA 02111-1307 USA 30 | 31 | ---------------------------------------------------------------------- 32 | 33 | Relevant literature: 34 | 35 | [1] C. M. Fonseca, L. Paquete, and M. Lopez-Ibanez. An 36 | improved dimension-sweep algorithm for the hypervolume 37 | indicator. In IEEE Congress on Evolutionary Computation, 38 | pages 1157-1163, Vancouver, Canada, July 2006. 39 | 40 | [2] Nicola Beume, Carlos M. Fonseca, Manuel Lopez-Ibanez, Luis Paquete, and 41 | J. Vahrenhold. On the complexity of computing the hypervolume 42 | indicator. IEEE Transactions on Evolutionary Computation, 43 | 13(5):1075-1082, 2009. 44 | 45 | *************************************************************************/ 46 | #include "io.h" 47 | #include "hv.h" 48 | #include "timer.h" 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include // for isspace() 56 | 57 | #include // for getopt() 58 | #include // for getopt_long() 59 | 60 | #ifdef __USE_GNU 61 | extern char *program_invocation_short_name; 62 | #else 63 | char *program_invocation_short_name; 64 | #endif 65 | 66 | static const char * const stdin_name = ""; 67 | static int verbose_flag = 1; 68 | static bool union_flag = false; 69 | #ifdef EXPERIMENTAL 70 | static bool order_flag = false; 71 | #endif 72 | static char *suffix = NULL; 73 | 74 | static void usage(void) 75 | { 76 | printf("\n" 77 | "Usage: %s [OPTIONS] [FILE...]\n\n", program_invocation_short_name); 78 | 79 | printf( 80 | "Calculate the hypervolume of each input set of each FILE. \n" 81 | "With no FILE, or when FILE is -, read standard input.\n\n" 82 | 83 | "Options:\n" 84 | " -h, --help print this summary and exit. \n" 85 | " --version print version number and exit. \n" 86 | " -v, --verbose print some information (time, maximum, etc). \n" 87 | " -q, --quiet print just the hypervolume (as opposed to --verbose). \n" 88 | " -u, --union treat all input sets within a FILE as a single set. \n" 89 | " -r, --reference=POINT use POINT as reference point. POINT must be within \n" 90 | " quotes, e.g., \"10 10 10\". If no reference point is \n" 91 | " given, it is taken as the maximum for each coordinate \n" 92 | " from the union of all input points. \n" 93 | /* 94 | " given, it is taken as max + 0.1 * (max - min) for each\n" 95 | " coordinate from the union of all input points. \n" 96 | */ 97 | " -s, --suffix=STRING Create an output file for each input file by appending\n" 98 | " this suffix. This is ignored when reading from stdin. \n" 99 | " If missing, output is sent to stdout. \n" 100 | #ifdef EXPERIMENTAL 101 | " -R --reorder find a good order to process the objectives and \n" 102 | " calculates the hypervolume using that order \n" 103 | #endif 104 | " -1, --stop-on-1D stop recursion in dimension 1 \n" 105 | " -2, --stop-on-2D stop recursion in dimension 2 %s\n" 106 | " -3, --stop-on-3D stop recursion in dimension 3 %s\n" 107 | "\n", 108 | (stop_dimension == 1) ? ("(default)") : (""), 109 | (stop_dimension == 2) ? ("(default)") : ("") ); 110 | 111 | } 112 | 113 | static void version(void) 114 | { 115 | printf("%s version " VERSION 116 | #ifdef ARCH 117 | " (optimised for " ARCH ")" 118 | #endif 119 | "\n\n", program_invocation_short_name); 120 | 121 | printf( 122 | "Copyright (C) 2010" 123 | "\nCarlos M. Fonseca " 124 | "\nManuel Lopez-Ibanez " 125 | "\nLuis Paquete " 126 | "\nAndreia P. Guerreiro \n" 127 | "\n" 128 | "This is free software, and you are welcome to redistribute it under certain\n" 129 | "conditions. See the GNU General Public License for details. There is NO \n" 130 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" 131 | "\n" ); 132 | } 133 | 134 | static inline void 135 | vector_printf (const double *vector, int size) 136 | { 137 | int k; 138 | for (k = 0; k < size; k++) 139 | printf (" %f", vector[k]); 140 | } 141 | 142 | static double * 143 | read_reference(char * str, int *nobj) 144 | { 145 | double * reference; 146 | char * endp; 147 | char * cursor; 148 | 149 | int k = 0, size = 10; 150 | 151 | reference = malloc(size * sizeof(double)); 152 | endp = str; 153 | 154 | do { 155 | cursor = endp; 156 | if (k == size) { 157 | size += 10; 158 | reference = realloc(reference, size * sizeof(double)); 159 | } 160 | reference[k] = strtod(cursor, &endp); 161 | k++; 162 | } while (cursor != endp); 163 | 164 | // not end of string: error 165 | while (*cursor != '\0') { 166 | if (!isspace(*cursor)) return NULL; 167 | cursor++; 168 | } 169 | 170 | // no number: error 171 | if (k == 1) return NULL; 172 | 173 | *nobj = k - 1; 174 | return reference; 175 | } 176 | 177 | static inline void 178 | handle_read_data_error (int err, const char *filename) 179 | { 180 | switch (err) { 181 | case 0: /* No error */ 182 | break; 183 | 184 | case READ_INPUT_FILE_EMPTY: 185 | errprintf ("%s: no input data.", filename); 186 | exit (EXIT_FAILURE); 187 | 188 | case READ_INPUT_WRONG_INITIAL_DIM: 189 | errprintf ("check the argument of -r, --reference.\n"); 190 | default: 191 | exit (EXIT_FAILURE); 192 | } 193 | } 194 | 195 | static void 196 | data_range (double **maximum, double **minimum, 197 | const double *data, int nobj, int rows) 198 | { 199 | int n, k = 0; 200 | int r = 0; 201 | 202 | if (*maximum == NULL) { 203 | *maximum = malloc (nobj*sizeof(double)); 204 | for (k = 0; k < nobj; k++) 205 | (*maximum)[k] = data[k]; 206 | r = 1; 207 | } 208 | 209 | if (*minimum == NULL) { 210 | *minimum = malloc (nobj*sizeof(double)); 211 | for (k = 0; k < nobj; k++) 212 | (*minimum)[k] = data[k]; 213 | r = 1; 214 | } 215 | 216 | for (; r < rows; r++) { 217 | for (n = 0; n < nobj; n++, k++) { 218 | if ((*maximum)[n] < data[k]) 219 | (*maximum)[n] = data[k]; 220 | if ((*minimum)[n] > data[k]) 221 | (*minimum)[n] = data[k]; 222 | } 223 | } 224 | } 225 | 226 | static void 227 | file_range (const char *filename, double **maximum_p, double **minimum_p, 228 | int *dim_p) 229 | { 230 | double *data = NULL; 231 | int *cumsizes = NULL; 232 | int nruns = 0; 233 | int dim = *dim_p; 234 | double *maximum = *maximum_p; 235 | double *minimum = *minimum_p; 236 | 237 | handle_read_data_error ( 238 | read_data (filename, &data, &dim, &cumsizes, &nruns), filename); 239 | 240 | data_range (&maximum, &minimum, data, dim, cumsizes[nruns-1]); 241 | 242 | *dim_p = dim; 243 | *maximum_p = maximum; 244 | *minimum_p = minimum; 245 | 246 | free (data); 247 | free (cumsizes); 248 | } 249 | 250 | /* 251 | FILENAME: input filename. If NULL, read stdin. 252 | 253 | REFERENCE: reference point. If NULL, use MAXIMUM. 254 | 255 | MAXIMUM: maximum objective vector. If NULL, caculate it from the 256 | input file. 257 | 258 | NOBJ_P: pointer to number of objectives. If NULL, calculate it from 259 | input file. 260 | 261 | */ 262 | 263 | static void 264 | hv_file (const char *filename, double *reference, 265 | double *maximum, double *minimum, int *nobj_p) 266 | { 267 | double *data = NULL; 268 | int *cumsizes = NULL; 269 | int cumsize; 270 | int nruns = 0; 271 | int n; 272 | int nobj = *nobj_p; 273 | char *outfilename = NULL; 274 | FILE *outfile = stdout; 275 | bool setmax = false; 276 | bool setref = false; 277 | 278 | int err = read_data (filename, &data, &nobj, &cumsizes, &nruns); 279 | if (!filename) filename = stdin_name; 280 | handle_read_data_error (err, filename); 281 | 282 | if (filename != stdin_name && suffix) { 283 | int outfilename_len = strlen(filename) + strlen(suffix) + 1; 284 | 285 | outfilename = malloc (sizeof(char) * outfilename_len); 286 | strcpy (outfilename, filename); 287 | strcat (outfilename, suffix); 288 | 289 | outfile = fopen (outfilename, "w"); 290 | if (outfile == NULL) { 291 | errprintf ("%s: %s\n", outfilename, strerror(errno)); 292 | exit (EXIT_FAILURE); 293 | } 294 | } 295 | 296 | if (union_flag) { 297 | cumsizes[0] = cumsizes[nruns - 1]; 298 | nruns = 1; 299 | } 300 | 301 | if (verbose_flag >= 2) 302 | printf("# file: %s\n", filename); 303 | 304 | if (maximum == NULL) { 305 | setmax = true; 306 | data_range (&maximum, &minimum, data, nobj, cumsizes[nruns-1]); 307 | if (verbose_flag >= 2) { 308 | printf ("# maximum:"); 309 | vector_printf (maximum, nobj); 310 | printf ("\n"); 311 | printf ("# minimum:"); 312 | vector_printf (minimum, nobj); 313 | printf ("\n"); 314 | } 315 | } 316 | 317 | if (reference != NULL) { 318 | for (n = 0; n < nobj; n++) { 319 | if (reference[n] <= maximum[n]) { 320 | warnprintf ("%s: some points do not strictly dominate " 321 | "the reference point and they will be discarded", 322 | filename); 323 | break; 324 | } 325 | } 326 | } else { 327 | setref = true; 328 | reference = malloc(nobj * sizeof(double)); 329 | for (n = 0; n < nobj; n++) { 330 | /* default reference point is: */ 331 | reference[n] = maximum[n]; 332 | /* however, a better reference point is: 333 | reference[n] = maximum[n] + 0.1 * (maximum[n] - minimum[n]); 334 | so that extreme points have some influence. */ 335 | } 336 | } 337 | 338 | if (verbose_flag >= 2) { 339 | printf ("# reference:"); 340 | vector_printf (reference, nobj); 341 | printf ("\n"); 342 | } 343 | 344 | for (n = 0, cumsize = 0; n < nruns; cumsize = cumsizes[n], n++) { 345 | double time_elapsed_cpu; 346 | double volume; 347 | 348 | if (verbose_flag >= 2) 349 | fprintf (outfile, "# Data set %d:\n", n + 1); 350 | 351 | Timer_start (); 352 | 353 | #ifdef EXPERIMENTAL 354 | if (order_flag) { 355 | int *order; 356 | double order_time; 357 | 358 | order = malloc(nobj * sizeof(int)); 359 | 360 | volume = fpli_hv_order(&data[nobj * cumsize], nobj, cumsizes[n] - cumsize, 361 | reference, order, &order_time, &time_elapsed_cpu); 362 | 363 | if (volume == 0.0) { 364 | errprintf ("none of the points strictly dominates the reference point\n"); 365 | exit (EXIT_FAILURE); 366 | } 367 | 368 | fprintf (outfile, "%-16.15g\n", volume); 369 | 370 | 371 | if(verbose_flag >= 2){ 372 | int i; 373 | fprintf (outfile, "# Order: "); 374 | for(i = 0; i < nobj; i++) 375 | fprintf(outfile, "%d ",order[i]); 376 | fprintf (outfile, "\n"); 377 | 378 | fprintf (outfile, "# Time computing order (cpu): %f seconds\n", order_time); 379 | } 380 | free(order); 381 | } else 382 | #endif 383 | { 384 | Timer_start (); 385 | volume = fpli_hv (&data[nobj * cumsize], nobj, 386 | cumsizes[n] - cumsize, reference); 387 | if (volume == 0.0) { 388 | errprintf ("none of the points strictly dominates the reference point\n"); 389 | exit (EXIT_FAILURE); 390 | } 391 | 392 | time_elapsed_cpu = Timer_elapsed_virtual (); 393 | 394 | fprintf (outfile, "%-16.15g\n", volume); 395 | 396 | #ifdef EXPERIMENTAL 397 | if (verbose_flag >= 2) { 398 | int i; 399 | fprintf (outfile, "# Order: "); 400 | for(i = 0; i < nobj; i++) 401 | fprintf(outfile, "%d ", i); 402 | fprintf (outfile, "\n"); 403 | } 404 | #endif 405 | } 406 | 407 | if (verbose_flag >= 2) { 408 | fprintf (outfile, "# Time computing hypervolume (cpu): %f seconds\n", time_elapsed_cpu); 409 | } 410 | 411 | } 412 | 413 | if (outfilename) { 414 | if (verbose_flag) 415 | fprintf (stderr, "# %s -> %s\n", filename, outfilename); 416 | fclose (outfile); 417 | free (outfilename); 418 | } 419 | free (data); 420 | free (cumsizes); 421 | if (setmax){ 422 | free (maximum); 423 | free (minimum); 424 | } 425 | if (setref) free(reference); 426 | *nobj_p = nobj; 427 | } 428 | 429 | int main(int argc, char *argv[]) 430 | { 431 | double *reference = NULL; 432 | int nobj = 0; 433 | int numfiles, k; 434 | 435 | int opt; /* it's actually going to hold a char. */ 436 | int longopt_index; 437 | 438 | /* see the man page for getopt_long for an explanation of these fields. */ 439 | static struct option long_options[] = { 440 | {"help", no_argument, NULL, 'h'}, 441 | {"version", no_argument, NULL, 'V'}, 442 | {"verbose", no_argument, NULL, 'v'}, 443 | {"quiet", no_argument, NULL, 'q'}, 444 | {"reference", required_argument, NULL, 'r'}, 445 | {"union", no_argument, NULL, 'u'}, 446 | {"stop-on-1D", no_argument, NULL, '1'}, 447 | {"stop-on-2D", no_argument, NULL, '2'}, 448 | {"stop-on-3D", no_argument, NULL, '3'}, 449 | {"suffix", required_argument, NULL, 's'}, 450 | #ifdef EXPERIMENTAL 451 | {"reorder", no_argument, NULL, 'R'}, 452 | #endif 453 | 454 | {NULL, 0, NULL, 0} /* marks end of list */ 455 | }; 456 | 457 | #ifndef __USE_GNU 458 | program_invocation_short_name = argv[0]; 459 | #endif 460 | 461 | while (0 < (opt = getopt_long (argc, argv, "hVvquRr:123s:", 462 | long_options, &longopt_index))) { 463 | switch (opt) { 464 | case '1': 465 | stop_dimension = 0; break; 466 | 467 | case '2': 468 | stop_dimension = 1; break; 469 | 470 | case '3': 471 | stop_dimension = 2; break; 472 | 473 | case 'r': // --reference 474 | reference = read_reference (optarg, &nobj); 475 | if (reference == NULL) { 476 | errprintf ("invalid reference point '%s'", 477 | optarg); 478 | exit (EXIT_FAILURE); 479 | } 480 | break; 481 | 482 | case 'u': // --union 483 | union_flag = true; 484 | break; 485 | 486 | case 's': // --suffix 487 | suffix = optarg; 488 | break; 489 | 490 | case 'V': // --version 491 | version(); 492 | exit(EXIT_SUCCESS); 493 | 494 | case 'q': // --quiet 495 | verbose_flag = 0; 496 | break; 497 | 498 | case 'v': // --verbose 499 | verbose_flag = 2; 500 | break; 501 | 502 | case 'R': // --reorder 503 | #ifdef EXPERIMENTAL 504 | order_flag = true; 505 | break; 506 | #endif 507 | case '?': 508 | // getopt prints an error message right here 509 | fprintf (stderr, "Try `%s --help' for more information.\n", 510 | program_invocation_short_name); 511 | exit(EXIT_FAILURE); 512 | case 'h': 513 | usage(); 514 | exit(EXIT_SUCCESS); 515 | 516 | default: // should never happen 517 | abort(); 518 | } 519 | } 520 | 521 | numfiles = argc - optind; 522 | 523 | if (numfiles < 1) /* Read stdin. */ 524 | hv_file (NULL, reference, NULL, NULL, &nobj); 525 | 526 | else if (numfiles == 1) { 527 | hv_file (argv[optind], reference, NULL, NULL, &nobj); 528 | } 529 | else { 530 | double *maximum = NULL; 531 | double *minimum = NULL; 532 | if (reference == NULL) { 533 | /* Calculate the maximum among all input files to use as 534 | reference point. */ 535 | for (k = 0; k < numfiles; k++) 536 | file_range (argv[optind + k], &maximum, &minimum, &nobj); 537 | 538 | if (verbose_flag >= 2) { 539 | printf ("# maximum:"); 540 | vector_printf (maximum, nobj); 541 | printf ("\n"); 542 | printf ("# minimum:"); 543 | vector_printf (minimum, nobj); 544 | printf ("\n"); 545 | } 546 | } 547 | for (k = 0; k < numfiles; k++) 548 | hv_file (argv[optind + k], reference, maximum, minimum, &nobj); 549 | 550 | free (maximum); 551 | free (minimum); 552 | } 553 | if (reference != NULL) free (reference); 554 | return EXIT_SUCCESS; 555 | } 556 | -------------------------------------------------------------------------------- /HV/mk/Darwin_i386_cc.mk: -------------------------------------------------------------------------------- 1 | include mk/gcc.mk 2 | 3 | ifdef MARCH 4 | OPT_CFLAGS += -march=$(MARCH) 5 | ARCH := $(MARCH) 6 | else ifeq ($(shell which gcc-mp-4.4 > /dev/null && echo y),y) 7 | CC := gcc-mp-4.4 8 | ARCH := $(gcc-guess-march) 9 | OPT_CFLAGS += -march=$(ARCH) 10 | else ifeq ($(shell which gcc-4.2 > /dev/null && echo y),y) 11 | CC := gcc-4.2 12 | ARCH := native 13 | OPT_CFLAGS += -mtune=$(ARCH) 14 | else 15 | $(warning No processor specific optimizations set. Consider defining OPT_CFLAGS manually.) 16 | endif 17 | -------------------------------------------------------------------------------- /HV/mk/Darwin_i386_gcc-4.2.mk: -------------------------------------------------------------------------------- 1 | include mk/gcc.mk 2 | 3 | ifdef MARCH 4 | ARCH := $(MARCH) 5 | OPT_CFLAGS += -march=$(MARCH) 6 | else 7 | ## gcc-4.2 does not support -march=native on OS X for some reason... 8 | ARCH := native 9 | OPT_CFLAGS += -mtune=$(ARCH) 10 | endif 11 | 12 | -------------------------------------------------------------------------------- /HV/mk/Linux_x86_64_icc.mk: -------------------------------------------------------------------------------- 1 | include mk/icc.mk 2 | 3 | ifdef XARCH 4 | OPT_CFLAGS += -x$(XARCH) 5 | ARCH := $(XARCH) 6 | else 7 | ARCH := native 8 | OPT_CFLAGS += -xHOST 9 | endif 10 | -------------------------------------------------------------------------------- /HV/mk/Linux_x86_64_pathcc.mk: -------------------------------------------------------------------------------- 1 | ## Patchscales compiler is partially based on gccs front-end. It is therefore safe to use 2 | ## the gcc defaults. 3 | 4 | ifndef MARCH 5 | ## auto is for pathscale what native is for gcc: 6 | MARCH=auto 7 | endif 8 | 9 | include mk/gcc.mk 10 | -------------------------------------------------------------------------------- /HV/mk/Linux_x86_64_pgcc.mk: -------------------------------------------------------------------------------- 1 | include mk/pgcc.mk 2 | 3 | ifdef MARCH 4 | ARCH := $(MARCH) 5 | OPT_CFLAGS += -tp=$(ARCH) 6 | else 7 | $(warning Using generic x64 cpu target. Consider setting MARCH to a value given by 'pgcc -tp') 8 | ARCH := x64 9 | OPT_CFLAGS += -tp=$(ARCH) 10 | endif 11 | 12 | -------------------------------------------------------------------------------- /HV/mk/Linux_x86_64_suncc.mk: -------------------------------------------------------------------------------- 1 | include mk/suncc.mk 2 | 3 | ifdef XTARGET 4 | ARCH := $(XTARGET) 5 | OPT_CFLAGS += -xtarget=$(ARCH) 6 | else 7 | ifdef XARCH 8 | ARCH := $(XARCH) 9 | OPT_CFLAGS += -xarch=$(ARCH) 10 | else 11 | ARCH := native 12 | OPT_CFLAGS += -xtarget=$(ARCH) 13 | endif 14 | endif 15 | -------------------------------------------------------------------------------- /HV/mk/README: -------------------------------------------------------------------------------- 1 | ------------------------ 2 | Adding new compilers 3 | ------------------------ 4 | 5 | If you want or need to add a new compiler / architecture combination 6 | to the build system you will need to create a file named 7 | 8 | $(uname -s)_$(uname -m)_.mk 9 | 10 | At a minimum it needs to set the OPT_CFLAGS and ARCH variables. If all 11 | you want to do is use GCC on a new platform you can usually simple 12 | include gcc.mk. In general this should only be necessary if you are 13 | cross-compiling or want to add additional flags after the general gcc 14 | detection logic. 15 | 16 | If your compiler is unknown, the build system will attempt to auto 17 | detect if it is a gcc variant and then use mk/gcc.mk. 18 | 19 | If you have new platform or compiler support files, please submit them 20 | to manuel.lopez-ibanezulb.ac.be. 21 | -------------------------------------------------------------------------------- /HV/mk/cc.mk: -------------------------------------------------------------------------------- 1 | # -*- Makefile-gmake -*- 2 | 3 | CCversion=$(shell $(CC) -v 2>&1) 4 | 5 | ## Is $(CC) a gcc variant? 6 | ifneq (,$(findstring gcc,$(CCversion))) 7 | $(info Detected C compiler to be a GCC variant.) 8 | include mk/gcc.mk 9 | endif 10 | 11 | # Is $(CC) the Sun C compiler? 12 | ifneq (,$(findstring Sun,$(CCversion))) 13 | $(info Detected C compiler to the Sun Studio C compiler.) 14 | include mk/suncc.mk 15 | endif 16 | -------------------------------------------------------------------------------- /HV/mk/gcc.mk: -------------------------------------------------------------------------------- 1 | # -*- Makefile-gmake -*- 2 | MISSING_MARCH_BEGIN=Cannot guess cpu type for gcc 3 | MISSING_MARCH_END=. Please specify your cpu type, \ 4 | 'make march=i686' typically works fine in most computers. \ 5 | For more fine tuning, consult compiler manual. 6 | 7 | 8 | ifneq ($(uname_S),mingw) 9 | GCC_MAJOR := $(shell $(CC) -E -dM - < /dev/null | grep "__GNUC__" | cut -d\ -f3) 10 | GCC_MINOR := $(shell $(CC) -E -dM - < /dev/null | grep "__GNUC_MINOR__" | cut -d\ -f3) 11 | 12 | gcc-guess-march = $(strip $(shell ${CC} -march=$(MARCH) -x c -S -\#\#\# - < /dev/null 2>&1 | \ 13 | grep -o -e "march=[^'\"]*" | head -n 1 | \ 14 | sed 's,march=,,')) 15 | else 16 | ifndef MARCH 17 | MARCH=native 18 | gcc-guess-march=native 19 | endif 20 | endif 21 | 22 | WARN_CFLAGS = -pedantic -Wall -Wextra -Wvla 23 | CFLAGS += -std=gnu99 $(WARN_CFLAGS) 24 | 25 | ifeq ($(DEBUG), 0) 26 | OPT_CFLAGS := -O3 -funroll-loops -ffast-math -DNDEBUG -mfpmath=sse 27 | # Options -msse -mfpmath=sse improve performance but are not portable. 28 | # Options -fstandard-precision=fast -ftree-vectorize are not well 29 | # supported in some versions/architectures. 30 | else 31 | CFLAGS += -g3 -mfpmath=sse 32 | endif 33 | 34 | ifndef MARCH 35 | ifeq ($(GCC_MAJOR),2) 36 | $(error Please upgrade to a recent version of GCC (>= 4.0)) 37 | endif 38 | ifeq ($(GCC_MAJOR),3) 39 | $(error $(MISSING_MARCH_BEGIN) 3$(MISSING_MARCH_END)) 40 | endif 41 | ifeq ($(GCC_MINOR),0) 42 | $(error $(MISSING_MARCH_BEGIN) 4.0$(MISSING_MARCH_END)) 43 | endif 44 | ifeq ($(GCC_MINOR),1) 45 | $(error $(MISSING_MARCH_BEGIN) 4.1$(MISSING_MARCH_END)) 46 | endif 47 | ifeq ($(GCC_MINOR),2) 48 | $(error $(MISSING_MARCH_BEGIN) 4.2$(MISSING_MARCH_END)) 49 | else 50 | MARCH := native 51 | ARCH := $(gcc-guess-march) 52 | OPT_CFLAGS += -march=$(MARCH) 53 | endif 54 | else 55 | ARCH := $(gcc-guess-march) 56 | OPT_CFLAGS += -march=$(MARCH) 57 | endif 58 | -------------------------------------------------------------------------------- /HV/mk/icc.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(DEBUG), 0) 2 | OPT_CFLAGS := -O3 -std=c99 -Wall -Wcheck 3 | else 4 | OPT_CFLAGS := -g -std=c99 -Wall -Wcheck 5 | endif 6 | 7 | AR := xiar 8 | -------------------------------------------------------------------------------- /HV/mk/pgcc.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(DEBUG), 0) 2 | OPT_CFLAGS := -fast -O3 -Msmartalloc -c99 3 | else 4 | OPT_CFLAGS := -g -c99 5 | endif 6 | -------------------------------------------------------------------------------- /HV/mk/suncc.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(DEBUG), 0) 2 | OPT_CFLAGS := -fast -xO3 -xc99=all 3 | else 4 | OPT_CFLAGS := -g -xc99=all 5 | endif 6 | -------------------------------------------------------------------------------- /HV/resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * resource.h 3 | * This file has no copyright assigned and is placed in the Public Domain. 4 | * This file is a part of the mingw-runtime package. 5 | * No warranty is given; refer to the file DISCLAIMER within the package. 6 | * 7 | * Based on: 8 | * http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/resource.h.html 9 | */ 10 | #ifndef _RESOURCE_H_ 11 | #define _RESOURCE_H_ 12 | 13 | #include /* for struct timeval */ 14 | 15 | #define RUSAGE_SELF (1<<0) 16 | #define RUSAGE_CHILDREN (1<<1) 17 | 18 | struct rusage 19 | { 20 | struct timeval ru_utime; /* user time used */ 21 | struct timeval ru_stime; /* system time used */ 22 | }; 23 | 24 | int getrusage(int who, struct rusage * usage); 25 | 26 | #endif /* Not _RESOURCE_H_ */ 27 | -------------------------------------------------------------------------------- /HV/svn_version: -------------------------------------------------------------------------------- 1 | 207:208 -------------------------------------------------------------------------------- /HV/timer.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | Simple timer functions. 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2005, 2006, 2007 Manuel Lopez-Ibanez 8 | TeX: \copyright 2005, 2006, 2007 Manuel L{\'o}pez-Ib{\'a}{\~n}ez 9 | 10 | This program is free software (software libre); you can redistribute 11 | it and/or modify it under the terms of the GNU General Public License 12 | as published by the Free Software Foundation; either version 2 of the 13 | License, or (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, but 16 | WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program; if not, you can obtain a copy of the GNU 22 | General Public License at: 23 | http://www.gnu.org/copyleft/gpl.html 24 | or by writing to: 25 | Free Software Foundation, Inc., 59 Temple Place, 26 | Suite 330, Boston, MA 02111-1307 USA 27 | 28 | ---------------------------------------------------------------------- 29 | 30 | NOTES: based on source code from Thomas Stuetzle. 31 | 32 | *************************************************************************/ 33 | 34 | #include 35 | #include /* for struct timeval */ 36 | #ifndef WIN32 37 | #include /* for getrusage */ 38 | #else 39 | #include "resource.h" 40 | #endif 41 | 42 | #include "timer.h" 43 | 44 | #define TIMER_CPUTIME(X) ( (double)X.ru_utime.tv_sec + \ 45 | (double)X.ru_stime.tv_sec + \ 46 | ((double)X.ru_utime.tv_usec + \ 47 | (double)X.ru_stime.tv_usec ) * 1.0E-6) 48 | 49 | #define TIMER_WALLTIME(X) ( (double)X.tv_sec + \ 50 | (double)X.tv_usec * 1.0E-6 ) 51 | 52 | static struct rusage res; 53 | static struct timeval tp; 54 | static double virtual_time, real_time; 55 | static double stop_virtual_time, stop_real_time; 56 | 57 | /* 58 | * The virtual time of day and the real time of day are calculated and 59 | * stored for future use. The future use consists of subtracting these 60 | * values from similar values obtained at a later time to allow the user 61 | * to get the amount of time used by the backtracking routine. 62 | */ 63 | 64 | void Timer_start() 65 | { 66 | gettimeofday (&tp, NULL ); 67 | real_time = TIMER_WALLTIME(tp); 68 | 69 | getrusage (RUSAGE_SELF, &res ); 70 | virtual_time = TIMER_CPUTIME(res); 71 | } 72 | 73 | /* 74 | * Return the time used in seconds (either 75 | * REAL or VIRTUAL time, depending on ``type''). 76 | */ 77 | double Timer_elapsed_virtual (void) 78 | { 79 | double timer_tmp_time; 80 | getrusage (RUSAGE_SELF, &res); 81 | timer_tmp_time = TIMER_CPUTIME(res) - virtual_time; 82 | 83 | #if DEBUG >= 4 84 | if (timer_tmp_time < 0.0) { 85 | fprintf(stderr, "%s: Timer_elapsed(): warning: " 86 | "negative increase in time ", __FILE__); 87 | fprintf(stderr, "(%.6g - %.6g = ", 88 | TIMER_CPUTIME(res) , virtual_time); 89 | fprintf(stderr, "%.6g)\n", timer_tmp_time); 90 | } 91 | #endif 92 | 93 | return (timer_tmp_time < 0.0) ? 0 : timer_tmp_time; 94 | } 95 | 96 | double Timer_elapsed_real (void) 97 | { 98 | double timer_tmp_time; 99 | 100 | gettimeofday (&tp, NULL); 101 | timer_tmp_time = TIMER_WALLTIME(tp) - real_time; 102 | 103 | #if DEBUG >= 2 104 | if (timer_tmp_time < 0.0) { 105 | fprintf(stderr, "%s: Timer_elapsed(): warning: " 106 | "negative increase in time ", __FILE__); 107 | fprintf(stderr, "(%.6g - %.6g = ", 108 | TIMER_WALLTIME(tp) , real_time); 109 | fprintf(stderr, "%.6g)\n", timer_tmp_time); 110 | } 111 | #endif 112 | 113 | return (timer_tmp_time < 0.0) ? 0 : timer_tmp_time; 114 | } 115 | 116 | double Timer_elapsed( TIMER_TYPE type ) 117 | { 118 | return (type == REAL_TIME) 119 | ? Timer_elapsed_real () 120 | : Timer_elapsed_virtual (); 121 | } 122 | 123 | void Timer_stop(void) 124 | { 125 | gettimeofday( &tp, NULL ); 126 | stop_real_time = TIMER_WALLTIME(tp); 127 | 128 | getrusage( RUSAGE_SELF, &res ); 129 | stop_virtual_time = TIMER_CPUTIME(res); 130 | } 131 | 132 | void Timer_continue(void) 133 | { 134 | double timer_tmp_time; 135 | 136 | gettimeofday( &tp, NULL ); 137 | timer_tmp_time = TIMER_WALLTIME(tp) - stop_real_time; 138 | 139 | #if DEBUG >= 2 140 | if (timer_tmp_time < 0.0) { 141 | fprintf(stderr, "%s: Timer_continue(): warning: " 142 | "negative increase in time (%.6g - %.6g = %.6g)\n", 143 | __FILE__, TIMER_WALLTIME(tp), stop_real_time, timer_tmp_time); 144 | } 145 | #endif 146 | 147 | if (timer_tmp_time > 0.0) real_time += timer_tmp_time; 148 | 149 | getrusage( RUSAGE_SELF, &res ); 150 | timer_tmp_time = TIMER_CPUTIME(res) - stop_virtual_time; 151 | 152 | #if DEBUG >= 2 153 | if (timer_tmp_time < 0.0) { 154 | fprintf(stderr, "%s: Timer_continue(): warning: " 155 | "negative increase in time (%.6g - %.6g = %.6g)\n", 156 | __FILE__, TIMER_CPUTIME(res),stop_virtual_time,timer_tmp_time); 157 | } 158 | #endif 159 | 160 | if (timer_tmp_time > 0.0) virtual_time += timer_tmp_time; 161 | } 162 | -------------------------------------------------------------------------------- /HV/timer.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | Simple timer functions. 4 | 5 | --------------------------------------------------------------------- 6 | 7 | Copyright (c) 2005, 2006, 2007 Manuel Lopez-Ibanez 8 | TeX: \copyright 2005, 2006, 2007 Manuel L{\'o}pez-Ib{\'a}{\~n}ez 9 | 10 | This program is free software (software libre); you can redistribute 11 | it and/or modify it under the terms of the GNU General Public License 12 | as published by the Free Software Foundation; either version 2 of the 13 | License, or (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, but 16 | WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program; if not, you can obtain a copy of the GNU 22 | General Public License at: 23 | http://www.gnu.org/copyleft/gpl.html 24 | or by writing to: 25 | Free Software Foundation, Inc., 59 Temple Place, 26 | Suite 330, Boston, MA 02111-1307 USA 27 | 28 | ---------------------------------------------------------------------- 29 | *************************************************************************/ 30 | #ifndef TIMER_H_ 31 | #define TIMER_H_ 32 | 33 | #include 34 | 35 | #define HUGE_TIME FLT_MAX 36 | 37 | typedef enum type_timer {REAL_TIME, VIRTUAL_TIME} TIMER_TYPE; 38 | 39 | void Timer_start(void); 40 | double Timer_elapsed_virtual(void); 41 | double Timer_elapsed_real(void); 42 | double Timer_elapsed(TIMER_TYPE type); 43 | void Timer_stop(void); 44 | void Timer_continue(void); 45 | 46 | #endif // TIMER_H_ 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hypervolume Calculation 2 | 3 | **Newer versions of the MOEA Framework, starting with version 3.4, include a significantly faster hypervolume implementation. This project is being archived and may not receive further updates.** 4 | 5 | This project contains a collection of open-source codes for computing the hypervolume of a Pareto set. The codes may have been modified 6 | from their original sources in order to standardize their interfaces. Please refer to the documentation and license information included with 7 | each implementation for additional details. 8 | 9 | The setup instructions below show how to compile and configure each implementation with the [MOEA Framework](http://www.moeaframework.org). 10 | Refer to section 10.1 in the MOEA Framework Beginner's Guide for additional information. 11 | 12 | ## WFG Setup 13 | 14 | Fast hypervolume calculation published by the Walking Fish Group (WFG) and described in: 15 | 16 | > While, Ronald Lyndon et al. “A Fast Way of Calculating Exact Hypervolumes.” IEEE Transactions on Evolutionary Computation 16 (2012): 86-95. 17 | 18 | Run `make` from the `WFG/` subdirectory to compile. Copy `wfg2` to the MOEA Framework root directory. Modify `moeaframework.properties` to include the following lines: 19 | 20 | ``` 21 | org.moeaframework.core.indicator.hypervolume = ./wfg2 {2} 22 | org.moeaframework.core.indicator.hypervolume_inverted = true 23 | ``` 24 | 25 | ## HV Setup 26 | 27 | Improved dimension-sweep hypervolume calculation as described in: 28 | 29 | > Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An improved dimension-sweep algorithm for the hypervolume indicator. In IEEE Congress on Evolutionary Computation, pages 1157-1163, Vancouver, Canada, July 2006. 30 | 31 | Run `make` from the `HV/` subdirectory to compile. Copy `hv` to the MOEA Framework root directory. Modify `moeaframework.properties` to include the following lines: 32 | 33 | ``` 34 | org.moeaframework.core.indicator.hypervolume = ./hv {2} 35 | org.moeaframework.core.indicator.hypervolume_inverted = true 36 | ``` 37 | 38 | ## HOY Setup 39 | 40 | Hypervolume calculation based on Klee's measure problem as described in: 41 | 42 | > Nicola Beume and Guenter Rudolph. Faster S-Metric Calculation by Considering Dominated Hypervolume 43 | as Klee's Measure Problem. In: B. Kovalerchuk (ed.): Proceedings of the Second IASTED Conference on Computational Intelligence (CI 2006), pp. 231-236. ACTA Press: Anaheim, 2006. 44 | 45 | Run `make` from the `HOY/` subdirectory to compile. Copy `hoy` to the MOEA Framework root directory. Modify `moeaframework.properties` to include the following lines: 46 | 47 | ``` 48 | org.moeaframework.core.indicator.hypervolume = ./hoy {0} {1} {2} {3} 49 | org.moeaframework.core.indicator.hypervolume_inverted = false 50 | ``` 51 | 52 | ## Building on Windows 53 | 54 | If compiling on Windows, please note the `.exe` extension might be added to the executable name. Be sure to include the correct extension when updating `moeaframework.properties`. 55 | 56 | ## Performance 57 | 58 | The performance of any hypervolume calculation is dependent on the number of objectives (dimensions) and the number of points in the Pareto front. 59 | Below is a very rough comparison of the performance of these implementations: 60 | 61 | Data Set | Objectives | Built-in | ./wfg2 | ./hv 62 | ----------- | ---------- | -------- | ------- | ------ 63 | DTLZ2.2D.pf | 2 | 252 ms | 275 ms | 273 ms 64 | DTLZ2.3D.pf | 3 | 251 ms | 293 ms | 280 ms 65 | DTLZ2.4D.pf | 4 | 296 ms | 322 ms | 303 ms 66 | DTLZ2.6D.pf | 6 | 468 ms | 359 ms | 682 ms 67 | DTLZ2.8D.pf | 8 | 5.8 sec | 1.5 sec | 101 sec 68 | 69 | This leads to a few conclusions: 70 | 1. The built-in implementation is close in performance to its natively compiled variant WFG. We only begin to see a difference with 8+ objectives. 71 | 2. Users performing many hypervolume calculations with 8+ more objectives could still benefit from using the compiled WFG implementation 72 | -------------------------------------------------------------------------------- /WFG/CHANGELOG.TXT: -------------------------------------------------------------------------------- 1 | 1.02 2 | * Accelerated domination checks 3 | * Corrected base case error for opt <= 1 4 | * Tided up code 5 | 1.01 6 | * Updated README.TXT and wfg.c with correct copyright and attribution to Fonseca, Lopez-Ibanez and Paquete. 7 | -------------------------------------------------------------------------------- /WFG/LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /WFG/README.TXT: -------------------------------------------------------------------------------- 1 | Lyndon While, Lucas Bradstreet, Luigi Barone 2 | 3 | Email {lyndon,lucas,luigi}@csse.uwa.edu.au for any queries regarding 4 | usage/bugs/improvements. 5 | 6 | This code includes a high performance implementation of the WFG algorithm, 7 | used to calculate the hypervolume indicator for a set of non-dominated points. 8 | 9 | CREDIT: 10 | 11 | Code used to calculate the 3D hypervolume base case was taken from hv-1.2 available at 12 | http://iridia.ulb.ac.be/~manuel/hypervolume and proposed by: 13 | 14 | Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An improved 15 | dimension-sweep algorithm for the hypervolume indicator. In IEEE 16 | Congress on Evolutionary Computation, pages 1157-1163, Vancouver, 17 | Canada, July 2006. 18 | 19 | Please find the copyright notice below. 20 | 21 | 22 | COMPILING: 23 | 24 | run make march=processortype, e.g. make march=pentium4 25 | 26 | USAGE: 27 | where X = 1-3 28 | 29 | wfgX FRONTFILE 30 | # calculates hypervolume for frontfile using reference point 0, 0, ..., 0 31 | wfgX FRONTFILE r1 r2 .. rd 32 | # calculates hypervolume for frontfile using reference point r1, r2, .., rd 33 | 34 | Code currently performs minimisation hypervolume calculations relative to the 35 | reference point. However, it can be easily transformed to allow maximisation calculations. 36 | 37 | 38 | FILE FORMAT: 39 | 40 | A file can contain any number of fronts, laid out as follows: 41 | 42 | # 43 | 0.598 0.737 0.131 0.916 6.745 44 | 0.263 0.740 0.449 0.753 6.964 45 | 0.109 8.483 0.199 0.302 8.872 46 | # 47 | 0.598 0.737 0.131 0.916 6.745 48 | 0.263 0.740 0.449 0.753 6.964 49 | 0.109 8.483 0.199 0.302 8.872 50 | # 51 | 52 | Notes: 53 | 54 | - objective values are separated by spaces. 55 | - one point per line. 56 | - fronts are separated by #s. 57 | 58 | - all fronts use the same reference point, therefore all points in all 59 | fronts must have the same number of objectives. 60 | 61 | 62 | COPYRIGHT: 63 | 64 | This software, aside from the hv3_AVL function contained in hv3d.c, 65 | is Copyright (C) 2010 Lyndon While, Lucas Bradstreet. 66 | 67 | This program is free software (software libre); you can redistribute it and/or 68 | modify it under the terms of the GNU General Public License as published by the 69 | Free Software Foundation; either version 2 of the License, or (at your option) 70 | any later version. 71 | 72 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 73 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 74 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 75 | 76 | -------- 77 | 78 | Code for the hv3_AVL function in wfg.c is Copyright (C) 2006-2010 Carlos M. Fonseca, Manuel 79 | López-Ibáñez and Luís Paquete. 80 | 81 | Original code contains the following notice: 82 | 83 | ######## 84 | This program is free software (software libre); you can redistribute 85 | it and/or modify it under the terms of the GNU General Public License 86 | as published by the Free Software Foundation; either version 2 of the 87 | License, or (at your option) any later version. 88 | 89 | This program is distributed in the hope that it will be useful, but 90 | WITHOUT ANY WARRANTY; without even the implied warranty of 91 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 92 | General Public License for more details. 93 | 94 | IMPORTANT NOTE: Please be aware that the fact that this program is 95 | released as Free Software does not excuse you from scientific 96 | propriety, which obligates you to give appropriate credit! If you 97 | write a scientific paper describing research that made substantive use 98 | of this program, it is your obligation as a scientist to (a) mention 99 | the fashion in which this software was used in the Methods section; 100 | (b) mention the algorithm in the References section. The appropriate 101 | citation is: 102 | 103 | Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An improved 104 | dimension-sweep algorithm for the hypervolume indicator. In IEEE 105 | Congress on Evolutionary Computation, pages 1157-1163, Vancouver, 106 | Canada, July 2006. 107 | 108 | Moreover, as a personal note, I would appreciate it if you would email 109 | manuel.lopez-ibanez@ulb.ac.be with citations of papers referencing this 110 | work so I can mention them to my funding agent and tenure committee. 111 | ######### 112 | -------------------------------------------------------------------------------- /WFG/avl.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | 3 | avl.c - Source code for the AVL-tree library. 4 | 5 | Copyright (C) 1998 Michael H. Buselli 6 | Copyright (C) 2000-2002 Wessel Dankers 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | 22 | Augmented AVL-tree. Original by Michael H. Buselli . 23 | 24 | Modified by Wessel Dankers to add a bunch of bloat to 25 | the sourcecode, change the interface and squash a few bugs. 26 | Mail him if you find new bugs. 27 | 28 | *****************************************************************************/ 29 | 30 | #include 31 | #include 32 | #include 33 | #include "avl.h" 34 | 35 | static void avl_rebalance(avl_tree_t *, avl_node_t *); 36 | 37 | #ifdef AVL_COUNT 38 | #define NODE_COUNT(n) ((n) ? (n)->count : 0) 39 | #define L_COUNT(n) (NODE_COUNT((n)->left)) 40 | #define R_COUNT(n) (NODE_COUNT((n)->right)) 41 | #define CALC_COUNT(n) (L_COUNT(n) + R_COUNT(n) + 1) 42 | #endif 43 | 44 | #ifdef AVL_DEPTH 45 | #define NODE_DEPTH(n) ((n) ? (n)->depth : 0) 46 | #define L_DEPTH(n) (NODE_DEPTH((n)->left)) 47 | #define R_DEPTH(n) (NODE_DEPTH((n)->right)) 48 | #define CALC_DEPTH(n) ((L_DEPTH(n)>R_DEPTH(n)?L_DEPTH(n):R_DEPTH(n)) + 1) 49 | #endif 50 | 51 | #ifndef AVL_DEPTH 52 | /* Also known as ffs() (from BSD) */ 53 | static int lg(unsigned int u) { 54 | int r = 1; 55 | if(!u) return 0; 56 | if(u & 0xffff0000) { u >>= 16; r += 16; } 57 | if(u & 0x0000ff00) { u >>= 8; r += 8; } 58 | if(u & 0x000000f0) { u >>= 4; r += 4; } 59 | if(u & 0x0000000c) { u >>= 2; r += 2; } 60 | if(u & 0x00000002) r++; 61 | return r; 62 | } 63 | #endif 64 | 65 | static int avl_check_balance(avl_node_t *avlnode) { 66 | #ifdef AVL_DEPTH 67 | int d; 68 | d = R_DEPTH(avlnode) - L_DEPTH(avlnode); 69 | return d<-1?-1:d>1?1:0; 70 | #else 71 | /* int d; 72 | * d = lg(R_COUNT(avlnode)) - lg(L_COUNT(avlnode)); 73 | * d = d<-1?-1:d>1?1:0; 74 | */ 75 | #ifdef AVL_COUNT 76 | int pl, r; 77 | 78 | pl = lg(L_COUNT(avlnode)); 79 | r = R_COUNT(avlnode); 80 | 81 | if(r>>pl+1) 82 | return 1; 83 | if(pl<2 || r>>pl-2) 84 | return 0; 85 | return -1; 86 | #else 87 | #error No balancing possible. 88 | #endif 89 | #endif 90 | } 91 | 92 | #ifdef AVL_COUNT 93 | unsigned int avl_count(const avl_tree_t *avltree) { 94 | return NODE_COUNT(avltree->top); 95 | } 96 | 97 | avl_node_t *avl_at(const avl_tree_t *avltree, unsigned int index) { 98 | avl_node_t *avlnode; 99 | unsigned int c; 100 | 101 | avlnode = avltree->top; 102 | 103 | while(avlnode) { 104 | c = L_COUNT(avlnode); 105 | 106 | if(index < c) { 107 | avlnode = avlnode->left; 108 | } else if(index > c) { 109 | avlnode = avlnode->right; 110 | index -= c+1; 111 | } else { 112 | return avlnode; 113 | } 114 | } 115 | return NULL; 116 | } 117 | 118 | unsigned int avl_index(const avl_node_t *avlnode) { 119 | avl_node_t *next; 120 | unsigned int c; 121 | 122 | c = L_COUNT(avlnode); 123 | 124 | while((next = avlnode->parent)) { 125 | if(avlnode == next->right) 126 | c += L_COUNT(next) + 1; 127 | avlnode = next; 128 | } 129 | 130 | return c; 131 | } 132 | #endif 133 | 134 | int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_node_t **avlnode) { 135 | avl_node_t *node; 136 | avl_compare_t cmp; 137 | int c; 138 | 139 | if(!avlnode) 140 | avlnode = &node; 141 | 142 | node = avltree->top; 143 | 144 | if(!node) 145 | return *avlnode = NULL, 0; 146 | 147 | cmp = avltree->cmp; 148 | 149 | for(;;) { 150 | c = cmp(item, node->item); 151 | 152 | if(c < 0) { 153 | if(node->left) 154 | node = node->left; 155 | else 156 | return *avlnode = node, -1; 157 | } else if(c > 0) { 158 | if(node->right) 159 | node = node->right; 160 | else 161 | return *avlnode = node, 1; 162 | } else { 163 | return *avlnode = node, 0; 164 | } 165 | } 166 | } 167 | 168 | /* 169 | * avl_search: 170 | * Return a pointer to a node with the given item in the tree. 171 | * If no such item is in the tree, then NULL is returned. 172 | */ 173 | avl_node_t *avl_search(const avl_tree_t *avltree, const void *item) { 174 | avl_node_t *node; 175 | return avl_search_closest(avltree, item, &node) ? NULL : node; 176 | } 177 | 178 | avl_tree_t *avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) { 179 | if(rc) { 180 | rc->head = NULL; 181 | rc->tail = NULL; 182 | rc->top = NULL; 183 | rc->cmp = cmp; 184 | rc->freeitem = freeitem; 185 | } 186 | return rc; 187 | } 188 | 189 | avl_tree_t *avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) { 190 | return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem); 191 | } 192 | 193 | void avl_clear_tree(avl_tree_t *avltree) { 194 | avltree->top = avltree->head = avltree->tail = NULL; 195 | } 196 | 197 | void avl_free_nodes(avl_tree_t *avltree) { 198 | avl_node_t *node, *next; 199 | avl_freeitem_t freeitem; 200 | 201 | freeitem = avltree->freeitem; 202 | 203 | for(node = avltree->head; node; node = next) { 204 | next = node->next; 205 | if(freeitem) 206 | freeitem(node->item); 207 | free(node); 208 | } 209 | return avl_clear_tree(avltree); 210 | } 211 | 212 | /* 213 | * avl_free_tree: 214 | * Free all memory used by this tree. If freeitem is not NULL, then 215 | * it is assumed to be a destructor for the items referenced in the avl_ 216 | * tree, and they are deleted as well. 217 | */ 218 | void avl_free_tree(avl_tree_t *avltree) { 219 | avl_free_nodes(avltree); 220 | free(avltree); 221 | } 222 | 223 | static void avl_clear_node(avl_node_t *newnode) { 224 | newnode->left = newnode->right = NULL; 225 | #ifdef AVL_COUNT 226 | newnode->count = 1; 227 | #endif 228 | #ifdef AVL_DEPTH 229 | newnode->depth = 1; 230 | #endif 231 | } 232 | 233 | avl_node_t *avl_init_node(avl_node_t *newnode, void *item) { 234 | if(newnode) { 235 | avl_clear_node(newnode); 236 | newnode->item = item; 237 | } 238 | return newnode; 239 | } 240 | 241 | avl_node_t *avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) { 242 | avl_clear_node(newnode); 243 | newnode->prev = newnode->next = newnode->parent = NULL; 244 | avltree->head = avltree->tail = avltree->top = newnode; 245 | return newnode; 246 | } 247 | 248 | avl_node_t *avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { 249 | if(!node) 250 | return avltree->tail 251 | ? avl_insert_after(avltree, avltree->tail, newnode) 252 | : avl_insert_top(avltree, newnode); 253 | 254 | if(node->left) 255 | return avl_insert_after(avltree, node->prev, newnode); 256 | 257 | avl_clear_node(newnode); 258 | 259 | newnode->next = node; 260 | newnode->parent = node; 261 | 262 | newnode->prev = node->prev; 263 | if(node->prev) 264 | node->prev->next = newnode; 265 | else 266 | avltree->head = newnode; 267 | node->prev = newnode; 268 | 269 | node->left = newnode; 270 | avl_rebalance(avltree, node); 271 | return newnode; 272 | } 273 | 274 | avl_node_t *avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { 275 | if(!node) 276 | return avltree->head 277 | ? avl_insert_before(avltree, avltree->head, newnode) 278 | : avl_insert_top(avltree, newnode); 279 | 280 | if(node->right) 281 | return avl_insert_before(avltree, node->next, newnode); 282 | 283 | avl_clear_node(newnode); 284 | 285 | newnode->prev = node; 286 | newnode->parent = node; 287 | 288 | newnode->next = node->next; 289 | if(node->next) 290 | node->next->prev = newnode; 291 | else 292 | avltree->tail = newnode; 293 | node->next = newnode; 294 | 295 | node->right = newnode; 296 | avl_rebalance(avltree, node); 297 | return newnode; 298 | } 299 | 300 | avl_node_t *avl_insert_node(avl_tree_t *avltree, avl_node_t *newnode) { 301 | avl_node_t *node; 302 | 303 | if(!avltree->top) 304 | return avl_insert_top(avltree, newnode); 305 | 306 | switch(avl_search_closest(avltree, newnode->item, &node)) { 307 | case -1: 308 | return avl_insert_before(avltree, node, newnode); 309 | case 1: 310 | return avl_insert_after(avltree, node, newnode); 311 | } 312 | 313 | return NULL; 314 | } 315 | 316 | /* 317 | * avl_insert: 318 | * Create a new node and insert an item there. 319 | * Returns the new node on success or NULL if no memory could be allocated. 320 | */ 321 | avl_node_t *avl_insert(avl_tree_t *avltree, void *item) { 322 | avl_node_t *newnode; 323 | 324 | newnode = avl_init_node(malloc(sizeof(avl_node_t)), item); 325 | if(newnode) { 326 | if(avl_insert_node(avltree, newnode)) 327 | return newnode; 328 | free(newnode); 329 | errno = EEXIST; 330 | } 331 | return NULL; 332 | } 333 | 334 | /* 335 | * avl_unlink_node: 336 | * Removes the given node. Does not delete the item at that node. 337 | * The item of the node may be freed before calling avl_unlink_node. 338 | * (In other words, it is not referenced by this function.) 339 | */ 340 | void avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) { 341 | avl_node_t *parent; 342 | avl_node_t **superparent; 343 | avl_node_t *subst, *left, *right; 344 | avl_node_t *balnode; 345 | 346 | if(avlnode->prev) 347 | avlnode->prev->next = avlnode->next; 348 | else 349 | avltree->head = avlnode->next; 350 | 351 | if(avlnode->next) 352 | avlnode->next->prev = avlnode->prev; 353 | else 354 | avltree->tail = avlnode->prev; 355 | 356 | parent = avlnode->parent; 357 | 358 | superparent = parent 359 | ? avlnode == parent->left ? &parent->left : &parent->right 360 | : &avltree->top; 361 | 362 | left = avlnode->left; 363 | right = avlnode->right; 364 | if(!left) { 365 | *superparent = right; 366 | if(right) 367 | right->parent = parent; 368 | balnode = parent; 369 | } else if(!right) { 370 | *superparent = left; 371 | left->parent = parent; 372 | balnode = parent; 373 | } else { 374 | subst = avlnode->prev; 375 | if(subst == left) { 376 | balnode = subst; 377 | } else { 378 | balnode = subst->parent; 379 | balnode->right = subst->left; 380 | if(balnode->right) 381 | balnode->right->parent = balnode; 382 | subst->left = left; 383 | left->parent = subst; 384 | } 385 | subst->right = right; 386 | subst->parent = parent; 387 | right->parent = subst; 388 | *superparent = subst; 389 | } 390 | 391 | avl_rebalance(avltree, balnode); 392 | } 393 | 394 | void *avl_delete_node(avl_tree_t *avltree, avl_node_t *avlnode) { 395 | void *item = NULL; 396 | if(avlnode) { 397 | item = avlnode->item; 398 | avl_unlink_node(avltree, avlnode); 399 | if(avltree->freeitem) 400 | avltree->freeitem(item); 401 | free(avlnode); 402 | } 403 | return item; 404 | } 405 | 406 | void *avl_delete(avl_tree_t *avltree, const void *item) { 407 | return avl_delete_node(avltree, avl_search(avltree, item)); 408 | } 409 | 410 | avl_node_t *avl_fixup_node(avl_tree_t *avltree, avl_node_t *newnode) { 411 | avl_node_t *oldnode = NULL, *node; 412 | 413 | if(!avltree || !newnode) 414 | return NULL; 415 | 416 | node = newnode->prev; 417 | if(node) { 418 | oldnode = node->next; 419 | node->next = newnode; 420 | } else { 421 | avltree->head = newnode; 422 | } 423 | 424 | node = newnode->next; 425 | if(node) { 426 | oldnode = node->prev; 427 | node->prev = newnode; 428 | } else { 429 | avltree->tail = newnode; 430 | } 431 | 432 | node = newnode->parent; 433 | if(node) { 434 | if(node->left == oldnode) 435 | node->left = newnode; 436 | else 437 | node->right = newnode; 438 | } else { 439 | oldnode = avltree->top; 440 | avltree->top = newnode; 441 | } 442 | 443 | return oldnode; 444 | } 445 | 446 | /* 447 | * avl_rebalance: 448 | * Rebalances the tree if one side becomes too heavy. This function 449 | * assumes that both subtrees are AVL-trees with consistant data. The 450 | * function has the additional side effect of recalculating the count of 451 | * the tree at this node. It should be noted that at the return of this 452 | * function, if a rebalance takes place, the top of this subtree is no 453 | * longer going to be the same node. 454 | */ 455 | void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) { 456 | avl_node_t *child; 457 | avl_node_t *gchild; 458 | avl_node_t *parent; 459 | avl_node_t **superparent; 460 | 461 | parent = avlnode; 462 | 463 | while(avlnode) { 464 | parent = avlnode->parent; 465 | 466 | superparent = parent 467 | ? avlnode == parent->left ? &parent->left : &parent->right 468 | : &avltree->top; 469 | 470 | switch(avl_check_balance(avlnode)) { 471 | case -1: 472 | child = avlnode->left; 473 | #ifdef AVL_DEPTH 474 | if(L_DEPTH(child) >= R_DEPTH(child)) { 475 | #else 476 | #ifdef AVL_COUNT 477 | if(L_COUNT(child) >= R_COUNT(child)) { 478 | #else 479 | #error No balancing possible. 480 | #endif 481 | #endif 482 | avlnode->left = child->right; 483 | if(avlnode->left) 484 | avlnode->left->parent = avlnode; 485 | child->right = avlnode; 486 | avlnode->parent = child; 487 | *superparent = child; 488 | child->parent = parent; 489 | #ifdef AVL_COUNT 490 | avlnode->count = CALC_COUNT(avlnode); 491 | child->count = CALC_COUNT(child); 492 | #endif 493 | #ifdef AVL_DEPTH 494 | avlnode->depth = CALC_DEPTH(avlnode); 495 | child->depth = CALC_DEPTH(child); 496 | #endif 497 | } else { 498 | gchild = child->right; 499 | avlnode->left = gchild->right; 500 | if(avlnode->left) 501 | avlnode->left->parent = avlnode; 502 | child->right = gchild->left; 503 | if(child->right) 504 | child->right->parent = child; 505 | gchild->right = avlnode; 506 | if(gchild->right) 507 | gchild->right->parent = gchild; 508 | gchild->left = child; 509 | if(gchild->left) 510 | gchild->left->parent = gchild; 511 | *superparent = gchild; 512 | gchild->parent = parent; 513 | #ifdef AVL_COUNT 514 | avlnode->count = CALC_COUNT(avlnode); 515 | child->count = CALC_COUNT(child); 516 | gchild->count = CALC_COUNT(gchild); 517 | #endif 518 | #ifdef AVL_DEPTH 519 | avlnode->depth = CALC_DEPTH(avlnode); 520 | child->depth = CALC_DEPTH(child); 521 | gchild->depth = CALC_DEPTH(gchild); 522 | #endif 523 | } 524 | break; 525 | case 1: 526 | child = avlnode->right; 527 | #ifdef AVL_DEPTH 528 | if(R_DEPTH(child) >= L_DEPTH(child)) { 529 | #else 530 | #ifdef AVL_COUNT 531 | if(R_COUNT(child) >= L_COUNT(child)) { 532 | #else 533 | #error No balancing possible. 534 | #endif 535 | #endif 536 | avlnode->right = child->left; 537 | if(avlnode->right) 538 | avlnode->right->parent = avlnode; 539 | child->left = avlnode; 540 | avlnode->parent = child; 541 | *superparent = child; 542 | child->parent = parent; 543 | #ifdef AVL_COUNT 544 | avlnode->count = CALC_COUNT(avlnode); 545 | child->count = CALC_COUNT(child); 546 | #endif 547 | #ifdef AVL_DEPTH 548 | avlnode->depth = CALC_DEPTH(avlnode); 549 | child->depth = CALC_DEPTH(child); 550 | #endif 551 | } else { 552 | gchild = child->left; 553 | avlnode->right = gchild->left; 554 | if(avlnode->right) 555 | avlnode->right->parent = avlnode; 556 | child->left = gchild->right; 557 | if(child->left) 558 | child->left->parent = child; 559 | gchild->left = avlnode; 560 | if(gchild->left) 561 | gchild->left->parent = gchild; 562 | gchild->right = child; 563 | if(gchild->right) 564 | gchild->right->parent = gchild; 565 | *superparent = gchild; 566 | gchild->parent = parent; 567 | #ifdef AVL_COUNT 568 | avlnode->count = CALC_COUNT(avlnode); 569 | child->count = CALC_COUNT(child); 570 | gchild->count = CALC_COUNT(gchild); 571 | #endif 572 | #ifdef AVL_DEPTH 573 | avlnode->depth = CALC_DEPTH(avlnode); 574 | child->depth = CALC_DEPTH(child); 575 | gchild->depth = CALC_DEPTH(gchild); 576 | #endif 577 | } 578 | break; 579 | default: 580 | #ifdef AVL_COUNT 581 | avlnode->count = CALC_COUNT(avlnode); 582 | #endif 583 | #ifdef AVL_DEPTH 584 | avlnode->depth = CALC_DEPTH(avlnode); 585 | #endif 586 | } 587 | avlnode = parent; 588 | } 589 | } 590 | -------------------------------------------------------------------------------- /WFG/avl.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | 3 | avl.h - Source code for the AVL-tree library. 4 | 5 | Copyright (C) 1998 Michael H. Buselli 6 | Copyright (C) 2000-2002 Wessel Dankers 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | 22 | Augmented AVL-tree. Original by Michael H. Buselli . 23 | 24 | Modified by Wessel Dankers to add a bunch of bloat to 25 | the sourcecode, change the interface and squash a few bugs. 26 | Mail him if you find new bugs. 27 | 28 | *****************************************************************************/ 29 | 30 | #ifndef _AVL_H 31 | #define _AVL_H 32 | 33 | /* We need either depths, counts or both (the latter being the default) */ 34 | #if !defined(AVL_DEPTH) && !defined(AVL_COUNT) 35 | #define AVL_DEPTH 36 | #define AVL_COUNT 37 | #endif 38 | 39 | /* User supplied function to compare two items like strcmp() does. 40 | * For example: cmp(a,b) will return: 41 | * -1 if a < b 42 | * 0 if a = b 43 | * 1 if a > b 44 | */ 45 | typedef int (*avl_compare_t)(const void *, const void *); 46 | 47 | /* User supplied function to delete an item when a node is free()d. 48 | * If NULL, the item is not free()d. 49 | */ 50 | typedef void (*avl_freeitem_t)(void *); 51 | 52 | typedef struct avl_node_t { 53 | struct avl_node_t *next; 54 | struct avl_node_t *prev; 55 | struct avl_node_t *parent; 56 | struct avl_node_t *left; 57 | struct avl_node_t *right; 58 | void *item; 59 | #ifdef AVL_COUNT 60 | unsigned int count; 61 | #endif 62 | #ifdef AVL_DEPTH 63 | unsigned char depth; 64 | #endif 65 | } avl_node_t; 66 | 67 | typedef struct avl_tree_t { 68 | avl_node_t *head; 69 | avl_node_t *tail; 70 | avl_node_t *top; 71 | avl_compare_t cmp; 72 | avl_freeitem_t freeitem; 73 | } avl_tree_t; 74 | 75 | /* Initializes a new tree for elements that will be ordered using 76 | * the supplied strcmp()-like function. 77 | * Returns the value of avltree (even if it's NULL). 78 | * O(1) */ 79 | extern avl_tree_t *avl_init_tree(avl_tree_t *avltree, avl_compare_t, avl_freeitem_t); 80 | 81 | /* Allocates and initializes a new tree for elements that will be 82 | * ordered using the supplied strcmp()-like function. 83 | * Returns NULL if memory could not be allocated. 84 | * O(1) */ 85 | extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_freeitem_t); 86 | 87 | /* Frees the entire tree efficiently. Nodes will be free()d. 88 | * If the tree's freeitem is not NULL it will be invoked on every item. 89 | * O(n) */ 90 | extern void avl_free_tree(avl_tree_t *); 91 | 92 | /* Reinitializes the tree structure for reuse. Nothing is free()d. 93 | * Compare and freeitem functions are left alone. 94 | * O(1) */ 95 | extern void avl_clear_tree(avl_tree_t *); 96 | 97 | /* Free()s all nodes in the tree but leaves the tree itself. 98 | * If the tree's freeitem is not NULL it will be invoked on every item. 99 | * O(n) */ 100 | extern void avl_free_nodes(avl_tree_t *); 101 | 102 | /* Initializes memory for use as a node. Returns NULL if avlnode is NULL. 103 | * O(1) */ 104 | extern avl_node_t *avl_init_node(avl_node_t *avlnode, void *item); 105 | 106 | /* Insert an item into the tree and return the new node. 107 | * Returns NULL and sets errno if memory for the new node could not be 108 | * allocated or if the node is already in the tree (EEXIST). 109 | * O(lg n) */ 110 | extern avl_node_t *avl_insert(avl_tree_t *, void *item); 111 | 112 | /* Insert a node into the tree and return it. 113 | * Returns NULL if the node is already in the tree. 114 | * O(lg n) */ 115 | extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *); 116 | 117 | /* Insert a node in an empty tree. If avlnode is NULL, the tree will be 118 | * cleared and ready for re-use. 119 | * If the tree is not empty, the old nodes are left dangling. 120 | * O(1) */ 121 | extern avl_node_t *avl_insert_top(avl_tree_t *, avl_node_t *avlnode); 122 | 123 | /* Insert a node before another node. Returns the new node. 124 | * If old is NULL, the item is appended to the tree. 125 | * O(lg n) */ 126 | extern avl_node_t *avl_insert_before(avl_tree_t *, avl_node_t *old, avl_node_t *new); 127 | 128 | /* Insert a node after another node. Returns the new node. 129 | * If old is NULL, the item is prepended to the tree. 130 | * O(lg n) */ 131 | extern avl_node_t *avl_insert_after(avl_tree_t *, avl_node_t *old, avl_node_t *new); 132 | 133 | /* Deletes a node from the tree. Returns immediately if the node is NULL. 134 | * The item will not be free()d regardless of the tree's freeitem handler. 135 | * This function comes in handy if you need to update the search key. 136 | * O(lg n) */ 137 | extern void avl_unlink_node(avl_tree_t *, avl_node_t *); 138 | 139 | /* Deletes a node from the tree. Returns immediately if the node is NULL. 140 | * If the tree's freeitem is not NULL, it is invoked on the item. 141 | * If it is, returns the item. 142 | * O(lg n) */ 143 | extern void *avl_delete_node(avl_tree_t *, avl_node_t *); 144 | 145 | /* Searches for an item in the tree and deletes it if found. 146 | * If the tree's freeitem is not NULL, it is invoked on the item. 147 | * If it is, returns the item. 148 | * O(lg n) */ 149 | extern void *avl_delete(avl_tree_t *, const void *item); 150 | 151 | /* If exactly one node is moved in memory, this will fix the pointers 152 | * in the tree that refer to it. It must be an exact shallow copy. 153 | * Returns the pointer to the old position. 154 | * O(1) */ 155 | extern avl_node_t *avl_fixup_node(avl_tree_t *, avl_node_t *new); 156 | 157 | /* Searches for a node with the key closest (or equal) to the given item. 158 | * If avlnode is not NULL, *avlnode will be set to the node found or NULL 159 | * if the tree is empty. Return values: 160 | * -1 if the returned node is smaller 161 | * 0 if the returned node is equal or if the tree is empty 162 | * 1 if the returned node is greater 163 | * O(lg n) */ 164 | extern int avl_search_closest(const avl_tree_t *, const void *item, avl_node_t **avlnode); 165 | 166 | /* Searches for the item in the tree and returns a matching node if found 167 | * or NULL if not. 168 | * O(lg n) */ 169 | extern avl_node_t *avl_search(const avl_tree_t *, const void *item); 170 | 171 | #ifdef AVL_COUNT 172 | /* Returns the number of nodes in the tree. 173 | * O(1) */ 174 | extern unsigned int avl_count(const avl_tree_t *); 175 | 176 | /* Searches a node by its rank in the list. Counting starts at 0. 177 | * Returns NULL if the index exceeds the number of nodes in the tree. 178 | * O(lg n) */ 179 | extern avl_node_t *avl_at(const avl_tree_t *, unsigned int); 180 | 181 | /* Returns the rank of a node in the list. Counting starts at 0. 182 | * O(lg n) */ 183 | extern unsigned int avl_index(const avl_node_t *); 184 | #endif 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /WFG/makefile: -------------------------------------------------------------------------------- 1 | OBJ = read.o avl.o 2 | OPT = -O3 -DSIMPLE 3 | CC = gcc -std=c99 -Wall $(OPT) 4 | 5 | compile: $(OBJ) wfg.c 6 | $(CC) -Dopt=0 -o wfg0 wfg.c $(OBJ) 7 | $(CC) -Dopt=1 -o wfg1 wfg.c $(OBJ) 8 | $(CC) -Dopt=2 -o wfg2 wfg.c $(OBJ) 9 | $(CC) -Dopt=3 -o wfg3 wfg.c $(OBJ) 10 | 11 | %.o: %.c 12 | $(CC) -c $< 13 | 14 | clean: 15 | rm -f wfg[0-4] wfg[0-4].exe *.o -------------------------------------------------------------------------------- /WFG/read.c: -------------------------------------------------------------------------------- 1 | #include "wfg.h" 2 | #include "avl.h" 3 | 4 | static void trimLine(char line[]) 5 | { 6 | int i = 0; 7 | 8 | while(line[i] != '\0') 9 | { 10 | if (line[i] == '\r' || line[i] == '\n') 11 | { 12 | line[i] = '\0'; 13 | break; 14 | } 15 | i++; 16 | } 17 | } 18 | 19 | void printContents(FILECONTENTS *f) 20 | { 21 | for (int i = 0; i < f->nFronts; i++) 22 | { 23 | printf("Front %d:\n", i+1); 24 | for (int j = 0; j < f->fronts[i].nPoints; j++) 25 | { 26 | printf("\t"); 27 | for (int k = 0; k < f->fronts[i].n; k++) 28 | { 29 | printf("%f ", f->fronts[i].points[j].objectives[k]); 30 | } 31 | printf("\n"); 32 | } 33 | printf("\n"); 34 | } 35 | } 36 | 37 | FILECONTENTS *readFile(char filename[]) 38 | { 39 | FILE *fp; 40 | char line[BUFSIZ]; 41 | int front = 0, point = 0, objective = 0; 42 | 43 | FILECONTENTS *fc = malloc(sizeof(FILECONTENTS)); 44 | fc->nFronts = 0; 45 | fc->fronts = NULL; 46 | 47 | fp = fopen(filename, "r"); 48 | if (fp == NULL) 49 | { 50 | fprintf(stderr, "File %s could not be opened\n", filename); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | #ifdef SIMPLE 55 | front = fc->nFronts; 56 | fc->nFronts++; 57 | fc->fronts = realloc(fc->fronts, sizeof(FRONT) * fc->nFronts); 58 | fc->fronts[front].nPoints = 0; 59 | fc->fronts[front].points = NULL; 60 | #endif 61 | 62 | while(fgets(line, sizeof line, fp) != NULL) 63 | { 64 | trimLine(line); 65 | 66 | #ifndef SIMPLE 67 | if (strcmp(line, "#") == 0) 68 | { 69 | front = fc->nFronts; 70 | fc->nFronts++; 71 | fc->fronts = realloc(fc->fronts, sizeof(FRONT) * fc->nFronts); 72 | fc->fronts[front].nPoints = 0; 73 | fc->fronts[front].points = NULL; 74 | } 75 | else 76 | { 77 | #endif 78 | FRONT *f = &fc->fronts[front]; 79 | point = f->nPoints; 80 | f->nPoints++; 81 | f->points = realloc(f->points, sizeof(POINT) * f->nPoints); 82 | f->n = 0; 83 | f->points[point].objectives = NULL; 84 | f->points[point].tnode = malloc(sizeof(avl_node_t)); 85 | char *tok = strtok(line, " \t\n"); 86 | do 87 | { 88 | POINT *p = &f->points[point]; 89 | objective = f->n; 90 | f->n++; 91 | p->objectives = realloc(p->objectives, sizeof(OBJECTIVE) * f->n); 92 | p->objectives[objective] = atof(tok); 93 | } while ((tok = strtok(NULL, " \t\n")) != NULL); 94 | #ifndef SIMPLE 95 | } 96 | #endif 97 | } 98 | 99 | #ifdef SIMPLE 100 | front = fc->nFronts; 101 | fc->nFronts++; 102 | fc->fronts = realloc(fc->fronts, sizeof(FRONT) * fc->nFronts); 103 | fc->fronts[front].nPoints = 0; 104 | fc->fronts[front].points = NULL; 105 | #endif 106 | 107 | fc->nFronts--; 108 | // for (int i = 0; i < fc->nFronts; i++) fc->fronts[i].n = fc->fronts[i].points[0].nObjectives; 109 | fclose(fp); 110 | /* printf("Read %d fronts\n", fc->nFronts); 111 | printContents(fc); */ 112 | return fc; 113 | } 114 | -------------------------------------------------------------------------------- /WFG/wfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This program is free software (software libre); you can redistribute 4 | it and/or modify it under the terms of the GNU General Public License 5 | as published by the Free Software Foundation; either version 2 of the 6 | License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, you can obtain a copy of the GNU 15 | General Public License at: 16 | http://www.gnu.org/copyleft/gpl.html 17 | or by writing to: 18 | Free Software Foundation, Inc., 59 Temple Place, 19 | Suite 330, Boston, MA 02111-1307 USA 20 | 21 | ---------------------------------------------------------------------- 22 | 23 | */ 24 | 25 | // To do: 26 | // - can we sort less often or reduce/optimise dominance checks? 27 | // - should we use FPL's data structure? 28 | // - two changes in read.c 29 | // - heuristics 30 | 31 | // opt: 0 = basic, 1 = sorting, 2 = slicing to 2D, 3 = slicing to 3D 32 | 33 | #include 34 | #include 35 | #include 36 | #ifndef SIMPLE 37 | #include 38 | #include 39 | #endif 40 | #include "wfg.h" 41 | #include "avl.h" 42 | 43 | #define MAXIMISING true 44 | 45 | #if MAXIMISING 46 | #define BEATS(x,y) (x > y) 47 | #define BEATSEQ(x,y) (x >= y) 48 | #else 49 | #define BEATS(x,y) (x < y) 50 | #define BEATSEQ(x,y) (x <= y) 51 | #endif 52 | 53 | #define WORSE(x,y) (BEATS(y,x) ? (x) : (y)) 54 | #define BETTER(x,y) (BEATS(y,x) ? (y) : (x)) 55 | 56 | int n; // the number of objectives 57 | POINT ref; // the reference point 58 | 59 | FRONT *fs; // memory management stuff 60 | int fr = 0; // current depth 61 | int frmax = -1; // max depth malloced so far (for opt = 0) 62 | int maxm = 0; // identify the biggest fronts in the file 63 | int maxn = 0; 64 | 65 | 66 | static avl_tree_t *tree; 67 | double hv(FRONT); 68 | 69 | static int compare_tree_asc( const void *p1, const void *p2) 70 | { 71 | const double x1= *((const double *)p1+1); 72 | const double x2= *((const double *)p2+1); 73 | 74 | if (x1 != x2) return (x1 > x2) ? -1 : 1; 75 | else return 0; 76 | } 77 | 78 | 79 | int greater(const void *v1, const void *v2) 80 | // this sorts points improving in the last objective 81 | { 82 | POINT p = *(POINT*)v1; 83 | POINT q = *(POINT*)v2; 84 | #if opt == 1 85 | for (int i = n - fr - 1; i >= 0; i--) 86 | #else 87 | for (int i = n - 1; i >= 0; i--) 88 | #endif 89 | if BEATS(p.objectives[i],q.objectives[i]) return 1; 90 | else 91 | if BEATS(q.objectives[i],p.objectives[i]) return -1; 92 | return 0; 93 | } 94 | 95 | 96 | int dominates2way(POINT p, POINT q) 97 | // returns -1 if p dominates q, 1 if q dominates p, 2 if p == q, 0 otherwise 98 | { 99 | // domination could be checked in either order 100 | #if opt == 1 101 | for (int i = n - fr - 1; i >= 0; i--) 102 | #else 103 | for (int i = n - 1; i >= 0; i--) 104 | #endif 105 | if BEATS(p.objectives[i],q.objectives[i]) 106 | {for (int j = i - 1; j >= 0; j--) 107 | if BEATS(q.objectives[j],p.objectives[j]) return 0; 108 | return -1;} 109 | else 110 | if BEATS(q.objectives[i],p.objectives[i]) 111 | {for (int j = i - 1; j >= 0; j--) 112 | if BEATS(p.objectives[j],q.objectives[j]) return 0; 113 | return 1;} 114 | return 2; 115 | } 116 | 117 | 118 | void makeDominatedBit(FRONT ps, int p) 119 | // creates the front ps[p+1 ..] in fs[fr], with each point bounded by ps[p] and dominated points removed 120 | { 121 | // when opt = 0 each new frame is allocated as needed, because the worst-case needs #frames = #points 122 | #if opt == 0 123 | if (fr > frmax) 124 | {frmax = fr; 125 | fs[fr].points = malloc(sizeof(POINT) * maxm); 126 | for (int j = 0; j < maxm; j++) 127 | { 128 | fs[fr].points[j].objectives = malloc(sizeof(OBJECTIVE) * maxn); 129 | } 130 | } 131 | #endif 132 | 133 | int z = ps.nPoints - 1 - p; 134 | for (int i = 0; i < z; i++) 135 | for (int j = 0; j < n; j++) 136 | fs[fr].points[i].objectives[j] = WORSE(ps.points[p].objectives[j],ps.points[p + 1 + i].objectives[j]); 137 | POINT t; 138 | fs[fr].nPoints = 1; 139 | for (int i = 1; i < z; i++) 140 | {int j = 0; 141 | bool keep = true; 142 | while (j < fs[fr].nPoints && keep) 143 | switch (dominates2way(fs[fr].points[i], fs[fr].points[j])) 144 | {case -1: t = fs[fr].points[j]; 145 | fs[fr].nPoints--; 146 | fs[fr].points[j] = fs[fr].points[fs[fr].nPoints]; 147 | fs[fr].points[fs[fr].nPoints] = t; 148 | break; 149 | case 0: j++; break; 150 | // case 2: printf("Identical points!\n"); 151 | default: keep = false; 152 | } 153 | if (keep) {t = fs[fr].points[fs[fr].nPoints]; 154 | fs[fr].points[fs[fr].nPoints] = fs[fr].points[i]; 155 | fs[fr].points[i] = t; 156 | fs[fr].nPoints++;} 157 | } 158 | fr++; 159 | } 160 | 161 | 162 | double hv2(FRONT ps) 163 | // returns the hypervolume of ps[0 ..] in 2D 164 | // assumes that ps is sorted improving 165 | { 166 | double volume = fabs((ps.points[0].objectives[0] - ref.objectives[0]) * 167 | (ps.points[0].objectives[1] - ref.objectives[1])); 168 | for (int i = 1; i < ps.nPoints; i++) 169 | volume += fabs((ps.points[i].objectives[0] - ref.objectives[0]) * 170 | (ps.points[i].objectives[1] - ps.points[i - 1].objectives[1])); 171 | return volume; 172 | } 173 | 174 | double hv3_AVL(FRONT ps) 175 | /* hv3_AVL: 3D algorithm code taken from version hv-1.2 available at 176 | http://iridia.ulb.ac.be/~manuel/hypervolume and proposed by: 177 | 178 | Carlos M. Fonseca, Luís Paquete, and Manuel López-Ibáñez. An improved 179 | dimension-sweep algorithm for the hypervolume indicator. In IEEE 180 | Congress on Evolutionary Computation, pages 1157-1163, Vancouver, 181 | Canada, July 2006. 182 | 183 | Copyright (c) 2009 184 | Carlos M. Fonseca 185 | Manuel Lopez-Ibanez 186 | Luis Paquete 187 | */ 188 | 189 | // returns the hypervolume of ps[0 ..] in 3D 190 | // assumes that ps is sorted improving 191 | { 192 | avl_init_node(ps.points[ps.nPoints-1].tnode,ps.points[ps.nPoints-1].objectives); 193 | avl_insert_top(tree,ps.points[ps.nPoints-1].tnode); 194 | 195 | double hypera = (ref.objectives[0] - ps.points[ps.nPoints-1].objectives[0]) * 196 | (ref.objectives[1] - ps.points[ps.nPoints-1].objectives[1]); 197 | 198 | double height; 199 | if (ps.nPoints == 1) 200 | height = ref.objectives[2] - ps.points[ps.nPoints-1].objectives[2]; 201 | else 202 | height = ps.points[ps.nPoints-2].objectives[2] - ps.points[ps.nPoints-1].objectives[2]; 203 | 204 | double hyperv = hypera * height; 205 | 206 | for (int i = ps.nPoints - 2; i >= 0; i--) 207 | { 208 | if (i == 0) 209 | height = ref.objectives[2] - ps.points[i].objectives[2]; 210 | else 211 | height = ps.points[i-1].objectives[2] - ps.points[i].objectives[2]; 212 | 213 | // search tree for point q to the right of current point 214 | const double * prv_ip, * nxt_ip; 215 | avl_node_t *tnode; 216 | 217 | avl_init_node(ps.points[i].tnode, ps.points[i].objectives); 218 | 219 | if (avl_search_closest(tree, ps.points[i].objectives, &tnode) <= 0) { 220 | nxt_ip = (double *)(tnode->item); 221 | tnode = tnode->prev; 222 | } else { 223 | nxt_ip = (tnode->next!=NULL) 224 | ? (double *)(tnode->next->item) 225 | : ref.objectives; 226 | } 227 | // if p is not dominated 228 | if (nxt_ip[0] > ps.points[i].objectives[0]) { 229 | 230 | // insert p in tree 231 | avl_insert_after(tree, tnode, ps.points[i].tnode); 232 | 233 | if (tnode !=NULL) { 234 | prv_ip = (double *)(tnode->item); 235 | 236 | if (prv_ip[0] > ps.points[i].objectives[0]) { 237 | const double * cur_ip; 238 | 239 | tnode = ps.points[i].tnode->prev; 240 | // cur_ip = point dominated by pp with highest [0]-coordinate 241 | cur_ip = (double *)(tnode->item); 242 | 243 | // for each point in s in tree dominated by p 244 | while (tnode->prev) { 245 | prv_ip = (double *)(tnode->prev->item); 246 | // decrease area by contribution of s 247 | hypera -= (prv_ip[1] - cur_ip[1])*(nxt_ip[0] - cur_ip[0]); 248 | if (prv_ip[0] < ps.points[i].objectives[0]) 249 | break; // prv is not dominated by pp 250 | cur_ip = prv_ip; 251 | // remove s from tree 252 | avl_unlink_node(tree,tnode); 253 | tnode = tnode->prev; 254 | } 255 | 256 | // remove s from tree 257 | avl_unlink_node(tree,tnode); 258 | 259 | if (!tnode->prev) { 260 | // decrease area by contribution of s 261 | hypera -= (ref.objectives[1] - cur_ip[1])*(nxt_ip[0] - cur_ip[0]); 262 | prv_ip = ref.objectives; 263 | } 264 | } 265 | } else 266 | prv_ip = ref.objectives; 267 | 268 | // increase area by contribution of p 269 | hypera += (prv_ip[1] - 270 | ps.points[i].objectives[1])*(nxt_ip[0] - 271 | ps.points[i].objectives[0]); 272 | 273 | } 274 | 275 | if (height > 0) 276 | hyperv += hypera * height; 277 | } 278 | avl_clear_tree(tree); 279 | return hyperv; 280 | } 281 | 282 | 283 | double inclhv(POINT p) 284 | // returns the inclusive hypervolume of p 285 | { 286 | double volume = 1; 287 | for (int i = 0; i < n; i++) 288 | volume *= fabs(p.objectives[i] - ref.objectives[i]); 289 | return volume; 290 | } 291 | 292 | 293 | double exclhv(FRONT ps, int p) 294 | // returns the exclusive hypervolume of ps[p] relative to ps[p+1 ..] 295 | { 296 | double volume = inclhv(ps.points[p]); 297 | if (ps.nPoints > p + 1) 298 | { 299 | makeDominatedBit(ps, p); 300 | volume -= hv(fs[fr - 1]); 301 | fr--; 302 | } 303 | return volume; 304 | } 305 | 306 | 307 | double hv(FRONT ps) 308 | // returns the hypervolume of ps[0 ..] 309 | { 310 | #if opt > 0 311 | qsort(ps.points, ps.nPoints, sizeof(POINT), greater); 312 | #endif 313 | 314 | #if opt == 2 315 | if (n == 2) return hv2(ps); 316 | #elif opt == 3 317 | if (n == 3) return hv3_AVL(ps); 318 | #endif 319 | 320 | double volume = 0; 321 | 322 | #if opt <= 1 323 | for (int i = 0; i < ps.nPoints; i++) volume += exclhv(ps, i); 324 | #else 325 | n--; 326 | for (int i = ps.nPoints - 1; i >= 0; i--) 327 | // we can ditch dominated points here, 328 | // but they will be ditched anyway in dominatedBit 329 | volume += fabs(ps.points[i].objectives[n] - ref.objectives[n]) * exclhv(ps, i); 330 | 331 | n++; 332 | #endif 333 | 334 | return volume; 335 | } 336 | 337 | 338 | int main(int argc, char *argv[]) 339 | // processes each front from the file 340 | { 341 | FILECONTENTS *f = readFile(argv[1]); 342 | 343 | // find the biggest fronts 344 | for (int i = 0; i < f->nFronts; i++) 345 | {if (f->fronts[i].nPoints > maxm) maxm = f->fronts[i].nPoints; 346 | if (f->fronts[i].n > maxn) maxn = f->fronts[i].n; 347 | } 348 | 349 | // allocate memory 350 | #if opt == 0 351 | fs = malloc(sizeof(FRONT) * maxm); 352 | #else 353 | 354 | // slicing (opt > 1) saves a level of recursion 355 | int maxd = maxn - (opt / 2 + 1); 356 | fs = malloc(sizeof(FRONT) * maxd); 357 | 358 | // 3D base (opt = 3) needs space for the sentinels 359 | int maxp = maxm + 2 * (opt / 3); 360 | //int maxp = 100000; 361 | for (int i = 0; i < maxd; i++) 362 | {fs[i].points = malloc(sizeof(POINT) * maxp); 363 | for (int j = 0; j < maxp; j++) 364 | { 365 | fs[i].points[j].tnode = malloc(sizeof(avl_node_t)); 366 | // slicing (opt > 1) saves one extra objective at each level 367 | fs[i].points[j].objectives = malloc(sizeof(OBJECTIVE) * (maxn - (i + 1) * (opt / 2))); 368 | } 369 | } 370 | #endif 371 | 372 | tree = avl_alloc_tree ((avl_compare_t) compare_tree_asc, 373 | (avl_freeitem_t) free); 374 | 375 | // initialise the reference point 376 | ref.objectives = malloc(sizeof(OBJECTIVE) * maxn); 377 | ref.tnode = malloc(sizeof(avl_node_t)); 378 | if (argc == 2) 379 | {printf("No reference point provided: using the origin\n"); 380 | for (int i = 0; i < maxn; i++) ref.objectives[i] = 0; 381 | } 382 | else if (argc - 2 != maxn) 383 | {printf("Your reference point should have %d values\n", maxn); 384 | return 0; 385 | } 386 | else 387 | for (int i = 2; i < argc; i++) ref.objectives[i - 2] = atof(argv[i]); 388 | 389 | for (int i = 0; i < f->nFronts; i++) 390 | { 391 | #ifndef SIMPLE 392 | struct timeval tv1, tv2; 393 | struct rusage ru_before, ru_after; 394 | getrusage (RUSAGE_SELF, &ru_before); 395 | #endif 396 | 397 | n = f->fronts[i].n; 398 | #if opt >= 3 399 | if (n == 2) 400 | {qsort(f->fronts[i].points, f->fronts[i].nPoints, sizeof(POINT), greater); 401 | printf("hv(%d) = %1.10f\n", i+1, hv2(f->fronts[i])); 402 | } 403 | else 404 | #endif 405 | printf("hv(%d) = %1.10f\n", i+1, hv(f->fronts[i])); 406 | 407 | #ifndef SIMPLE 408 | getrusage (RUSAGE_SELF, &ru_after); 409 | tv1 = ru_before.ru_utime; 410 | tv2 = ru_after.ru_utime; 411 | 412 | printf("Time: %f (s)\n", tv2.tv_sec + tv2.tv_usec * 1e-6 - tv1.tv_sec - tv1.tv_usec * 1e-6); 413 | #endif 414 | } 415 | 416 | return 0; 417 | } 418 | -------------------------------------------------------------------------------- /WFG/wfg.h: -------------------------------------------------------------------------------- 1 | #ifndef _WFG_H_ 2 | #define _WFG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef double OBJECTIVE; 9 | 10 | typedef struct 11 | { 12 | OBJECTIVE *objectives; 13 | struct avl_node_t * tnode; 14 | } POINT; 15 | 16 | typedef struct 17 | { 18 | int nPoints; 19 | int n; 20 | POINT *points; 21 | } FRONT; 22 | 23 | typedef struct 24 | { 25 | int nFronts; 26 | FRONT *fronts; 27 | } FILECONTENTS; 28 | 29 | FILECONTENTS *readFile(char[]); 30 | 31 | extern void printContents(FILECONTENTS *); 32 | 33 | #endif 34 | --------------------------------------------------------------------------------