#!/usr/bin/env python
###############################################################################
# Version: 1.1
# Last modified on: 3 April, 2016 
# Developers: Michael G. Epitropakis
#      email: m_(DOT)_epitropakis_(AT)_lancaster_(DOT)_ac_(DOT)_uk 
###############################################################################
from pycec2013.cec2013 import *
import PyNomad
import numpy as np
import sys, getopt
from gtk.keysyms import function

f = None

def main(argv):
	accuracy = 0.1
	max_eval = '100'
	try:
		opts, args = getopt.getopt(argv,"hf:de:ba:OP:E:i:n:")
	except getopt.GetoptError:
		help()
		sys.exit(2)
		

		
	for opt, arg in opts:
		if opt in opt == '-h':
			help()
			sys.exit()
		if opt in ("-f"): #Define the function
			global f
			f = CEC2013(int(arg))
		if opt in ("-a"):#Define the accuracy level
			accuracy = float(arg)
		if opt in ("-O"):# Returns the number of optima
			print f.get_no_goptima()
		if opt in ("-d"):#Returns the number of dimensions
			print f.get_dimension()
		elif opt in ("-b"):#Returns a double list with lower and upper bounds
			lb,up = bounds(f)
			print lb,up
		elif opt in ("-e"):#Returns a fitness for an individual
			if arg.count(',') == 0:
				x = np.ones(1)
				x[0] = float(arg) 
			else:
				x = [float(numeric_string) for numeric_string in arg.split(',')]
			fitness = f.evaluate(x)
			if f.get_dimension() == 1:
				print fitness[0]
			else:
				print fitness		
		elif opt in ("-P"):#Returns [count, seed] fitness for an individual
			population(arg, f, accuracy)
		elif opt in ("-E"):#Returns a list of fitnesses for a population
			eval_population(arg, f)
		elif opt in ("-i"):#Maximum number of evaluations
			max_eval = arg
		elif opt in ("-n"):
			if arg.count(',') == 0:
				x0 = np.ones(1)
				x0[0] = float(arg) 
			else:
				x0 = [float(numeric_string) for numeric_string in arg.split(',')]
				
			#print x0
			#sys.exit()
			nomad(x0,max_eval)


def nomad(x0,max_eval):
	lb,ub = bounds(f)
	max_bb_eval = 'MAX_BB_EVAL '+max_eval
	params = ['BB_OUTPUT_TYPE OBJ EB',max_bb_eval,'DISPLAY_ALL_EVAL yes','DISPLAY_STATS BBE ( SOL ) OBJ']
	[ x_return , f_return , h_return, nb_evals , nb_iters ,  stopflag ] = PyNomad.optimize(evaluate,x0,lb,ub,params)
	print ('\n NOMAD outputs \n X_sol={} \n F_sol={} \n H_sol={} \n NB_evals={} \n NB_iters={} \n'.format(x_return,f_return,h_return,nb_evals,nb_iters))

def evaluate(x):
	if f.get_dimension() == 1:
		x_coor = np.ones(1)
		x_coor[0] = x.get_coord(0)
		#print x_coor
		fitness = -f.evaluate(x_coor)
		#print fitness
		x.set_bb_output(0, fitness )
		
	else:
		dim = x.get_n()
		x_coord = [x.get_coord(i) for i in xrange(dim)]
		fitness = -f.evaluate(x_coord)
		x.set_bb_output(0, fitness )
			
	return 1

def eval(x):
	if f.get_dimension() == 1:
		x_coor = np.ones(1)
		x_coor[0] = x.get_coord(0)
		#print x_coor
		fitness = f.evaluate(x_coor)
		#print fitness
		x.set_bb_output(0, fitness )
		
	else:
		dim = x.get_n()
		x_coord = [x.get_coord(i) for i in xrange(dim)]
		fitness = f.evaluate(x_coord)
		x.set_bb_output(0, fitness )
			
	return 1

def eval_population(arg,f):
	pop_size = arg.count(':')+1 # counts the pop_size 
	X = np.zeros( (pop_size, f.get_dimension()) )
	fitness = np.zeros( pop_size )
	list_individuals = [i for i in arg.split(':')]
	j = 0
	for i in list_individuals:
		X[j] = [float(numeric_string) for numeric_string in i.split(',')]
		#fitness[j] = f.evaluate(X[j])
		#fitness[i] = f.evaluate(X[j])
		print f.evaluate(X[j])
		j = j+1
		

def population(arg,f,accuracy):
	pop_size = arg.count(':')+1 # counts the pop_size 
	X = np.zeros( (pop_size, f.get_dimension()) )
	fitness = np.zeros( pop_size )
	list_individuals = [i for i in arg.split(':')]
	j = 0
	for i in list_individuals:
		X[j] = [float(numeric_string) for numeric_string in i.split(',')]
		#fitness[j] = f.evaluate(X[j])
		print X[j]
		j = j+1
		
	count, seeds = how_many_goptima(X, f, accuracy)
	print "In the current population there exist (", count, ") global optimizers."
	print "Global optimizers:", seeds			
      	
def bounds(func):
	dim = func.get_dimension()

	# Create population of position vectors
	ub =np.zeros( dim )
	lb =np.zeros( dim )
	# Get lower, upper bounds
	for k in range(dim):
		ub[k] = func.get_ubound(k)
		lb[k] = func.get_lbound(k)	
	return lb,ub

def help():
	print 'nomad.py [options]'
	print '[CEC2013 options]:'
	print '\t -f function: function number de 1 to 21'
	print '\t -d: returns the number of dimensions of the function'
	print '\t -e individual: returns the fitness of individual for a given function'
	print '\t -b: returns the bounds of the function'
	print '\t -O: returns the number of optima of the function'
	print '\t -a accuracy: it provides a given accuracy'
	print '\t -P population: returns [count,seeds] for a population with '
	print '\t -E population: #Returns a list of fitnesses for a population '
	print '[NOMAD options]:'
	print '\t -n x0: starting to evaluate from this point'
	print '\t -i iterations: define the maximum number of iterations'

if __name__ == "__main__":
	main(sys.argv[1:])
