예제 #1
0
    def test_control(self):
        '''
        Test observer together with a control object.
        '''
        ctl = Control()
        ctl.register_observer(self.obs)
        ctl.add('base', [], '''\
            b.
            {c}.
            a :- b, not c.
            #minimize{7@10,a:a; 5@10,c:c}.
            #project a.
            #project b.
            #external a.
            ''')
        ctl.ground([('base', [])])

        a, b, c = (Function(s) for s in ('a', 'b', 'c'))
        la, lb, lc = (ctl.symbolic_atoms[sym].literal for sym in (a, b, c))

        self.prg.sort()

        self.assertEqual(self.prg, Program(
            output_atoms={la: a, lc: c},
            shows=[],
            facts=[Fact(symbol=b)],
            rules=[Rule(choice=False, head=[lb], body=[]),
                   Rule(choice=False, head=[la], body=[-lc]),
                   Rule(choice=True, head=[lc], body=[])],
            minimizes=[Minimize(priority=10, literals=[(lc, 5), (la, 7)])],
            externals=[External(atom=la, value=TruthValue.False_)],
            projects=[Project(atom=lb), Project(atom=la)]).sort())
예제 #2
0
 def test_theory(self):
     '''
     Test observer via grounding.
     '''
     ctl = Control()
     obs = TestObserverTheory(self)
     ctl.register_observer(obs)
     ctl.add(
         'base', [], '''\
     #theory test {
         t { };
         &a/0 : t, head
     }.
     {a; b}.
     #show t : a, b.
     &a { (1,a): a,b }.
     ''')
     ctl.ground([('base', [])])
     self.assertIn('output_term', obs.called)
     self.assertIn('theory_term_number', obs.called)
     self.assertIn('theory_term_string', obs.called)
     self.assertIn('theory_term_compound', obs.called)
     self.assertIn('theory_element', obs.called)
     self.assertIn('theory_atom', obs.called)
     ctl.solve()
예제 #3
0
class Solver:
    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 on_model(self, model):
        self.models.append(str(model))

    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 stop(self):
        self.future.cancel()

    def finish(self):
        ret = self.future.get()
        return ret

    def set_more_pigeon(self, more):
        self.prg.assign_external(Function("p"), more)
예제 #4
0
def symbolic_atoms_to_facts_test1(q,facts_only):
    prgstr="""xq(1). xq("a"). 1 { xp(1);xp(2) }2."""
    ctrl=Control()
    add_program_string(ctrl,prgstr)
    ctrl.ground([("base",[])])
    fb=symbolic_atoms_to_facts(ctrl.symbolic_atoms,[XP,XQ,XQ2],
                               facts_only=facts_only)
    q.put(fb)
예제 #5
0
파일: main.py 프로젝트: glaserL/vizlo
def get_ground_universe(program: Program) -> Set[Symbol]:
    prg = program_to_string(program)
    ctl = Control()
    ctl.add("base", [], prg)
    ctl.ground([("base", [])])
    ground_universe = set(
        [ground_atom.symbol for ground_atom in ctl.symbolic_atoms])
    log(f"Ground universe: {ground_universe}")
    return ground_universe
예제 #6
0
 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)])])
예제 #7
0
 def test_simple_stats(self):
     '''
     Test simple statistics.
     '''
     ctl = Control(['-t', '2', '--stats=2'])
     ctl.add('base', [], '1 { a; b }.')
     ctl.ground([('base', [])])
     ctl.solve()
     stats = ctl.statistics
     self.assertGreaterEqual(stats['problem']['lp']['atoms'], 2)
     self.assertGreaterEqual(stats['solving']['solvers']['choices'], 1)
예제 #8
0
 def test_lower(self):
     '''
     Test lower bounds reported during optimization.
     '''
     ctl = Control(['--opt-str=usc,oll,0', '--stats=2'])
     ctl.add('base', [], '1 { p(X); q(X) } 1 :- X=1..3. #minimize { 1,p,X: p(X); 1,q,X: q(X) }.')
     ctl.ground([('base', [])])
     lower = []
     self.assertTrue(ctl.solve(on_unsat=lower.append).satisfiable)
     self.assertEqual(lower, [[1], [2], [3]])
     self.assertEqual(ctl.statistics['summary']['lower'], [3.0])
예제 #9
0
    def test_control_add_facts(self):
        class F(Predicate):
            anum = IntegerField

        f1 = F(1) ; f2 = F(2)
        ctrl = Control()
        control_add_facts(ctrl,[f1,f2])
        ctrl.ground([("base",[])])
        model = None
        with ctrl.solve(yield_=True) as sh:
            for m in sh:
                model=str(m)
        self.assertEqual(model, "{} {}".format(f1,f2))
예제 #10
0
    def test_solve(self):
        cc = Control()

        cc.add('base', [], '''
        a(X) :- not b(X), d(X).
        b(X) :- not a(X), d(X).''')
        cc.add('base', [], "d(1;2;3).")
        cc.ground([("base",[])])

        out = {}
        def onmodel(m):
            out['out'] = str(m)
        cc.solve(on_model = onmodel)

        self.assertEqual('d(1) d(2) d(3) b(1) b(2) b(3)', out['out'])
예제 #11
0
    def __init__(self):
        self.size           = 1
        self.blocked        = set()
        self.barriers       = set()
        self.targets        = set()
        self.pos            = dict()
        self.robots         = [{}]
        self.moves          = []
        self.current_target = None
        self.solution       = None

        ctl = Control()
        ctl.load("board.lp")
        ctl.ground([("base", [])])
        ctl.solve(on_model=self.__on_model)
예제 #12
0
    def test_user_stats(self):
        '''
        Test user statistics.
        '''
        def on_statistics(step, accu):
            step['test'] = {'a': 0, 'b': [1, 2], 'c': {'d': 3}}
            accu['test'] = step['test']
            step['test'] = {
                'a': lambda a: a + 1,
                'e': lambda a: 4 if a is None else 0,
                'b': [-1, 2, 3]
            }
            self.assertEqual(len(step['test']), 4)
            self.assertEqual(len(step['test']['b']), 3)
            self.assertEqual(len(step['test']['c']), 1)
            self.assertIn('a', step['test'])
            self.assertEqual(sorted(step['test']), ['a', 'b', 'c', 'e'])
            self.assertEqual(sorted(step['test'].keys()), ['a', 'b', 'c', 'e'])
            self.assertEqual(sorted(step['test']['c'].items()), [('d', 3.0)])
            self.assertEqual(sorted(step['test']['c'].values()), [3.0])

            step['test']['b'][1] = 99
            self.assertEqual(step['test']['b'][1], 99)
            step['test']['b'].extend([3, 4])
            step['test']['b'] += [3, 4]

        ctl = Control(['-t', '2', '--stats=2'])
        ctl.add('base', [], '1 { a; b }.')
        ctl.ground([('base', [])])
        ctl.solve(on_statistics=on_statistics)
        stats = ctl.statistics
        self.assertEqual(
            stats['user_step']['test'], {
                'a': 1.0,
                'b': [-1.0, 99.0, 3.0, 3.0, 4.0, 3.0, 4.0],
                'c': {
                    'd': 3.0
                },
                'e': 4.0
            })
        self.assertEqual(stats['user_accu']['test'], {
            'a': 0,
            'b': [1, 2],
            'c': {
                'd': 3
            }
        })
예제 #13
0
    def test_error_handling(self):
        '''
        Test basic error handling during solving.
        '''
        ctl = Control()
        ctl.add('base', [], '1 {a; b} 1.')
        ctl.ground([('base', [])])

        self.assertRaises(ZeroDivisionError,
                          lambda: ctl.solve(on_model=lambda m: 1 / 0))

        with ctl.solve(on_model=lambda m: 1 / 0, yield_=True) as handle:
            self.assertRaises(ZeroDivisionError, lambda: [_ for _ in handle])

        # Note: currently clasp does not store and re-raise the exception in
        # asynchronous mode, so we get a runtime error instead
        with ctl.solve(on_model=lambda m: 1 / 0, async_=True) as handle:
            self.assertRaises(RuntimeError, handle.get)
예제 #14
0
class TestSymbol(TestCase):
    '''
    Tests basic solving and related functions.
    '''

    def setUp(self):
        self.mcb = _MCB()
        self.ctl = Control(['0'])

    def tearDown(self):
        self.mcb = None
        self.ctl = None

    def test_propagator_control(self):
        '''
        Test PropagateControl.
        '''
        self.ctl.add("base", [], "{a}.")
        self.ctl.ground([("base", [])])
        self.ctl.register_propagator(TestPropagatorControl(self))
        _check_sat(self, cast(SolveResult, self.ctl.solve(on_model=self.mcb.on_model, yield_=False, async_=False)))
        self.assertEqual(self.mcb.models, _p(['a']))

    def test_propagator_init(self):
        '''
        Test PropagateInit and Assignment.
        '''
        self.ctl.add("base", [], "{a; b; c}.")
        self.ctl.ground([("base", [])])
        self.ctl.register_propagator(TestPropagatorInit(self))
        _check_sat(self, cast(SolveResult, self.ctl.solve(on_model=self.mcb.on_model, yield_=False, async_=False)))
        self.assertEqual(self.mcb.models[-1:], _p(['a', 'b', 'c']))

    def test_propagator(self):
        '''
        Test adding literals while solving.
        '''
        self.ctl.add("base", [], "")
        self.ctl.ground([("base", [])])
        self.ctl.register_propagator(TestPropagator(self))
        _check_sat(self, cast(SolveResult, self.ctl.solve(on_model=self.mcb.on_model, yield_=False, async_=False)))
        self.assertEqual(self.mcb.models, _p([], []))

    def test_heurisitc(self):
        '''
        Test decide.
        '''
        self.ctl = Control(['1'])
        self.ctl.add("base", [], "{a;b}.")
        self.ctl.ground([("base", [])])
        self.ctl.register_propagator(TestHeuristic(self))
        self.ctl.solve(on_model=self.mcb.on_model)
        self.assertEqual(self.mcb.models, _p(['a']))
예제 #15
0
    def solve_instance(self):
        prg = Control()

        prg.load("puzzle15.lp")
        prg.load(self.new_filename)
        ret, parts, step = SolveResult.unsatisfiable, [], 1
        parts.append(("base", []))
        while ret == SolveResult.unsatisfiable:
            parts.append(("step", [step]))
            parts.append(("check", [step]))
            prg.ground(parts)
            prg.release_external(Function("query", [step - 1]))
            prg.assign_external(Function("query", [step]), True)
            #f = lambda m: stdout.write(str(m)+'\n')
            print("step:" + str(step) + " Solving...")
            ret, parts, step = prg.solve(on_model=self.on_model), [], step + 1
            if ret.__repr__() == 'UNSAT':
                ret = SolveResult.unsatisfiable
            else:
                ret = SolveResult.satisfiable
예제 #16
0
 def test_theory_with_guard(self):
     '''
     Test observer via grounding.
     '''
     ctl = Control()
     obs = TestObserverTheoryWithGuard(self)
     ctl.register_observer(obs)
     ctl.add(
         'base', [], '''\
     #theory test {
         t { };
         &a/0 : t, {=}, t, head
     }.
     &a { } = a.
     ''')
     ctl.ground([('base', [])])
     self.assertIn('theory_term_string: a', obs.called)
     self.assertIn('theory_term_string: =', obs.called)
     self.assertIn('theory_atom_with_guard', obs.called)
     ctl.solve()
예제 #17
0
def main():
    # Create a Control object that will unify models against the appropriate
    # predicates. Then load the asp file that encodes the problem domain.
    ctrl = Control(unifier=[Driver, Item, Assignment])
    ctrl.load(ASP_PROGRAM)

    # Dynamically generate the instance data
    drivers = [Driver(name=n) for n in ["dave", "morri", "michael"]]
    items = [Item(name="item{}".format(i)) for i in range(1, 6)]
    instance = FactBase(drivers + items)

    # Add the instance data and ground the ASP program
    ctrl.add_facts(instance)
    ctrl.ground([("base", [])])

    # Generate a solution - use a call back that saves the solution
    solution = None

    def on_model(model):
        nonlocal solution
        solution = model.facts(atoms=True)

    ctrl.solve(on_model=on_model)
    if not solution:
        raise ValueError("No solution found")

    # Do something with the solution - create a query so we can print out the
    # assignments for each driver.

    #    query=solution.select(Assignment).where(lambda x,o: x.driver == o)
    query=solution.query(Driver,Assignment)\
                  .join(Driver.name == Assignment.driver)\
                  .group_by(Driver.name).order_by(Assignment.time).select(Assignment)
    for d, aiter in query.all():
        assignments = list(aiter)
        if not assignments:
            print("Driver {} is not working today".format(d))
        else:
            print("Driver {} must deliver: ".format(d))
            for a in assignments:
                print("\t Item {} at time {}".format(a.item, a.time))
예제 #18
0
def sols(instance, compare, comp):
    files = [
        os.path.join("encodings", "encoding.lp"),
        os.path.join("encodings", "types.lp"), instance
    ]
    thy = ClingconTheory()
    ctl = Control(['0'])
    thy.register(ctl)
    with ProgramBuilder(ctl) as bld:
        parse_files(files, lambda ast: thy.rewrite_ast(ast, bld.add))

    ctl.ground([('base', [])])
    thy.prepare(ctl)
    models = []
    with ctl.solve(yield_=True, on_model=thy.on_model) as hnd:
        for mdl in hnd:
            model = [str(a) for a in mdl.symbols(shown=True)]
            model += [
                "{}={}".format(str(key).strip('"'), val)
                for key, val in thy.assignment(mdl.thread_id)
            ]
            models.append(set(model))

    bool_herbrand = set(
        [i for sl in compare for i in sl if i.startswith("var(")])

    compare = [set(c) for c in compare]

    assert comp(
        len(models), len(compare)
    ), f"{models}\n vs {compare}\ncomputed {len(models)} expected {len(compare)}"
    for c in compare:
        # for all in herbrand which are not in compare -> ensure that they are not in model
        found = False
        for m in models:
            if c.issubset(m):
                if ((bool_herbrand - c) & m) == set():
                    found = True
                    break
        assert found == True, f"{c} not in {models}"
예제 #19
0
    def test_monkey(self):
        from clingo import Control
        from clorm import Predicate, IntegerField, StringField, FactBase, SymbolPredicateUnifier

        spu = SymbolPredicateUnifier()

        @spu.register
        class Afact(Predicate):
            num1 = IntegerField()
            str1 = StringField()

        @spu.register
        class Bfact(Predicate):
            num1 = IntegerField()
            str1 = StringField()

        af1 = Afact(1, "aaa")
        af2 = Afact(2, "bbb")
        af3 = Afact(3, "aaa")
        bf1 = Bfact(1, "eee")
        bf2 = Bfact(2, "fff")
        bf2 = Bfact(3, "ggg")

        fb2 = None

        def on_model(model):
            nonlocal fb2
            fb2 = model.facts(spu, atoms=True)

        fb1 = FactBase([af1, af2, af3, bf1, bf2])
        ctrl = Control()
        ctrl.add_facts(fb1)
        ctrl.ground([("base", [])])
        ctrl.solve(on_model=on_model)

        s_a_all = fb2.select(Afact)
        self.assertEqual(set([a for a in s_a_all.get()]), set([af1, af2, af3]))
예제 #20
0
def test_sum_of_salaries():
    context = Context()

    @context.valasp()
    class Income:
        company: str  # String
        amount: int  # Integer

        def __post_init__(self):
            if not (self.amount > 0):
                raise ValueError("amount must be positive")
            self.__class__.amount_sum += self.amount
            if self.__class__.amount_sum > Integer.max():
                raise OverflowError(
                    f"sum of amount may exceed {Integer.max()}")

        @classmethod
        def before_grounding_init_amount_sum(cls):
            cls.amount_sum = 0

        @classmethod
        def after_grounding_check_amount_sum(cls):
            if cls.amount_sum < 10000:
                raise ValueError(f"sum of amount cannot reach 10000")
            if cls.amount_sum == 3000000000:
                raise OverflowError(f"catch this!")

    control = Control()
    control.add(
        "base", [],
        'income("Acme ASP",1500000000). income("Yoyodyne YAML",1500000000).')
    control.add("valasp", [], context.valasp_validators())
    context.valasp_run_class_methods('before_grounding')
    with pytest.raises(RuntimeError):
        control.ground([("base", []), ("valasp", [])], context=context)
    with pytest.raises(OverflowError):
        context.valasp_run_class_methods('after_grounding')
예제 #21
0
    def valasp_run(self, control: clingo.Control, on_validation_done: Callable = None, on_model: Callable = None,
                   aux_program: List[str] = None, with_validators: bool = True, with_solve: bool = True) -> None:
        """Run grounder on the given controller, possibly performing validation and searching for a model.

        :param control: a controller
        :param on_validation_done: a function invoked after grounding, if no validation error is reported
        :param on_model: a callback function to process a model
        :param aux_program: more ASP code to add to the program
        :param with_validators: if True, validator constraints are added, and ``before_grounding*`` and ``after_grounding*`` class methods are called
        :param with_solve: if True, a model is searched
        """
        if with_validators:
            control.add("valasp", [], self.valasp_validators())
            self.valasp_run_class_methods('before_grounding')
        if aux_program:
            control.add("aux_program", [], '\n'.join(aux_program))
        control.ground([("base", []), ("valasp", []), ("aux_program", [])], context=self)
        if with_validators:
            self.valasp_run_class_methods('after_grounding')
        if on_validation_done:
            on_validation_done()
        if with_solve:
            # noinspection PyUnresolvedReferences
            control.solve(on_model=on_model)
예제 #22
0
from clingo import Control
from clingo.ast import parse_string, ProgramBuilder
from clingodl import ClingoDLTheory

prg = '&diff { x } >= 1. &diff { y } >= 3.'

thy = ClingoDLTheory()
ctl = Control(['0'])
thy.register(ctl)
with ProgramBuilder(ctl) as bld:
    parse_string(prg, lambda ast: thy.rewrite_ast(ast, bld.add))

ctl.ground([('base', [])])
thy.prepare(ctl)
with ctl.solve(yield_=True, on_model=thy.on_model) as hnd:
    for mdl in hnd:
        print([f'{key}={val}' for key, val in thy.assignment(mdl.thread_id)])

예제 #23
0
class TestAtoms(TestCase):
    '''
    Tests for theory and symbolic atoms.
    '''
    def setUp(self):
        self.ctl = Control()

    def test_symbolic_atom(self):
        '''
        Test symbolic atom.
        '''
        self.ctl.add('base', [], 'p(1). {p(2)}. #external p(3).')
        self.ctl.ground([('base', [])])

        atoms = self.ctl.symbolic_atoms

        p1 = atoms[Function('p', [Number(1)])]
        self.assertIsNotNone(p1)
        self.assertTrue(p1.is_fact)
        self.assertFalse(p1.is_external)
        self.assertTrue(p1.literal >= 1)
        self.assertEqual(p1.symbol, Function('p', [Number(1)]))
        self.assertTrue(p1.match('p', 1, True))
        self.assertFalse(p1.match('p', 2, True))

        p2 = atoms[Function('p', [Number(2)])]
        self.assertIsNotNone(p2)
        self.assertFalse(p2.is_fact)
        self.assertFalse(p2.is_external)
        self.assertTrue(p2.literal >= 2)
        self.assertEqual(p2.symbol, Function('p', [Number(2)]))
        self.assertTrue(p2.match('p', 1, True))
        self.assertFalse(p2.match('p', 2, True))

        p3 = atoms[Function('p', [Number(3)])]
        self.assertIsNotNone(p3)
        self.assertFalse(p3.is_fact)
        self.assertTrue(p3.is_external)
        self.assertTrue(p3.literal >= 2)
        self.assertEqual(p3.symbol, Function('p', [Number(3)]))
        self.assertTrue(p3.match('p', 1, True))
        self.assertFalse(p3.match('p', 2, True))

        p4 = atoms[Function('p', [Number(4)])]
        self.assertIsNone(p4)

    def test_symbolic_atoms(self):
        '''
        Test symbolic atoms.
        '''
        self.ctl.add(
            'base', [],
            'p(1). {p(2)}. #external p(3). q(1). -p(1). {q(2)}. #external q(3).'
        )
        self.ctl.ground([('base', [])])

        atoms = self.ctl.symbolic_atoms
        self.assertEqual(sorted(atoms.signatures), [('p', 1, False),
                                                    ('p', 1, True),
                                                    ('q', 1, True)])

        ps = list(atoms.by_signature('p', 1, True))
        self.assertEqual(len(ps), 3)
        for p in ps:
            self.assertEqual(p.symbol.name, 'p')
            self.assertTrue(p.symbol.positive)
            self.assertEqual(len(p.symbol.arguments), 1)

        nps = list(atoms.by_signature('p', 1, False))
        self.assertEqual(len(nps), 1)
        for p in nps:
            self.assertEqual(p.symbol.name, 'p')
            self.assertTrue(p.symbol.negative)
            self.assertEqual(p.symbol.arguments, [Number(1)])

        self.assertEqual(len(atoms), 7)
        self.assertEqual(len(list(atoms)), 7)

        self.assertIn(Function('p', [Number(1)], True), atoms)
        self.assertIn(Function('p', [Number(1)], False), atoms)
        self.assertIn(Function('q', [Number(2)], True), atoms)
        self.assertNotIn(Function('q', [Number(2)], False), atoms)

    def test_theory_term(self):
        '''
        Test theory term.
        '''
        self.ctl.add('base', [], THEORY)
        self.ctl.add('base', [], '&a { 1,a,f(a),{1},(1,),[1] }.')
        self.ctl.ground([('base', [])])

        terms = next(self.ctl.theory_atoms).elements[0].terms
        self.assertEqual([str(term) for term in terms],
                         ['1', 'a', 'f(a)', '{1}', '(1,)', '[1]'])
        num, sym, fun, set_, tup, lst = terms
        self.assertEqual(num.type, TheoryTermType.Number)
        self.assertEqual(num.number, 1)
        self.assertEqual(sym.type, TheoryTermType.Symbol)
        self.assertEqual(sym.name, 'a')
        self.assertEqual(fun.type, TheoryTermType.Function)
        self.assertEqual(fun.name, 'f')
        self.assertEqual(fun.arguments, [sym])
        self.assertEqual(set_.type, TheoryTermType.Set)
        self.assertEqual(set_.arguments, [num])
        self.assertEqual(tup.type, TheoryTermType.Tuple)
        self.assertEqual(tup.arguments, [num])
        self.assertEqual(lst.type, TheoryTermType.List)
        self.assertEqual(lst.arguments, [num])

        self.assertNotEqual(hash(num), hash(sym))
        self.assertEqual(hash(num), hash(lst.arguments[0]))
        self.assertNotEqual(num < sym, sym < num)

        self.assertRegex(repr(num), 'TheoryTerm(.*)')

    def test_theory_element(self):
        '''
        Test theory element.
        '''
        self.ctl.add('base', [], THEORY)
        self.ctl.add('base', [], '{a; b}.')
        self.ctl.add('base', [], '&a { 1; 2,3: a,b }.')
        self.ctl.ground([('base', [])])

        atom = next(self.ctl.theory_atoms)
        elements = sorted(atom.elements, key=lambda elem: len(elem.terms))
        self.assertEqual([str(elem) for elem in elements], ['1', '2,3: a,b'])

        a, b = elements
        self.assertEqual(len(a.condition), 0)
        self.assertEqual(len(b.condition), 2)
        self.assertTrue(all(lit >= 1 for lit in b.condition))
        self.assertGreaterEqual(b.condition_id, 1)

        self.assertEqual(a, a)
        self.assertNotEqual(a, b)
        self.assertNotEqual(hash(a), hash(b))
        self.assertNotEqual(a < b, b < a)

        self.assertRegex(repr(a), 'TheoryElement(.*)')

    def test_theory_atom(self):
        '''
        Test theory atom.
        '''
        self.ctl.add('base', [], THEORY)
        self.ctl.add('base', [], '&a {}.')
        self.ctl.add('base', [], '&b {} = 1.')
        self.ctl.ground([('base', [])])

        atoms = sorted(list(self.ctl.theory_atoms),
                       key=lambda atom: atom.term.name)
        self.assertEqual([str(atom) for atom in atoms], ['&a{}', '&b{}=1'])

        a, b = atoms
        self.assertTrue(a.literal >= 1)
        self.assertIsNone(a.guard)
        self.assertIsNotNone(b.guard)
        self.assertEqual(b.guard[0], "=")
        self.assertEqual(str(b.guard[1]), "1")
        self.assertEqual(len(a.elements), 0)

        self.assertEqual(a, a)
        self.assertNotEqual(a, b)
        self.assertNotEqual(hash(a), hash(b))
        self.assertNotEqual(a < b, b < a)

        self.assertRegex(repr(a), 'TheoryAtom(.*)')
예제 #24
0
파일: lpmln.py 프로젝트: nrueh/LPMLN
    def main(self, ctl: Control, files: Sequence[str]):
        '''
        Parse LP^MLN program and convert to ASP with weak constraints.
        '''
        observer = Observer()
        ctl.register_observer(observer)

        ctl.add("base", [], THEORY)
        ctl.add("base", [], self.evidence_file)
        if self.two_solve_calls:
            ctl.add("base", [], '#external ext_helper.')
        # TODO: Make sure the ext_helper atom is not contained in the program.

        if not files:
            files = ["-"]
        self._convert(ctl, files)

        ctl.ground([("base", [])])
        if self.query != []:
            self._ground_queries(ctl.symbolic_atoms)

        bound_hr = 2**63 - 1
        if self.two_solve_calls:
            # First solve call
            # Soft rules are deactivated
            # TODO: Suppress output of first solve call, add flag
            # TODO: Activate this per flag

            ctl.assign_external(Function("ext_helper"), False)
            with ctl.solve(yield_=True) as h:
                for m in h:
                    bound_hr = m.cost[0]
            # TODO: Don't show ext_helper
            # ctl.release_external(Function("ext_helper"))
            ctl.assign_external(Function("ext_helper"), True)

        if self.display_all_probs:
            ctl.configuration.solve.opt_mode = f'enum, {bound_hr}, {(2**63)-1}'
            ctl.configuration.solve.models = 0

        model_costs = []
        with ctl.solve(yield_=True) as handle:
            for model in handle:
                if self.display_all_probs or self.query != []:
                    model_costs.append(model.cost)
                    if self.query != []:
                        self._check_model_for_query(model)

        if model_costs != [] and (self.display_all_probs or self.query != []):
            if 0 not in observer.priorities:
                # TODO: Should this be error or warning?
                print(
                    'No soft weights in program. Cannot calculate probabilites'
                )
            # TODO: What about case where there are other priorities than 0/1?
            # elif not self.two_solve_calls and any(
            #         x > 1 for x in observer.priorities):
            #     print(observer.priorities)
            #     print('testasd')
            else:
                probs = ProbabilityModule(
                    model_costs, observer.priorities,
                    [self.translate_hard_rules, self.two_solve_calls])
                if self.display_all_probs:
                    probs.print_probs()
                if self.query != []:
                    probs.get_query_probability(self.query)
예제 #25
0
파일: main.py 프로젝트: glaserL/vizlo
class VizloControl(Control):
    def add_to_painter(self, model: Union[Model, PythonModel,
                                          Collection[clingo.Symbol]]):
        """
        will register model with the internal painter. On all consecutive calls to paint(), this model will be painted.
        :param model: the model to add to the painter.
        :return:
        """
        self.painter.append(PythonModel(model))

    def __init__(self,
                 arguments: List[str] = [],
                 logger=None,
                 message_limit: int = 20,
                 print_entire_models=False,
                 atom_draw_maximum=15):
        self.control = Control(arguments, logger, message_limit)
        self.painter: List[PythonModel] = list()
        self.program: ASTProgram = list()
        self.raw_program: str = ""
        self.transformer = JustTheRulesTransformer()
        self._print_changes_only = not print_entire_models
        self._atom_draw_maximum = atom_draw_maximum

    def _set_print_only_changes(self, value: bool) -> None:
        self._print_changes_only = value

    def ground(self,
               parts: List[Tuple[str, List[Symbol]]],
               context: Any = None) -> None:
        self.control.ground(parts, context)

    def solve(self,
              assumptions: List[Union[Tuple[Symbol, bool], int]] = [],
              on_model=None,
              on_statistics=None,
              on_finish=None,
              yield_: bool = False,
              async_: bool = False) -> Union[SolveHandle, SolveResult]:
        return self.control.solve(assumptions, on_model, on_statistics,
                                  on_finish, yield_, async_)

    def load(self, path):
        prg = ""
        with open(path) as f:
            for line in f:
                prg += line
        self.program += prg
        self.control.load(path)

    def add(self, name: str, parameters: List[str], program: str) -> None:
        self.raw_program += program
        self.control.add(name, parameters, program)

    def find_nodes_corresponding_to_stable_models(self, g, stable_models):
        correspoding_nodes = set()
        for model in stable_models:
            for node in g.nodes():
                log(f"{node} {type(node.model)} == {model} {type(model)} -> {set(node.model) == model}"
                    )
                if set(node.model) == model and len(
                        g.edges(node)) == 0:  # This is a leaf
                    log(f"{node} <-> {model}")
                    correspoding_nodes.add(node)
                    break
        return correspoding_nodes

    def prune_graph_leading_to_models(self, graph: nx.DiGraph,
                                      models_as_nodes):
        before = len(graph)
        relevant_nodes = set()
        for model in models_as_nodes:
            for relevant_node in nx.all_simple_paths(graph, INITIAL_EMPTY_SET,
                                                     model):
                relevant_nodes.update(relevant_node)
        all_nodes = set(graph.nodes())
        irrelevant_nodes = all_nodes - relevant_nodes
        graph.remove_nodes_from(irrelevant_nodes)
        after = len(graph)
        log(f"Removed {before - after} of {before} nodes ({(before - after) / before})"
            )

    def _make_graph(self, _sort=True):
        """
        Ties together transformation and solving. Transforms the already added program parts and creates a solving tree.
        :param _sort: Whether the program should be sorted automatically. Setting this to false will likely result into
        wrong results!
        :return:
        :raises ValueError:
        """
        if not len(self.raw_program):
            raise ValueError("Can't paint an empty program.")
        else:
            t = JustTheRulesTransformer()
            program = t.transform(self.raw_program, _sort)
        if len(self.painter):
            universe = get_ground_universe(program)
            global_assumptions = make_global_assumptions(
                universe, self.painter)
            solve_runner = SolveRunner(program, t.rule2signatures)
            g = solve_runner.make_graph(global_assumptions)
        else:
            solve_runner = SolveRunner(program,
                                       symbols_in_heads_map=t.rule2signatures)
            g = solve_runner.make_graph()
        return g

    def paint(self,
              atom_draw_maximum: int = 20,
              show_entire_model: bool = False,
              sort_program: bool = True,
              **kwargs):
        """
         Will create a graph visualization of the solving process. If models have been added using add_to_painter,
         only the solving paths that lead to these models will be drawn.
         :param atom_draw_maximum: int
             The maximum amount of atoms that will be printed for each partial model. (default=20)
         :param show_entire_model: bool
             If false, only the atoms that have been added at a solving step will be printed (up to atom_draw_maximum).
             If true, all atoms will always be printed (up to atom_draw_maximum). (default=False)
         :param sort_program:
             If true, the rules of a program will be sorted and grouped by their dependencies.
             Each set of rules will contain all rules in which each atom in its heads is contained in a head.
         :param kwargs:
             kwargs will be forwarded to the visualisation module. See graph.draw()
         :return:
         """
        if type(atom_draw_maximum) != int:
            raise ValueError(
                f"Argument atom_draw_maximum should be an integer (received {atom_draw_maximum})."
            )
        g = self._make_graph(sort_program)
        display = NetworkxDisplay(g, atom_draw_maximum, not show_entire_model)
        img = display.draw(**kwargs)
        return img

    def _add_and_ground(self, prg):
        """Short cut for complex add and ground calls, should only be used for debugging purposes."""
        self.add("base", [], prg)
        self.ground([("base", [])])

    ##################
    # Just pass-through stuff
    ##################

    @property
    def configuration(self) -> Configuration:
        return self.control.configuration

    @property
    def is_conflicting(self) -> bool:
        return self.control.is_conflicting

    @property
    def statistics(self) -> dict:
        return self.control.statistics

    @property
    def symbolic_atoms(self) -> SymbolicAtoms:
        return self.control.symbolic_atoms

    @property
    def theory_atoms(self) -> TheoryAtomIter:
        return self.control.theory_atoms

    @property
    def use_enumeration_assumption(self) -> bool:
        return self.control.use_enumeration_assumption

    def assign_external(self, external: Union[Symbol, int],
                        truth: Optional[bool], **kwargs) -> None:
        self.control.assign_external(external, truth, **kwargs)

    def backend(self) -> Backend:
        return self.control.backend()

    def builder(self) -> ProgramBuilder:
        return self.control.builder()

    def cleanup(self) -> None:
        self.control.cleanup()

    def get_const(self, name: str) -> Optional[Symbol]:
        return self.control.get_const(name)

    def interrupt(self):
        self.control.interrupt()

    def register_observer(self, observer, replace=False):
        self.register_observer(observer, replace)

    def release_external(self, symbol: Union[Symbol, int]) -> None:
        self.control.release_external(symbol)
예제 #26
0
class TestSolving(TestCase):
    '''
    Tests basic solving and related functions.
    '''

    def setUp(self):
        self.mcb = _MCB()
        self.mit = _MCB()
        self.ctl = Control(['0'])

    def tearDown(self):
        self.mcb = None
        self.mit = None
        self.ctl = None

    def test_solve_result_str(self):
        '''
        Test string representation of solve results.
        '''
        ret = self.ctl.solve()
        self.assertEqual(str(ret), 'SAT')
        self.assertRegex(repr(ret), 'SolveResult(.*)')

    def test_model_str(self):
        '''
        Test string representation of models.
        '''
        self.ctl.add('base', [], 'a.')
        self.ctl.ground([('base', [])])
        with self.ctl.solve(yield_=True) as hnd:
            for mdl in hnd:
                self.assertEqual(str(mdl), "a")
                self.assertRegex(repr(mdl), "Model(.*)")

    def test_solve_cb(self):
        '''
        Test solving using callback.
        '''
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        _check_sat(self, cast(SolveResult, self.ctl.solve(on_model=self.mcb.on_model, yield_=False, async_=False)))
        self.assertEqual(self.mcb.models, _p(['a', 'c'], ['b', 'c']))
        self.assertEqual(self.mcb.last[0], ModelType.StableModel)

    def test_solve_async(self):
        '''
        Test asynchonous solving.
        '''
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        with cast(SolveHandle, self.ctl.solve(on_model=self.mcb.on_model, yield_=False, async_=True)) as hnd:
            _check_sat(self, hnd.get())
            self.assertEqual(self.mcb.models, _p(['a', 'c'], ['b', 'c']))

    def test_solve_yield(self):
        '''
        Test solving yielding models.
        '''
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        with cast(SolveHandle, self.ctl.solve(on_model=self.mcb.on_model, yield_=True, async_=False)) as hnd:
            for m in hnd:
                self.mit.on_model(m)
            _check_sat(self, hnd.get())
            self.assertEqual(self.mcb.models, _p(['a', 'c'], ['b', 'c']))
            self.assertEqual(self.mit.models, _p(['a', 'c'], ['b', 'c']))

    def test_solve_async_yield(self):
        '''
        Test solving yielding models asynchronously.
        '''
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        with self.ctl.solve(on_model=self.mcb.on_model, yield_=True, async_=True) as hnd:
            while True:
                hnd.resume()
                _ = hnd.wait()
                m = hnd.model()
                if m is None:
                    break
                self.mit.on_model(m)
            _check_sat(self, hnd.get())
            self.assertEqual(self.mcb.models, _p(['a', 'c'], ['b', 'c']))
            self.assertEqual(self.mit.models, _p(['a', 'c'], ['b', 'c']))

    def test_solve_interrupt(self):
        '''
        Test interrupting solving.
        '''
        self.ctl.add("base", [], "1 { p(P,H): H=1..99 } 1 :- P=1..100.\n1 { p(P,H): P=1..100 } 1 :- H=1..99.")
        self.ctl.ground([("base", [])])
        with self.ctl.solve(async_=True) as hnd:
            hnd.resume()
            hnd.cancel()
            ret = hnd.get()
            self.assertTrue(ret.interrupted)

        with self.ctl.solve(async_=True) as hnd:
            hnd.resume()
            self.ctl.interrupt()
            ret = hnd.get()
            self.assertTrue(ret.interrupted)

    def test_solve_core(self):
        '''
        Test core retrieval.
        '''
        self.ctl.add("base", [], "3 { p(1..10) } 3.")
        self.ctl.ground([("base", [])])
        ass = []
        for atom in self.ctl.symbolic_atoms.by_signature("p", 1):
            ass.append(-atom.literal)
        ret = cast(SolveResult, self.ctl.solve(on_core=self.mcb.on_core, assumptions=ass))
        self.assertTrue(ret.unsatisfiable)
        self.assertTrue(len(self.mcb.core) > 7)

    def test_enum(self):
        '''
        Test core retrieval.
        '''
        self.ctl = Control(['0', '-e', 'cautious'])
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        self.ctl.solve(on_model=self.mcb.on_model)
        self.assertEqual(self.mcb.last[0], ModelType.CautiousConsequences)
        self.assertEqual([self.mcb.last[1]], _p(['c']))

        self.ctl = Control(['0', '-e', 'brave'])
        self.ctl.add("base", [], "1 {a; b} 1. c.")
        self.ctl.ground([("base", [])])
        self.ctl.solve(on_model=self.mcb.on_model)
        self.assertEqual(self.mcb.last[0], ModelType.BraveConsequences)
        self.assertEqual([self.mcb.last[1]], _p(['a', 'b', 'c']))

    def test_model(self):
        '''
        Test functions of model.
        '''
        def on_model(m: Model):
            self.assertTrue(m.contains(Function('a')))
            self.assertTrue(m.is_true(cast(SymbolicAtom, m.context.symbolic_atoms[Function('a')]).literal))
            self.assertFalse(m.is_true(1000))
            self.assertEqual(m.thread_id, 0)
            self.assertEqual(m.number, 1)
            self.assertFalse(m.optimality_proven)
            self.assertEqual(m.cost, [3])
            m.extend([Function('e')])
            self.assertSequenceEqual(m.symbols(theory=True), [Function('e')])
        self.ctl.add("base", [], "a. b. c. #minimize { 1,a:a; 1,b:b; 1,c:c }.")
        self.ctl.ground([("base", [])])
        self.ctl.solve(on_model=on_model)

    def test_control_clause(self):
        '''
        Test adding clauses while solving.
        '''
        self.ctl.add("base", [], "1 {a; b; c} 1.")
        self.ctl.ground([("base", [])])
        with cast(SolveHandle, self.ctl.solve(on_model=self.mcb.on_model, yield_=True, async_=False)) as hnd:
            for m in hnd:
                clause = []
                if m.contains(Function('a')):
                    clause.append((Function('b'), False))
                else:
                    clause.append((Function('a'), False))
                m.context.add_clause(clause)

            _check_sat(self, hnd.get())
            self.assertEqual(len(self.mcb.models), 2)

    def test_control_nogood(self):
        '''
        Test adding nogoods while solving.
        '''
        self.ctl.add("base", [], "1 {a; b; c} 1.")
        self.ctl.ground([("base", [])])
        with cast(SolveHandle, self.ctl.solve(on_model=self.mcb.on_model, yield_=True, async_=False)) as hnd:
            for m in hnd:
                clause = []
                if m.contains(Function('a')):
                    clause.append((Function('b'), True))
                else:
                    clause.append((Function('a'), True))
                m.context.add_nogood(clause)

            _check_sat(self, hnd.get())
            self.assertEqual(len(self.mcb.models), 2)
예제 #27
0
class Solver:
    def __init__(self, horizon=0):
        self.__horizon = horizon
        self.__prg = Control(['-t4'])
        self.__future = None
        self.__solution = None
        self.__assign = []

        self.__prg.load("board.lp")
        self.__prg.load("robots.lp")
        parts = [ ("base", [])
                , ("check", [Number(0)])
                , ("state", [Number(0)])
                ]
        for t in range(1, self.__horizon+1):
            parts.extend([ ("trans", [Number(t)])
                         , ("check", [Number(t)])
                         , ("state", [Number(t)])
                         ])
        self.__prg.ground(parts)
        self.__prg.assign_external(Function("horizon", [Number(self.__horizon)]), True)

    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, 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 busy(self):
        if self.__future is None:
            return False
        if self.__future.wait(0):
            if self.__solution is None:
                self.__next()
                self.__future = self.__prg.solve(on_model=self.__on_model, async_=True)
                return True
            else:
                self.__future = None
                return False
        return True

    def stop(self):
        if self.__future is not None:
            self.__future.cancel()
            self.__future.wait()
            self.__future = None
            self.get()

    def get(self):
        solution = self.__solution
        self.__solution = None
        for x in self.__assign:
            self.__prg.assign_external(x, False)
        self.__assign = []
        return solution

    def __on_model(self, m):
        self.__solution = []
        for atom in m.symbols(atoms=True):
            if atom.name == "move" and len(atom.arguments) == 4:
                c, x, y, t = [(n.number if n.type == SymbolType.Number else str(n)) for n in atom.arguments]
                self.__solution.append((c, x, y, t))
        self.__solution.sort(key=lambda x: x[3])
        p = None
        i = 0
        for x in self.__solution:
            if p is not None and \
               p[0] == x[0]  and \
               p[1] == x[1]  and \
               p[2] == x[2]:
                break
            p = x
            i += 1
        del self.__solution[i:]
예제 #28
0
class SolveThread(Thread):
    STATE_SOLVE = 1
    STATE_IDLE = 2
    STATE_EXIT = 3

    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 on_model(self, model):
        self.output.send("answer: " + str(model)),

    def on_finish(self, ret):
        self.output.send("finish: " + str(ret) +
                         (" (INTERRUPTED)" if ret.interrupted else ""))

    def handle_message(self, msg):
        if msg == "interrupt":
            self.state = SolveThread.STATE_IDLE
        elif msg == "exit":
            self.state = SolveThread.STATE_EXIT
        elif msg == "less_pigeon_please":
            self.prg.assign_external(Function("p"), False)
            self.state = SolveThread.STATE_IDLE
        elif msg == "more_pigeon_please":
            self.prg.assign_external(Function("p"), True)
            self.state = SolveThread.STATE_IDLE
        elif msg == "solve":
            self.state = SolveThread.STATE_SOLVE
        else:
            raise (RuntimeError("unexpected message: " + msg))

    def run(self):
        while True:
            if self.state == SolveThread.STATE_SOLVE:
                f = self.prg.solve(on_model=self.on_model,
                                   on_finish=self.on_finish,
                                   async_=True)
            msg = self.input.receive()
            if self.state == SolveThread.STATE_SOLVE:
                f.cancel()
                ret = f.get()
            else:
                ret = None
            self.handle_message(msg)
            if self.state == SolveThread.STATE_EXIT:
                return
            elif ret is not None and not ret.unknown:
                self.k = self.k + 1
                self.prg.ground([("sleep", [Number(self.k)])])
                self.prg.release_external(
                    Function("sleep", [Number(self.k - 1)]))
                self.prg.assign_external(Function("sleep", [Number(self.k)]),
                                         True)
예제 #29
0
class App:
    def __init__(self, args):
        self.control = Control()
        self.args = args
        self.horizon = 0
        self.objects = 0
        self.end = None

    def show(self, model):
        if not self.args.quiet:
            print("Model: {}".format(model))

    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 run(self):
        for source in self.args.file:
            self.control.load(source)
        if self.args.maxobj is None:
            self.end = self.control.get_const("n").number
        else:
            self.end = self.args.maxobj

        while self.objects < self.end:
            self.ground(True)
            while True:
                ret = self.control.solve(on_model=self.show)
                if self.args.stats:
                    args = {
                        "sort_keys": True,
                        "indent": 0,
                        "separators": (',', ': ')
                    }
                    stats = {}
                    for x in [
                            "step", "enumerated", "time_cpu", "time_solve",
                            "time_sat", "time_unsat", "time_total"
                    ]:
                        stats[x] = self.control.statistics[x]
                    for x in ["lp", "ctx", "solvers"]:
                        for y in self.control.statistics[x]:
                            stats[y] = self.control.statistics[x][y]
                    print(json.dumps(stats, *args))
                if ret.satisfiable:
                    break
                self.ground(False)