def parse_term(t): ret = [None] def extract_term(s): if s.type == ast.ASTType.Rule: ret[0] = s.head.atom.term clingo.parse_program("{}.".format(t), lambda s: extract_term(s)) return ret[0]
def test_solvehandle_wrapper(self): spu = SymbolPredicateUnifier() @spu.register class Fact(Predicate): num1 = IntegerField() class Meta: name = "f" prgstr = """{ g(N) : f(N) } = 1.""" f1 = Fact(1) f2 = Fact(2) f3 = Fact(3) ctrl = cclingo.Control(['-n 0']) with ctrl.builder() as b: oclingo.parse_program(prgstr, lambda stm: b.add(stm)) ctrl.add_facts([f1, f2, f3]) ctrl.ground([("base", [])]) with ctrl.solve(yield_=True) as sh: self.assertTrue(isinstance(sh, cclingo.SolveHandle)) self.assertFalse(isinstance(sh, oclingo.SolveHandle)) self.assertTrue(sh.solvehandle_) num_models = 0 for m in sh: self.assertTrue(isinstance(m, cclingo.Model)) self.assertFalse(isinstance(m, oclingo.Model)) num_models += 1 self.assertEqual(num_models, 3)
def transform(builder, s, shift): """ Transform the program with csp constraints in the given file and pass it to the builder. """ t = HeadBodyTransformer(shift) clingo.parse_program(s, lambda stm: builder.add(t.visit(stm)))
def main(self, prg, files): """ Overwrites clingo's main loop taking care of appending the __aux atom. """ pos = {"filename": "<generated>", "line": 1, "column": 1} loc = {"begin": pos, "end": pos} sym = ast.Symbol(loc, clingo.Function(auxiliary_atom_name, [], True)) aux = ast.Literal(loc, ast.Sign.NoSign, ast.SymbolicAtom(sym)) atf = AuxTransformer(aux) files = [open(f) for f in files] if not files: files.append(sys.stdin) # prg.add("base", [], "#external " + auxiliary_atom_name + ".") with prg.builder() as bld: for f in files: clingo.parse_program(f.read(), lambda stm: bld.add(atf.visit(stm))) atf.add_auxiliary_rules(bld) prg.ground((("base", ()), )) prg.solve()
def test_solve_with_assumptions_complex(self): class F(Predicate): num1 = IntegerField() class G(Predicate): num1 = IntegerField() prgstr = """ 1 { g(N) : f(N) } 2.""" f1 = F(1) f2 = F(2) f3 = F(3) g1 = G(1) g2 = G(2) g3 = G(3) ctrl = cclingo.Control(['-n 0'], unifier=[G]) with ctrl.builder() as b: oclingo.parse_program(prgstr, lambda stm: b.add(stm)) ctrl.add_facts([f1, f2, f3]) ctrl.ground([("base", [])]) num_models = 0 def on_model(m): nonlocal num_models fb = m.facts(atoms=True) self.assertTrue(len(fb) <= 2) self.assertTrue(len(fb) >= 1) num_models += 1 num_models = 0 ctrl.solve(on_model=on_model, assumptions=None) self.assertEqual(num_models, 6) num_models = 0 ctrl.solve(on_model=on_model) self.assertEqual(num_models, 6) num_models = 0 ctrl.solve(on_model=on_model, assumptions=[(g1, True)]) self.assertEqual(num_models, 3) # Mixing raw symbol and predicate in a set num_models = 0 ctrl.solve(on_model=on_model, assumptions=[(set([g1.raw, g2]), True)]) self.assertEqual(num_models, 1) num_models = 0 ctrl.solve(on_model=on_model, assumptions=[(FactBase([g1, g2]), True)]) self.assertEqual(num_models, 1) num_models = 0 ctrl.solve(on_model=on_model, assumptions=[(FactBase([g1]), True), (set([g2]), False)]) self.assertEqual(num_models, 2) num_models = 0 ctrl.solve(on_model=on_model, assumptions=[(FactBase([g1]), True), (set([g2]), False)]) self.assertEqual(num_models, 2)
def transform_program(p): a = set() c = {} r = [] ret = [] t = _prg.ProgramTransformer(a, c, r) def append(s): if s is not None: ret.append(str(s)) clingo.parse_program(p, lambda s: append(t.visit(s))) return (ret, a, {key: [(str(r), str(l)) for r, l in stms] for key, stms in c.items()})
def __init__(self, programObserver): self.po = programObserver self.cc = clingo.Control() prog = self._build() with self.cc.builder() as b: for rule in prog: logging.debug('RAP rule: ' + repr(rule)) # TODO ask Benjamin/benchmark if it is faster to parse one by one or all in one string clingo.parse_program(rule, lambda ast: b.add(ast)) logging.debug("RAP grounding starts") self.cc.ground([("base", [])]) logging.debug("RAP grounding finished")
def test_solve_with_assumptions_simple(self): spu = SymbolPredicateUnifier() @spu.register class F(Predicate): num1 = IntegerField() @spu.register class G(Predicate): num1 = IntegerField() prgstr = """{ g(N) : f(N) } = 1.""" f1 = F(1) f2 = F(2) f3 = F(3) g1 = G(1) g2 = G(2) g3 = G(3) ctrl = cclingo.Control(['-n 0']) with ctrl.builder() as b: oclingo.parse_program(prgstr, lambda stm: b.add(stm)) ctrl.add_facts([f1, f2, f3]) ctrl.ground([("base", [])]) num_models = 0 def on_modelT(m): nonlocal num_models fb = m.facts(spu, atoms=True) self.assertTrue(g1 in fb) num_models += 1 def on_modelF(m): nonlocal num_models fb = m.facts(spu, atoms=True) self.assertTrue(g1 not in fb) self.assertFalse(g1 in fb) num_models += 1 num_models = 0 ctrl.solve(on_model=on_modelT, assumptions=[(g1, True)]) self.assertEqual(num_models, 1) num_models = 0 ctrl.solve(on_model=on_modelT, assumptions=[(g1.raw, True)]) self.assertEqual(num_models, 1) num_models = 0 ctrl.solve(on_model=on_modelF, assumptions=[(g1, False)]) self.assertEqual(num_models, 2) fb2 = FactBase([g1]) num_models = 0 ctrl.solve(on_model=on_modelT, assumptions=[(fb2, True)]) self.assertEqual(num_models, 1)
def parse(self): if self._control is None: return try: with self._control.builder() as bb: for key in self._programs: clingo.parse_program(self._programs[key], lambda stm: bb.add(stm)) self._control.ground([('base', [])]) result = self._control.solve(on_model=self.on_model) print(result) except RuntimeError as error: print(error) return -2 return 0
def transform(inputs, add): """ Rewrites the given statement if it is a parity constraint and the resulting rules to the program using a callback. Arguments: statement -- The statement to rewrite. add -- Callback to add statements to the logic program beeing rewritten. """ pt = ProgramTransformer(add) def add_if_not_none(statement): statement = pt(statement) if statement is not None: add(statement) for s in inputs: _clingo.parse_program(s, add_if_not_none)
def add_programs(self, types, builder, observer_builder=None): # visitors constants = self.__options['constants_nb'] # set preference and preference_unsat builders preference_builder, preference_unsat_builder = builder, builder if observer_builder and self.__options['meta'] == META_COMBINE and \ self.__options['preference_unsat']: preference_unsat_builder = observer_builder elif observer_builder: preference_builder = observer_builder # do preference v = preference.PreferenceProgramVisitor( preference_builder, PREFP, U_PREFP, constants ) visitors = [(PREFP, v)] # do approximations if self.__options['solving_mode'] == 'weak': v = basic.BasicProgramVisitor( builder, APPROX, U_APPROX, constants ) visitors.append((APPROX,v)) elif self.__options['solving_mode'] == 'heuristic': v = basic.HeuristicProgramVisitor( builder, HEURISTIC, U_HEURISTIC, constants ) visitors.append((HEURISTIC,v)) # do preference unsat if self.__options['preference_unsat']: v = preference.PreferenceProgramVisitor( preference_unsat_builder, UNSATP, U_UNSATP, constants ) visitors.append((UNSATP,v)) # add programs for name, visitor in visitors: for type_, program in self.__programs[name].items(): if type_ in types: s = "#program " + name + ".\n" + program.get_string() clingo.parse_program(s, lambda x: visitor.visit(x)) ret = visitor.finish() # error if unsat preference program not stratified and not meta if ret and self.__options['meta'] == META_OPEN and \ self.__options['max_models'] != 1 and \ ((not self.__options['preference_unsat'] and name == PREFP) or ( self.__options['preference_unsat'] and name == UNSATP)): raise Exception(ERROR_UNSTRAT_PROGRAM.format(name))
def _add_to_base(rules_to_add, builder, t_option): """ @param str rules_to_add: the rules that will be added to the base program. @param clingo.ProgramBuilder builder: builder of the clingo control object that will receive the generated rules. @param bool t_option: if true, the rules will not be added to the program. They will be printed by stdout instead. @return None: """ if t_option: print(rules_to_add) return # Adds the generated rules to the base program try: parse_program("#program base." + rules_to_add, lambda new_ast: builder.add(new_ast)) except RuntimeError as error: if str(error) == "syntax error": print("Translation error:\n\n{0}".format(rules_to_add)) exit(0)
def test_recursion_detection_recognizes_recursion_with_choice_rules(): prg = """ {x(X)} :- y(X). y(Y) :- x(Y). """ rule_set = [] clingo.parse_program(prg, lambda stm: filter_prg(stm, rule_set)) rt = FindRecursiveRulesTransformer() for rule in rule_set: rt.visit(rule) g = rt.make_dependency_graph(rule_set) g = remove_loops(g) assert len(g) > 0, "dependency graph should be created." assert len( g.nodes) == 2, "There should be rule nodes in the dependency graph." assert len( g.edges) == 2, "There should be no dependency in the dependency graph." assert len(list(nx.simple_cycles( g))) == 1, "There should be a circle in the dependency graph."
def run(self): """Parse and transform the program""" print("\nRewriting " + ' '.join(self.setting.ENCODINGS) + "\n\n") with open(self.setting.OUTFILE, "w") as out_fd: with self.control.builder() as b: transformer = Transformer(b, self.setting, out_fd) parse_start = time.time() clingo.parse_program( open_files(self.setting.ENCODINGS), lambda stm: transformer.add_statement(stm)) parse_time = time.time() - parse_start if self.setting.DEBUG: transformer.print_input_statements() transform_start = time.time() transformer.explore_statements() transformer.transform_statements() transform_time = time.time() - transform_start if self.setting.DEBUG: transformer.print_output_statements() transformer.write_statements() print("\n\nOutput written to " + self.setting.OUTFILE + "\n") if self.setting.RUN_CLINGO: print("\nGrounding and solving...") transformer.build_statements() ground_time, solve_time, satisfiable = self.run_clingo() self.log_statistics(parse_time, transform_time, ground_time, solve_time, satisfiable) if self.setting.DEBUG: print( json.dumps(self.control.statistics, sort_keys=True, indent=2, separators=(',', ': '))) else: print("SAT" if satisfiable else "UNSAT")
def __init__(self, programObserver, propagatorFactory): self.po = programObserver # name of this propagator = FLP checker self.eatomPropagator = propagatorFactory('FLP') # build program self.cc = clingo.Control() # dictionary from self.po.chatoms (int) to the respective choice auxiliaries (str) self.chauxatoms = {} # list of str of all cmatoms that are relevant for the compatible set self.cmatoms = [] prog = self._build() with self.cc.builder() as b: for rule in prog: logging.debug('COP rule: ' + repr(rule)) # TODO ask Benjamin/benchmark if it is faster to parse one by one or all in one string clingo.parse_program(rule, lambda ast: b.add(ast)) logging.debug("COP grounding starts") self.cc.ground([("base", [])]) logging.debug("COP grounding finished") # register propagator for upcoming solve calls self.cc.register_propagator(self.eatomPropagator)
def test_recursion_detection_doesnt_add_conditionals(): prg = """ 1 { q(X,Y) : number(Y) } 1 :- number(X). 1 { q(X,Y) : number(X) } 1 :- number(Y). """ rule_set = [] clingo.parse_program(prg, lambda stm: filter_prg(stm, rule_set)) rt = FindRecursiveRulesTransformer() for rule in rule_set: rt.visit(rule) g = rt.make_dependency_graph(rule_set) g = remove_loops(g) assert len(g) > 0, "dependency graph should be created." assert len( g.nodes ) == 2, "There should be two rule nodes in the dependency graph." assert len( g.edges) == 0, "There should be no dependency in the dependency graph." assert len(list(nx.simple_cycles( g))) == 0, "There should be no circles in the dependency graph."
def test_recursion_detection_doesnt_confuse_choice_rules(): prg = """ a. {b} :- a. 1{x(b)} :- b. """ rule_set = [] clingo.parse_program(prg, lambda stm: filter_prg(stm, rule_set)) rt = FindRecursiveRulesTransformer() for rule in rule_set: rt.visit(rule) g = rt.make_dependency_graph(rule_set) g = remove_loops(g) assert len(g) > 0, "dependency graph should be created." assert len( g.nodes) == 3, "There should be rule nodes in the dependency graph." assert len( g.edges ) == 2, "There should be two dependency in the dependency graph." assert len(list(nx.simple_cycles( g))) == 0, "There should be no circles in the dependency graph."
def solve(self, max_sol, threads): self.stopwatch.start() seeds = random.sample(range(1, 999999), max_sol) print("SEEDS: %s" % str(seeds)) for seed in seeds: prg = clingo.Control([]) prg.configuration.solve.models = 1 # get one solution per seed prg.configuration.solve.parallel_mode = threads # number of threads to use for solving prg.configuration.solver.sign_def = 'rnd' # turn off default sign heuristic and switch to random signs prg.configuration.solver.seed = seed # seed to use for solving print("----- LOADING -----") print("Loading prolog file: %s..." % self.prolog_file) prg.load(self.prolog_file) print(self.stopwatch.get_lap_time_str("Load prolog file")) print("Adding %d tmp_prolog_statements..." % (len(self.tmp_prolog_statements.split("\n")))) with prg.builder() as builder: clingo.parse_program(self.tmp_prolog_statements, lambda stm: builder.add(stm)) print( self.stopwatch.get_lap_time_str("Parse tmp prolog statements")) prg.add('base', [], "") print("----- GROUNDING -----") print("Start: %s" % str(datetime.now())) prg.ground([('base', [])]) print(self.stopwatch.get_lap_time_str("Ground")) print("----- SOLVING (%d/%d) -----" % (self.answer_set_count, max_sol - 1)) print("Start: %s" % str(datetime.now())) prg.solve(on_model=lambda m: self.process_answer_set(repr(m))) print(self.stopwatch.get_lap_time_str("Solve")) self.stopwatch.stop()
def add_programs(self, types, builder): # visitors constants = self.__options['constants_nb'] v = preference.PreferenceProgramVisitor(builder, PREFP, U_PREFP, constants) visitors = [(PREFP, v)] if self.__options['solving_mode'] == 'approx': v = basic.BasicProgramVisitor(builder, APPROX, U_APPROX, constants) visitors.append((APPROX, v)) elif self.__options['solving_mode'] == 'heuristic': v = basic.HeuristicProgramVisitor(builder, HEURISTIC, U_HEURISTIC, constants) visitors.append((HEURISTIC, v)) if self.__options['preference_unsat']: v = preference.PreferenceProgramVisitor(builder, UNSATP, U_UNSATP, constants) visitors.append((UNSATP, v)) # add programs for name, visitor in visitors: for type_, program in self.__programs[name].items(): if type_ in types: s = "#program " + name + ".\n" + program.get_string() clingo.parse_program(s, lambda x: visitor.visit(x)) visitor.finish()
def transform_rules_gdl(prog_str, fixed_time=None): """ Transforms a program rules using gdl into explicit time steps Args: prog_str: The string with all rules from the program fixed_time: If a number is passed it used insted of 'T' as specific time_step Returns: The list of rules translated """ updated_rules = [] def add_time_rule(stm): added_time = add_time(stm, fixed_time) if (added_time and fixed_time is None): time_f = clingo.ast.Function( stm.location, "time", [clingo.ast.Variable(stm.location, "T")], False) stm.body.append(time_f) updated_rules.append(str(stm)) clingo.parse_program(prog_str, add_time_rule) return updated_rules
def prepare_xclingo_program(clingo_arguments, original_program, debug_level): control = XClingoProgramControl(clingo_arguments) # Pre-processing original program translated_program = _translate_trace(original_program) translated_program = _translate_trace_all(translated_program) aux = translated_program translated_program = _translate_show_all(translated_program) control.have_explain = bool(aux != translated_program) # Prints translated_program and exits if debug_level == "magic-comments": print(translated_program) exit(0) # Sets theory atom &label and parses/handles input program with control.builder() as builder: # Adds theories parse_program( """#program base. #theory trace { t { - : 7, unary; + : 6, binary, left; - : 6, binary, left }; &trace/0: t, any}.""", lambda ast_object: builder.add(ast_object)) print() parse_program( """#program base. #theory trace_all { t { - : 7, unary; + : 6, binary, left; - : 6, binary, left }; &trace_all/0: t, any}.""", lambda ast_object: builder.add(ast_object)) # Handle xclingo sentences parse_program( "#program base." + translated_program, lambda ast_object: _translate_to_fired_holds( ast_object, control, builder, debug_level == "translation")) # Translation was printed during _translate_to_fired_holds so we can now exit if debug_level == "translation": exit(0) return control
def str_to_ast(rule): ast = [] clingo.parse_program(rule, lambda stm: filter_prg(stm, ast)) return ast
def transform(inputs, callback): """ Transforms the given list of temporal programs in string form into an ASP program. Returns the future predicates whose atoms have to be set to false if referring to the future, and program parts that have to be regrounded if there are constraints referring to the future. Arguments: inputs -- The list of inputs. callback -- Callback for rewritten statements. """ loc = { 'begin': { 'line': 1, 'column': 1, 'filename': '<transform>' }, 'end': { 'line': 1, 'column': 1, 'filename': '<transform>' } } future_predicates = set() constraint_parts = {} time = _ast.Symbol(loc, _clingo.Function(_tf.g_time_parameter_name)) wrap_lit = lambda a: _ast.Literal(loc, _ast.Sign.NoSign, a) # apply transformer to program def append(s): if s is not None: callback(s) aux_rules = [] transformer = _prg.ProgramTransformer(future_predicates, constraint_parts, aux_rules) for i in inputs: _clingo.parse_program(i, lambda s: append(transformer.visit(s))) if aux_rules: callback( _ast.Program(loc, "always", [ _ast.Id(loc, _tf.g_time_parameter_name), _ast.Id(loc, _tf.g_time_parameter_name_alt) ])) for rule in aux_rules: callback(rule) # add auxiliary rules for future predicates future_sigs = [] if len(future_predicates) > 0: callback( _ast.Program(loc, "always", [ _ast.Id(loc, _tf.g_time_parameter_name), _ast.Id(loc, _tf.g_time_parameter_name_alt) ])) for name, arity, positive, shift in sorted(future_predicates): variables = [ _ast.Variable(loc, "{}{}".format(_tf.g_variable_prefix, i)) for i in range(arity) ] s = _ast.Symbol(loc, _clingo.Number(shift)) t_shifted = _ast.BinaryOperation(loc, _ast.BinaryOperator.Plus, time, s) add_sign = lambda lit: lit if positive else _ast.UnaryOperation( loc, _ast.UnaryOperator.Minus, lit) p_current = _ast.SymbolicAtom( add_sign(_ast.Function(loc, name, variables + [time], False))) f_current = _ast.SymbolicAtom( add_sign( _ast.Function(loc, _tf.g_future_prefix + name, variables + [s, time], False))) callback(_ast.Rule(loc, wrap_lit(p_current), [wrap_lit(f_current)])) future_sigs.append( (_tf.g_future_prefix + name, arity + 2, positive)) # gather rules for constraints referring to the future reground_parts = [] if len(constraint_parts) > 0: for (name, shift), rules in constraint_parts.items(): assert (shift > 0) params = [ _ast.Id(loc, _tf.g_time_parameter_name), _ast.Id(loc, _tf.g_time_parameter_name_alt) ] # parts to be regrounded part = "{}_0_{}".format(name, shift - 1) callback(_ast.Program(loc, part, params)) for p, l in rules: callback(p) reground_parts.append((name, part, range(shift))) # parts that no longer have to be regrounded last_part = "{}_{}".format(name, shift) callback(_ast.Program(loc, last_part, params)) for p, l in rules: callback(l) reground_parts.append((name, last_part, range(shift, shift + 1))) def add_part(part_name, atom_name, statement, wrap=lambda x: x): params = [ _ast.Id(loc, _tf.g_time_parameter_name), _ast.Id(loc, _tf.g_time_parameter_name_alt) ] callback(_ast.Program(loc, part_name, params)) atom = wrap( _ast.SymbolicAtom(_ast.Function(loc, atom_name, [time], False))) callback(statement(loc, atom, [])) add_part('initial', '__initial', _ast.Rule, wrap_lit) add_part('always', '__final', _tf.External) reground_parts.append(('always', 'always', range(1))) reground_parts.append(('dynamic', 'dynamic', range(1))) reground_parts.append(('initial', 'initial', range(1))) def no_program(s): if s.type != _ast.ASTType.Program: callback(s) _clingo.parse_program( _dedent('''\ #theory tel { formula_body { & : 7, unary; % prefix for keywords - : 7, unary; % classical negation + : 6, binary, left; % arithmetic + - : 6, binary, left; % arithmetic - ~ : 5, unary; % negation < : 5, unary; % previous < : 5, binary, right; % n x previous <: : 5, unary; % weak previous <: : 5, binary, right; % n x weak previous <? : 5, unary; % eventually- <* : 5, unary; % always- << : 5, unary; % initially > : 5, unary; % next > : 5, binary, right; % n x next >: : 5, unary; % weak next >: : 5, binary, right; % n x weak next >? : 5, unary; % eventually+ >* : 5, unary; % always+ >> : 5, unary; % finally >* : 4, binary, left; % release >? : 4, binary, left; % until <* : 4, binary, left; % trigger <? : 4, binary, left; % since & : 3, binary, left; % and | : 2, binary, left; % or <- : 1, binary, left; % left implication -> : 1, binary, left; % right implication <> : 1, binary, left; % equivalence ;> : 0, binary, right; % sequence next ;>: : 0, binary, right; % sequence weak next <; : 0, binary, left; % sequence previous <:; : 0, binary, left % sequence weak previous }; formula_head { & : 7, unary; % prefix for keywords - : 7, unary; % classical negation + : 6, binary, left; % arithmetic + - : 6, binary, left; % arithmetic - ~ : 5, unary; % negation > : 5, unary; % next > : 5, binary, right; % n x next >: : 5, unary; % weak next >: : 5, binary, right; % n x weak next >? : 5, unary; % eventually+ >* : 5, unary; % always+ >> : 5, unary; % finally >* : 4, binary, left; % release >? : 4, binary, left; % until & : 3, binary, left; % and | : 2, binary, left; % or ;> : 0, binary, right; % sequence next ;>: : 0, binary, right % sequence weak next }; &tel/1 : formula_body, body; &__tel_head/1 : formula_body, head }. '''), no_program) _clingo.parse_program( _dedent('''\ #theory del { formula_body { & : 7, unary; % prefix for keywords ? : 4, unary; % check * : 3, unary; % kleene star + : 2, binary, left; % choice ;; : 1, binary, left; % sequence .>? : 0, binary, right; % diamond (eventually) .>* : 0, binary, right % box (always) }; &del/1 : formula_body, body }. '''), no_program) return future_sigs, reground_parts
def _split_program_into_rules(self, program: str) -> ASTRuleSet: rules = [] clingo.parse_program( program, lambda stm: add_to_list_if_is_not_program(self.visit(stm), rules)) return rules
def preprocess(self, program): clingo.parse_program(program, lambda ast: self._preprocess(ast))
def parse_rule(r): ret = [] clingo.parse_program(r, lambda s: ret.append(s)) return ret[-1]
def parse_rule_set(rule_set: RuleSet) -> ASTRuleSet: ast_rule_set = [] for rule in rule_set: clingo.parse_program(rule, lambda ast_rule: add_to_list_if_is_not_program(ast_rule, ast_rule_set)) return ast_rule_set
import clingo as cln def print_tree(ast): print(str(ast)) program = """ p :- not p. """ cln.parse_program(program, print_tree)
def add_program_string(ctrl, prgstr): with ctrl.builder() as pb: parse_program(prgstr, lambda stm: pb.add(stm))
def test_assign_and_release_external(self): class F(Predicate): num1 = IntegerField() class G(Predicate): num1 = IntegerField() prgstr = """ #external f(1..3). g(N) :- f(N).""" f1 = F(1) f2 = F(2) f3 = F(3) g1 = G(1) g2 = G(2) g3 = G(3) ctrl = cclingo.Control(unifier=[F, G]) with ctrl.builder() as b: oclingo.parse_program(prgstr, lambda stm: b.add(stm)) ctrl.ground([("base", [])]) # Assign external for a factbase ctrl.assign_external(FactBase([f1, f2, f3]), True) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f1, f2, f3, g1, g2, g3])) # Assign external for a single clorm fact ctrl.assign_external(f1, False) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f2, f3, g2, g3])) # Assign external for a single clingo symbol ctrl.assign_external(f2.raw, False) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f3, g3])) # Back to all true so we can test release_external # Assign external for a factbase ctrl.assign_external(FactBase([f1, f2, f3]), True) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f1, f2, f3, g1, g2, g3])) # Release external for a FactBase ctrl.release_external(FactBase([f1])) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f2, f3, g2, g3])) # Release external for a single clorm fact ctrl.release_external(f2) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase([f3, g3])) # Release external for a single clingo symbol ctrl.release_external(f3.raw) with ctrl.solve(yield_=True) as sh: m = list(sh)[0] fb = m.facts(atoms=True) self.assertEqual(fb, FactBase())