def translate_task(strips_to_sas, ranges, translation_key, mutex_dict, mutex_ranges, mutex_key, init, goals, actions, axioms, metric, implied_facts): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() if options.dump_task: # Remove init facts that don't occur in strips_to_sas: they're constant. nonconstant_init = filter(strips_to_sas.get, init) dump_task(nonconstant_init, goals, actions, axioms, axiom_layer_dict) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: curr_val = init_values[var] if curr_val != ranges[var] - 1 and curr_val != val: assert False, "Inconsistent init facts! [fact = %s]" % fact init_values[var] = val init = sas_tasks.SASInit(init_values) goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, mutex_dict, mutex_ranges) if goal_dict_list is None: # "None" is a signal that the goal is unreachable because it # violates a mutex. return unsolvable_sas_task("Goal violates a mutex") assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = list(goal_dict_list[0].items()) goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, mutex_dict, mutex_ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.items(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] return sas_tasks.SASTask(variables, mutexes, init, goal, operators, axioms, metric)
def translate_task(strips_to_sas, ranges, translation_key, mutex_key, init, goals, actions, axioms, metric): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val init = sas_tasks.SASInit(init_values) goal_pairs = list(translate_strips_conditions(goals, strips_to_sas, ranges).items()) goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.items(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] return sas_tasks.SASTask(variables, mutexes, init, goal, operators, axioms, metric)
def translate_task(strips_to_sas, ranges, mutex_dict, mutex_ranges, init, goals, actions, axioms, metric, implied_facts): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: pair = strips_to_sas.get(fact) pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val init = sas_tasks.SASInit(init_values) goal_dict_list = translate_strips_goal(goals, strips_to_sas, ranges, mutex_dict, mutex_ranges) assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = goal_dict_list[0].items() goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, mutex_dict, mutex_ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers) return sas_tasks.SASTask(variables, init, goal, operators, axioms, metric)
def translate_task(strips_to_sas, ranges, translation_key, mutex_dict, mutex_ranges, mutex_key, init, init_unknown, init_oneof, init_formula, goals, actions, observation_actions, axioms, metric, implied_facts): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() if DUMP_TASK: # Remove init facts that don't occur in strips_to_sas: they're constant. nonconstant_init = filter(strips_to_sas.get, init) dump_task(nonconstant_init, goals, actions, axioms, axiom_layer_dict) # Closed World Assumption false_facts = list(range(len(ranges))) for fact in init_unknown: pairs = strips_to_sas.get(fact, []) for pair in pairs: false_facts.remove(pair[0]) facts = [] for fact in init: assert fact not in init_unknown pairs = strips_to_sas.get(fact, []) for pair in pairs: false_facts.remove(pair[0]) if pairs: facts = facts + pairs for var in false_facts: assert fact not in init_unknown facts.append((var, ranges[var] - 1)) facts_oneof = [] for oneof in init_oneof: assert len(oneof) >= 2 for fact in oneof: assert fact in init_unknown l = [] for one in oneof: l = l + strips_to_sas.get(one, []) facts_oneof.append(l) # move to conditions.py? def translate_formula(formula, result, strips_to_sas, ranges, mutex_dict, mutex_ranges): if isinstance(formula, pddl.conditions.Atom): assert formula in init_unknown result.append(strips_to_sas.get(formula, [])) elif isinstance(formula, pddl.conditions.NegatedAtom): dict_list = translate_strips_conditions([formula], strips_to_sas, ranges, mutex_dict, mutex_ranges) assert len(dict_list) == 1 result.append(dict_list[0].items()) elif isinstance(formula, pddl.conditions.Disjunction): result.append("or(") for part in formula.parts: translate_formula(part, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) result.append(")") elif isinstance(formula, pddl.conditions.Conjunction): result.append("and(") for part in formula.parts: translate_formula(part, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) result.append(")") else: assert False, print(formula) formulae = [] for formula in init_formula: result = [] translate_formula(formula, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) formulae.append(result) init = sas_tasks.SASInit(facts, facts_oneof, formulae) goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, mutex_dict, mutex_ranges) if goal_dict_list is None: # "None" is a signal that the goal is unreachable because it # violates a mutex. return unsolvable_sas_task("Goal violates a mutex") assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = list(goal_dict_list[0].items()) goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) observation_operators = translate_strips_operators(observation_actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, mutex_dict, mutex_ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.items(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] return sas_tasks.SASTask(variables, mutexes, init, goal, operators + observation_operators, axioms, metric)
def translate_task(strips_to_sas, ranges, init, goals, actions, durative_actions, axioms, num_axioms, num_axioms_by_layer, max_num_layer, num_axiom_map, const_num_axioms): axioms, axiom_init, axiom_layer_dict, true_atoms, false_atoms = axiom_rules.handle_axioms( actions, durative_actions, axioms, goals) init = init + axiom_init # filter trivial true_atoms from goal goals = [g for g in goals if g not in true_atoms ] # FIXME: empty goal would be handled nicely by search # if any atom in goal is false, the task is unsolvable for fa in false_atoms: if fa in goals: print "False atom in goal:" fa.dump() return unsolvable_sas_task("False atom in goal") comp_axioms = [{}, []] goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, comp_axioms) assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = goal_dict_list[0].items() goal = sas_tasks.SASGoal(goal_pairs) # FIXME: remove this, defunct anyways operators = translate_strips_operators(actions, strips_to_sas, ranges, comp_axioms) temp_operators = translate_temporal_strips_operators( durative_actions, strips_to_sas, ranges, comp_axioms, true_atoms, false_atoms) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, comp_axioms) sas_num_axioms = [ translate_numeric_axiom(axiom, strips_to_sas) for axiom in num_axioms if axiom not in const_num_axioms and axiom.effect not in num_axiom_map ] axiom_layers = [-1] * len(ranges) ## each numeric axiom gets its own layer (a wish of a colleague for ## knowledge compilation or search. If you use only the translator, ## you can change this) num_axiom_layer = 0 for layer in num_axioms_by_layer: num_axioms_by_layer[layer].sort(lambda x, y: cmp(x.name, y.name)) for axiom in num_axioms_by_layer[layer]: if axiom.effect not in num_axiom_map: [(var, val)] = strips_to_sas[axiom.effect] if layer == -1: axiom_layers[var] = -1 else: axiom_layers[var] = num_axiom_layer num_axiom_layer += 1 for axiom in comp_axioms[1]: axiom_layers[axiom.effect] = num_axiom_layer for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer + num_axiom_layer + 1 variables = sas_tasks.SASVariables(ranges, axiom_layers) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: if isinstance(fact, pddl.Atom): pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[ var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val else: # isinstance(fact,pddl.FunctionAssignment) pairs = strips_to_sas.get(fact.fluent, []) #empty for constant functions for (var, _) in pairs: val = fact.expression.value assert init_values[ var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val for axiom in const_num_axioms: var = strips_to_sas.get(axiom.effect)[0][0] val = axiom.parts[0].value init_values[var] = val init = sas_tasks.SASInit(init_values) return sas_tasks.SASTask(variables, init, goal, operators, temp_operators, axioms, sas_num_axioms, comp_axioms[1])
def translate_task(strips_to_sas, ranges, translation_key, mutex_dict, mutex_ranges, mutex_key, init, init_unknown, init_oneof, init_formula, goals, actions, observation_actions, axioms, metric, implied_facts): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() if DUMP_TASK: # Remove init facts that don't occur in strips_to_sas: they're constant. nonconstant_init = filter(strips_to_sas.get, init) dump_task(nonconstant_init, goals, actions, axioms, axiom_layer_dict) # Closed World Assumption false_facts = list(range(len(ranges))) for fact in init_unknown: pairs = strips_to_sas.get(fact, []) for pair in pairs: false_facts.remove(pair[0]) facts = [] for fact in init: assert fact not in init_unknown pairs = strips_to_sas.get(fact, []) for pair in pairs: false_facts.remove(pair[0]) if pairs: facts = facts + pairs for var in false_facts: for fact in init_unknown: assert not var == strips_to_sas.get(fact, [])[0][0] facts.append((var, ranges[var] - 1)) facts_oneof = [] for oneof in init_oneof: assert len(oneof) >= 2 for fact in oneof: assert fact in init_unknown l = [] for one in oneof: l = l + strips_to_sas.get(one, []) facts_oneof.append(l) # move to conditions.py? def translate_formula(formula, result, strips_to_sas, ranges, mutex_dict, mutex_ranges): if isinstance(formula, pddl.conditions.Atom): assert formula in init_unknown result.append(strips_to_sas.get(formula, [])) elif isinstance(formula, pddl.conditions.NegatedAtom): dict_list = translate_strips_conditions([formula], strips_to_sas, ranges, mutex_dict, mutex_ranges) assert len(dict_list) == 1 result.append(dict_list[0].items()) elif isinstance(formula, pddl.conditions.Disjunction): result.append("or(") for part in formula.parts: translate_formula(part, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) result.append(")") elif isinstance(formula, pddl.conditions.Conjunction): result.append("and(") for part in formula.parts: translate_formula(part, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) result.append(")") else: assert False, print(formula) formulae = [] for formula in init_formula: result = [] translate_formula(formula, result, strips_to_sas, ranges, mutex_dict, mutex_ranges) formulae.append(result) init = sas_tasks.SASInit(facts, facts_oneof, formulae) goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, mutex_dict, mutex_ranges) if goal_dict_list is None: # "None" is a signal that the goal is unreachable because it # violates a mutex. return unsolvable_sas_task("Goal violates a mutex") assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = list(goal_dict_list[0].items()) goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) observation_operators = translate_strips_operators(observation_actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, mutex_dict, mutex_ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.items(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] return sas_tasks.SASTask(variables, mutexes, init, goal, operators + observation_operators, axioms, metric)
def translate_task(strips_to_sas, ranges, translation_key, mutex_dict, mutex_ranges, mutex_key, init, goals, actions, axioms, metric, implied_facts): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goals) init = init + axiom_init #axioms.sort(key=lambda axiom: axiom.name) #for axiom in axioms: # axiom.dump() if options.dump_task: # Remove init facts that don't occur in strips_to_sas: they're constant. nonconstant_init = filter(strips_to_sas.get, init) dump_task(nonconstant_init, goals, actions, axioms, axiom_layer_dict) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: curr_val = init_values[var] if curr_val != ranges[var] - 1 and curr_val != val: assert False, "Inconsistent init facts! [fact = %s]" % fact init_values[var] = val init = sas_tasks.SASInit(init_values) goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, mutex_dict, mutex_ranges) if goal_dict_list is None: # "None" is a signal that the goal is unreachable because it # violates a mutex. return unsolvable_sas_task("Goal violates a mutex") assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = list(goal_dict_list[0].items()) if not goal_pairs: return solvable_sas_task("Empty goal") goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, mutex_dict, mutex_ranges, implied_facts) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, mutex_dict, mutex_ranges) axiom_layers = [-1] * len(ranges) for atom, layer in axiom_layer_dict.items(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] return sas_tasks.SASTask(variables, mutexes, init, goal, operators, axioms, metric)
def translate_task(strips_to_sas, module_effects_to_sas, module_groundings_to_sas, ranges, init, goals, actions, durative_actions, axioms, num_axioms, num_axioms_by_layer, max_num_layer, num_axiom_map, const_num_axioms, oplinit, objects, modules, module_inits, module_exits, subplan_generators, init_constant_predicates, init_constant_numerics): axioms, axiom_init, axiom_layer_dict, true_atoms, false_atoms = axiom_rules.handle_axioms( actions, durative_actions, axioms, goals) init = init + axiom_init # filter trivial true_atoms from goal goals = [g for g in goals if g not in true_atoms ] # FIXME: empty goal would be handled nicely by search # if any atom in goal is false, the task is unsolvable for fa in false_atoms: if fa in goals: print "False atom in goal:" fa.dump() return unsolvable_sas_task("False atom in goal") comp_axioms = [{}, []] goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, comp_axioms) assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = goal_dict_list[0].items() goal = sas_tasks.SASGoal(goal_pairs) # FIXME: remove this, defunct anyways operators = translate_strips_operators(actions, strips_to_sas, module_effects_to_sas, ranges, comp_axioms) temp_operators = translate_temporal_strips_operators( durative_actions, strips_to_sas, module_effects_to_sas, module_groundings_to_sas, ranges, comp_axioms, true_atoms, false_atoms) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, comp_axioms) sas_num_axioms = [ translate_numeric_axiom(axiom, strips_to_sas) for axiom in num_axioms if axiom not in const_num_axioms and axiom.effect not in num_axiom_map ] axiom_layers = [-1] * len(ranges) ## each numeric axiom gets its own layer (a wish of a colleague for ## knowledge compilation or search. If you use only the translator, ## you can change this) num_axiom_layer = 0 for layer in num_axioms_by_layer: num_axioms_by_layer[layer].sort(lambda x, y: cmp(x.name, y.name)) for axiom in num_axioms_by_layer[layer]: if axiom.effect not in num_axiom_map: [(var, val)] = strips_to_sas[axiom.effect] if layer == -1: axiom_layers[var] = -1 else: axiom_layers[var] = num_axiom_layer num_axiom_layer += 1 for axiom in comp_axioms[1]: axiom_layers[axiom.effect] = num_axiom_layer for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer + num_axiom_layer + 1 variables = sas_tasks.SASVariables(ranges, axiom_layers) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: if isinstance(fact, pddl.Atom): pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[ var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val else: # isinstance(fact,pddl.FunctionAssignment) pairs = strips_to_sas.get(fact.fluent, []) #empty for constant functions for (var, _) in pairs: val = fact.expression.value assert init_values[ var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val for axiom in const_num_axioms: var = strips_to_sas.get(axiom.effect)[0][0] val = axiom.parts[0].value init_values[var] = val init = sas_tasks.SASInit(init_values) # TODO: move this block to translate_modules strips_condition_modules = [ module for module in modules if module.type == "conditionchecker" ] strips_effect_modules = [ module for module in modules if module.type == "effect" ] strips_cost_modules = [ module for module in modules if module.type == "cost" ] strips_grounding_modules = [ module for module in modules if module.type == "grounding" ] strips_condition_modules.sort(lambda x, y: cmp(str(x), str(y))) strips_effect_modules.sort(lambda x, y: cmp(str(x), str(y))) strips_cost_modules.sort(lambda x, y: cmp(str(x), str(y))) strips_grounding_modules.sort(lambda x, y: cmp(str(x), str(y))) condition_modules = [] effect_modules = [] cost_modules = [] grounding_modules = [] for mod in strips_condition_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append( (pddl_param.name, ground_param.type, ground_param.name)) # strips_to_sas call is very hacky assert len(strips_to_sas[mod.toModuleCall()]) == 1 assert len(strips_to_sas[mod.toModuleCall()][0]) == 2 mod_var = strips_to_sas[mod.toModuleCall()][0][0] condition_modules.append( sas_tasks.SASConditionModule(mod.modulecall, sas_params, mod_var)) for mod in strips_effect_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append( (pddl_param.name, ground_param.type, ground_param.name)) sas_effs = [] for eff in mod.effects: assert len(strips_to_sas[eff]) == 1 assert len(strips_to_sas[eff][0]) == 2 sas_effs.append(strips_to_sas[eff][0][0]) # missing eff num + eff vars effect_modules.append( sas_tasks.SASEffectModule( mod.modulecall, sas_params, module_effects_to_sas[mod.toModuleCall()][0], sas_effs)) for mod in strips_cost_modules: assert mod.parent is not None # ? sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append( (pddl_param.name, ground_param.type, ground_param.name)) # make sure strips_to_sas is not mixed badly with condition modules assert len(strips_to_sas[mod.toModuleCall()]) == 1 assert len(strips_to_sas[mod.toModuleCall()][0]) == 2 mod_var = strips_to_sas[mod.toModuleCall()][0][0] cost_modules.append( sas_tasks.SASConditionModule(mod.modulecall, sas_params, mod_var)) for mod in strips_grounding_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append( (pddl_param.name, ground_param.type, ground_param.name)) grounding_modules.append( sas_tasks.SASGroundingModule( mod.modulecall, sas_params, module_groundings_to_sas[mod.toModuleCall()][0])) return sas_tasks.SASTask(variables, init, goal, operators, temp_operators, axioms, sas_num_axioms, comp_axioms[1], oplinit, objects, condition_modules, effect_modules, cost_modules, grounding_modules, sas_tasks.SASTranslation(strips_to_sas), module_inits, module_exits, subplan_generators, init_constant_predicates, init_constant_numerics)
def translate_task(strips_to_sas, module_effects_to_sas, module_groundings_to_sas, ranges, init, goals, actions, durative_actions, axioms, num_axioms, num_axioms_by_layer, max_num_layer, num_axiom_map, const_num_axioms, oplinit, objects, modules, module_inits, module_exits, subplan_generators, init_constant_predicates, init_constant_numerics): axioms, axiom_init, axiom_layer_dict, true_atoms, false_atoms = axiom_rules.handle_axioms( actions, durative_actions, axioms, goals) init = init + axiom_init # filter trivial true_atoms from goal goals = [g for g in goals if g not in true_atoms] # FIXME: empty goal would be handled nicely by search # if any atom in goal is false, the task is unsolvable for fa in false_atoms: if fa in goals: print "False atom in goal:" fa.dump() return unsolvable_sas_task("False atom in goal") comp_axioms = [{},[]] goal_dict_list = translate_strips_conditions(goals, strips_to_sas, ranges, comp_axioms) assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = goal_dict_list[0].items() goal = sas_tasks.SASGoal(goal_pairs) # FIXME: remove this, defunct anyways operators = translate_strips_operators(actions, strips_to_sas, module_effects_to_sas, ranges, comp_axioms) temp_operators = translate_temporal_strips_operators(durative_actions, strips_to_sas, module_effects_to_sas, module_groundings_to_sas, ranges, comp_axioms, true_atoms, false_atoms) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, comp_axioms) sas_num_axioms = [translate_numeric_axiom(axiom,strips_to_sas) for axiom in num_axioms if axiom not in const_num_axioms and axiom.effect not in num_axiom_map] axiom_layers = [-1] * len(ranges) ## each numeric axiom gets its own layer (a wish of a colleague for ## knowledge compilation or search. If you use only the translator, ## you can change this) num_axiom_layer = 0 for layer in num_axioms_by_layer: num_axioms_by_layer[layer].sort(lambda x,y: cmp(x.name,y.name)) for axiom in num_axioms_by_layer[layer]: if axiom.effect not in num_axiom_map: [(var,val)] = strips_to_sas[axiom.effect] if layer == -1: axiom_layers[var] = -1 else: axiom_layers[var] = num_axiom_layer num_axiom_layer += 1 for axiom in comp_axioms[1]: axiom_layers[axiom.effect] = num_axiom_layer for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer + num_axiom_layer + 1 variables = sas_tasks.SASVariables(ranges, axiom_layers) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: if isinstance(fact,pddl.Atom): pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val else: # isinstance(fact,pddl.FunctionAssignment) pairs = strips_to_sas.get(fact.fluent,[]) #empty for constant functions for (var, _) in pairs: val = fact.expression.value assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var]=val for axiom in const_num_axioms: var = strips_to_sas.get(axiom.effect)[0][0] val = axiom.parts[0].value init_values[var]=val init = sas_tasks.SASInit(init_values) # TODO: move this block to translate_modules strips_condition_modules = [module for module in modules if module.type == "conditionchecker"] strips_effect_modules = [module for module in modules if module.type == "effect"] strips_cost_modules = [module for module in modules if module.type == "cost"] strips_grounding_modules = [module for module in modules if module.type == "grounding"] strips_condition_modules.sort(lambda x,y : cmp(str(x), str(y))) strips_effect_modules.sort(lambda x,y : cmp(str(x), str(y))) strips_cost_modules.sort(lambda x,y : cmp(str(x), str(y))) strips_grounding_modules.sort(lambda x,y : cmp(str(x), str(y))) condition_modules = [] effect_modules = [] cost_modules = [] grounding_modules = [] for mod in strips_condition_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append((pddl_param.name, ground_param.type, ground_param.name)) # strips_to_sas call is very hacky assert len(strips_to_sas[mod.toModuleCall()]) == 1 assert len(strips_to_sas[mod.toModuleCall()][0]) == 2 mod_var = strips_to_sas[mod.toModuleCall()][0][0] condition_modules.append(sas_tasks.SASConditionModule(mod.modulecall, sas_params, mod_var)) for mod in strips_effect_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append((pddl_param.name, ground_param.type, ground_param.name)) sas_effs = [] for eff in mod.effects: assert len(strips_to_sas[eff]) == 1 assert len(strips_to_sas[eff][0]) == 2 sas_effs.append(strips_to_sas[eff][0][0]) # missing eff num + eff vars effect_modules.append(sas_tasks.SASEffectModule(mod.modulecall, sas_params, module_effects_to_sas[mod.toModuleCall()][0], sas_effs)) for mod in strips_cost_modules: assert mod.parent is not None # ? sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append((pddl_param.name, ground_param.type, ground_param.name)) # make sure strips_to_sas is not mixed badly with condition modules assert len(strips_to_sas[mod.toModuleCall()]) == 1 assert len(strips_to_sas[mod.toModuleCall()][0]) == 2 mod_var = strips_to_sas[mod.toModuleCall()][0][0] cost_modules.append(sas_tasks.SASConditionModule(mod.modulecall, sas_params, mod_var)) for mod in strips_grounding_modules: assert mod.parent is not None sas_params = [] for (ground_param, pddl_param) in zip(mod.parameters, mod.parent.parameters): sas_params.append((pddl_param.name, ground_param.type, ground_param.name)) grounding_modules.append(sas_tasks.SASGroundingModule(mod.modulecall, sas_params, module_groundings_to_sas[mod.toModuleCall()][0])) return sas_tasks.SASTask(variables, init, goal, operators, temp_operators, axioms, sas_num_axioms, comp_axioms[1], oplinit, objects, condition_modules, effect_modules, cost_modules, grounding_modules, sas_tasks.SASTranslation(strips_to_sas), module_inits, module_exits, subplan_generators, init_constant_predicates, init_constant_numerics)
def recover_stream_plan(evaluations, goal_expression, domain, stream_results, action_plan, negative, unit_costs, optimize=True): import pddl_to_prolog import build_model import pddl import axiom_rules import instantiate # Universally quantified conditions are converted into negative axioms # Existentially quantified conditions are made additional preconditions # Universally quantified effects are instantiated by doing the cartesian produce of types (slow) # Added effects cancel out removed effects opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results) opt_task = task_from_domain_problem(domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs)) real_task = task_from_domain_problem(domain, get_problem(evaluations, goal_expression, domain, unit_costs)) function_assignments = {fact.fluent: fact.expression for fact in opt_task.init # init_facts if isinstance(fact, pddl.f_expression.FunctionAssignment)} type_to_objects = instantiate.get_objects_by_type(opt_task.objects, opt_task.types) results_from_head = get_results_from_head(opt_evaluations) action_instances = [] for name, args in action_plan: # TODO: negative atoms in actions candidates = [] for action in opt_task.actions: if action.name != name: continue if len(action.parameters) != len(args): raise NotImplementedError('Existential quantifiers are not currently ' 'supported in preconditions: {}'.format(name)) variable_mapping = {p.name: a for p, a in zip(action.parameters, args)} instance = action.instantiate(variable_mapping, set(), MockSet(), type_to_objects, opt_task.use_min_cost_metric, function_assignments) assert (instance is not None) candidates.append(((action, args), instance)) if not candidates: raise RuntimeError('Could not find an applicable action {}'.format(name)) action_instances.append(candidates) action_instances.append([(None, get_goal_instance(opt_task.goal))]) axioms_from_name = get_derived_predicates(opt_task.axioms) negative_from_name = {n.name: n for n in negative} opt_task.actions = [] opt_state = set(opt_task.init) real_state = set(real_task.init) preimage_plan = [] function_plan = set() for layer in action_instances: for pair, instance in layer: nonderived_preconditions = [l for l in instance.precondition if l.predicate not in axioms_from_name] #nonderived_preconditions = instance.precondition if not conditions_hold(opt_state, nonderived_preconditions): continue opt_task.init = opt_state original_axioms = opt_task.axioms axiom_from_action = get_necessary_axioms(instance, original_axioms, negative_from_name) opt_task.axioms = [] opt_task.actions = axiom_from_action.keys() # TODO: maybe it would just be better to drop the negative throughout this process until this end with Verbose(False): model = build_model.compute_model(pddl_to_prolog.translate(opt_task)) # Changes based on init opt_task.axioms = original_axioms opt_facts = instantiate.get_fluent_facts(opt_task, model) | (opt_state - real_state) mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or (item in opt_facts)) instantiated_axioms = instantiate_necessary_axioms(model, real_state, mock_fluent, axiom_from_action) with Verbose(False): helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms([instance], instantiated_axioms, []) axiom_from_atom = get_achieving_axioms(opt_state, helpful_axioms, axiom_init, negative_from_name) axiom_plan = [] # Could always add all conditions extract_axioms(axiom_from_atom, instance.precondition, axiom_plan) # TODO: test if no derived solution # TODO: compute required stream facts in a forward way and allow opt facts that are already known required for effects in [instance.add_effects, instance.del_effects]: for i, (conditions, effect) in enumerate(effects[::-1]): if any(c.predicate in axioms_from_name for c in conditions): raise NotImplementedError('Conditional effects cannot currently involve derived predicates') if conditions_hold(real_state, conditions): # Holds in real state effects[i] = ([], effect) elif not conditions_hold(opt_state, conditions): # Does not hold in optimistic state effects.pop(i) else: # TODO: handle more general case where can choose to achieve particular conditional effects raise NotImplementedError('Conditional effects cannot currently involve certified predicates') #if any(conditions for conditions, _ in instance.add_effects + instance.del_effects): # raise NotImplementedError('Conditional effects are not currently supported: {}'.format(instance.name)) # TODO: add axiom init to reset state? apply_action(opt_state, instance) apply_action(real_state, instance) preimage_plan.extend(axiom_plan + [instance]) if not unit_costs and (pair is not None): function_plan.update(extract_function_results(results_from_head, *pair)) break else: raise RuntimeError('No action instances are applicable') preimage = plan_preimage(preimage_plan, set()) preimage -= set(real_task.init) negative_preimage = set(filter(lambda a: a.predicate in negative_from_name, preimage)) preimage -= negative_preimage # visualize_constraints(map(fact_from_fd, preimage)) # TODO: prune with rules # TODO: linearization that takes into account satisfied goals at each level # TODO: can optimize for all streams & axioms all at once for literal in negative_preimage: negative = negative_from_name[literal.predicate] instance = negative.get_instance(map(obj_from_pddl, literal.args)) value = not literal.negated if instance.enumerated: assert (instance.value == value) else: function_plan.add(PredicateResult(instance, value, opt_index=instance.opt_index)) node_from_atom = get_achieving_streams(evaluations, stream_results) preimage_facts = list(map(fact_from_fd, filter(lambda l: not l.negated, preimage))) stream_plan = [] extract_stream_plan(node_from_atom, preimage_facts, stream_plan) if not optimize: # TODO: detect this based on unique or not return stream_plan + list(function_plan) # TODO: search in space of partially ordered plans # TODO: local optimization - remove one and see if feasible reschedule_problem = get_problem(evaluations, And(*preimage_facts), domain, unit_costs=True) reschedule_task = task_from_domain_problem(domain, reschedule_problem) reschedule_task.actions, stream_result_from_name = get_stream_actions(stream_results) new_plan, _ = solve_from_task(reschedule_task, planner='max-astar', debug=False) # TODO: investigate admissible heuristics if new_plan is None: return stream_plan + list(function_plan) new_stream_plan = [stream_result_from_name[name] for name, _ in new_plan] return new_stream_plan + list(function_plan)
def translate_task(strips_to_sas, ranges, translation_key, numeric_strips_to_sas, num_count, mutex_dict, mutex_ranges, mutex_key, init, num_init, goal_list, global_constraint, actions, axioms, num_axioms, num_axioms_by_layer, num_axiom_map, const_num_axioms, metric, implied_facts, init_constant_predicates, init_constant_numerics): with timers.timing("Processing axioms", block=True): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, axioms, goal_list, global_constraint) init = init + axiom_init if options.dump_task: # Remove init facts that don't occur in strips_to_sas: they're constant. nonconstant_init = filter(strips_to_sas.get, init) dump_task(nonconstant_init, goal_list, actions, axioms, axiom_layer_dict) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: curr_val = init_values[var] if curr_val != ranges[var] - 1 and curr_val != val: assert False, "Inconsistent init facts! [fact = %s]" % fact init_values[var] = val comparison_axioms = [{}, []] goal_dict_list = translate_strips_conditions(goal_list, strips_to_sas, ranges, numeric_strips_to_sas, mutex_dict, mutex_ranges, comparison_axioms) global_constraint_dict_list = translate_strips_conditions( [global_constraint], strips_to_sas, ranges, numeric_strips_to_sas, mutex_dict, mutex_ranges, comparison_axioms) # print("goal_dict_list = %s" % goal_dict_list) # print("comparison_axioms = %s" %comparison_axioms) if goal_dict_list is None: # "None" is a signal that the goal_list is unreachable because it # violates a mutex. return unsolvable_sas_task("Goal violates a mutex") assert len(goal_dict_list) == 1, "Negative goal not supported" ## we could substitute the negative goal literal in ## normalize.substitute_complicated_goal, using an axiom. We currently ## don't do this, because we don't run into this assertion, if the ## negative goal is part of finite domain variable with only two ## values, which is most of the time the case, and hence refrain from ## introducing axioms (that are not supported by all heuristics) goal_pairs = list(goal_dict_list[0].items()) if not goal_pairs: return solvable_sas_task("Empty goal") sas_goal = sas_tasks.SASGoal(goal_pairs) assert len( global_constraint_dict_list ) == 1 # the key is the axiom fluent, the value (0) the evaluation to true num_init_values = [0.0 ] * num_count # initialize numeric varialbes with 0.0 # if DEBUG: # print("Strips-to-sas dict is") # for entry in strips_to_sas: # print("%s -> %s"%(entry, strips_to_sas[entry])) # print("Numeric Strips-to-sas dict is") # for entry in numeric_strips_to_sas: # print("%s -> %s"%(entry,numeric_strips_to_sas[entry])) relevant_numeric = [] for fact in num_init: var = numeric_strips_to_sas.get(fact.fluent, -1) if var > -1: val = fact.expression.value num_init_values[var] = val if fact.fluent.ntype == 'R': # the corresponding numeric variable is "regular" and therefore relevant relevant_numeric.append(var) operators = translate_strips_operators(actions, strips_to_sas, ranges, numeric_strips_to_sas, mutex_dict, mutex_ranges, implied_facts, comparison_axioms, num_init_values, relevant_numeric) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, numeric_strips_to_sas, mutex_dict, mutex_ranges, comparison_axioms) sas_num_axioms = [ translate_numeric_axiom(axiom, strips_to_sas, numeric_strips_to_sas) for axiom in num_axioms if axiom not in const_num_axioms and axiom.effect not in num_axiom_map ] axiom_layers = [-1] * len(ranges) # default axiom layer is -1 ## each numeric axiom gets its own layer (a wish of a colleague for ## knowledge compilation or search. If you use only the translator, ## you can change this) num_axiom_layers = [-1] * num_count num_axiom_layer = 0 for layer in num_axioms_by_layer: num_axioms_by_layer[layer].sort(lambda x, y: cmp(x.name, y.name)) for axiom in num_axioms_by_layer[layer]: if axiom.effect not in num_axiom_map: var = numeric_strips_to_sas[axiom.effect] if layer == -1: num_axiom_layers[var] = -1 else: num_axiom_layers[var] = num_axiom_layer num_axiom_layer += 1 # print("comparison_axioms = %s" %comparison_axioms) comp_axiom_init = [2] * len( comparison_axioms[1] ) # initializing comparison axioms with value 3 (none of those) init_values.extend(comp_axiom_init) # for axiom in comparison_axioms[1]: axiom_layers[axiom.effect] = num_axiom_layer for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer + num_axiom_layer + 1 add_key_to_comp_axioms(comparison_axioms, translation_key) variables = sas_tasks.SASVariables(ranges, axiom_layers, translation_key, num_axiom_layer) num_variables = [-1] * num_count num_var_types = ['U'] * num_count # variable type is unknown for entry in numeric_strips_to_sas: num_variables[numeric_strips_to_sas[entry]] = entry num_var_types[numeric_strips_to_sas[entry]] = entry.ntype assert num_count == len(num_variables), "%d nc <-> variables %d" % ( num_count, len(num_variables)) numeric_variables = sas_tasks.SASNumericVariables(num_variables, num_axiom_layers, num_var_types) mutexes = [sas_tasks.SASMutexGroup(group) for group in mutex_key] for axiom in const_num_axioms: # print("Axiom = %s" % axiom) # print("Axiom.effect = %s" % axiom.effect) # print("corresponding variable = %s" % numeric_strips_to_sas.get(axiom.effect)) var = numeric_strips_to_sas.get(axiom.effect) val = axiom.parts[0].value num_init_values[var] = val sas_init = sas_tasks.SASInit(init_values, num_init_values) # print("SASInit is") # sas_init.dump() # look up metric fluent if metric[1] == -1: # minimize unit cost, no metric fluent specified assert metric[0] == '<' sas_metric = metric else: assert metric[ 1] in numeric_strips_to_sas, "Metric fluent %s missing in strips_to_sas_dict" % metric[ 1] # look up (possibly derived) metric fluent to be optimized sas_metric = (metric[0], numeric_strips_to_sas[metric[1]]) # print ("debug check metric: metric=") # print (metric) # print ("sas_metric fluent %d" % sas_metric[1]) # print ("Returning task with global constraint = ",global_constraint_dict_list[0].items()[0]) return sas_tasks.SASTask(variables, numeric_variables, mutexes, sas_init, sas_goal, operators, axioms, comparison_axioms[1], sas_num_axioms, global_constraint_dict_list[0].items()[0], sas_metric, init_constant_predicates, init_constant_numerics)
def translate_task(strips_to_sas, ranges, init, goals, actions, durative_actions, axioms, num_axioms, num_axioms_by_layer, max_num_layer, num_axiom_map, const_num_axioms): axioms, axiom_init, axiom_layer_dict = axiom_rules.handle_axioms( actions, durative_actions, axioms, goals) init = init + axiom_init comp_axioms = [{},[]] goal_pairs = translate_strips_conditions(goals, strips_to_sas, ranges, comp_axioms).items() goal = sas_tasks.SASGoal(goal_pairs) operators = translate_strips_operators(actions, strips_to_sas, ranges, comp_axioms) temp_operators = translate_temporal_strips_operators(durative_actions, strips_to_sas, ranges, comp_axioms) axioms = translate_strips_axioms(axioms, strips_to_sas, ranges, comp_axioms) sas_num_axioms = [translate_numeric_axiom(axiom,strips_to_sas) for axiom in num_axioms if axiom not in const_num_axioms and axiom.effect not in num_axiom_map] axiom_layers = [-1] * len(ranges) ## each numeric axiom gets its own layer (a wish of a colleague for ## knowledge compilation or search. If you use only the translator, ## you can change this) num_axiom_layer = 0 for layer in num_axioms_by_layer: num_axioms_by_layer[layer].sort(lambda x,y: cmp(x.name,y.name)) for axiom in num_axioms_by_layer[layer]: if axiom.effect not in num_axiom_map: [(var,val)] = strips_to_sas[axiom.effect] if layer == -1: axiom_layers[var] = -1 else: axiom_layers[var] = num_axiom_layer num_axiom_layer += 1 for axiom in comp_axioms[1]: axiom_layers[axiom.effect] = num_axiom_layer for atom, layer in axiom_layer_dict.iteritems(): assert layer >= 0 [(var, val)] = strips_to_sas[atom] axiom_layers[var] = layer + num_axiom_layer + 1 variables = sas_tasks.SASVariables(ranges, axiom_layers) init_values = [rang - 1 for rang in ranges] # Closed World Assumption: Initialize to "range - 1" == Nothing. for fact in init: if isinstance(fact,pddl.Atom): pairs = strips_to_sas.get(fact, []) # empty for static init facts for var, val in pairs: assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var] = val else: # isinstance(fact,pddl.FunctionAssignment) pairs = strips_to_sas.get(fact.fluent,[]) #empty for constant functions for (var,dummy) in pairs: val = fact.expression.value assert init_values[var] == ranges[var] - 1, "Inconsistent init facts!" init_values[var]=val for axiom in const_num_axioms: var = strips_to_sas.get(axiom.effect)[0][0] val = axiom.parts[0].value init_values[var]=val init = sas_tasks.SASInit(init_values) return sas_tasks.SASTask(variables, init, goal, operators, temp_operators, axioms, sas_num_axioms, comp_axioms[1])