def create_complex_symbol(a,b): return Function("p",[ Function("",[ Number(1), Function("",[ Number(1), Function("",[ Number(1), Function("pt",[ Number(a),Number(b)])])])])])
def test_unify_same_sig(self): class ATuple(ComplexTerm): aconst=ConstantField() bint = IntegerField() class Meta: is_tuple = True class Fact1(Predicate): aint = IntegerField() aconst = ConstantField() class Meta: name = "fact" class Fact2(Predicate): aint = IntegerField() atuple = ATuple.Field() class Meta: name = "fact" r1 = Function("fact",[Number(1), Function("bob",[])]) r2 = Function("fact",[Number(1), Function("", [Function("bob",[]),Number(1)])]) # r1 only unifies with Fact1 and r2 only unifies with Fact2 f1 = Fact1(raw=r1) self.assertEqual(f1.raw, r1) with self.assertRaises(ValueError) as ctx: f2 = Fact1(raw=r2) f2 = Fact2(raw=r2) self.assertEqual(f2.raw, r2) with self.assertRaises(ValueError) as ctx: f1 = Fact2(raw=r1) # The unify() function should correctly unify both facts res = unify([Fact1,Fact2],[r1,r2]) self.assertEqual(len(res), 2)
def test_match(self): ''' Test symbol matching. ''' self.assertTrue(Function('f', [Number(1)]).match("f", 1)) self.assertFalse(Function('f', [Number(1), Number(2)]).match("f", 1)) self.assertFalse(Number(1).match("f", 1))
def test_make_method_asp_callable_error_feedback(self): class Tmp(object): def test1(self, v): return v @make_method_asp_callable def test_sig1(self, v: IntegerField) -> IntegerField: return float(v) @make_method_asp_callable def test_sig2(self, v: IntegerField) -> IntegerField: raise ValueError("Error") tmp = Tmp() with self.assertRaises(TypeError) as ctx: tmp.test_sig1(Number(1), Number(2)) check_errmsg("test_sig1() takes 2 positional arguments but 3 ", ctx) if clingo.__version__ >= "5.5.0": with self.assertRaises(TypeError) as ctx: tmp.test_sig1(Number(1)) check_errmsg("an integer is required for output of test_sig1()", ctx) with self.assertRaises(ValueError) as ctx: tmp.test_sig2(Number(1)) check_errmsg("Error: raised by test_sig2()", ctx)
def test_class_can_have_attributes(): context = Context() @context.valasp() class Node: value: Integer count = [ 0, 1, 2 ] # a way to track the number of instances, and check they are in 1..2 @classmethod def all_instances_known(cls): if not (cls.count[1] <= cls.count[0] <= cls.count[2]): raise ValueError( f"expecting {cls.count[1]}..{cls.count[2]} instances of {cls.__name__}, " "but found {cls.count[0]} of them") def __post_init__(self): self.__class__.count[0] += 1 with pytest.raises(ValueError): Node.all_instances_known() Node(Number(1)) Node.all_instances_known() Node(Number(2)) Node.all_instances_known() Node(Number(3)) with pytest.raises(ValueError): Node.all_instances_known()
def test_symbolpredicateunifier_with_subfields(self): spu = SymbolPredicateUnifier() class CT(ComplexTerm): a = IntegerField b = StringField(index=True) c = (IntegerField(index=True),ConstantField) @spu.register class P(Predicate): d = CT.Field(index=True) e = CT.Field() expected=set([hashable_path(P.d), hashable_path(P.d.b), hashable_path(P.d.c.arg1), hashable_path(P.e.b), hashable_path(P.e.c.arg1)]) self.assertEqual(spu.predicates, (P,)) self.assertEqual(set([hashable_path(p) for p in spu.indexes]), set(expected)) ct_func=Function("ct",[Number(1),String("aaa"), Function("",[Number(1),Function("const",[])])]) p1=Function("p",[ct_func,ct_func]) fb=spu.unify(symbols=[p1],raise_on_empty=True) self.assertEqual(len(fb),1) self.assertEqual(set([hashable_path(p) for p in fb.indexes]), expected)
def test_run_class_checks(): class Foo: def __init__(self, _: Symbol): Foo.instances += 1 self.check_foo() @classmethod def check_exactly_two_instances(cls): if Foo.instances != 2: raise ValueError("please, define exactly two instances") def check_foo(self): pass Foo.instances = 0 context = Context() context.valasp_register_class(Foo) context.valasp_add_validator(PredicateName('foo'), 1) with pytest.raises(ValueError): Foo(Number(1)) context.valasp_run_class_methods() Foo(Number(2)) context.valasp_run_class_methods() with pytest.raises(ValueError): Foo(Number(3)) context.valasp_run_class_methods()
def test_unify_nullary(self): raws = [ Function("afact",[Number(1),String("test")]), Function("nullary1",[]), Function("nullary2",[]), Function("afact",[Number(2),String("test")]), ] class Afact(Predicate): anum=IntegerField() astr=StringField() class Meta: name = "afact" class Nullary1(Predicate): class Meta: name = "nullary1" class Nullary2(Predicate): class Meta: name = "nullary2" af_1=Afact(anum=1,astr="test") af_2=Afact(anum=2,astr="test") u_1=Nullary1() u_2=Nullary2() self.assertEqual(list(unify([Nullary1],raws)),[u_1]) self.assertEqual(list(unify([Nullary2],raws)),[u_2]) self.assertEqual(set(unify([Afact,Nullary1,Nullary2],raws)), set([af_1,af_2,u_1,u_2]))
def __init__(self): self.k = 0 self.prg = Control() self.prg.load("client.lp") self.prg.ground([("pigeon", []), ("sleep", [Number(self.k)])]) self.prg.assign_external(Function("sleep", [Number(self.k)]), True) self.ret = None self.models = []
def __next(self): assert(self.__horizon < 30) self.__prg.assign_external(Function("horizon", [Number(self.__horizon)]), False) self.__horizon += 1 self.__prg.ground([ ("trans", [Number(self.__horizon)]) , ("check", [Number(self.__horizon)]) , ("state", [Number(self.__horizon)]) ]) self.__prg.assign_external(Function("horizon", [Number(self.__horizon)]), True)
def start(self, on_finish): if self.ret is not None and not self.ret.unknown(): self.k = self.k + 1 self.prg.ground([("sleep", [self.k])]) self.prg.release_external(Function("sleep", [Number(self.k - 1)])) self.prg.assign_external(Function("sleep", [Number(self.k)]), True) self.future = self.prg.solve(on_model=self.on_model, on_finish=on_finish, async_=True)
def test_register_name(self): SF = StringField IF = IntegerField CF = ConstantField n1 = Number(1) n2 = Number(2) n3 = Number(3) n4 = Number(4) s1 = String("ab") s2 = String("cd") s3 = String("abcd") c1 = Function("ab", []) c2 = Function("cd", []) c3 = Function("abcd", []) # Test the register_name as a decorator cb1 = ContextBuilder() @cb1.register_name("addi") # use function annotations def add1(a: IF, b: IF) -> IF: return a + b # external signature self.assertEqual(add1(1, 2), 3) @cb1.register_name("adds", SF, SF, SF) def add2(a, b): return a + b self.assertEqual(add2("ab", "cd"), "abcd") # Non-decorator call - re-using a function but with a different signature cb1.register_name("addc", CF, CF, CF, add1) # Non-decorator call - setting a function with the function annotation cb1.register_name("addi_alt", add1) ctx1 = cb1.make_context() self.assertEqual(ctx1.addi(n1, n2), n3) self.assertEqual(ctx1.addi_alt(n1, n2), n3) self.assertEqual(ctx1.adds(s1, s2), s3) self.assertEqual(ctx1.addc(c1, c2), c3) # Things that should fail with self.assertRaises(TypeError) as ctx: self.assertEqual(ctx1.addc(s1, s2), s3) with self.assertRaises(TypeError) as ctx: self.assertEqual(ctx1.addc(s1, s2), c3) # Fails since add2 has no function annotations with self.assertRaises(TypeError) as ctx: cb1.register_name("addo", add2) # Function name already assigned with self.assertRaises(ValueError) as ctx: cb1.register_name("addi", add1)
def __init__(self, connection): Thread.__init__(self) self.k = 0 self.prg = Control() self.prg.load("client.lp") self.prg.ground([("pigeon", []), ("sleep", [Number(self.k)])]) self.prg.assign_external(Function("sleep", [Number(self.k)]), True) self.state = SolveThread.STATE_IDLE self.input = Connection() self.output = connection
def test_ground(self): ''' Test grounding with context and parameters. ''' ctx = Context() ctl = Control() ctl.add('part', ['c'], 'p(@cb_num(c)).') ctl.ground([('part', [Number(1)])], ctx) symbols = [atom.symbol for atom in ctl.symbolic_atoms] self.assertEqual(sorted(symbols), [Function('p', [Number(0)]), Function('p', [Number(2)])])
def ground(self, kind): count = self.objects + self.horizon + 1 parts = [("expand", [Number(count)])] if self.args.scratch and count > 1: self.control = Control() for source in self.args.file: self.control.load(source) for i in range(0, self.objects): parts.append(("object", [Number(i + 1, count)])) for i in range(0, self.horizon): parts.append(("horizon", [Number(i + 1, count)])) if self.args.scratch or count == 1: for option in self.args.option: setattr(self.control.configuration, option[0], option[1]) parts.append(("base", [])) if kind: self.objects += 1 parts.append(("object", [Number(self.objects), Number(count)])) else: self.horizon += 1 parts.append(("horizon", [Number(self.horizon), Number(count)])) if self.args.verbose: print("") print("Objects: {}".format(Number(self.objects))) print("Horizon: {}".format(Number(self.horizon))) self.control.ground(parts) if self.args.verbose: print("Solving: {}".format(count))
def test_function(self): ''' Test functions. ''' f = Function("f", [Number(1)], False) self.assertEqual(f.arguments, [Number(1)]) self.assertFalse(f.positive) self.assertTrue(f.negative) self.assertEqual(f.name, "f") self.assertEqual(f.type, SymbolType.Function) self.assertEqual(Tuple_([]).type, SymbolType.Function)
def test_with_fun_forward_must_have_arity_one(): context = Context() with pytest.raises(TypeError): @context.valasp(with_fun=Fun.FORWARD) class Pair: a: Integer b: Integer Pair(Number(1), Number(2))
def test_any_type(): context = Context() @context.valasp() class Weak: mystery: Any Weak(Number(1)) Weak(QString('abc')) Weak(Function('abc', [])) Weak(Function('abc', [Number(1)]))
def test_disable_auto_blacklist(): context = Context() @context.valasp(auto_blacklist=False) class Edge: source: Integer dest: Integer Edge(Function('edge', [Number(1), Number(2)])) assert str(context.valasp_run_solver(["edge(1,2). edge((1,2))." ])) == '[edge(1,2), edge((1,2))]'
def test_with_fun_forward_of_pair(): context = Context() @context.valasp() class Pair: a: Integer b: Integer @context.valasp() class Foo: x: Pair Foo(Function('pair', [Number(0), Number(1)]))
def start(self, board): self.__assign = [] for robot, (x, y) in board.pos.items(): self.__assign.append(Function("pos", [Function(robot), Number(x+1), Number(y+1), Number(0)])) self.__assign.append(Function("target", [ Function(board.current_target[0]) , Number(board.current_target[2] + 1) , Number(board.current_target[3] + 1) ])) for x in self.__assign: self.__prg.assign_external(x, True) self.__solution = None self.__future = self.__prg.solve(on_model=self.__on_model, async_=True)
def test_auto_blacklist(): context = Context() @context.valasp(with_fun=Fun.TUPLE) class Edge: source: Integer dest: Integer Edge(Tuple([Number(1), Number(2)])) assert str(context.valasp_run_solver(["edge(1,2)."])) == '[edge(1,2)]' with pytest.raises(RuntimeError): context.valasp_run_solver(["edge(1,2). edge((1,2))."])
def main(self, prg, files): for f in files: prg.load(f) prg.add("check", ["k"], "#external query(k).") t = 0 sat = False prg.ground([("base", [])]) while not sat: t += 1 prg.ground([("step", [Number(t)])]) prg.ground([("check", [Number(t)])]) prg.release_external(Function("query", [Number(t - 1)])) prg.assign_external(Function("query", [Number(t)]), True) sat = prg.solve(on_model=self.__on_model).satisfiable
def test_repr(self): ''' Test representation of symbols. ''' self.assertEqual( repr(Function('test', [Number(10), Infimum, Supremum, String("test")], False)), "Function('test', [Number(10), Infimum, Supremum, String('test')], False)")
def test_number(self): ''' Test numbers. ''' n = Number(1) self.assertEqual(n.number, 1) self.assertEqual(n.type, SymbolType.Number)
def test_underscore_in_annotations(): context = Context() @context.valasp() class Foo: __init__: Integer assert str(Foo(Number(1))) == 'Foo(1)' assert Foo(Number(1)).__init__ == 1 @context.valasp() class Bar: __str__: Integer assert str(Bar(Number(1))) == 'Bar(1)' assert Bar(Number(1)).__str__ == 1
def main(prg): with open(".controller.PORT", "r") as f: p = int(f.read()) os.remove(".controller.PORT") conn = socket.create_connection(("127.0.0.1", p)) try: recv = Receiver(conn) state = States.IDLE k = 0 prg.ground([("pigeon", []), ("sleep", [Number(k)])]) prg.assign_external(Function("sleep", [Number(k)]), True) while True: if state == States.SOLVE: f = prg.solve(on_model=lambda model: conn.sendall( b"Answer: " + str(model).encode() + b"\n"), on_finish=lambda ret: conn. sendall(b"finish:" + str(ret).encode() + (b":INTERRUPTED" if ret.interrupted else b"") + b"\n"), async_=True) msg = recv.readline().decode() if state == States.SOLVE: f.cancel() ret = f.get() else: ret = None if msg == "interrupt": state = States.IDLE elif msg == "exit": return elif msg == "less_pigeon_please": prg.assign_external(Function("p"), False) state = States.IDLE elif msg == "more_pigeon_please": prg.assign_external(Function("p"), True) state = States.IDLE elif msg == "solve": state = States.SOLVE else: raise (RuntimeError("unexpected message: " + msg)) if ret is not None and not ret.unknown: k = k + 1 prg.ground([("sleep", [Number(k)])]) prg.release_external(Function("sleep", [Number(k - 1)])) prg.assign_external(Function("sleep", [Number(k)]), True) finally: conn.close()
def test_ground_error(self): ''' Test grounding with context and parameters. ''' ctx = Context() ctl = Control() ctl.add('part', ['c'], 'p(@cb_error()).') self.assertRaisesRegex(TestError, 'test', ctl.ground, [('part', [Number(1)])], ctx)
def test_is_not_predicate(): context = Context() @context.valasp(validate_predicate=False) class Month: value: int def __post_init__(self): if not (1 <= self.value <= 12): raise ValueError('month not in 1..12') assert str(Month(Number(1))) == 'Month(1)' with pytest.raises(ValueError): Month(Number(0)) with pytest.raises(TypeError): Month(QString('Sep')) @context.valasp(with_fun=Fun.TUPLE) class Salary: amount: Integer month: Month assert str(Salary(Tuple([Number(1000), Number(1)]))) == 'Salary(1000,Month(1))' with pytest.raises(ValueError): Salary(Tuple([Number(1000), Number(13)])) with pytest.raises(TypeError): Salary(Tuple([Number(1000), QString('Jan')]))
def __get_param(self, name, location): n = name.replace('\'', '') primes = len(name) - len(n) param = ast.SymbolicTerm(location, self.parameter) if primes > 0: param = ast.BinaryOperation( location, ast.BinaryOperator.Minus, param, ast.SymbolicTerm(location, Number(primes))) return n, param