class ImplementationTestCase(unittest.TestCase): """Test cases for implementation clauses in a pl-file.""" def setUp(self): self.__pli = ProblogInterface(librarypaths=["model/"]) def tearDown(self): self.__pli = None def __get_substitutions(self, query): result = self.__pli.evaluate(query) S = [] for k, v in result.items(): if v == 0.0: continue s = self.__pli.parse_substitution(str(k)) S.append(s) return S def __execute_substitutions(self, S, itoms): output = Itoms() for i, s in enumerate(S): output[s] = s.execute(itoms) return output def test_implementation_simple(self): self.__pli.load("test/test_py-implementation-simple.pl") S = self.__get_substitutions("query(substitution(x,S)).") # create some dummy data x1 = Itom('x1', 2, variable='x') x2 = Itom('x2', 2, variable='x') a1 = Itom('a1', 1, variable='a') b1 = Itom('b1', 1, variable='b') c1 = Itom('c1', 1, variable='c') d1 = Itom('d1', 4, variable='d') itoms = Itoms([x1, x2, a1, b1, c1, d1]) # execute substitutions outputs = self.__execute_substitutions(S, itoms) # check for output_itoms in outputs.values(): self.assertAlmostEqual(output_itoms['x'].v, 2) def test_implementation_multiline(self): self.__pli.reset() self.__pli.load("test/test_py-implementation-multiline.pl") result = self.__pli.evaluate("query(implementation(r1, X)).") relation, code = self.__pli.parse_implementation(list(result)[0]) self.assertEqual(relation, "r1") # create function to execute f = Function('a', 'b', code, name='r1') itoms = f.execute(Itoms([Itom('b', 1, timestamp=0, variable='b')])) self.assertEqual(itoms['a'].v, 2) self.assertEqual(itoms['a'].t, 0) # execute through substitution S = self.__get_substitutions("query(substitution(a,S)).") itoms = Itoms([Itom('b1', 1, timestamp=0, variable='b')]) outputs = self.__execute_substitutions(S, itoms) s = list(S)[0] self.assertEqual(outputs[s]['a'].v, 2) self.assertEqual(outputs[s]['a'].t, 0)
def test_evaluate(self): pli = ProblogInterface(["test/test_shsa.pl"], ["model/"]) # evaluate all queries in test_shsa.pl # (testcase -> should all return true) result = pli.evaluate() self.assertEqual(sum(result.values()), len(result.values())) # program without queries pli.reset() pli.append("itom(a).") # evaluate a query without adding it to the program result = pli.evaluate("query(itom(X)).") self.assertEqual(len(result), 1)
def __init__(self, model, domain, itoms=[], librarypaths=["./model/"], recollect=True): """Initialize the monitor. model -- SHSA knowledge base collecting the relations between variables. domain -- Common domain (a variable in the knowledge base) where the itoms will be compared to each other. itoms -- Itoms-object holding inputs to the monitor. librarypaths -- Set paths of problog libraries used in model. filter_window_size -- Set the size of the window for the median filter. """ self.__pli = ProblogInterface(librarypaths=librarypaths) self.__pli.load(model) """SHSA knowledge base.""" self.__domain = domain """Variable domain where the itoms shall be compared.""" self.__recollect_enabled = recollect """Indicates that a change in the itoms should trigger a re-query of the substitutions.""" self.__itoms = Itoms(itoms) """Available itoms or last itoms monitored. Used to identify a change in the itoms.""" self.__substitutions = None """List of substitutions used to bring the itoms into the common domain.""" # workaround: for ROS monitor (subscribe based on model) try: self.__substitutions = self.__collect_substitutions(itoms) # workaround: triggers reset on first monitor (necessary to fully initialize) self.__itoms = Itoms(itoms) except problog.engine.UnknownClause as e: # no itomsOf in the problog model (needed to find substitutions) # we will try later (monitor) pass # debugging self._debug_callback = None """Called at the end of monitor(.) to debug the monitor step."""
def _monitor(self, itoms, reset=False): # calculate error between substitutions error, overlap, outputs, values = self._compare(itoms, reset) match = self._match(error) assert np.equal(match, match.transpose()).all() pli = ProblogInterface(librarypaths=[]) assert len(match) == 3 pli.load("model/vote3.pl") program = "" for i in range(0,len(match)): for j in range(i+1,len(match)): m = str(match[i, j]).lower() program += "evidence(match(s{},s{}), {}).\n".format(i, j, m) for i in range(len(match)): program += "query(failed(s{}, s{}, s{})).\n".format(i, (i+1)%3, (i+2)%3) result = pli.evaluate(program) probs = result.values() # probabilities # return substitution with highest failure probability failed = None if min(probs) > 0.49: # 0.5 .. no idea if a failure occured or not idx = list(probs).index(max(probs)) failed = self.substitutions[idx] return failed
def setUp(self): self.__pli = ProblogInterface(librarypaths=["model/"])
nargs='*', help="""Path to ProbLog files to include.""") parser.add_argument('model', type=str, help="""SHSA model in Prolog/ProbLog.""") parser.add_argument('csv', type=str, help="""CSV file of itoms. Header must match the itom names in the model.""") args = parser.parse_args() # # load the model # pli = ProblogInterface(librarypaths=args.include) pli.load(args.model) # define epsilon for itoms (static) epsilon = { 't_clock': 0, 'x1': 1, 'x2': 1, 'a1': 1, 'b1': 1, 'c1': 1, 'd1': 1, } # # get the available itoms
class BaseMonitor(object): """Base class for monitors.""" def __init__(self, model, domain, itoms=[], librarypaths=["./model/"], recollect=True): """Initialize the monitor. model -- SHSA knowledge base collecting the relations between variables. domain -- Common domain (a variable in the knowledge base) where the itoms will be compared to each other. itoms -- Itoms-object holding inputs to the monitor. librarypaths -- Set paths of problog libraries used in model. filter_window_size -- Set the size of the window for the median filter. """ self.__pli = ProblogInterface(librarypaths=librarypaths) self.__pli.load(model) """SHSA knowledge base.""" self.__domain = domain """Variable domain where the itoms shall be compared.""" self.__recollect_enabled = recollect """Indicates that a change in the itoms should trigger a re-query of the substitutions.""" self.__itoms = Itoms(itoms) """Available itoms or last itoms monitored. Used to identify a change in the itoms.""" self.__substitutions = None """List of substitutions used to bring the itoms into the common domain.""" # workaround: for ROS monitor (subscribe based on model) try: self.__substitutions = self.__collect_substitutions(itoms) # workaround: triggers reset on first monitor (necessary to fully initialize) self.__itoms = Itoms(itoms) except problog.engine.UnknownClause as e: # no itomsOf in the problog model (needed to find substitutions) # we will try later (monitor) pass # debugging self._debug_callback = None """Called at the end of monitor(.) to debug the monitor step.""" @property def model(self): """Returns the underlying SHSA model.""" return self.__pli.program @property def domain(self): """Returns the monitoring domain.""" return self.__domain @property def substitutions(self): """Returns the list of substitutions used to bring the itoms into the common domain.""" return self.__substitutions def update(self, model, domain): """Resets the model and the domain, i.e., variable to monitor.""" self.__domain = domain self.__pli.reset() self.__pli.load(model) def set_debug_callback(self, fct): self._debug_callback = fct return def __collect_substitutions(self, itoms=[]): """Find relations from variables (given itoms) to domain.""" program = "\n" if "itomsOf" not in self.__pli.program and len(itoms) > 0: # be sure itoms is of the right type 'Itoms' itoms = Itoms(itoms) # append available itoms to program with "itomsOf(variable,[itom1,..])" for variable, il in itoms.availability.items(): assert variable is not None and variable != "" names = [i.name for i in il] program += "itomsOf({},[{}]).\n".format(variable, ','.join(names)) program += "\n" if len(itoms) > 0: assert "itomsOf" in program or "itomsOf" in self.__pli.program # get all valid substitutions for the domain # -> query problog knowledge base program += "query(substitution({},S)).".format(self.__domain) result = self.__pli.evaluate(program) S = [] for r in result.keys(): s = self.__pli.parse_substitution(str(r)) S.append(s) if len(itoms) == 0: # set itoms used (default value) for s in S: for v in s.vin: self.__itoms[v.name] = Itom(v.name, 0.0, variable=v.name) return S def __recollect(self, itoms): itoms = Itoms(itoms) recollected = False if self.__substitutions is None \ or set(itoms.keys()) != set(self.__itoms.keys()): self.__substitutions = self.__collect_substitutions(itoms) recollected = True return recollected def _monitor(self, itoms, reset=False): raise NotImplementedError def monitor(self, itoms): reset = False if self.__recollect_enabled: # recollect substitutions if itoms changed reset = self.__recollect(itoms) self.__itoms = itoms # save to identify changes in the next monitor step # monitor implemented in sub class failed = self._monitor(itoms, reset) # done return failed
def test_init(self): pli = ProblogInterface() self.assertEqual(pli.program, "") pli.load("test/test_lists.pl") self.assertNotEqual(pli.program, "") pli = ProblogInterface(["test/test_shsa.pl"], ["model/"]) self.assertNotEqual(pli.program, "") pli.reset() self.assertEqual(pli.program, "") pli.append("query(itom(X)).") self.assertNotEqual(pli.program, "") with self.assertRaises(Exception): problog = ProblogInterface("test")
def test_parse_substitution(self): pli = ProblogInterface() s = pli.parse_substitution("substitution(a,a1)") self.assertEqual(len(s), 1) self.assertEqual(set([v.name for v in s.vin]), set(['a1'])) # simple tests pli.append('implementation(r1,"a = b + c").') pli.append('implementation(r2,"c = 2 * d").') pli.append( 'implementation(rstep,"a.v = (t - a_last.t)*0.1 + a_last.v").') s = pli.parse_substitution( "substitution(a, [function(a,r1,[b,c]), b1, c1] )") self.assertEqual(len(s), 3) self.assertEqual(s.vout.name, 'a') self.assertEqual(set([v.name for v in s.vin]), set(['b1', 'c1'])) s = pli.parse_substitution( "substitution(a, [function(a,r1,[b,c]), b1, [function(c,r2,[d]),d1]] )" ) self.assertEqual(len(s), 4) self.assertEqual(s.vout.name, 'a') self.assertEqual(set([v.name for v in s.vin]), set(['b1', 'd1'])) s = pli.parse_substitution( "substitution(a, [function(a,rstep,[t, a_last]), t_clock, a1_last] )" ) self.assertEqual(len(s), 3) self.assertEqual(s.vout.name, 'a') self.assertEqual(set([v.name for v in s.vin]), set(['t_clock', 'a1_last'])) # strings as identifiers pli.append('implementation(rds,"dmin.v = min(sonar.v)").') s = pli.parse_substitution( 'substitution(dmin,[function(dmin,rds,[sonar]), "/p2os/sonar"])') self.assertEqual(len(s), 2) self.assertEqual(s.vout.name, 'dmin') self.assertEqual(set([v.name for v in s.vin]), set(['/p2os/sonar']))
def test_parse_function(self): pli = ProblogInterface() # problog needs some clauses to be able to evaluate (e.g., get the code) # the code is retrieved from an implementation(relation_name,..) clause pli.append('implementation(r1,"a.v = b.v + c.v").') pli.append( 'implementation(rstep,"a.v = (t.v - a_last.t)*0.1 + a_last.v").') pli.append('implementation(r2,"a.v = 2*b.v").') # single input f = pli.parse_function("function(a,r2,[b])") self.assertEqual(f.vout.name, 'a') self.assertEqual(set([str(v) for v in f.vin]), set(['b'])) self.assertEqual(f.name, 'r2') result = f.execute({'b': 1}) self.assertEqual(result['a'].v, 2) # valid formats pli.parse_function("function(a,r1,[b,c])") pli.parse_function("function( a , r1 , [b,c])") pli.parse_function("function( a , r1 , [ b , c ] )") pli.parse_function("function( a, rstep, [t, a_last])") # test initialization of function f = pli.parse_function("function( a , r1 , [b,c])") self.assertEqual(f.vout.name, 'a') self.assertEqual(set([v.name for v in f.vin]), set(['b', 'c'])) self.assertEqual(f.name, 'r1') self.assertTrue("a.v = b.v + c.v" in f.code) result = f.execute({'b': -1, 'c': 2}) self.assertEqual(result['a'].v, 1) # no implementation (unknown clause) pli.reset() with self.assertRaises(Exception): f = pli.parse_function("function( a , r1 , [b,c])") # ambiguous implementation pli.append('implementation(r1,"a.v = b.v + c.v").') pli.append('implementation(r1,"a.v = b.v * c.v").') with self.assertRaises(AmbiguousImplementation): f = pli.parse_function("function( a , r1 , [b,c])") # invalid formats (parse errors) with self.assertRaises(Exception): pli.parse_function("function(a, r1, invalid)") with self.assertRaises(Exception): pli.parse_function("function(a, r1, [b, c], invalid)")
def test_parse_implementation(self): pli = ProblogInterface() relation, execstr = pli.parse_implementation( 'implementation(r1,"a = 2*b")') self.assertEqual(relation, 'r1') self.assertEqual(execstr, "a = 2*b")
def test_parse_variableOf(self): pli = ProblogInterface() v = pli.parse_variableOf("variableOf(a1,a)") self.assertEqual(v, 'a')
def test_parse_and_execute_substitution(self): pli = ProblogInterface() pli.append('implementation(r1, "x.v = 2 * a.v").') # parse s = pli.parse_substitution( "substitution(x, [function(x,r1,[a]), a1] )") self.assertEqual(s.vout.name, 'x') self.assertEqual(set([v.name for v in s.vin]), set(['a1'])) self.assertEqual(len(s), 2) # execute a1 = Itom('a1', 1) result = s.execute([a1]) self.assertEqual(result['x'].v, 2) # ambiguous implementation pli.append('implementation(r1, "x.v = 4 * a.v").') with self.assertRaises(AmbiguousImplementation): s = pli.parse_substitution( "substitution(x, [function(x,r1,[a]), a1] )") # no implementation pli.reset() with self.assertRaises(Exception): s = pli.parse_substitution( "substitution(x, [function(x,r1,[a]), a1] )") # any string as itom identifiers pli.reset() b = Itom('/p2os/sonar', [1, 2, 3]) pli.append('implementation(min, "a.v = min(b.v)").') s = pli.parse_substitution( "substitution(a, [function(a, min, [b]), {}]).".format('"' + b.name + '"')) v = s.execute([b]) self.assertEqual(v['a'].v, 1)