From 164cf022747b06d1f9058f4ff3729098e4412310 Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Wed, 24 Dec 2014 12:24:42 +0100 Subject: PrologEngine: add load/unload functions --- prolog/engine.py | 66 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 29 deletions(-) (limited to 'prolog/engine.py') diff --git a/prolog/engine.py b/prolog/engine.py index 85c5559..597ebc4 100644 --- a/prolog/engine.py +++ b/prolog/engine.py @@ -135,29 +135,23 @@ class PrologEngine(object): self.problems[pid] = Problem(name, solution, facts, tests) # Load the solution in 'solution' module. - m_problem = 'problem{}'.format(pid) + mod_problem = 'problem{}'.format(pid) fid = PL_open_foreign_frame() - predicates = set() - for rule in prolog.util.split(solution): - self.call('assertz/1', [Term('{}:({})'.format(m_problem, rule))]) - predicates.add('{}:{}'.format(m_problem, self.predicate_indicator(rule))) - if facts: - for rule in prolog.util.split(facts): - if rule not in self.facts: - self.call('assertz/1', [Term(rule)]) - predicates.add(self.predicate_indicator(rule)) - self.facts.add(rule) + predicates = self.load(solution, mod_problem) + if facts and facts not in self.facts: + predicates |= self.load(facts) + self.facts.add(facts) self.call('compile_predicates/1', [Term([Term(p) for p in predicates])]) # Import solutions for dependency predicates. for i in depends: - m_dependency = 'problem{}'.format(i) - self.call('add_import_module/3', [Term(m_problem), Term(m_dependency), Term('end')]) + mod_dependency = 'problem{}'.format(i) + self.call('add_import_module/3', [Term(mod_problem), Term(mod_dependency), Term('end')]) # Find the correct test answers. for query in tests: - result = self.query(query, m_problem) + result = self.query(query, mod_problem) if result is None or len(result) < 1 or 'X' not in result[0]: raise Exception('Error finding correct answer to query "{}"'.format(query)) self.problems[pid].tests[query] = result[0]['X'] @@ -165,11 +159,11 @@ class PrologEngine(object): # Import the correct solution for problem [pid] into module for user [uid]. def mark_solved(self, uid, pid): - m_user = 'user{}'.format(uid) - m_problem = 'problem{}'.format(pid) + mod_user = 'user{}'.format(uid) + mod_problem = 'problem{}'.format(pid) fid = PL_open_foreign_frame() - result = self.call('add_import_module/3', [Term(m_user), Term(m_problem), Term('end')]) + result = self.call('add_import_module/3', [Term(mod_user), Term(mod_problem), Term('end')]) PL_discard_foreign_frame(fid) return result @@ -229,20 +223,15 @@ class PrologEngine(object): # Test whether [code] gives the same answer to [query] as the correct # solution for problem [pid]. The solution should be loaded beforehand. def test(self, uid, pid, code): - # Module name for user code. - m_user = 'user{}'.format(uid) + mod_user = 'user{}'.format(uid) fid = PL_open_foreign_frame() correct = True predicates = set() try: - # Load the user program [code]. - for rule in prolog.util.split(code): - self.call('assertz/1', [Term('{}:({})'.format(m_user, rule))]) - predicates.add(self.predicate_indicator(rule)) - + self.load(code, mod_user, predicates) for query, answer in sorted(self.problems[pid].tests.items()): - result = self.query(query, m_user, n=1) + result = self.query(query, mod_user, n=1) if len(result) != 1 or result[0]['X'] != answer: correct = False break @@ -250,7 +239,7 @@ class PrologEngine(object): # If a correct solution was found, see if another (incorrect) # solution is found in the first 10 answers. try: - result = self.query(query, m_user, n=10) + result = self.query(query, mod_user, n=10) unique = set([r['X'] for r in result]) if len(unique) != 1: correct = False @@ -262,9 +251,7 @@ class PrologEngine(object): except Exception as ex: correct = False - # Unload all loaded rules. - for predicate in predicates: - self.call('abolish/1', [Term(m_user + ':' + predicate)]) + self.unload(predicates) PL_discard_foreign_frame(fid) return correct @@ -283,6 +270,27 @@ class PrologEngine(object): PL_cut_query(qid) return True + # Load rules from [program] into [module] and return the corresponding + # predicate names. Since this function might not return due to exception, + # the [predicates] argument can be passed where the names will be stored. + def load(self, program, module=None, predicates=None): + if predicates is None: + predicates = set() + for rule in prolog.util.split(program): + name = self.predicate_indicator(rule) + if module: + rule = '{}:({})'.format(module, rule) + name = '{}:{}'.format(module, name) + self.call('assertz/1', [Term(rule)]) + predicates.add(name) + return predicates + + # Unload and remove the "dynamic" property for all rules implementing + # [predicates]. + def unload(self, predicates): + for predicate in predicates: + self.call('abolish/1', [Term(predicate)]) + # Return a description of the last exception, or None if no error occurred. def error(self, qid): error_ref = PL_exception(qid) -- cgit v1.2.1