import sys
sys.path.append("../../pynisher")
sys.path.append('..')

import pysmac

import sklearn.ensemble
import sklearn.neighbors
import sklearn.datasets
import sklearn.cross_validation

# We use a random classification data set generated by sklearn
# As commonly done, we use a train-test split to avoid overfitting.
X,Y = sklearn.datasets.make_classification(1000, 20)
X_train, X_test, Y_train, Y_test = \
	sklearn.cross_validation.train_test_split(X,Y, test_size=0.33, random_state=1)


# training a random forest
def random_forest (n_trees=None, criterion=None, max_features=None, max_depth=None):
	predictor = sklearn.ensemble.RandomForestClassifier(n_trees, criterion, max_features, max_depth)
	predictor.fit(X_train, Y_train)
	return (-predictor.score(X_test, Y_test))

# and defining some of its parameters
parameters_trees = dict(\
	max_depth =  ("integer", [1,10],  4),
	max_features=("integer", [1,20], 10),
	n_trees=("integer", [1,100],10 ,'log'),          
	criterion =("categorical", ['gini', 'entropy'], 'entropy'),
	)

# training a k-nearest neighbor classifier
def knn (n_neighbors=None, weights=None):
	predictor = sklearn.neighbors.KNeighborsClassifier(n_neighbors, weights)
	predictor.fit(X_train, Y_train)
	return (-predictor.score(X_test, Y_test))

# and defining some of its paramers
parameters_knn = dict(\
	n_neighbors = ("integer", [1,100], 10, 'log'),
	weights = ("categorical", ['uniform', 'distance'], 'uniform'),
	)



# convenience function
from pysmac.utils.pcs_merge import merge_configuration_spaces

# returns a parameter config space, the conditionals, forbiddens and two wrapper functions
p,c,f,wrapper_str = merge_configuration_spaces(\
		(random_forest, parameters_trees, [], []),
		(knn, parameters_knn, [],[]))

# workaround to make the generated functions pickable (needed for pySMAC internals):
# they are generated as strings, and instantiated by executing this string
exec(wrapper_str)


# create optimizer object
opt = pysmac.SMAC_optimizer( debug = 0,
							 working_directory = '/tmp/pySMAC_test/',
							 persistent_files=True, )

# perform actual optimization
value, parameters = opt.minimize(pysmac_merged_pcs_wrapper, 
					#wrapper function generated by merge_configuration_spaces
                    50, # number of function evaluations
                    p, # parameter defintion
                    conditional_clauses = c,
                    forbidden_clauses = f)

print('The highest accuracy found: %f'%(-value))
print('Parameter setting %s'%parameters)


# For very complex configuration spaces, looking at the final values might be hard.
# You can use a function defined in 'wrapper_str' that finds the right callable and
# the corresponding arguments (with their original name). That way, it is more
# human readable.

func, kwargs = pysmac_merged_pcs_reduce_args(**parameters)
print("The best result was found calling '{}' with the arguments {}".format(func.__name__, kwargs))



