/*
This program allows the computation of a weakly Pareto compliant 
unary quality indicator called Degree of Approximation (DOA).
DOA evaluates the performance of a multi- or many-objective optimization algorithm. 
More specifically, DOA is computed for the solution set that the algorithm provides for a test problem.
Finally, the knowledge  of the Pareto Optimal Front of the test problem is necessary for DOA computation. 
Copyright (C) 2017 Emanuele Dilettoso, Santi Agatino Rizzo and Nunzio Salerno.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

For any bug information and support, please contact
Santi Agatino Rizzo
santi.rizzo@dieei.unict.it


*******************************************
***   PLEASE CITE THE FOLLOWING PAPER   ***
*******************************************
E. Dilettoso, S.A. Rizzo, N. Salerno, A weakly Pareto compliant quality indicator, 
Mathematical and Computational Applications, vol. 22(1), 25, March 2017. 

MCA is an OPEN ACCESS Journal,
then you can obtain the paper for FREE. 

You can download the paper at the same page where you downloaded this code, 
or at:
http://www.mdpi.com/2297-8747/22/1/25/htm


*******************************************
***       HOW TO USE THIS PROGRAM       ***
*******************************************
The program asks for two input text files:

(1) a file containing the solutions belonging to the Pareto Optimal Front (POF)
(2) a file containing the non-dominated solutions

The input files must be in the same folder of the DOA executable file.
The input file requirements are as follows.


-----------------------
Description of file (1)
-----------------------

---   file (1) name   ---

The name of the file must be like 
 example_n_M.txt

where:
example is the name of the optimization problem;
n       is a positive integer equal to the number of objective functions;
M       is a positive integer equal to the number of solutions belonging to the POF.

(e.g. DTLZ1_5_1000000.txt)

---   file (1) format   ---

f_1,1 f_1,2 ... f_1,n
f_2,1 f_2,2 ... f_2,n
.....................
.....   f_i,k   .....
.....................
f_M,1 f_M,2 ... f_M,n

where:
f_i,k is the value of the k-th objective function related to the i-th solution belonging to the POF.

The values can be separated by blanks, tab characters or carriage returns.
There is no need to organize them in rows and columns. 


-----------------------
Description of file (2)
-----------------------

---   file (2) name   ---

The file (2) name must be as follows:
 example_n_algorithm.txt

where:
example   is the name of the optimization problem;
n         is a positive integer equal to the number of objective functions;
algorithm is the name of the optimization algorithm.

(e.g. DTLZ1_5_GA.txt)

---   file (2) format   ---

f_1,1 f_1,2 ... f_1,n
f_2,1 f_2,2 ... f_2,n
.....................
.....   f_a,k   .....
.....................
f_m,1 f_m,2 ... f_m,n

where:
f_i,k is the value of the k-th objective function related to the a-th solution belonging to the non-dominated solution set;
m     is a positive integer equal to the number of solutions belonging to the non-dominated solution set

The values can be separated by blanks, tab characters or carriage returns.
There is no need to organize them in rows and columns. 

*/

#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main (int argc, char * argv[]) {
   
   int NumObjFunc, POFsize, APFsize; 
	double DOA, s_i_A, rf_i_a; 
   string OptProbName, AlgName;
   stringstream filename;
   fstream file;
   vector <double> POF, A; 
    
   cout << endl << endl << "**********************************************************************";
	cout << endl << endl << "**********         PLEASE CITE THE FOLLOWING PAPER         ***********";
	cout << endl << endl << "**********************************************************************";
	cout << endl << endl << "E. Dilettoso, S.A. Rizzo, N. Salerno, A weakly Pareto compliant quality indicator,"; 
   cout << endl <<         "Mathematical and Computational Applications, vol. 22(1), 25, March 2017.";
	cout << endl << endl << "**********************************************************************";
	cout << endl << endl << "MCA is an OPEN ACCESS Journal, so you can obtain the paper for FREE !";
	cout << endl << endl << "You can download the paper at the same page where you downloaded this code\nor at:";
	cout << endl << endl << "http://www.mdpi.com/2297-8747/22/1/25/htm";
	cout << endl << endl << "**********************************************************************";
	cout << endl << endl << "Press ENTER to start";
	cout << endl << endl;
	getchar();
   cout << endl << "----------------------------------------------------------------------";
	cout << endl << endl << "Type the name of the optimization problem: ";
   cin >> OptProbName;
   cout << endl << endl << "----------------------------------------------------------------------";
   NumObjFunc = 0;
   while (NumObjFunc <= 0){
   	cout << endl << endl << "Insert the number of objective functions in \"" << OptProbName <<"\": ";
	   cin >> NumObjFunc;	   
		if (NumObjFunc <= 0) {
	   	cout << endl << endl << "The number must be positive";
	   }
   }
   cout << endl << endl << "----------------------------------------------------------------------";
   POFsize = 0;
   while (POFsize <= 0){
   	cout << endl << endl << "Insert the number of solutions in the Pareto Optimal Front: ";
	   cin >> POFsize;	   
		if (POFsize <= 0) {
	   	cout << endl << endl << "The number must be positive";
	   }
   }
   cout << endl << endl << "----------------------------------------------------------------------";
	cout << endl << endl << "Type the name of the optimization algorithm: ";
   cin >> AlgName;
   cout << endl << endl << "----------------------------------------------------------------------";
   
	filename.str(string());
   filename << OptProbName << "_" << NumObjFunc << "_" << POFsize << ".txt";
   file.open(filename.str(),fstream::in);
	if (!file.is_open()){
	   cout << "Error: " << filename << "not found" << endl << endl;
		getchar();
		exit(EXIT_FAILURE);
   }	
   POF.clear();
	POF.resize(POFsize*NumObjFunc);
   for (int i=0; i < POFsize ;i++){
   	for (int k=0; k < NumObjFunc ;k++){
   		file >> POF[i*NumObjFunc+k];
   	}
   }
	file.clear();
	file.close();
		
	filename.str(string());
   filename << OptProbName << "_" << NumObjFunc << "_" << AlgName << ".txt";
   file.open(filename.str(),fstream::in);
	if (!file.is_open()){
	   cout << "Error: " << filename << "not found" << endl << endl;
		getchar();
		exit(EXIT_FAILURE);
   }	
   file >> APFsize;
	A.clear();   
	A.resize(APFsize*NumObjFunc);
   for (int a=0; a < APFsize ;a++){
   	for (int k=0; k < NumObjFunc ;k++){
   		file >> A[a*NumObjFunc+k];
   	}
   }   
	file.clear();
	file.close();
	
   /*
   The following code is based on a consideration highlighted in the paper [1]
   that is:
	rf_i_a = df_i_a when "a" belongs to D_i_A 
	
	Recalling that
	s_i_a = min (d_i_A, r_i_A) = min ( min(df_i_a1),  min(rf_i_a2))
	with:
   "a1" a generic solution in D_i_A
	"a2" a generic solution in A\D_i_A 
	
	and exploting the previous consideration, it follows that:
	s_i_a = min (rf_i_a)
	with:
	"a" a generic solution in A	
	*/
   
   DOA = 0.;
   for (int i=0; i < POFsize ;i++){
 		s_i_A = DBL_MAX;
	   for (int a=0; a < APFsize ;a++) {
	      rf_i_a = 0.;
  		   for (int k=0; k < NumObjFunc ;k++){
 			   rf_i_a += ( max(A[a*NumObjFunc+k]-POF[i*NumObjFunc+k],0.) * (A[a*NumObjFunc+k]-POF[i*NumObjFunc+k]) );
  		   }
   		if (rf_i_a < s_i_A) {
   			s_i_A = rf_i_a;
   		}
   	}
   	DOA += sqrt(s_i_A);
   }
   DOA /= (double) POFsize;
      
   cout << endl << endl << "-----------------               RESULT               -----------------";
   cout << endl << endl << "----------------------------------------------------------------------";
	cout << endl << endl << "Optimization problem: "<< OptProbName << " (" << NumObjFunc << " objective functions)";
   cout << endl << endl << "Algorithm: "<< AlgName << " (" << APFsize << " non-dominated solutions)";
   cout << endl << endl << "DOA = "<< DOA;
   cout << endl << endl << "Computed by means of a POF with "<< POFsize << " points";
   cout << endl << endl << "----------------------------------------------------------------------";
   getchar();
	cout <<endl<<endl;
}
