///*
// * To change this license header, choose License Headers in Project Properties.
// * To change this template file, choose Tools | Templates
// * and open the template in the editor.
// */
//package hh.creditassignment.fitnessindicator;
//
//import java.util.ArrayList;
//import java.util.Arrays;
//import java.util.List;
//import org.moeaframework.core.NondominatedPopulation;
//import org.moeaframework.core.Problem;
//import org.moeaframework.core.Solution;
//import org.moeaframework.core.comparator.DominanceComparator;
//import org.moeaframework.core.comparator.ParetoDominanceComparator;
//import org.moeaframework.core.indicator.jmetal.FastHypervolume;
//
///**
// * Binary hypervolume indicator from Zitzler, E., & Simon, K. (2004).
// * Indicator-Based Selection in Multiobjective Search. 8th International
// * Conference on Parallel Problem Solving from Nature (PPSN VIII), 832–842.
// * doi:10.1007/978-3-540-30217-9_84
// *
// * @author nozomihitomi
// */
//public class HypervolumeIndicator implements IIndicator {
//
// private final DominanceComparator domComparator;
//
// private final FastHypervolume FHV;
//
// /**
// *
// * @param problem being solved
// */
// public HypervolumeIndicator(Problem problem) {
// NondominatedPopulation refPop = new NondominatedPopulation();
// //Create a refpopulation with solutions that have objectives all 0 except
// //in one dimension set to 1.0. This is so that when using the
// //MOEAFramework HV calculator, the normalization doesn't do anything
// for (int i = 0; i < problem.getNumberOfObjectives(); i++) {
// Solution soln = problem.newSolution();
// for (int j = 0; j < problem.getNumberOfObjectives(); j++) {
// soln.setObjective(j, 0.0);
// }
// soln.setObjective(i, 1.0);
// refPop.add(soln);
// }
// this.domComparator = new ParetoDominanceComparator();
// this.FHV = new FastHypervolume(problem, refPop, null);
// }
//
// @Override
// public double compute(Solution solnA, Solution solnB, Solution refPt) {
// int dom = domComparator.compare(solnA, solnB);
// if (dom == -1) {
// return 0;
// } else if (dom == 1) {
// return volume(solnB, refPt) - volume(solnA, refPt);
// } else {
// return volume(new Solution[]{solnA, solnB}, refPt) - volume(solnA, refPt);
// }
// }
//
// /**
// * Calculates the hypervolume created by one solution
// *
// * @param soln
// * @return
// */
// private double volume(Solution soln, Solution refPt) {
// double vol = 1.0;
// for (int i = 0; i < soln.getNumberOfObjectives(); i++) {
// vol *= refPt.getObjective(i) - soln.getObjective(i); //assume minimization problem
// }
// if (vol < 0) //if point is dominated by reference point
// {
// vol = 0;
// }
// return vol;
// }
//
// /**
// * Calculates the Hypervolume created by the union of multiple solutions
// *
// * @param solutions
// * @return
// */
// private double volume(Solution[] solutions, Solution refPt) {
// FHV.updateReferencePoint(refPt);
// return FHV.evaluate(new NondominatedPopulation(Arrays.asList(solutions)));
// }
//
// /**
// * Calculates the Hypervolume created by the union of multiple solutions in
// * a nondominated population
// */
// private double volume(NondominatedPopulation ndpop, Solution refPt) {
// Solution[] solns = new Solution[ndpop.size()];
// for (int i = 0; i < ndpop.size(); i++) {
// solns[i] = ndpop.get(i);
// }
// return volume(solns, refPt);
// }
//
// @Override
// public String toString() {
// return "BIHV";
// }
//
// @Override
// public List<Double> computeContributions(NondominatedPopulation pop, Solution refPt) {
// List<Double> contribution = new ArrayList<>(pop.size());
//
// for (int i = 0; i < pop.size(); i++) {
// contribution.add(computeContribution(pop, pop.get(i), refPt));
// }
// return contribution;
// }
//// @Override
//// public List<Double> computeContributions(NondominatedPopulation pop, ArrayList<SortedLinkedList<Double>> sortedObjs, Solution refPt) {
//// List<Double> contribution = new ArrayList<>(pop.size());
//// for (int i = 0; i < pop.size(); i++) {
//// Solution soln = unnormalize(pop.get(i), sortedObjs);
//// contribution.add(computeContribution(pop, sortedObjs, soln, refPt));
//// }
//// return contribution;
//// }
//
// @Override
// public double computeContribution(NondominatedPopulation pop, Solution offspring, Solution refPt) {
// double contribution;
// switch (offspring.getNumberOfObjectives()) {
//// case 2:
//// contribution = computeContribution2D(sortedObjs, offspring, refPt);
//// break;
//// case 3:
//// contribution = computeContribution3D(sortedObjs,pop, offspring, refPt);
//// break;
// default:
// //Create a nondominated popualtion without the offspring
// NondominatedPopulation popWOSolution = new NondominatedPopulation();
// for (int i = 0; i < pop.size(); i++) {
// if (!Arrays.equals(pop.get(i).getObjectives(), offspring.getObjectives())) {
// popWOSolution.forceAddWithoutCheck(pop.get(i));
// }
// }
// contribution = computeContribution(pop, popWOSolution, refPt);
// break;
// }
// return contribution;
// }
//
// private double computeContribution(NondominatedPopulation pop1, NondominatedPopulation pop2, Solution refPt){
// return volume(pop1, refPt)-volume(pop2, refPt);
// }
//
// /**
// * Assumes minimization problem. Uses 2D hypervolume contribution approach
// * from SMS-EMOA Beume, Nicola, Boris Naujoks, and Michael Emmerich. 2007.
// * “SMS-EMOA: Multiobjective Selection Based on Dominated Hypervolume.”
// * European Journal of Operational Research 181 (3): 1653–1669.
// * doi:10.1016/j.ejor.2006.08.008.
// *
// * @param list array of sorted lists of objective values. List should be in
// * ascending order
// * @param offspring
// * @param oldPopIndicatorVal
// * @param refPt
// * @return
// */
// private double computeContribution2D(ArrayList<SortedLinkedList<Double>> list, Solution offspring, Solution refPt) {
// double contribution = 1;
// for (int i = 0; i < offspring.getNumberOfObjectives(); i++) {
// int ind = list.get(i).binaryFind(offspring.getObjective(i));
// double min = list.get(i).getFirst();
// double max = list.get(i).getLast();
// if (ind < list.get(0).size() - 1) {
// contribution *= (list.get(i).get(ind + 1) - min) / (max - min) - (list.get(i).get(ind) - min) / (max - min);
// } else {
// contribution *= refPt.getObjective(i) - (list.get(i).get(ind) - min) / (max - min);
// }
// }
// if (contribution < 0) {
// throw new IllegalStateException("Hypervolume contribution negative: should be positive for nondominated set");
// }
// return contribution;
// }
//
// /**
// * Uses 3D hypervolume contribution approach as Naujoks, B., N. Beume, and
// * M. Emmerich. 2005. “Multi-Objective Optimisation Using S-Metric
// * Selection: Application to Three-Dimensional Solution Spaces.” 2005 IEEE
// * Congress on Evolutionary Computation 2: 1282–1289.
// * doi:10.1109/CEC.2005.1554838.
// *
// * @param list
// * @param ndpop
// * @param offspring
// * @param refPt
// * @return
// */
// private List<Double> computeContributions3D(ArrayList<SortedLinkedList<Double>> list,NondominatedPopulation ndpop,Solution refPt) {
//
// int numSoln = list.get(0).size();
//
// //create normalized sorted lists
// ArrayList<Double> alpha = new ArrayList<>(numSoln);
// ArrayList<Double> beta = new ArrayList<>(numSoln);
// for(int i=0;i<numSoln;i++){
// alpha.add(i, (list.get(0).get(i) - list.get(0).getFirst()) / (list.get(0).getLast() - list.get(0).getFirst()));
// beta.add(i, (list.get(1).get(i) - list.get(1).getFirst()) / (list.get(1).getLast() - list.get(1).getFirst()));
// }
// alpha.add(refPt.getObjective(0));
// beta.add(refPt.getObjective(1));
//
// double[][] best1_f3 = new double[numSoln][numSoln];
// double[][] best2_f3 = new double[numSoln][numSoln];
// for(int i=0;i<numSoln;i++){
// Arrays.fill(best1_f3[i], refPt.getObjective(2));
// Arrays.fill(best2_f3[i], refPt.getObjective(2));
// }
// int[][] ownerNumbers = new int[numSoln][numSoln];
// int[][] owners = new int[numSoln][numSoln];
// Double[] contributions = new Double[numSoln];
// Arrays.fill(contributions, 0.0);
// for (int i = 0; i < numSoln; i++) {
// for (int j = 0; j < numSoln; j++) {
// int ownerNumber = 0;
// int owner = -1;
// for (int k = 0; k < numSoln; k++) {
// //check to see if s_k dominates cell (i,j) conc. f_1, f_2
// if (ndpop.get(k).getObjective(0) <= alpha.get(i)
// && ndpop.get(k).getObjective(1) <= beta.get(j)) {
// ownerNumber++;
// owner = k;
// if (ndpop.get(k).getObjective(2) < best1_f3[i][j]) {
// best2_f3[i][j] = best1_f3[i][j]; //update second best
// best1_f3[i][j] = ndpop.get(k).getObjective(2); //update best
// } else if (ndpop.get(k).getObjective(2) < best2_f3[i][j]) {
// best2_f3[i][j] = ndpop.get(k).getObjective(2); //updated second best
// }
// }
// }
// ownerNumbers[i][j]=ownerNumber;
// owners[i][j]=owner;
// }
// }
// for (int i = 0; i < numSoln; i++) {
// for (int j = 0; j < numSoln; j++) {
// if(ownerNumbers[i][j]==1){//cell(i,j) is dominated disjoint
// contributions[owners[i][j]]+=(alpha.get(i+1)-alpha.get(i))*(beta.get(i+1)-beta.get(i))*(best2_f3[i][j]-best1_f3[i][j]);
// }
// }
// }
// return Arrays.asList(contributions);
// }
//
// /**
// *
// * @param list
// * @param ndpop
// * @param offspring
// * @param refPt
// * @return
// */
// private double computeContribution3D(ArrayList<SortedLinkedList<Double>> list,NondominatedPopulation ndpop, Solution offspring, Solution refPt) {
// //find offspring in population
// int ind=-1;
// for(int i=0;i<ndpop.size();i++){
// if(Arrays.equals(ndpop.get(i).getObjectives(),offspring.getObjectives())){
// ind = i;
// }
// }
// List<Double> contributions = computeContributions3D(list, ndpop, refPt);
//
// return contributions.get(ind);
// }
//
//}