diff --git a/bin/hyppopy_exe.py b/bin/hyppopy_exe.py
index 2296c38..10f41e7 100644
--- a/bin/hyppopy_exe.py
+++ b/bin/hyppopy_exe.py
@@ -1,85 +1,86 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
-from hyppopy.workflows.unet_usecase import unet_usecase
-from hyppopy.workflows.svc_usecase import svc_usecase
-from hyppopy.workflows.randomforest_usecase import randomforest_usecase
+from hyppopy.workflows.unet_usecase.unet_usecase import unet_usecase
+from hyppopy.workflows.svc_usecase.svc_usecase import svc_usecase
+from hyppopy.workflows.randomforest_usecase.randomforest_usecase import randomforest_usecase
import os
import sys
import argparse
import hyppopy.solverfactory as sfac
solver_factory = sfac.SolverFactory.instance()
def print_warning(msg):
print("\n!!!!! WARNING !!!!!")
print(msg)
sys.exit()
def args_check(args):
if not args.workflow:
print_warning("No workflow specified, check --help")
if not args.config:
print_warning("Missing config parameter, check --help")
if not args.data:
print_warning("Missing data parameter, check --help")
if not os.path.isdir(args.data):
print_warning("Couldn't find data path, please check your input --data")
if not os.path.isfile(args.config):
tmp = os.path.join(args.data, args.config)
if not os.path.isfile(tmp):
print_warning("Couldn't find the config file, please check your input --config")
args.config = tmp
- if args.plugin not in solver_factory.list_solver():
- print_warning(f"The requested plugin {args.plugin} is not available, please check for typos. Plugin options :"
- f"{', '.join(solver_factory.list_solver())}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='UNet Hyppopy UseCase Example Optimization.')
parser.add_argument('-w', '--workflow', type=str,
help='workflow to be executed')
- parser.add_argument('-p', '--plugin', type=str, default='hyperopt',
+ parser.add_argument('-p', '--plugin', type=str, default='',
help='plugin to be used default=[hyperopt], optunity')
parser.add_argument('-d', '--data', type=str, help='training data path')
parser.add_argument('-c', '--config', type=str, help='config filename, .xml or .json formats are supported.'
'pass a full path filename or the filename only if the'
'configfile is in the data folder')
parser.add_argument('-i', '--iterations', type=int, default=0,
help='number of iterations, default=[0] if set to 0 the value set via configfile is used, '
'otherwise the configfile value will be overwritten')
args = parser.parse_args()
args_check(args)
if args.workflow == "svc_usecase":
- svc_usecase.svc_usecase(args)
+ uc = svc_usecase(args)
elif args.workflow == "randomforest_usecase":
- randomforest_usecase.randomforest_usecase(args)
+ uc = randomforest_usecase(args)
elif args.workflow == "unet_usecase":
- unet_usecase.unet_usecase(args)
+ uc = unet_usecase(args)
else:
print(f"No workflow called {args.workflow} found!")
+ sys.exit()
+
+ uc.run()
+ print(uc.get_results())
diff --git a/hyppopy/plugins/hyperopt_solver_plugin.py b/hyppopy/plugins/hyperopt_solver_plugin.py
index b21bc2e..c94ae6a 100644
--- a/hyppopy/plugins/hyperopt_solver_plugin.py
+++ b/hyppopy/plugins/hyperopt_solver_plugin.py
@@ -1,67 +1,70 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import os
import logging
from hyppopy.globals import DEBUGLEVEL
LOG = logging.getLogger(os.path.basename(__file__))
LOG.setLevel(DEBUGLEVEL)
from pprint import pformat
from hyperopt import fmin, tpe, hp, STATUS_OK, STATUS_FAIL, Trials
from yapsy.IPlugin import IPlugin
from hyppopy.solverpluginbase import SolverPluginBase
class hyperopt_Solver(SolverPluginBase, IPlugin):
trials = None
best = None
def __init__(self):
SolverPluginBase.__init__(self)
LOG.debug("initialized")
def loss_function(self, params):
try:
loss = self.loss(self.data, params)
status = STATUS_OK
except Exception as e:
LOG.error(f"execution of self.loss(self.data, params) failed due to:\n {e}")
status = STATUS_FAIL
return {'loss': loss, 'status': status}
def execute_solver(self, parameter):
LOG.debug(f"execute_solver using solution space:\n\n\t{pformat(parameter)}\n")
self.trials = Trials()
try:
self.best = fmin(fn=self.loss_function,
space=parameter,
algo=tpe.suggest,
max_evals=self.settings.max_iterations,
trials=self.trials)
except Exception as e:
msg = f"internal error in hyperopt.fmin occured. {e}"
LOG.error(msg)
raise BrokenPipeError(msg)
def convert_results(self):
+ txt = ""
solution = dict([(k, v) for k, v in self.best.items() if v is not None])
- print('Solution\n========')
- print("\n".join(map(lambda x: "%s \t %s" % (x[0], str(x[1])), solution.items())))
+ txt += 'Solution Hyperopt Plugin\n========\n'
+ txt += "\n".join(map(lambda x: "%s \t %s" % (x[0], str(x[1])), solution.items()))
+ txt += "\n"
+ return txt
diff --git a/hyppopy/plugins/optunity_solver_plugin.py b/hyppopy/plugins/optunity_solver_plugin.py
index 9b2779c..c92ab52 100644
--- a/hyppopy/plugins/optunity_solver_plugin.py
+++ b/hyppopy/plugins/optunity_solver_plugin.py
@@ -1,69 +1,72 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import os
import logging
from hyppopy.globals import DEBUGLEVEL
LOG = logging.getLogger(os.path.basename(__file__))
LOG.setLevel(DEBUGLEVEL)
from pprint import pformat
import optunity
from yapsy.IPlugin import IPlugin
from hyppopy.solverpluginbase import SolverPluginBase
class optunity_Solver(SolverPluginBase, IPlugin):
solver_info = None
trials = None
best = None
status = None
def __init__(self):
SolverPluginBase.__init__(self)
LOG.debug("initialized")
def loss_function(self, **params):
try:
loss = self.loss(self.data, params)
self.status.append('ok')
return loss
except Exception as e:
LOG.error(f"computing loss failed due to:\n {e}")
self.status.append('fail')
return 1e9
def execute_solver(self, parameter):
LOG.debug(f"execute_solver using solution space:\n\n\t{pformat(parameter)}\n")
self.status = []
try:
self.best, self.trials, self.solver_info = optunity.minimize_structured(f=self.loss_function,
num_evals=self.settings.max_iterations,
search_space=parameter)
except Exception as e:
LOG.error(f"internal error in optunity.minimize_structured occured. {e}")
raise BrokenPipeError(f"internal error in optunity.minimize_structured occured. {e}")
def convert_results(self):
solution = dict([(k, v) for k, v in self.best.items() if v is not None])
- print('Solution\n========')
- print("\n".join(map(lambda x: "%s \t %s" % (x[0], str(x[1])), solution.items())))
- print(f"Solver used: {self.solver_info['solver_name']}")
- print(f"Optimum: {self.trials.optimum}")
- print(f"Iterations used: {self.trials.stats['num_evals']}")
- print(f"Duration: {self.trials.stats['time']} s")
+
+ txt = ""
+ txt += 'Solution Optunity Plugin\n========\n'
+ txt += "\n".join(map(lambda x: "%s \t %s" % (x[0], str(x[1])), solution.items()))
+ txt += f"\nSolver used: {self.solver_info['solver_name']}"
+ txt += f"\nOptimum: {self.trials.optimum}"
+ txt += f"\nIterations used: {self.trials.stats['num_evals']}"
+ txt += f"\nDuration: {self.trials.stats['time']} s\n"
+ return txt
diff --git a/hyppopy/solver.py b/hyppopy/solver.py
index e2a9a5e..14262fd 100644
--- a/hyppopy/solver.py
+++ b/hyppopy/solver.py
@@ -1,84 +1,84 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import os
import logging
from hyppopy.globals import DEBUGLEVEL
LOG = logging.getLogger(os.path.basename(__file__))
LOG.setLevel(DEBUGLEVEL)
class Solver(object):
_name = None
_solver_plugin = None
_settings_plugin = None
def __init__(self):
pass
def set_data(self, data):
self.solver.set_data(data)
def set_parameters(self, params):
self.settings.set(params)
self.settings.set_attributes(self.solver)
def read_parameter(self, fname):
self.settings.read(fname)
self.settings.set_attributes(self.settings)
def set_loss_function(self, loss_func):
self.solver.set_loss_function(loss_func)
def run(self):
self.solver.settings = self.settings
self.solver.run()
def get_results(self):
- self.solver.get_results()
+ return self.solver.get_results()
@property
def is_ready(self):
return self.solver is not None and self.settings is not None
@property
def solver(self):
return self._solver_plugin
@solver.setter
def solver(self, value):
self._solver_plugin = value
@property
def settings(self):
return self._settings_plugin
@settings.setter
def settings(self, value):
self._settings_plugin = value
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
LOG.error(f"Invalid input, str type expected for value, got {type(value)} instead")
raise IOError(f"Invalid input, str type expected for value, got {type(value)} instead")
self._name = value
diff --git a/hyppopy/solverpluginbase.py b/hyppopy/solverpluginbase.py
index 91ce6ba..63a16d7 100644
--- a/hyppopy/solverpluginbase.py
+++ b/hyppopy/solverpluginbase.py
@@ -1,86 +1,86 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import abc
import os
import logging
from hyppopy.globals import DEBUGLEVEL
from hyppopy.settingspluginbase import SettingsPluginBase
LOG = logging.getLogger(os.path.basename(__file__))
LOG.setLevel(DEBUGLEVEL)
class SolverPluginBase(object):
data = None
loss = None
_settings = None
_name = None
def __init__(self):
pass
@abc.abstractmethod
def loss_function(self, params):
raise NotImplementedError('users must define loss_func to use this base class')
@abc.abstractmethod
def execute_solver(self):
raise NotImplementedError('users must define execute_solver to use this base class')
@abc.abstractmethod
def convert_results(self):
raise NotImplementedError('users must define convert_results to use this base class')
def set_data(self, data):
self.data = data
def set_loss_function(self, func):
self.loss = func
def get_results(self):
- self.convert_results()
+ return self.convert_results()
def run(self):
self.execute_solver(self.settings.get_hyperparameter())
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
msg = f"Invalid input, str type expected for value, got {type(value)} instead"
LOG.error(msg)
raise IOError(msg)
self._name = value
@property
def settings(self):
return self._settings
@settings.setter
def settings(self, value):
if not isinstance(value, SettingsPluginBase):
msg = f"Invalid input, SettingsPluginBase type expected for value, got {type(value)} instead"
LOG.error(msg)
raise IOError(msg)
self._settings = value
diff --git a/hyppopy/tests/data/Iris/rf_config.json b/hyppopy/tests/data/Iris/rf_config.json
new file mode 100644
index 0000000..869c319
--- /dev/null
+++ b/hyppopy/tests/data/Iris/rf_config.json
@@ -0,0 +1,42 @@
+{"hyperparameter": {
+ "n_estimators": {
+ "domain": "uniform",
+ "data": "[3,500]",
+ "type": "int"
+ },
+ "criterion": {
+ "domain": "categorical",
+ "data": "[gini,entropy]",
+ "type": "str"
+ },
+ "max_depth": {
+ "domain": "uniform",
+ "data": "[3, 50]",
+ "type": "int"
+ },
+ "min_samples_split": {
+ "domain": "uniform",
+ "data": "[0.0001,1]",
+ "type": "float"
+ },
+ "min_samples_leaf": {
+ "domain": "uniform",
+ "data": "[0.0001,0.5]",
+ "type": "float"
+ },
+ "max_features": {
+ "domain": "categorical",
+ "data": "[auto,sqrt,log2]",
+ "type": "str"
+ }
+},
+"settings": {
+ "solver": {
+ "max_iterations": "3",
+ "use_plugin" : "optunity"
+ },
+ "custom": {
+ "data_name": "train_data.npy",
+ "labels_name": "train_labels.npy"
+ }
+}}
\ No newline at end of file
diff --git a/hyppopy/tests/data/Iris/rf_config.xml b/hyppopy/tests/data/Iris/rf_config.xml
new file mode 100644
index 0000000..925d164
--- /dev/null
+++ b/hyppopy/tests/data/Iris/rf_config.xml
@@ -0,0 +1,44 @@
+
+
+
+ uniform
+ [3,200]
+ int
+
+
+ categorical
+ [gini,entropy]
+ str
+
+
+ uniform
+ [3, 50]
+ int
+
+
+ uniform
+ [0.0001,1]
+ float
+
+
+ uniform
+ [0.0001,0.5]
+ float
+
+
+ categorical
+ [auto,sqrt,log2]
+ str
+
+
+
+
+ 3
+ optunity
+
+
+ train_data.npy
+ train_labels.npy
+
+
+
\ No newline at end of file
diff --git a/hyppopy/tests/data/Iris/svc_config.json b/hyppopy/tests/data/Iris/svc_config.json
new file mode 100644
index 0000000..0628f97
--- /dev/null
+++ b/hyppopy/tests/data/Iris/svc_config.json
@@ -0,0 +1,32 @@
+{"hyperparameter": {
+ "C": {
+ "domain": "uniform",
+ "data": "[0,20]",
+ "type": "float"
+ },
+ "gamma": {
+ "domain": "uniform",
+ "data": "[0.0001,20.0]",
+ "type": "float"
+ },
+ "kernel": {
+ "domain": "categorical",
+ "data": "[linear, sigmoid, poly, rbf]",
+ "type": "str"
+ },
+ "decision_function_shape": {
+ "domain": "categorical",
+ "data": "[ovo,ovr]",
+ "type": "str"
+ }
+},
+"settings": {
+ "solver": {
+ "max_iterations": "3",
+ "use_plugin" : "optunity"
+ },
+ "custom": {
+ "data_name": "train_data.npy",
+ "labels_name": "train_labels.npy"
+ }
+}}
\ No newline at end of file
diff --git a/hyppopy/tests/data/Iris/svc_config.xml b/hyppopy/tests/data/Iris/svc_config.xml
new file mode 100644
index 0000000..fb4f50b
--- /dev/null
+++ b/hyppopy/tests/data/Iris/svc_config.xml
@@ -0,0 +1,34 @@
+
+
+
+ uniform
+ [0,20]
+ float
+
+
+ uniform
+ [0.0001,20.0]
+ float
+
+
+ categorical
+ [linear,sigmoid,poly,rbf]
+ str
+
+
+ categorical
+ [ovo,ovr]
+ str
+
+
+
+
+ 3
+ hyperopt
+
+
+ train_data.npy
+ train_labels.npy
+
+
+
\ No newline at end of file
diff --git a/hyppopy/tests/data/Iris/train_data.npy b/hyppopy/tests/data/Iris/train_data.npy
new file mode 100644
index 0000000..b4cdefd
Binary files /dev/null and b/hyppopy/tests/data/Iris/train_data.npy differ
diff --git a/hyppopy/tests/data/Iris/train_labels.npy b/hyppopy/tests/data/Iris/train_labels.npy
new file mode 100644
index 0000000..797abe7
Binary files /dev/null and b/hyppopy/tests/data/Iris/train_labels.npy differ
diff --git a/hyppopy/tests/data/Titanic/rf_config.json b/hyppopy/tests/data/Titanic/rf_config.json
new file mode 100644
index 0000000..7993c78
--- /dev/null
+++ b/hyppopy/tests/data/Titanic/rf_config.json
@@ -0,0 +1,27 @@
+{"hyperparameter": {
+ "n_estimators": {
+ "domain": "uniform",
+ "data": "[3,500]",
+ "type": "int"
+ },
+ "criterion": {
+ "domain": "categorical",
+ "data": "[gini,entropy]",
+ "type": "str"
+ },
+ "max_depth": {
+ "domain": "uniform",
+ "data": "[3, 50]",
+ "type": "int"
+ }
+},
+"settings": {
+ "solver": {
+ "max_iterations": "3",
+ "use_plugin" : "optunity"
+ },
+ "custom": {
+ "data_name": "train_cleaned.csv",
+ "labels_name": "Survived"
+ }
+}}
\ No newline at end of file
diff --git a/hyppopy/tests/data/Titanic/rf_config.xml b/hyppopy/tests/data/Titanic/rf_config.xml
new file mode 100644
index 0000000..5dd0797
--- /dev/null
+++ b/hyppopy/tests/data/Titanic/rf_config.xml
@@ -0,0 +1,29 @@
+
+
+
+ uniform
+ [3,200]
+ int
+
+
+ categorical
+ [gini,entropy]
+ str
+
+
+ uniform
+ [3, 50]
+ int
+
+
+
+
+ 3
+ optunity
+
+
+ train_cleaned.csv
+ Survived
+
+
+
\ No newline at end of file
diff --git a/hyppopy/tests/data/Titanic/svc_config.json b/hyppopy/tests/data/Titanic/svc_config.json
new file mode 100644
index 0000000..3291024
--- /dev/null
+++ b/hyppopy/tests/data/Titanic/svc_config.json
@@ -0,0 +1,32 @@
+{"hyperparameter": {
+ "C": {
+ "domain": "uniform",
+ "data": "[0,20]",
+ "type": "float"
+ },
+ "gamma": {
+ "domain": "uniform",
+ "data": "[0.0001,20.0]",
+ "type": "float"
+ },
+ "kernel": {
+ "domain": "categorical",
+ "data": "[linear, sigmoid, poly, rbf]",
+ "type": "str"
+ },
+ "decision_function_shape": {
+ "domain": "categorical",
+ "data": "[ovo,ovr]",
+ "type": "str"
+ }
+},
+"settings": {
+ "solver": {
+ "max_iterations": "3",
+ "use_plugin" : "hyperopt"
+ },
+ "custom": {
+ "data_name": "train_cleaned.csv",
+ "labels_name": "Survived"
+ }
+}}
\ No newline at end of file
diff --git a/hyppopy/tests/data/Titanic/svc_config.xml b/hyppopy/tests/data/Titanic/svc_config.xml
new file mode 100644
index 0000000..5c2b275
--- /dev/null
+++ b/hyppopy/tests/data/Titanic/svc_config.xml
@@ -0,0 +1,34 @@
+
+
+
+ uniform
+ [0,20]
+ float
+
+
+ uniform
+ [0.0001,20.0]
+ float
+
+
+ categorical
+ [linear,sigmoid,poly,rbf]
+ str
+
+
+ categorical
+ [ovo,ovr]
+ str
+
+
+
+
+ 3
+ hyperopt
+
+
+ train_cleaned.csv
+ Survived
+
+
+
\ No newline at end of file
diff --git a/hyppopy/tests/data/Titanic/train_cleaned.csv b/hyppopy/tests/data/Titanic/train_cleaned.csv
new file mode 100644
index 0000000..c587d3b
--- /dev/null
+++ b/hyppopy/tests/data/Titanic/train_cleaned.csv
@@ -0,0 +1,892 @@
+Pclass,Sex,Age,Embarked_C,Embarked_Q,Survived
+3,1,22.0,0,0,0
+1,0,38.0,1,0,1
+3,0,26.0,0,0,1
+1,0,35.0,0,0,1
+3,1,35.0,0,0,0
+3,1,42.0,0,1,0
+1,1,54.0,0,0,0
+3,1,2.0,0,0,0
+3,0,27.0,0,0,1
+2,0,14.0,1,0,1
+3,0,4.0,0,0,1
+1,0,58.0,0,0,1
+3,1,20.0,0,0,0
+3,1,39.0,0,0,0
+3,0,14.0,0,0,0
+2,0,55.0,0,0,1
+3,1,2.0,0,1,0
+2,1,42.0,0,0,1
+3,0,31.0,0,0,0
+3,0,4.574166666666667,1,0,1
+2,1,35.0,0,0,0
+2,1,34.0,0,0,1
+3,0,15.0,0,1,1
+1,1,28.0,0,0,1
+3,0,8.0,0,0,0
+3,0,38.0,0,0,1
+3,1,42.0,1,0,0
+1,1,19.0,0,0,0
+3,0,70.0,0,1,1
+3,1,42.0,0,0,0
+1,1,40.0,1,0,0
+1,0,4.574166666666667,1,0,1
+3,0,70.0,0,1,1
+2,1,66.0,0,0,0
+1,1,28.0,1,0,0
+1,1,42.0,0,0,0
+3,1,42.0,1,0,1
+3,1,21.0,0,0,0
+3,0,18.0,0,0,0
+3,0,14.0,1,0,1
+3,0,40.0,0,0,0
+2,0,27.0,0,0,0
+3,1,42.0,1,0,0
+2,0,3.0,1,0,1
+3,0,19.0,0,1,1
+3,1,42.0,0,0,0
+3,1,42.0,0,1,0
+3,0,70.0,0,1,1
+3,1,42.0,1,0,0
+3,0,18.0,0,0,0
+3,1,7.0,0,0,0
+3,1,21.0,0,0,0
+1,0,49.0,1,0,1
+2,0,29.0,0,0,1
+1,1,65.0,1,0,0
+1,1,42.0,0,0,1
+2,0,21.0,0,0,1
+3,1,28.5,1,0,0
+2,0,5.0,0,0,1
+3,1,11.0,0,0,0
+3,1,22.0,1,0,0
+1,0,38.0,0,0,1
+1,1,45.0,0,0,0
+3,1,4.0,0,0,0
+1,1,42.0,1,0,0
+3,1,40.0,1,0,1
+2,0,29.0,0,0,1
+3,1,19.0,0,0,0
+3,0,17.0,0,0,1
+3,1,26.0,0,0,0
+2,1,32.0,0,0,0
+3,0,16.0,0,0,0
+2,1,21.0,0,0,0
+3,1,26.0,1,0,0
+3,1,32.0,0,0,1
+3,1,25.0,0,0,0
+3,1,42.0,0,0,0
+3,1,42.0,0,0,0
+2,1,0.83,0,0,1
+3,0,30.0,0,0,1
+3,1,22.0,0,0,0
+3,1,29.0,0,0,1
+3,0,70.0,0,1,1
+1,1,28.0,0,0,0
+2,0,17.0,0,0,1
+3,0,33.0,0,0,1
+3,1,16.0,0,0,0
+3,1,42.0,0,0,0
+1,0,23.0,0,0,1
+3,1,24.0,0,0,0
+3,1,29.0,0,0,0
+3,1,20.0,0,0,0
+1,1,46.0,0,0,0
+3,1,26.0,0,0,0
+3,1,59.0,0,0,0
+3,1,42.0,0,0,0
+1,1,71.0,1,0,0
+1,1,23.0,1,0,1
+2,0,34.0,0,0,1
+2,1,34.0,0,0,0
+3,0,28.0,0,0,0
+3,1,42.0,0,0,0
+1,1,21.0,0,0,0
+3,1,33.0,0,0,0
+3,1,37.0,0,0,0
+3,1,28.0,0,0,0
+3,0,21.0,0,0,1
+3,1,42.0,0,0,1
+3,1,38.0,0,0,0
+3,0,70.0,0,1,1
+1,1,47.0,0,0,0
+3,0,14.5,1,0,0
+3,1,22.0,0,0,0
+3,0,20.0,0,0,0
+3,0,17.0,1,0,0
+3,1,21.0,0,0,0
+3,1,70.5,0,1,0
+2,1,29.0,0,0,0
+1,1,24.0,1,0,0
+3,0,2.0,0,0,0
+2,1,21.0,0,0,0
+3,1,42.0,0,0,0
+2,1,32.5,1,0,0
+2,0,32.5,0,0,1
+1,1,54.0,0,0,0
+3,1,12.0,1,0,1
+3,1,42.0,0,1,0
+3,1,24.0,0,0,1
+3,0,70.0,1,0,1
+3,1,45.0,0,0,0
+3,1,33.0,1,0,0
+3,1,20.0,0,0,0
+3,0,47.0,0,0,0
+2,0,29.0,0,0,1
+2,1,25.0,0,0,0
+2,1,23.0,1,0,0
+1,0,19.0,0,0,1
+1,1,37.0,0,0,0
+3,1,16.0,0,0,0
+1,1,24.0,1,0,0
+3,0,4.574166666666667,1,0,0
+3,0,22.0,0,0,1
+3,0,24.0,0,0,1
+3,1,19.0,0,1,0
+2,1,18.0,0,0,0
+2,1,19.0,0,0,0
+3,1,27.0,0,0,1
+3,0,9.0,0,0,0
+2,1,36.5,0,0,0
+2,1,42.0,0,0,0
+2,1,51.0,0,0,0
+1,0,22.0,0,0,1
+3,1,55.5,0,0,0
+3,1,40.5,0,0,0
+3,1,42.0,0,0,0
+1,1,51.0,1,0,0
+3,0,16.0,0,1,1
+3,1,30.0,0,0,0
+3,1,42.0,0,0,0
+3,1,40.0,0,0,0
+3,1,44.0,0,0,0
+2,0,40.0,0,0,1
+3,1,26.0,0,0,0
+3,1,17.0,0,0,0
+3,1,1.0,0,0,0
+3,1,9.0,0,0,1
+1,0,4.574166666666667,0,0,1
+3,0,45.0,0,0,0
+1,1,42.0,0,0,0
+3,1,28.0,0,0,0
+1,1,61.0,0,0,0
+3,1,4.0,0,1,0
+3,0,1.0,0,0,1
+3,1,21.0,0,0,0
+1,1,56.0,1,0,0
+3,1,18.0,0,0,0
+3,1,40.0,0,0,0
+1,0,50.0,1,0,0
+2,1,30.0,0,0,0
+3,1,36.0,0,0,0
+3,0,70.0,0,0,0
+2,1,42.0,1,0,0
+3,1,9.0,0,0,0
+2,1,1.0,0,0,1
+3,0,4.0,0,0,1
+1,1,42.0,0,0,0
+3,0,4.574166666666667,0,1,1
+1,1,45.0,0,0,1
+3,1,40.0,0,1,0
+3,1,36.0,0,0,0
+2,0,32.0,0,0,1
+2,1,19.0,0,0,0
+3,0,19.0,0,0,1
+2,1,3.0,0,0,1
+1,0,44.0,1,0,1
+1,0,58.0,1,0,1
+3,1,42.0,0,1,0
+3,1,42.0,0,0,0
+3,0,70.0,0,1,1
+2,0,24.0,0,0,0
+3,1,28.0,0,0,0
+3,1,42.0,0,0,0
+3,1,34.0,0,0,0
+3,1,45.5,1,0,0
+3,1,18.0,0,0,1
+3,0,2.0,0,0,0
+3,1,32.0,0,0,0
+3,1,26.0,1,0,1
+3,0,16.0,0,1,1
+1,1,40.0,1,0,1
+3,1,24.0,0,0,0
+2,0,35.0,0,0,1
+3,1,22.0,0,0,0
+2,1,30.0,0,0,0
+3,1,42.0,0,1,0
+1,0,31.0,1,0,1
+3,0,27.0,0,0,1
+2,1,42.0,0,0,0
+1,0,32.0,1,0,1
+2,1,30.0,0,0,0
+3,1,16.0,0,0,1
+2,1,27.0,0,0,0
+3,1,51.0,0,0,0
+3,1,42.0,0,0,0
+1,1,38.0,0,0,1
+3,1,22.0,0,0,0
+2,1,19.0,0,0,1
+3,1,20.5,0,0,0
+2,1,18.0,0,0,0
+3,0,70.0,0,0,0
+1,0,35.0,0,0,1
+3,1,29.0,0,0,0
+2,1,59.0,0,0,0
+3,0,5.0,0,0,1
+2,1,24.0,0,0,0
+3,0,70.0,0,0,0
+2,1,44.0,0,0,0
+2,0,8.0,0,0,1
+2,1,19.0,0,0,0
+2,1,33.0,0,0,0
+3,0,70.0,1,0,0
+3,0,70.0,0,1,1
+2,1,29.0,0,0,0
+3,1,22.0,0,0,0
+3,1,30.0,1,0,0
+1,1,44.0,0,1,0
+3,0,25.0,0,0,0
+2,0,24.0,0,0,1
+1,1,37.0,0,0,1
+2,1,54.0,0,0,0
+3,1,42.0,0,0,0
+3,0,29.0,0,0,0
+1,1,62.0,0,0,0
+3,1,30.0,0,0,0
+3,0,41.0,0,0,0
+3,0,29.0,1,0,1
+1,0,4.574166666666667,1,0,1
+1,0,30.0,0,0,1
+1,0,35.0,1,0,1
+2,0,50.0,0,0,1
+3,1,42.0,0,1,0
+3,1,3.0,0,0,1
+1,1,52.0,0,0,0
+1,1,40.0,0,0,0
+3,0,70.0,0,1,0
+2,1,36.0,0,0,0
+3,1,16.0,0,0,0
+3,1,25.0,0,0,1
+1,0,58.0,0,0,1
+1,0,35.0,0,0,1
+1,1,42.0,0,0,0
+3,1,25.0,0,0,1
+2,0,41.0,0,0,1
+1,1,37.0,1,0,0
+3,0,70.0,0,1,1
+1,0,63.0,0,0,1
+3,0,45.0,0,0,0
+2,1,42.0,0,0,0
+3,1,7.0,0,1,0
+3,0,35.0,0,0,1
+3,1,65.0,0,1,0
+3,1,28.0,0,0,0
+3,1,16.0,0,0,0
+3,1,19.0,0,0,1
+1,1,42.0,0,0,0
+3,1,33.0,1,0,0
+3,1,30.0,0,0,1
+3,1,22.0,0,0,0
+2,1,42.0,0,0,1
+3,0,22.0,0,1,1
+1,0,26.0,0,0,1
+1,0,19.0,1,0,1
+2,1,36.0,1,0,0
+3,0,24.0,0,0,0
+3,1,24.0,0,0,0
+1,1,42.0,1,0,0
+3,1,23.5,1,0,0
+1,0,2.0,0,0,0
+1,1,42.0,0,0,1
+1,0,50.0,1,0,1
+3,0,70.0,0,1,1
+3,1,42.0,0,1,1
+3,1,19.0,0,0,0
+2,0,70.0,0,1,1
+3,1,42.0,0,0,0
+1,1,0.92,0,0,1
+1,0,70.0,1,0,1
+1,0,17.0,1,0,1
+2,1,30.0,1,0,0
+1,0,30.0,1,0,1
+1,0,24.0,1,0,1
+1,0,18.0,1,0,1
+2,0,26.0,0,0,0
+3,1,28.0,0,0,0
+2,1,43.0,0,0,0
+3,0,26.0,0,0,1
+2,0,24.0,0,0,1
+2,1,54.0,0,0,0
+1,0,31.0,0,0,1
+1,0,40.0,1,0,1
+3,1,22.0,0,0,0
+3,1,27.0,0,0,0
+2,0,30.0,0,1,1
+2,0,22.0,0,0,1
+3,1,42.0,0,0,0
+1,0,36.0,1,0,1
+3,1,61.0,0,0,0
+2,0,36.0,0,0,1
+3,0,31.0,0,0,1
+1,0,16.0,1,0,1
+3,0,70.0,0,1,1
+1,1,45.5,0,0,0
+1,1,38.0,0,0,0
+3,1,16.0,0,0,0
+1,0,4.574166666666667,0,0,1
+3,1,42.0,0,0,0
+1,1,29.0,0,0,0
+1,0,41.0,1,0,1
+3,1,45.0,0,0,1
+1,1,45.0,0,0,0
+2,1,2.0,0,0,1
+1,0,24.0,0,0,1
+2,1,28.0,0,0,0
+2,1,25.0,0,0,0
+2,1,36.0,0,0,0
+2,0,24.0,0,0,1
+2,0,40.0,0,0,1
+3,0,4.574166666666667,0,0,1
+3,1,3.0,0,0,1
+3,1,42.0,0,0,0
+3,1,23.0,0,0,0
+1,1,42.0,0,0,0
+3,1,15.0,1,0,0
+3,1,25.0,0,0,0
+3,1,42.0,1,0,0
+3,1,28.0,0,0,0
+1,0,22.0,0,0,1
+2,0,38.0,0,0,0
+3,0,70.0,0,1,1
+3,0,70.0,0,1,1
+3,1,40.0,0,0,0
+2,1,29.0,1,0,0
+3,0,45.0,1,0,0
+3,1,35.0,0,0,0
+3,1,42.0,0,1,0
+3,1,30.0,0,0,0
+1,0,60.0,1,0,1
+3,0,4.574166666666667,1,0,1
+3,0,70.0,0,1,1
+1,0,24.0,1,0,1
+1,1,25.0,1,0,1
+3,1,18.0,0,0,0
+3,1,19.0,0,0,0
+1,1,22.0,1,0,0
+3,0,3.0,0,0,0
+1,0,4.574166666666667,1,0,1
+3,0,22.0,0,0,1
+1,1,27.0,1,0,0
+3,1,20.0,1,0,0
+3,1,19.0,0,0,0
+1,0,42.0,1,0,1
+3,0,1.0,1,0,1
+3,1,32.0,0,0,0
+1,0,35.0,0,0,1
+3,1,42.0,0,0,0
+2,1,18.0,0,0,0
+3,1,1.0,0,0,0
+2,0,36.0,0,0,1
+3,1,42.0,0,1,0
+2,0,17.0,1,0,1
+1,1,36.0,0,0,1
+3,1,21.0,0,0,1
+3,1,28.0,0,0,0
+1,0,23.0,1,0,1
+3,0,24.0,0,0,1
+3,1,22.0,0,0,0
+3,0,31.0,0,0,0
+2,1,46.0,0,0,0
+2,1,23.0,0,0,0
+2,0,28.0,0,0,1
+3,1,39.0,0,0,1
+3,1,26.0,0,0,0
+3,0,21.0,0,0,0
+3,1,28.0,0,0,0
+3,0,20.0,0,0,0
+2,1,34.0,0,0,0
+3,1,51.0,0,0,0
+2,1,3.0,0,0,1
+3,1,21.0,0,0,0
+3,0,70.0,0,0,0
+3,1,42.0,0,0,0
+3,1,42.0,0,1,0
+1,0,33.0,0,1,1
+2,1,42.0,0,0,0
+3,1,44.0,0,0,1
+3,0,4.574166666666667,0,0,0
+2,0,34.0,0,0,1
+2,0,18.0,0,0,1
+2,1,30.0,0,0,0
+3,0,10.0,0,0,0
+3,1,42.0,1,0,0
+3,1,21.0,0,1,0
+3,1,29.0,0,0,0
+3,0,28.0,0,0,0
+3,1,18.0,0,0,0
+3,1,42.0,0,0,0
+2,0,28.0,0,0,1
+2,0,19.0,0,0,1
+3,1,42.0,0,1,0
+3,1,32.0,0,0,1
+1,1,28.0,0,0,1
+3,0,4.574166666666667,0,0,1
+2,0,42.0,0,0,1
+3,1,17.0,0,0,0
+1,1,50.0,0,0,0
+1,0,14.0,0,0,1
+3,0,21.0,0,0,0
+2,0,24.0,0,0,1
+1,1,64.0,0,0,0
+2,1,31.0,0,0,0
+2,0,45.0,0,0,1
+3,1,20.0,0,0,0
+3,1,25.0,0,0,0
+2,0,28.0,0,0,1
+3,1,42.0,0,0,1
+1,1,4.0,0,0,1
+2,0,13.0,0,0,1
+1,1,34.0,0,0,1
+3,0,5.0,1,0,1
+1,1,52.0,0,0,1
+2,1,36.0,0,0,0
+3,1,42.0,0,0,0
+1,1,30.0,1,0,0
+1,1,49.0,1,0,1
+3,1,42.0,0,0,0
+3,1,29.0,1,0,1
+1,1,65.0,0,0,0
+1,0,4.574166666666667,0,0,1
+2,0,50.0,0,0,1
+3,1,42.0,0,1,0
+1,1,48.0,0,0,1
+3,1,34.0,0,0,0
+1,1,47.0,0,0,0
+2,1,48.0,0,0,0
+3,1,42.0,0,0,0
+3,1,38.0,0,0,0
+2,1,42.0,0,0,0
+1,1,56.0,0,0,0
+3,1,42.0,0,1,0
+3,0,0.75,1,0,1
+3,1,42.0,0,0,0
+3,1,38.0,0,0,0
+2,0,33.0,0,0,1
+2,0,23.0,1,0,1
+3,0,22.0,0,0,0
+1,1,42.0,0,0,0
+2,1,34.0,0,0,0
+3,1,29.0,0,0,0
+3,1,22.0,0,0,0
+3,0,2.0,0,0,1
+3,1,9.0,0,0,0
+2,1,42.0,0,0,0
+3,1,50.0,0,0,0
+3,0,63.0,0,0,1
+1,1,25.0,1,0,1
+3,0,70.0,0,0,0
+1,0,35.0,0,0,1
+1,1,58.0,1,0,0
+3,1,30.0,0,0,0
+3,1,9.0,0,0,1
+3,1,42.0,0,0,0
+3,1,21.0,0,0,0
+1,1,55.0,0,0,0
+1,1,71.0,1,0,0
+3,1,21.0,0,0,0
+3,1,42.0,1,0,0
+1,0,54.0,1,0,1
+3,1,42.0,0,0,0
+1,0,25.0,0,0,0
+3,1,24.0,0,0,0
+3,1,17.0,0,0,0
+3,0,21.0,0,1,0
+3,0,70.0,0,1,0
+3,0,37.0,0,0,0
+1,0,16.0,0,0,1
+1,1,18.0,1,0,0
+2,0,33.0,0,0,1
+1,1,42.0,0,0,1
+3,1,28.0,0,0,0
+3,1,26.0,0,0,1
+3,1,29.0,0,1,1
+3,1,42.0,0,0,0
+1,1,36.0,0,0,1
+1,0,54.0,1,0,1
+3,1,24.0,0,0,0
+1,1,47.0,0,0,0
+2,0,34.0,0,0,1
+3,1,42.0,0,1,0
+2,0,36.0,0,0,1
+3,1,32.0,0,0,0
+1,0,30.0,0,0,1
+3,1,22.0,0,0,0
+3,1,42.0,1,0,0
+1,0,44.0,1,0,1
+3,1,42.0,1,0,0
+3,1,40.5,0,1,0
+2,0,50.0,0,0,1
+1,1,42.0,0,0,0
+3,1,39.0,0,0,0
+2,1,23.0,0,0,0
+2,0,2.0,0,0,1
+3,1,42.0,1,0,0
+3,1,17.0,1,0,0
+3,0,4.574166666666667,1,0,1
+3,0,30.0,0,0,0
+2,0,7.0,0,0,1
+1,1,45.0,0,0,0
+1,0,30.0,1,0,1
+3,1,42.0,0,0,0
+1,0,22.0,1,0,1
+1,0,36.0,0,0,1
+3,0,9.0,0,0,0
+3,0,11.0,0,0,0
+2,1,32.0,0,0,1
+1,1,50.0,1,0,0
+1,1,64.0,0,0,0
+2,0,19.0,0,0,1
+2,1,42.0,1,0,1
+3,1,33.0,0,0,0
+2,1,8.0,0,0,1
+1,1,17.0,1,0,1
+2,1,27.0,0,0,0
+3,1,42.0,0,1,0
+3,1,22.0,1,0,1
+3,0,22.0,0,0,1
+1,1,62.0,0,0,0
+1,0,48.0,1,0,1
+1,1,42.0,1,0,0
+1,0,39.0,0,0,1
+3,0,36.0,0,0,1
+3,1,42.0,0,1,0
+3,1,40.0,0,0,0
+2,1,28.0,0,0,0
+3,1,42.0,0,0,0
+3,0,70.0,0,0,0
+3,1,24.0,0,0,0
+3,1,19.0,0,0,0
+3,0,29.0,0,0,0
+3,1,42.0,1,0,0
+3,1,32.0,0,0,1
+2,1,62.0,0,0,1
+1,0,53.0,0,0,1
+1,1,36.0,0,0,1
+3,0,70.0,0,1,1
+3,1,16.0,0,0,0
+3,1,19.0,0,0,0
+2,0,34.0,0,0,1
+1,0,39.0,0,0,1
+3,0,4.574166666666667,1,0,0
+3,1,32.0,0,0,1
+2,0,25.0,0,0,1
+1,0,39.0,1,0,1
+2,1,54.0,0,0,0
+1,1,36.0,1,0,0
+3,1,42.0,1,0,0
+1,0,18.0,0,0,1
+2,1,47.0,0,0,0
+1,1,60.0,1,0,1
+3,1,22.0,0,0,0
+3,1,42.0,0,0,0
+3,1,35.0,0,0,0
+1,0,52.0,1,0,1
+3,1,47.0,0,0,0
+3,0,70.0,0,1,0
+2,1,37.0,0,0,0
+3,1,36.0,0,0,0
+2,0,70.0,0,0,1
+3,1,49.0,0,0,0
+3,1,42.0,1,0,0
+1,1,49.0,1,0,1
+2,0,24.0,0,0,1
+3,1,42.0,0,0,0
+1,1,42.0,0,0,0
+3,1,44.0,0,0,0
+1,1,35.0,1,0,1
+3,1,36.0,0,0,0
+3,1,30.0,0,0,0
+1,1,27.0,0,0,1
+2,0,22.0,1,0,1
+1,0,40.0,0,0,1
+3,0,39.0,0,0,0
+3,1,42.0,0,0,0
+3,0,70.0,0,1,1
+3,1,42.0,0,1,0
+3,1,35.0,0,0,0
+2,0,24.0,0,0,1
+3,1,34.0,0,0,0
+3,0,26.0,0,0,0
+2,0,4.0,0,0,1
+2,1,26.0,0,0,0
+3,1,27.0,1,0,0
+1,1,42.0,0,0,1
+3,1,20.0,1,0,1
+3,1,21.0,0,0,0
+3,1,21.0,0,0,0
+1,1,61.0,0,0,0
+2,1,57.0,0,1,0
+1,0,21.0,0,0,1
+3,1,26.0,0,0,0
+3,1,42.0,0,1,0
+1,1,80.0,0,0,1
+3,1,51.0,0,0,0
+1,1,32.0,1,0,1
+1,1,42.0,0,0,0
+3,0,9.0,0,0,0
+2,0,28.0,0,0,1
+3,1,32.0,0,0,0
+2,1,31.0,0,0,0
+3,0,41.0,0,0,0
+3,1,42.0,0,0,0
+3,1,20.0,0,0,0
+1,0,24.0,1,0,1
+3,0,2.0,0,0,0
+3,1,42.0,0,0,1
+3,0,0.75,1,0,1
+1,1,48.0,1,0,1
+3,1,19.0,0,0,0
+1,1,56.0,1,0,1
+3,1,42.0,0,0,0
+3,0,23.0,0,0,1
+3,1,42.0,0,0,0
+2,0,18.0,0,0,1
+3,1,21.0,0,0,0
+3,0,70.0,0,1,1
+3,0,18.0,0,1,0
+2,1,24.0,0,0,0
+3,1,42.0,0,0,0
+3,0,32.0,0,1,0
+2,1,23.0,0,0,0
+1,1,58.0,1,0,0
+1,1,50.0,0,0,1
+3,1,40.0,1,0,0
+1,1,47.0,0,0,0
+3,1,36.0,0,0,0
+3,1,20.0,0,0,1
+2,1,32.0,0,0,0
+2,1,25.0,0,0,0
+3,1,42.0,0,0,0
+3,1,43.0,0,0,0
+1,0,4.574166666666667,0,0,1
+2,0,40.0,0,0,1
+1,1,31.0,0,0,0
+2,1,70.0,0,0,0
+2,1,31.0,0,0,1
+2,1,42.0,0,0,0
+3,1,18.0,0,0,0
+3,1,24.5,0,0,0
+3,0,18.0,0,0,1
+3,0,43.0,0,0,0
+1,1,36.0,1,0,1
+3,0,70.0,0,1,0
+1,1,27.0,1,0,1
+3,1,20.0,0,0,0
+3,1,14.0,0,0,0
+2,1,60.0,0,0,0
+2,1,25.0,1,0,0
+3,1,14.0,0,0,0
+3,1,19.0,0,0,0
+3,1,18.0,0,0,0
+1,0,15.0,0,0,1
+1,1,31.0,0,0,1
+3,0,4.0,1,0,1
+3,1,42.0,0,0,1
+3,1,25.0,1,0,0
+1,1,60.0,0,0,0
+2,1,52.0,0,0,0
+3,1,44.0,0,0,0
+3,0,70.0,0,1,1
+1,1,49.0,1,0,0
+3,1,42.0,0,0,0
+1,0,18.0,1,0,1
+1,1,35.0,0,0,1
+3,0,18.0,1,0,0
+3,1,25.0,0,1,0
+3,1,26.0,0,0,0
+2,1,39.0,0,0,0
+2,0,45.0,0,0,1
+1,1,42.0,0,0,1
+1,0,22.0,0,0,1
+3,1,40.0,1,0,1
+1,0,24.0,1,0,1
+1,1,42.0,0,0,0
+1,1,48.0,0,0,1
+3,1,29.0,0,0,0
+2,1,52.0,0,0,0
+3,1,19.0,0,0,0
+1,0,38.0,1,0,1
+2,0,27.0,0,0,1
+3,1,42.0,0,1,0
+3,1,33.0,0,0,0
+2,0,6.0,0,0,1
+3,1,17.0,0,0,0
+2,1,34.0,0,0,0
+2,1,50.0,0,0,0
+1,1,27.0,0,0,1
+3,1,20.0,0,0,0
+2,0,30.0,0,0,1
+3,0,70.0,0,1,1
+2,1,25.0,0,0,0
+3,0,25.0,0,0,0
+1,0,29.0,0,0,1
+3,1,11.0,1,0,0
+2,1,42.0,0,0,0
+2,1,23.0,0,0,0
+2,1,23.0,0,0,0
+3,1,28.5,0,0,0
+3,0,48.0,0,0,0
+1,1,35.0,1,0,1
+3,1,42.0,0,0,0
+3,1,42.0,0,0,0
+1,1,42.0,0,0,1
+1,1,36.0,0,0,0
+1,0,21.0,1,0,1
+3,1,24.0,0,0,0
+3,1,31.0,0,0,1
+1,1,70.0,0,0,0
+3,1,16.0,0,0,0
+2,0,30.0,0,0,1
+1,1,19.0,0,0,0
+3,1,31.0,0,1,0
+2,0,4.0,0,0,1
+3,1,6.0,0,0,1
+3,1,33.0,0,0,0
+3,1,23.0,0,0,0
+2,0,48.0,0,0,1
+2,1,0.67,0,0,1
+3,1,28.0,0,0,0
+2,1,18.0,0,0,0
+3,1,34.0,0,0,0
+1,0,33.0,0,0,1
+3,1,42.0,0,0,0
+3,1,41.0,0,0,0
+3,1,20.0,1,0,1
+1,0,36.0,0,0,1
+3,1,16.0,0,0,0
+1,0,51.0,0,0,1
+1,1,35.898148148148145,1,0,0
+3,0,30.5,0,1,0
+3,1,42.0,0,1,0
+3,1,32.0,0,0,0
+3,1,24.0,0,0,0
+3,1,48.0,0,0,0
+2,0,57.0,0,0,0
+3,1,42.0,1,0,0
+2,0,54.0,0,0,1
+3,1,18.0,0,0,0
+3,1,42.0,0,1,0
+3,0,5.0,0,0,1
+3,1,42.0,0,1,0
+1,0,43.0,0,0,1
+3,0,13.0,1,0,1
+1,0,17.0,0,0,1
+1,1,29.0,0,0,0
+3,1,42.0,0,0,0
+3,1,25.0,0,0,0
+3,1,25.0,0,0,0
+3,0,18.0,0,0,1
+3,1,8.0,0,1,0
+3,1,1.0,0,0,1
+1,1,46.0,1,0,0
+3,1,42.0,0,1,0
+2,1,16.0,0,0,0
+3,0,70.0,0,0,0
+1,1,42.0,1,0,0
+3,1,25.0,0,0,0
+2,1,39.0,0,0,0
+1,0,49.0,0,0,1
+3,0,31.0,0,0,1
+3,1,30.0,1,0,0
+3,0,30.0,0,0,0
+2,1,34.0,0,0,0
+2,0,31.0,0,0,1
+1,1,11.0,0,0,1
+3,1,0.42,1,0,1
+3,1,27.0,0,0,1
+3,1,31.0,0,0,0
+1,1,39.0,0,0,0
+3,0,18.0,0,0,0
+2,1,39.0,0,0,0
+1,0,33.0,0,0,1
+3,1,26.0,0,0,0
+3,1,39.0,0,0,0
+2,1,35.0,0,0,0
+3,0,6.0,0,0,0
+3,1,30.5,0,0,0
+1,1,42.0,0,0,0
+3,0,23.0,0,0,0
+2,1,31.0,1,0,0
+3,1,43.0,0,0,0
+3,1,10.0,0,0,0
+1,0,52.0,0,0,1
+3,1,27.0,0,0,1
+1,1,38.0,0,0,0
+3,0,27.0,0,0,1
+3,1,2.0,0,0,0
+3,1,42.0,0,1,0
+3,1,42.0,0,0,0
+2,1,1.0,1,0,1
+3,1,42.0,0,1,1
+1,0,62.0,0,0,1
+3,0,15.0,1,0,1
+2,1,0.83,0,0,1
+3,1,42.0,1,0,0
+3,1,23.0,0,0,0
+3,1,18.0,0,0,0
+1,0,39.0,1,0,1
+3,1,21.0,0,0,0
+3,1,42.0,0,0,0
+3,1,32.0,0,0,1
+1,1,42.0,1,0,1
+3,1,20.0,0,0,0
+2,1,16.0,0,0,0
+1,0,30.0,1,0,1
+3,1,34.5,1,0,0
+3,1,17.0,0,0,0
+3,1,42.0,0,0,0
+3,1,42.0,0,0,0
+3,1,35.0,1,0,0
+2,1,28.0,0,0,0
+1,0,4.574166666666667,1,0,1
+3,1,4.0,0,0,0
+3,1,74.0,0,0,0
+3,0,9.0,1,0,0
+1,0,16.0,0,0,1
+2,0,44.0,0,0,0
+3,0,18.0,0,0,1
+1,0,45.0,0,0,1
+1,1,51.0,0,0,1
+3,0,24.0,1,0,1
+3,1,42.0,1,0,0
+3,1,41.0,0,0,0
+2,1,21.0,0,0,0
+1,0,48.0,0,0,1
+3,0,70.0,0,0,0
+2,1,24.0,0,0,0
+2,0,42.0,0,0,1
+2,0,27.0,1,0,1
+1,1,31.0,0,0,0
+3,1,42.0,0,0,0
+3,1,4.0,0,0,1
+3,1,26.0,0,0,0
+1,0,47.0,0,0,1
+1,1,33.0,0,0,0
+3,1,47.0,0,0,0
+2,0,28.0,1,0,1
+3,0,15.0,1,0,1
+3,1,20.0,0,0,0
+3,1,19.0,0,0,0
+3,1,42.0,0,0,0
+1,0,56.0,1,0,1
+2,0,25.0,0,0,1
+3,1,33.0,0,0,0
+3,0,22.0,0,0,0
+2,1,28.0,0,0,0
+3,1,25.0,0,0,0
+3,0,39.0,0,1,0
+2,1,27.0,0,0,0
+1,0,19.0,0,0,1
+3,0,70.0,0,0,0
+1,1,26.0,1,0,1
+3,1,32.0,0,1,0
diff --git a/hyppopy/tests/test_workflows.py b/hyppopy/tests/test_workflows.py
new file mode 100644
index 0000000..ac64601
--- /dev/null
+++ b/hyppopy/tests/test_workflows.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+#
+# DKFZ
+#
+#
+# Copyright (c) German Cancer Research Center,
+# Division of Medical and Biological Informatics.
+# All rights reserved.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.
+#
+# See LICENSE.txt or http://www.mitk.org for details.
+#
+# Author: Sven Wanner (s.wanner@dkfz.de)
+
+import os
+import unittest
+from hyppopy.globals import TESTDATA_DIR
+IRIS_DATA = os.path.join(TESTDATA_DIR, 'Iris')
+TITANIC_DATA = os.path.join(TESTDATA_DIR, 'Titanic')
+
+from hyppopy.workflows.svc_usecase.svc_usecase import svc_usecase
+from hyppopy.workflows.randomforest_usecase.randomforest_usecase import randomforest_usecase
+
+
+class Args(object):
+
+ def __init__(self):
+ pass
+
+ def set_arg(self, name, value):
+ setattr(self, name, value)
+
+
+class WorkflowTestSuite(unittest.TestCase):
+
+ def setUp(self):
+ self.results = []
+
+ def test_workflow_svc_on_iris_from_xml(self):
+ svc_args_xml = Args()
+ svc_args_xml.set_arg('plugin', '')
+ svc_args_xml.set_arg('data', IRIS_DATA)
+ svc_args_xml.set_arg('config', os.path.join(IRIS_DATA, 'svc_config.xml'))
+ uc = svc_usecase(svc_args_xml)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def test_workflow_rf_on_iris_from_xml(self):
+ rf_args_xml = Args()
+ rf_args_xml.set_arg('plugin', '')
+ rf_args_xml.set_arg('data', IRIS_DATA)
+ rf_args_xml.set_arg('config', os.path.join(IRIS_DATA, 'rf_config.xml'))
+ uc = svc_usecase(rf_args_xml)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def test_workflow_svc_on_iris_from_json(self):
+ svc_args_json = Args()
+ svc_args_json.set_arg('plugin', '')
+ svc_args_json.set_arg('data', IRIS_DATA)
+ svc_args_json.set_arg('config', os.path.join(IRIS_DATA, 'svc_config.json'))
+ uc = svc_usecase(svc_args_json)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def test_workflow_rf_on_iris_from_json(self):
+ rf_args_json = Args()
+ rf_args_json.set_arg('plugin', '')
+ rf_args_json.set_arg('data', IRIS_DATA)
+ rf_args_json.set_arg('config', os.path.join(IRIS_DATA, 'rf_config.json'))
+ uc = svc_usecase(rf_args_json)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ # def test_workflow_svc_on_titanic_from_xml(self):
+ # svc_args_xml = Args()
+ # svc_args_xml.set_arg('plugin', '')
+ # svc_args_xml.set_arg('data', TITANIC_DATA)
+ # svc_args_xml.set_arg('config', os.path.join(TITANIC_DATA, 'svc_config.xml'))
+ # uc = svc_usecase(svc_args_xml)
+ # uc.run()
+ # self.results.append(uc.get_results())
+ # self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def test_workflow_rf_on_titanic_from_xml(self):
+ rf_args_xml = Args()
+ rf_args_xml.set_arg('plugin', '')
+ rf_args_xml.set_arg('data', TITANIC_DATA)
+ rf_args_xml.set_arg('config', os.path.join(TITANIC_DATA, 'rf_config.xml'))
+ uc = svc_usecase(rf_args_xml)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ # def test_workflow_svc_on_titanic_from_json(self):
+ # svc_args_json = Args()
+ # svc_args_json.set_arg('plugin', '')
+ # svc_args_json.set_arg('data', TITANIC_DATA)
+ # svc_args_json.set_arg('config', os.path.join(TITANIC_DATA, 'svc_config.json'))
+ # uc = svc_usecase(svc_args_json)
+ # uc.run()
+ # self.results.append(uc.get_results())
+ # self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def test_workflow_rf_on_titanic_from_json(self):
+ rf_args_json = Args()
+ rf_args_json.set_arg('plugin', '')
+ rf_args_json.set_arg('data', TITANIC_DATA)
+ rf_args_json.set_arg('config', os.path.join(TITANIC_DATA, 'rf_config.json'))
+ uc = svc_usecase(rf_args_json)
+ uc.run()
+ self.results.append(uc.get_results())
+ self.assertTrue(uc.get_results().find("Solution") != -1)
+
+ def tearDown(self):
+ print("")
+ for r in self.results:
+ print(r)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/hyppopy/workflowbase.py b/hyppopy/workflowbase.py
new file mode 100644
index 0000000..548c0e9
--- /dev/null
+++ b/hyppopy/workflowbase.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+#
+# DKFZ
+#
+#
+# Copyright (c) German Cancer Research Center,
+# Division of Medical and Biological Informatics.
+# All rights reserved.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.
+#
+# See LICENSE.txt or http://www.mitk.org for details.
+#
+# Author: Sven Wanner (s.wanner@dkfz.de)
+
+import hyppopy.solverfactory as sfac
+from hyppopy.deepdict import DeepDict
+from hyppopy.globals import SETTINGSPATH
+
+import os
+import abc
+import logging
+from hyppopy.globals import DEBUGLEVEL
+LOG = logging.getLogger(os.path.basename(__file__))
+LOG.setLevel(DEBUGLEVEL)
+
+
+class Workflow(object):
+ _solver = None
+ _args = None
+
+ def __init__(self, args):
+ self._args = args
+ factory = sfac.SolverFactory.instance()
+ if args.plugin is None or args.plugin == '':
+ dd = DeepDict(args.config)
+ ppath = "use_plugin"
+ if not dd.has_section(ppath):
+ msg = f"invalid config file, missing section {ppath}"
+ LOG.error(msg)
+ raise LookupError(msg)
+ plugin = dd[SETTINGSPATH+'/'+ppath]
+ else:
+ plugin = args.plugin
+ self._solver = factory.get_solver(plugin)
+ self.solver.read_parameter(args.config)
+
+ def run(self):
+ self.setup()
+ self.solver.set_loss_function(self.blackbox_function)
+ self.solver.run()
+ self.test()
+
+ def get_results(self):
+ return self.solver.get_results()
+
+ @abc.abstractmethod
+ def setup(self):
+ raise NotImplementedError('the user has to implement this function')
+
+ @abc.abstractmethod
+ def blackbox_function(self):
+ raise NotImplementedError('the user has to implement this function')
+
+ @abc.abstractmethod
+ def test(self):
+ pass
+
+ @property
+ def solver(self):
+ return self._solver
+
+ @property
+ def args(self):
+ return self._args
diff --git a/hyppopy/workflows/randomforest_usecase/randomforest_usecase.py b/hyppopy/workflows/randomforest_usecase/randomforest_usecase.py
index 683a2af..18137ca 100644
--- a/hyppopy/workflows/randomforest_usecase/randomforest_usecase.py
+++ b/hyppopy/workflows/randomforest_usecase/randomforest_usecase.py
@@ -1,65 +1,60 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import os
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
-import hyppopy.solverfactory as sfac
+from hyppopy.workflowbase import Workflow
def data_loader(path, data_name, labels_name):
if data_name.endswith(".npy"):
if not labels_name.endswith(".npy"):
raise IOError("Expect both data_name and labels_name being of type .npy!")
data = [np.load(os.path.join(path, data_name)), np.load(os.path.join(path, labels_name))]
elif data_name.endswith(".csv"):
try:
dataset = pd.read_csv(os.path.join(path, data_name))
y = dataset[labels_name].values
X = dataset.drop([labels_name], axis=1).values
data = [X, y]
except Exception as e:
print("Precondition violation, this usage case expects as data_name a "
"csv file and as label_name a name of a column in this csv table!")
else:
raise NotImplementedError("This combination of data_name and labels_name "
"does not yet exist, feel free to add it")
return data
-def randomforest_usecase(args):
- print("Execute Random Forest UseCase...")
+class randomforest_usecase(Workflow):
- factory = sfac.SolverFactory.instance()
- solver = factory.get_solver(args.plugin)
- solver.read_parameter(args.config)
+ def __init__(self, args):
+ Workflow.__init__(self, args)
- data = data_loader(args.data, solver.settings.data_name, solver.settings.labels_name)
- solver.set_data(data)
+ def setup(self):
+ data = data_loader(self.args.data, self.solver.settings.data_name, self.solver.settings.labels_name)
+ self.solver.set_data(data)
- def rf_loss(data, params):
+ def blackbox_function(self, data, params):
if "n_estimators" in params.keys():
params["n_estimators"] = int(round(params["n_estimators"]))
clf = RandomForestClassifier(**params)
return -cross_val_score(estimator=clf, X=data[0], y=data[1], cv=3).mean()
-
- solver.set_loss_function(rf_loss)
- solver.run()
- solver.get_results()
diff --git a/hyppopy/workflows/svc_usecase/svc_usecase.py b/hyppopy/workflows/svc_usecase/svc_usecase.py
index 45ab10c..60ae83d 100644
--- a/hyppopy/workflows/svc_usecase/svc_usecase.py
+++ b/hyppopy/workflows/svc_usecase/svc_usecase.py
@@ -1,63 +1,58 @@
# -*- coding: utf-8 -*-
#
# DKFZ
#
#
# Copyright (c) German Cancer Research Center,
# Division of Medical and Biological Informatics.
# All rights reserved.
#
# This software is distributed WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# See LICENSE.txt or http://www.mitk.org for details.
#
# Author: Sven Wanner (s.wanner@dkfz.de)
import os
import numpy as np
import pandas as pd
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
-import hyppopy.solverfactory as sfac
+from hyppopy.workflowbase import Workflow
def data_loader(path, data_name, labels_name):
if data_name.endswith(".npy"):
if not labels_name.endswith(".npy"):
raise IOError("Expect both data_name and labels_name being of type .npy!")
data = [np.load(os.path.join(path, data_name)), np.load(os.path.join(path, labels_name))]
elif data_name.endswith(".csv"):
try:
dataset = pd.read_csv(os.path.join(path, data_name))
y = dataset[labels_name].values
X = dataset.drop([labels_name], axis=1).values
data = [X, y]
except Exception as e:
print("Precondition violation, this usage case expects as data_name a "
"csv file and as label_name a name of a column in this csv table!")
else:
raise NotImplementedError("This combination of data_name and labels_name "
"does not yet exist, feel free to add it")
return data
-def svc_usecase(args):
- print("Execute SVC UseCase...")
+class svc_usecase(Workflow):
- factory = sfac.SolverFactory.instance()
- solver = factory.get_solver(args.plugin)
- solver.read_parameter(args.config)
+ def __init__(self, args):
+ Workflow.__init__(self, args)
- data = data_loader(args.data, solver.settings.data_name, solver.settings.labels_name)
- solver.set_data(data)
+ def setup(self):
+ data = data_loader(self.args.data, self.solver.settings.data_name, self.solver.settings.labels_name)
+ self.solver.set_data(data)
- def svc_loss(data, params):
+ def blackbox_function(self, data, params):
clf = SVC(**params)
return -cross_val_score(estimator=clf, X=data[0], y=data[1], cv=3).mean()
-
- solver.set_loss_function(svc_loss)
- solver.run()
- solver.get_results()