def test_and_conjunction(self): self.assertRaises(TypeError, AndConjunction, "String1", "String2") hp1 = CategoricalHyperparameter("input1", [0, 1]) hp2 = CategoricalHyperparameter("input2", [0, 1]) hp3 = CategoricalHyperparameter("input3", [0, 1]) hp4 = Constant("And", "True") cond1 = EqualsCondition(hp4, hp1, 1) # Only one condition in an AndConjunction! self.assertRaises(ValueError, AndConjunction, cond1) cond2 = EqualsCondition(hp4, hp2, 1) cond3 = EqualsCondition(hp4, hp3, 1) andconj1 = AndConjunction(cond1, cond2) andconj1_ = AndConjunction(cond1, cond2) self.assertEqual(andconj1, andconj1_) andconj2 = AndConjunction(cond2, cond3) self.assertNotEqual(andconj1, andconj2) andconj3 = AndConjunction(cond1, cond2, cond3) self.assertEqual( "(And | input1 == 1 && And | input2 == 1 && And | " "input3 == 1)", str(andconj3)) # Test __eq__ self.assertNotEqual(andconj1, andconj3) self.assertNotEqual(andconj1, "String")
def _construct_and_condition( condition: Dict, cs: ConfigurationSpace, ) -> AndConjunction: conditions = [ _construct_condition(cond, cs) for cond in condition['conditions'] ] return AndConjunction(*conditions)
def test_all_components_have_the_same_child(self): hp1 = CategoricalHyperparameter("input1", [0, 1]) hp2 = CategoricalHyperparameter("input2", [0, 1]) hp3 = CategoricalHyperparameter("input3", [0, 1]) hp4 = CategoricalHyperparameter("input4", [0, 1]) hp5 = CategoricalHyperparameter("input5", [0, 1]) hp6 = Constant("AND", "True") cond1 = EqualsCondition(hp1, hp2, 1) cond2 = EqualsCondition(hp1, hp3, 1) cond3 = EqualsCondition(hp1, hp4, 1) cond4 = EqualsCondition(hp6, hp4, 1) cond5 = EqualsCondition(hp6, hp5, 1) AndConjunction(cond1, cond2, cond3) AndConjunction(cond4, cond5) self.assertRaisesRegexp( ValueError, "All Conjunctions and Conditions must have " "the same child.", AndConjunction, cond1, cond4)
def get_hyperparameter_search_space(**kwargs): cs = ConfigurationSpace() penalty = CategoricalHyperparameter("penalty", ["l1", "l2", "elasticnet", "none"], default_value='l2') solver = CategoricalHyperparameter("solver", ["newton-cg", "lbfgs", "liblinear", "sag", "saga"], default_value="lbfgs") dual = CategoricalHyperparameter("dual", choices=[True, False], default_value=False) tol = UniformFloatHyperparameter("tol", lower=1e-7, upper=100., default_value=1.0e-4, log=True) C = UniformFloatHyperparameter("C", lower=1e-7, upper=100., default_value=1.0, log=True) fit_intercept = CategoricalHyperparameter("fit_intercept", choices=[True, False], default_value=True) intercept_scaling = UniformFloatHyperparameter("intercept_scaling", lower=0.0001, upper=2.0, default_value=1.0, log=True) max_iter = UniformIntegerHyperparameter("max_iter", lower=50, upper=10000, default_value=100) multi_class = CategoricalHyperparameter("multi_class", ["ovr", "multinomial", "auto"], default_value="auto") l1_ratio = UniformFloatHyperparameter("l1_ratio", lower=0., upper=1., default_value=0.1) l1_ratio_condition = InCondition(l1_ratio, penalty, ["elasticnet"]) dual_condition = AndConjunction(InCondition(dual, penalty, ["l2"]), InCondition(dual, solver, ["liblinear"])) cs.add_hyperparameters([penalty, solver, dual, tol, C, fit_intercept, intercept_scaling, max_iter, multi_class, l1_ratio]) penaltyAndLbfgs = ForbiddenAndConjunction( ForbiddenEqualsClause(solver, "lbfgs"), ForbiddenInClause(penalty, ["l1", "elasticnet"]) ) penaltyAndNewton = ForbiddenAndConjunction( ForbiddenEqualsClause(solver, "newton-cg"), ForbiddenInClause(penalty, ["l1", "elasticnet"]) ) penaltyAndSag = ForbiddenAndConjunction( ForbiddenEqualsClause(solver, "sag"), ForbiddenInClause(penalty, ["l1", "elasticnet"]) ) penaltyAndSaga = ForbiddenAndConjunction( ForbiddenInClause(penalty, ["elasticnet"]), ForbiddenInClause(solver, ["newton-cg", "lbfgs", "sag"]) ) penaltyAndSagaa = ForbiddenAndConjunction( ForbiddenInClause(penalty, ["elasticnet", "none"]), ForbiddenInClause(solver, ["liblinear"]) ) penaltyAndSagaaa = ForbiddenAndConjunction( ForbiddenInClause(multi_class, ["multinomial"]), ForbiddenInClause(solver, ["liblinear"]) ) cs.add_forbidden_clause(penaltyAndLbfgs) cs.add_forbidden_clause(penaltyAndNewton) cs.add_forbidden_clause(penaltyAndSag) cs.add_forbidden_clause(penaltyAndSagaa) cs.add_forbidden_clause(penaltyAndSaga) cs.add_forbidden_clause(penaltyAndSagaaa) cs.add_condition(l1_ratio_condition) cs.add_condition(dual_condition) return cs
def test_and_conjunction(self): self.assertRaises(TypeError, AndConjunction, "String1", "String2") hp1 = CategoricalHyperparameter("input1", [0, 1]) hp2 = CategoricalHyperparameter("input2", [0, 1]) hp3 = CategoricalHyperparameter("input3", [0, 1]) hp4 = Constant("And", "True") cond1 = EqualsCondition(hp4, hp1, 1) # Only one condition in an AndConjunction! self.assertRaises(ValueError, AndConjunction, cond1) cond2 = EqualsCondition(hp4, hp2, 1) cond3 = EqualsCondition(hp4, hp3, 1) andconj1 = AndConjunction(cond1, cond2) andconj1_ = AndConjunction(cond1, cond2) self.assertEqual(andconj1, andconj1_) # Test setting vector idx hyperparameter_idx = { hp1.name: 0, hp2.name: 1, hp3.name: 2, hp4.name: 3 } andconj1.set_vector_idx(hyperparameter_idx) self.assertEqual(andconj1.get_parents_vector(), [0, 1]) self.assertEqual(andconj1.get_children_vector(), [3, 3]) andconj2 = AndConjunction(cond2, cond3) self.assertNotEqual(andconj1, andconj2) andconj3 = AndConjunction(cond1, cond2, cond3) self.assertEqual( "(And | input1 == 1 && And | input2 == 1 && And | " "input3 == 1)", str(andconj3)) # Test __eq__ self.assertNotEqual(andconj1, andconj3) self.assertNotEqual(andconj1, "String")
def test_nested_conjunctions(self): hp1 = CategoricalHyperparameter("input1", [0, 1]) hp2 = CategoricalHyperparameter("input2", [0, 1]) hp3 = CategoricalHyperparameter("input3", [0, 1]) hp4 = CategoricalHyperparameter("input4", [0, 1]) hp5 = CategoricalHyperparameter("input5", [0, 1]) hp6 = Constant("AND", "True") cond1 = EqualsCondition(hp6, hp1, 1) cond2 = EqualsCondition(hp6, hp2, 1) cond3 = EqualsCondition(hp6, hp3, 1) cond4 = EqualsCondition(hp6, hp4, 1) cond5 = EqualsCondition(hp6, hp5, 1) conj1 = AndConjunction(cond1, cond2) conj2 = OrConjunction(conj1, cond3) conj3 = AndConjunction(conj2, cond4, cond5) # TODO: this does not look nice, And should depend on a large # conjunction, there should not be many ANDs inside this string! self.assertEqual("(((AND | input1 == 1 && AND | input2 == 1) || AND | " "input3 == 1) && AND | input4 == 1 && AND | input5 " "== 1)", str(conj3))
def test_get_parents(self): # Necessary because we couldn't call cs.get_parents for # clasp-sat-params-nat.pcs counter = UniformIntegerHyperparameter('bump', 10, 4096, log=True) _1_S_countercond = CategoricalHyperparameter('cony', ['yes', 'no']) _1_0_restarts = CategoricalHyperparameter( 'restarts', ['F', 'L', 'D', 'x', '+', 'no'], default='x') condition = EqualsCondition(counter, _1_S_countercond, 'yes') # All conditions inherit get_parents from abstractcondition self.assertEqual([_1_S_countercond], condition.get_parents()) condition2 = InCondition(counter, _1_0_restarts, ['F', 'D', 'L', 'x', '+']) # All conjunctions inherit get_parents from abstractconjunction conjunction = AndConjunction(condition, condition2) self.assertEqual([_1_S_countercond, _1_0_restarts], conjunction.get_parents())
def test_write_AndConjunction_condition(self): expected = "lp '--lp ' c {mi,bo}\nls '--ls ' c {sa,ca,ny}\ntemp '--temp ' r (0.500000, 1.000000)| ls %in% c(sa,ca) && lp %in% c(bo)\n" temp = UniformFloatHyperparameter("temp", 0.5, 1) ls = CategoricalHyperparameter("ls", ["sa", "ca", "ny"], "sa") lp = CategoricalHyperparameter("lp", ["mi", "bo"], "bo") cs = ConfigurationSpace() cs.add_hyperparameter(temp) cs.add_hyperparameter(lp) cs.add_hyperparameter(ls) c1 = InCondition(temp, ls, ['sa','ca']) c2 = InCondition(temp, lp, ['bo']) c3 = AndConjunction(c1, c2) cs.add_condition(c3) value = irace.write(cs) self.assertEqual(expected, value)
def test_read_new_configuration_space_complex_conditionals(self): classi = OrdinalHyperparameter( "classi", [ "random_forest", "extra_trees", "k_nearest_neighbors", "something" ], ) knn_weights = CategoricalHyperparameter("knn_weights", ["uniform", "distance"]) weather = OrdinalHyperparameter( "weather", ["sunny", "rainy", "cloudy", "snowing"]) temperature = CategoricalHyperparameter("temperature", ["high", "low"]) rain = CategoricalHyperparameter("rain", ["yes", "no"]) gloves = OrdinalHyperparameter("gloves", ["none", "yarn", "leather", "gortex"]) heur1 = CategoricalHyperparameter("heur1", ["off", "on"]) heur2 = CategoricalHyperparameter("heur2", ["off", "on"]) heur_order = CategoricalHyperparameter("heur_order", ["heur1then2", "heur2then1"]) gloves_condition = OrConjunction( EqualsCondition(gloves, rain, "yes"), EqualsCondition(gloves, temperature, "low")) heur_condition = AndConjunction( EqualsCondition(heur_order, heur1, "on"), EqualsCondition(heur_order, heur2, "on")) and_conjunction = AndConjunction( NotEqualsCondition(knn_weights, classi, "extra_trees"), EqualsCondition(knn_weights, classi, "random_forest")) Cl_condition = OrConjunction( EqualsCondition(knn_weights, classi, "k_nearest_neighbors"), and_conjunction, EqualsCondition(knn_weights, classi, "something")) and1 = AndConjunction(EqualsCondition(temperature, weather, "rainy"), EqualsCondition(temperature, weather, "cloudy")) and2 = AndConjunction( EqualsCondition(temperature, weather, "sunny"), NotEqualsCondition(temperature, weather, "snowing")) another_condition = OrConjunction(and1, and2) complex_conditional_space = ConfigurationSpace() complex_conditional_space.add_hyperparameter(classi) complex_conditional_space.add_hyperparameter(knn_weights) complex_conditional_space.add_hyperparameter(weather) complex_conditional_space.add_hyperparameter(temperature) complex_conditional_space.add_hyperparameter(rain) complex_conditional_space.add_hyperparameter(gloves) complex_conditional_space.add_hyperparameter(heur1) complex_conditional_space.add_hyperparameter(heur2) complex_conditional_space.add_hyperparameter(heur_order) complex_conditional_space.add_condition(gloves_condition) complex_conditional_space.add_condition(heur_condition) complex_conditional_space.add_condition(Cl_condition) complex_conditional_space.add_condition(another_condition) complex_cs = list() complex_cs.append( "classi ordinal {random_forest,extra_trees,k_nearest_neighbors, something} " "[random_forest]") complex_cs.append( "knn_weights categorical {uniform, distance} [uniform]") complex_cs.append( "weather ordinal {sunny, rainy, cloudy, snowing} [sunny]") complex_cs.append("temperature categorical {high, low} [high]") complex_cs.append("rain categorical { yes, no } [yes]") complex_cs.append( "gloves ordinal { none, yarn, leather, gortex } [none]") complex_cs.append("heur1 categorical { off, on } [off]") complex_cs.append("heur2 categorical { off, on } [off]") complex_cs.append( "heur_order categorical { heur1then2, heur2then1 } [heur1then2]") complex_cs.append("gloves | rain == yes || temperature == low") complex_cs.append("heur_order | heur1 == on && heur2 == on") complex_cs.append( "knn_weights | classi == k_nearest_neighbors || " "classi != extra_trees && classi == random_forest || classi == something" ) complex_cs.append( "temperature | weather == rainy && weather == cloudy || " "weather == sunny && weather != snowing") cs_new = pcs_new.read(complex_cs) self.assertEqual(cs_new, complex_conditional_space)
def read(pcs_string, debug=False): """ Reads in a :py:class:`~ConfigSpace.configuration_space.ConfigurationSpace` definition from a pcs file. Example ------- >>> from ConfigSpace.read_and_write import pcs_new >>> with open('configspace.pcs', 'r') as fh: >>> restored_conf = pcs_new.read(fh) Parameters ---------- pcs_string : str ConfigSpace definition in pcs format debug : bool Provides debug information. Defaults to False. Returns ------- :py:class:`~ConfigSpace.configuration_space.ConfigurationSpace` The restored ConfigurationSpace object """ configuration_space = ConfigurationSpace() conditions = [] forbidden = [] # some statistics ct = 0 cont_ct = 0 cat_ct = 0 ord_ct = 0 line_ct = 0 for line in pcs_string: line_ct += 1 if "#" in line: # It contains a comment pos = line.find("#") line = line[:pos] # Remove quotes and whitespaces at beginning and end line = line.replace('"', "").replace("'", "") line = line.strip() if "|" in line: # It's a condition try: c = pp_condition.parseString(line) conditions.append(c) except pyparsing.ParseException: raise NotImplementedError("Could not parse condition: %s" % line) continue if "}" not in line and "]" not in line: continue if line.startswith("{") and line.endswith("}"): forbidden.append(line) continue if len(line.strip()) == 0: continue ct += 1 param = None create = { "int": UniformIntegerHyperparameter, "float": UniformFloatHyperparameter, "categorical": CategoricalHyperparameter, "ordinal": OrdinalHyperparameter } try: param_list = pp_cont_param.parseString(line) name = param_list[0] if param_list[1] == 'integer': paramtype = 'int' elif param_list[1] == 'real': paramtype = 'float' else: paramtype = None if paramtype in ['int', 'float']: log = param_list[10:] param_list = param_list[:10] if len(log) > 0: log = log[0] lower = float(param_list[3]) upper = float(param_list[5]) log_on = True if "log" in log else False default_value = float(param_list[8]) param = create[paramtype](name=name, lower=lower, upper=upper, q=None, log=log_on, default_value=default_value) cont_ct += 1 except pyparsing.ParseException: pass try: if "categorical" in line: param_list = pp_cat_param.parseString(line) name = param_list[0] choices = [choice for choice in param_list[3:-4:2]] default_value = param_list[-2] param = create["categorical"](name=name, choices=choices, default_value=default_value) cat_ct += 1 elif "ordinal" in line: param_list = pp_ord_param.parseString(line) name = param_list[0] sequence = [seq for seq in param_list[3:-4:2]] default_value = param_list[-2] param = create["ordinal"](name=name, sequence=sequence, default_value=default_value) ord_ct += 1 except pyparsing.ParseException: pass if param is None: raise NotImplementedError("Could not parse: %s" % line) configuration_space.add_hyperparameter(param) for clause in forbidden: param_list = pp_forbidden_clause.parseString(clause) tmp_list = [] clause_list = [] for value in param_list[1:]: if len(tmp_list) < 3: tmp_list.append(value) else: # So far, only equals is supported by SMAC if tmp_list[1] == '=': # TODO maybe add a check if the hyperparameter is # actually in the configuration space clause_list.append( ForbiddenEqualsClause( configuration_space.get_hyperparameter( tmp_list[0]), tmp_list[2])) else: raise NotImplementedError() tmp_list = [] configuration_space.add_forbidden_clause( ForbiddenAndConjunction(*clause_list)) conditions_per_child = OrderedDict() for condition in conditions: child_name = condition[0] if child_name not in conditions_per_child: conditions_per_child[child_name] = list() conditions_per_child[child_name].append(condition) for child_name in conditions_per_child: for condition in conditions_per_child[child_name]: condition = condition[2:] condition = ' '.join(condition) if '||' in str(condition): ors = [] # 1st case we have a mixture of || and && if '&&' in str(condition): ors_combis = [] for cond_parts in str(condition).split('||'): condition = str(cond_parts).split('&&') # if length is 1 it must be or if len(condition) == 1: element_list = condition[0].split() ors_combis.append( condition_specification( child_name, element_list, configuration_space)) else: # now taking care of ands ands = [] for and_part in condition: element_list = [ element for part in condition for element in and_part.split() ] ands.append( condition_specification( child_name, element_list, configuration_space)) ors_combis.append(AndConjunction(*ands)) mixed_conjunction = OrConjunction(*ors_combis) configuration_space.add_condition(mixed_conjunction) else: # 2nd case: we only have ors for cond_parts in str(condition).split('||'): element_list = [ element for element in cond_parts.split() ] ors.append( condition_specification(child_name, element_list, configuration_space)) or_conjunction = OrConjunction(*ors) configuration_space.add_condition(or_conjunction) else: # 3rd case: we only have ands if '&&' in str(condition): ands = [] for cond_parts in str(condition).split('&&'): element_list = [ element for element in cond_parts.split() ] ands.append( condition_specification(child_name, element_list, configuration_space)) and_conjunction = AndConjunction(*ands) configuration_space.add_condition(and_conjunction) else: # 4th case: we have a normal condition element_list = [element for element in condition.split()] normal_condition = condition_specification( child_name, element_list, configuration_space) configuration_space.add_condition(normal_condition) return configuration_space
def get_hyperparameter_search_space(dataset_properties=None): """Get the configuratin space used for hyperparameter searching.""" cs = ConfigurationSpace() conditions = [] base_estimator = CategoricalHyperparameter( name="base_estimator", choices=["rf", "lr", "svc"], default_value="rf", ) n_features_to_select = UniformIntegerHyperparameter( name="n_features_to_select", lower=1, upper=30, default_value=10) step = UniformFloatHyperparameter(name="step", lower=0.01, upper=0.25, default_value=0.1) # RF rf_n_estimators = UniformIntegerHyperparameter(name="rf_n_estimators", lower=1, upper=1000, default_value=100) rf_criterion = CategoricalHyperparameter( name="rf_criterion", choices=["gini", "entropy"], default_value="gini", ) rf_max_depth = UniformIntegerHyperparameter(name="rf_max_depth", lower=1, upper=100, default_value=10) rf_class_weight = CategoricalHyperparameter( name="rf_class_weight", choices=["balanced", "balanced_subsample"], default_value="balanced_subsample", ) conditions.append( EqualsCondition(rf_n_estimators, base_estimator, "rf")) conditions.append(EqualsCondition(rf_criterion, base_estimator, "rf")) conditions.append(EqualsCondition(rf_max_depth, base_estimator, "rf")) conditions.append( EqualsCondition(rf_class_weight, base_estimator, "rf")) # LR lr_C = UniformFloatHyperparameter(name="lr_C", lower=1.0e-3, upper=1.0e3, default_value=1.0, log=True) lr_penalty = CategoricalHyperparameter(name="lr_penalty", choices=["l1", "l2"], default_value="l2") lr_fit_intercept = CategoricalHyperparameter(name="lr_fit_intercept", choices=[True, False], default_value=True) lr_intercept_scaling = UniformFloatHyperparameter( name="lr_intercept_scaling", lower=1.0, upper=1.0e3, default_value=1.0, ) lr_class_weight = CategoricalHyperparameter( name="lr_class_weight", choices=["balanced", "None"], default_value="balanced", ) conditions.append(EqualsCondition(lr_C, base_estimator, "lr")) conditions.append(EqualsCondition(lr_penalty, base_estimator, "lr")) conditions.append( EqualsCondition(lr_fit_intercept, base_estimator, "lr")) conditions.append( AndConjunction( EqualsCondition(lr_intercept_scaling, base_estimator, "lr"), EqualsCondition(lr_intercept_scaling, lr_fit_intercept, True), )) conditions.append( EqualsCondition(lr_class_weight, base_estimator, "lr")) # SVC svc_C = UniformFloatHyperparameter(name="svc_C", lower=1.0e-3, upper=1.0e3, default_value=1.0, log=True) svc_penalty = CategoricalHyperparameter(name="svc_penalty", choices=["l1", "l2"], default_value="l2") svc_class_weight = CategoricalHyperparameter( name="svc_class_weight", choices=["balanced", "None"], default_value="balanced", ) svc_loss = CategoricalHyperparameter( name="svc_loss", choices=["hinge", "squared_hinge"], default_value="squared_hinge", ) svc_fit_intercept = CategoricalHyperparameter(name="svc_fit_intercept", choices=[True, False], default_value=True) conditions.append(EqualsCondition(svc_C, base_estimator, "svc")) conditions.append(EqualsCondition(svc_penalty, base_estimator, "svc")) conditions.append( EqualsCondition(svc_class_weight, base_estimator, "svc")) conditions.append(EqualsCondition(svc_loss, base_estimator, "svc")) conditions.append( EqualsCondition(svc_fit_intercept, base_estimator, "svc")) cs.add_hyperparameters([ base_estimator, n_features_to_select, step, rf_n_estimators, rf_criterion, rf_max_depth, rf_class_weight, lr_C, lr_penalty, lr_fit_intercept, lr_intercept_scaling, lr_class_weight, svc_C, svc_penalty, svc_class_weight, svc_loss, svc_fit_intercept, ]) for c in conditions: cs.add_condition(c) return cs
def read(pcs_string, debug=False): """ Read in a :py:class:`~ConfigSpace.configuration_space.ConfigurationSpace` definition from a pcs file. Example ------- .. testsetup:: pcs_new_test from ConfigSpace import ConfigurationSpace import ConfigSpace.hyperparameters as CSH from ConfigSpace.read_and_write import pcs_new cs = ConfigurationSpace() cs.add_hyperparameter(CSH.CategoricalHyperparameter('a', choices=[1, 2, 3])) with open('configspace.pcs_new', 'w') as f: f.write(pcs_new.write(cs)) .. doctest:: pcs_new_test >>> from ConfigSpace.read_and_write import pcs_new >>> with open('configspace.pcs_new', 'r') as fh: ... deserialized_conf = pcs_new.read(fh) Parameters ---------- pcs_string : str ConfigSpace definition in pcs format debug : bool Provides debug information. Defaults to False. Returns ------- :py:class:`~ConfigSpace.configuration_space.ConfigurationSpace` The deserialized ConfigurationSpace object """ configuration_space = ConfigurationSpace() conditions = [] forbidden = [] # some statistics ct = 0 cont_ct = 0 cat_ct = 0 ord_ct = 0 line_ct = 0 for line in pcs_string: line_ct += 1 if "#" in line: # It contains a comment pos = line.find("#") line = line[:pos] # Remove quotes and whitespaces at beginning and end line = line.replace('"', "").replace("'", "") line = line.strip() if "|" in line: # It's a condition try: c = pp_condition.parseString(line) conditions.append(c) except pyparsing.ParseException: raise NotImplementedError("Could not parse condition: %s" % line) continue if "}" not in line and "]" not in line: continue if line.startswith("{") and line.endswith("}"): forbidden.append(line) continue if len(line.strip()) == 0: continue ct += 1 param = None create = { "int": UniformIntegerHyperparameter, "float": UniformFloatHyperparameter, "categorical": CategoricalHyperparameter, "ordinal": OrdinalHyperparameter } try: param_list = pp_cont_param.parseString(line) name = param_list[0] if param_list[1] == 'integer': paramtype = 'int' elif param_list[1] == 'real': paramtype = 'float' else: paramtype = None if paramtype in ['int', 'float']: log = param_list[10:] param_list = param_list[:10] if len(log) > 0: log = log[0] lower = float(param_list[3]) upper = float(param_list[5]) log_on = True if "log" in log else False default_value = float(param_list[8]) param = create[paramtype](name=name, lower=lower, upper=upper, q=None, log=log_on, default_value=default_value) cont_ct += 1 except pyparsing.ParseException: pass try: if "categorical" in line: param_list = pp_cat_param.parseString(line) name = param_list[0] choices = [choice for choice in param_list[3:-4:2]] default_value = param_list[-2] param = create["categorical"]( name=name, choices=choices, default_value=default_value, ) cat_ct += 1 elif "ordinal" in line: param_list = pp_ord_param.parseString(line) name = param_list[0] sequence = [seq for seq in param_list[3:-4:2]] default_value = param_list[-2] param = create["ordinal"]( name=name, sequence=sequence, default_value=default_value, ) ord_ct += 1 except pyparsing.ParseException: pass if param is None: raise NotImplementedError("Could not parse: %s" % line) configuration_space.add_hyperparameter(param) for clause in forbidden: param_list = pp_forbidden_clause.parseString(clause) tmp_list = [] clause_list = [] for value in param_list[1:]: if len(tmp_list) < 3: tmp_list.append(value) else: # So far, only equals is supported by SMAC if tmp_list[1] == '=': hp = configuration_space.get_hyperparameter(tmp_list[0]) if isinstance(hp, NumericalHyperparameter): if isinstance(hp, IntegerHyperparameter): forbidden_value = int(tmp_list[2]) elif isinstance(hp, FloatHyperparameter): forbidden_value = float(tmp_list[2]) else: raise NotImplementedError if forbidden_value < hp.lower or forbidden_value > hp.upper: raise ValueError( f'forbidden_value is set out of the bound, it needs to' f' be set between [{hp.lower}, {hp.upper}]' f' but its value is {forbidden_value}') elif isinstance( hp, (CategoricalHyperparameter, OrdinalHyperparameter)): hp_values = hp.choices if isinstance(hp, CategoricalHyperparameter)\ else hp.sequence forbidden_value_in_hp_values = tmp_list[2] in hp_values if forbidden_value_in_hp_values: forbidden_value = tmp_list[2] else: raise ValueError( f'forbidden_value is set out of the allowed value ' f'sets, it needs to be one member from {hp_values} ' f'but its value is {forbidden_value}') else: raise ValueError('Unsupported Hyperparamter sorts') clause_list.append( ForbiddenEqualsClause( configuration_space.get_hyperparameter( tmp_list[0]), forbidden_value)) else: raise NotImplementedError() tmp_list = [] configuration_space.add_forbidden_clause( ForbiddenAndConjunction(*clause_list)) conditions_per_child = OrderedDict() for condition in conditions: child_name = condition[0] if child_name not in conditions_per_child: conditions_per_child[child_name] = list() conditions_per_child[child_name].append(condition) for child_name in conditions_per_child: for condition in conditions_per_child[child_name]: condition = condition[2:] condition = ' '.join(condition) if '||' in str(condition): ors = [] # 1st case we have a mixture of || and && if '&&' in str(condition): ors_combis = [] for cond_parts in str(condition).split('||'): condition = str(cond_parts).split('&&') # if length is 1 it must be or if len(condition) == 1: element_list = condition[0].split() ors_combis.append( condition_specification( child_name, element_list, configuration_space, )) else: # now taking care of ands ands = [] for and_part in condition: element_list = [ element for part in condition for element in and_part.split() ] ands.append( condition_specification( child_name, element_list, configuration_space, )) ors_combis.append(AndConjunction(*ands)) mixed_conjunction = OrConjunction(*ors_combis) configuration_space.add_condition(mixed_conjunction) else: # 2nd case: we only have ors for cond_parts in str(condition).split('||'): element_list = [ element for element in cond_parts.split() ] ors.append( condition_specification( child_name, element_list, configuration_space, )) or_conjunction = OrConjunction(*ors) configuration_space.add_condition(or_conjunction) else: # 3rd case: we only have ands if '&&' in str(condition): ands = [] for cond_parts in str(condition).split('&&'): element_list = [ element for element in cond_parts.split() ] ands.append( condition_specification( child_name, element_list, configuration_space, )) and_conjunction = AndConjunction(*ands) configuration_space.add_condition(and_conjunction) else: # 4th case: we have a normal condition element_list = [element for element in condition.split()] normal_condition = condition_specification( child_name, element_list, configuration_space, ) configuration_space.add_condition(normal_condition) return configuration_space
def read(pcs_string, debug=False): configuration_space = ConfigurationSpace() conditions = [] forbidden = [] # some statistics ct = 0 cont_ct = 0 cat_ct = 0 line_ct = 0 for line in pcs_string: line_ct += 1 if "#" in line: # It contains a comment pos = line.find("#") line = line[:pos] # Remove quotes and whitespaces at beginning and end line = line.replace('"', "").replace("'", "") line = line.strip() if "|" in line: # It's a condition try: c = pp_condition.parseString(line) conditions.append(c) except pyparsing.ParseException: raise NotImplementedError("Could not parse condition: %s" % line) continue if "}" not in line and "]" not in line: continue if line.startswith("{") and line.endswith("}"): forbidden.append(line) continue if len(line.strip()) == 0: continue ct += 1 param = None create = { "int": UniformIntegerHyperparameter, "float": UniformFloatHyperparameter, "categorical": CategoricalHyperparameter } try: param_list = pp_cont_param.parseString(line) il = param_list[9:] if len(il) > 0: il = il[0] param_list = param_list[:9] name = param_list[0] lower = float(param_list[2]) upper = float(param_list[4]) paramtype = "int" if "i" in il else "float" log = True if "l" in il else False default = float(param_list[7]) param = create[paramtype](name=name, lower=lower, upper=upper, q=None, log=log, default=default) cont_ct += 1 except pyparsing.ParseException: pass try: param_list = pp_cat_param.parseString(line) name = param_list[0] choices = [c for c in param_list[2:-4:2]] default = param_list[-2] param = create["categorical"](name=name, choices=choices, default=default) cat_ct += 1 except pyparsing.ParseException: pass if param is None: raise NotImplementedError("Could not parse: %s" % line) configuration_space.add_hyperparameter(param) for clause in forbidden: # TODO test this properly! # TODO Add a try/catch here! # noinspection PyUnusedLocal param_list = pp_forbidden_clause.parseString(clause) tmp_list = [] clause_list = [] for value in param_list[1:]: if len(tmp_list) < 3: tmp_list.append(value) else: # So far, only equals is supported by SMAC if tmp_list[1] == '=': # TODO maybe add a check if the hyperparameter is # actually in the configuration space clause_list.append( ForbiddenEqualsClause( configuration_space.get_hyperparameter( tmp_list[0]), tmp_list[2])) else: raise NotImplementedError() tmp_list = [] configuration_space.add_forbidden_clause( ForbiddenAndConjunction(*clause_list)) #Now handle conditions # If there are two conditions for one child, these two conditions are an # AND-conjunction of conditions, thus we have to connect them conditions_per_child = OrderedDict() for condition in conditions: child_name = condition[0] if child_name not in conditions_per_child: conditions_per_child[child_name] = list() conditions_per_child[child_name].append(condition) for child_name in conditions_per_child: condition_objects = [] for condition in conditions_per_child[child_name]: child = configuration_space.get_hyperparameter(child_name) parent_name = condition[2] parent = configuration_space.get_hyperparameter(parent_name) restrictions = condition[5:-1:2] # TODO: cast the type of the restriction! if len(restrictions) == 1: condition = EqualsCondition(child, parent, restrictions[0]) else: condition = InCondition(child, parent, values=restrictions) condition_objects.append(condition) # Now we have all condition objects for this child, so we can build a # giant AND-conjunction of them (if number of conditions >= 2)! if len(condition_objects) > 1: and_conjunction = AndConjunction(*condition_objects) configuration_space.add_condition(and_conjunction) else: configuration_space.add_condition(condition_objects[0]) return configuration_space