예제 #1
0
 def visit_TheoryAtom(self, atom):
     """
     Rewrites theory atoms related to parity constraints.
     """
     if atom.term.type == _ast.ASTType.Function and len(
             atom.term.arguments) == 0:
         if atom.term.name in ["odd", "even"]:
             self.__remove = True
             i = _ast.Symbol(atom.location, _clingo.Number(self.__id))
             ct = _ast.Symbol(atom.location,
                              _clingo.Function(atom.term.name))
             head = _ast.SymbolicAtom(
                 _ast.Function(atom.location, g_aux_name, [i, ct], False))
             head = _ast.Literal(atom.location, _ast.Sign.NoSign, head)
             self.__add(_ast.Rule(atom.location, head, []))
             for element in atom.elements:
                 head = _ast.Function(
                     atom.location, "",
                     [theory_term_to_term(t) for t in element.tuple], False)
                 head = _ast.SymbolicAtom(
                     _ast.Function(atom.location, g_aux_name, [i, ct, head],
                                   False))
                 head = _ast.Literal(atom.location, _ast.Sign.NoSign, head)
                 body = element.condition
                 self.__add(_ast.Rule(atom.location, head, body))
             self.__id += 1
     return atom
예제 #2
0
 def visit_TheoryFunction(self, x):
     """
     Theory functions are mapped to functions.
     """
     isnum = lambda y: y.type == _ast.ASTType.Symbol and y.symbol.type == _clingo.SymbolType.Number
     if x.name == "-" and len(x.arguments) == 1:
         rhs = self(x.arguments[0])
         if isnum(rhs):
             return _ast.Symbol(x.location, _clingo.Number(-rhs.symbol.number))
         else:
             return _ast.UnaryOperation(x.location, _ast.UnaryOperator.Minus, rhs)
     elif (x.name == "+" or x.name == "-") and len(x.arguments) == 2:
         lhs = self(x.arguments[0])
         rhs = self(x.arguments[1])
         op  = _ast.BinaryOperator.Plus if x.name == "+" else _ast.BinaryOperator.Minus
         if isnum(lhs) and isnum(rhs):
             lhs = lhs.symbol.number
             rhs = rhs.symbol.number
             return _ast.Symbol(x.location, _clingo.Number(lhs + rhs if x.name == "+" else lhs - rhs))
         else:
             return _ast.BinaryOperation(x.location, op, lhs, rhs)
     elif x.name == "-" and len(x.arguments) == 2:
         return _ast.BinaryOperation(x.location, _ast.BinaryOperator.Minus, self(x.arguments[0]), self(x.arguments[1]))
     elif (x.name, TheoryParser.binary) in TheoryParser.table or (x.name, TheoryParser.unary) in TheoryParser.table:
         raise RuntimeError("operator not handled: {}".format(str_location(x.location)))
     else:
         return _ast.Function(x.location, x.name, [self(a) for a in x.arguments], False)
예제 #3
0
파일: head.py 프로젝트: susuhahnml/telingo
    def add(atm, lhs, rhs):
        if isinstance(lhs, _Number):
            lhs = _ast.Symbol(atom.location, _clingo.Number(lhs))
        if rhs == float("inf"):
            rhs = _ast.Symbol(atom.location, _clingo.Supremum)
        elif isinstance(rhs, _Number):
            rhs = _ast.Symbol(atom.location, _clingo.Number(rhs))

        rng = (lhs, rhs)
        other.setdefault(str(rng), (rng, {}))[1].setdefault(str(atm), atm)
예제 #4
0
    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()
예제 #5
0
 def visit_Literal_in_Head_Disjuntion(self, x, *args, **kwargs):
     if x.sign == ast.Sign.DoubleNegation:
         sign = self.__dnegative_term
     elif x.sign == ast.Sign.Negation:
         sign = self.__negative_term
     else:
         sign = self.__positive_term
     rule_id = ast.Symbol(x.location, self.__rule_id_number)
     sign = ast.Symbol(x.location, sign)
     fun = ast.Function(x.location, auxiliary_atom_name,
                        [rule_id, sign, x.atom.term], False)
     new_literal = ast.Literal(x.location, ast.Sign.NoSign,
                               ast.SymbolicAtom(fun))
     self.__auxiliary_atoms.append(new_literal)
     rule = ast.Rule(x.location, head=x, body=[new_literal])
     self.__auxiliary_rules.append(rule)
     return new_literal
예제 #6
0
파일: head.py 프로젝트: susuhahnml/telingo
 def add(a, b):
     if a == 0:
         return b
     elif b == 0:
         return a
     elif a == float("inf") or b == float("inf"):
         return float("inf")
     elif isinstance(a, _Number) and isinstance(b, _Number):
         return a + b
     else:
         lhs = _ast.Symbol(location, _clingo.Number(a)) if isinstance(
             a, _Number) else a
         rhs = _ast.Symbol(location, _clingo.Number(b)) if isinstance(
             b, _Number) else b
         return _clingo.ast.BinaryOperation(location,
                                            _ast.BinaryOperator.Plus,
                                            lhs, rhs)
예제 #7
0
 def __append_final(self, x, param=None):
     loc = x.location
     x.body.append(
         _ast.Literal(
             loc, _ast.Sign.NoSign,
             _ast.SymbolicAtom(
                 _ast.Function(
                     loc, "__final",
                     [_ast.Symbol(loc, param)] if param is not None else [],
                     False))))
예제 #8
0
 def control_add_facts(ctrl, facts):
     with ctrl.builder() as bldr:
         line = 1
         for f in facts:
             raw = f.raw if isinstance(f, Predicate) else f
             floc = {"filename": "<input>", "line": line, "column": 1}
             location = {"begin": floc, "end": floc}
             r = ast.Rule(
                 location,
                 ast.Literal(location, ast.Sign.NoSign,
                             ast.SymbolicAtom(ast.Symbol(location, raw))),
                 [])
             bldr.add(r)
             line += 1
예제 #9
0
    def visit_TheoryAtom(self, atom):
        """
        Rewrites theory atoms related to temporal formulas.

        An atom of form `&tel {...}` is rewritten to `&tel(k) {...}`, atoms of
        form `&initial` and `&final` are rewritten to `__initial` and
        `__final`, and atoms of form `&true` and `&false` are rewritten to
        `#true` and `#false`.
        """
        if atom.term.type == _ast.ASTType.Function and len(atom.term.arguments) == 0:
            time = lambda loc: _ast.Symbol(loc, _clingo.Function(_tf.g_time_parameter_name))
            wrap = lambda loc, atom: _ast.Literal(loc, _ast.Sign.DoubleNegation, atom) if self.__head else atom
            if atom.term.name == "del" :
                if not self.__negation and not self.__constraint:
                        raise RuntimeError("dynamic formulas not supported in this context: {}".format(_tf.str_location(atom.location)))
                atom.term.arguments = [_ast.Symbol(atom.term.location, _clingo.Function("__t"))]
            elif atom.term.name == "tel" :
                if self.__head:
                    atom, rules = self.__head_transformer.transform(atom)
                    self.__aux_rules.extend(rules)
                else:
                    if not self.__negation and not self.__constraint:
                        raise RuntimeError("temporal formulas not supported in this context: {}".format(_tf.str_location(atom.location)))
                    for element in atom.elements:
                        if len(element.tuple) != 1:
                            raise RuntimeError("invalid temporal formula: {}".format(_tf.str_location(atom.location)))
                        self.visit(element.condition)
                    atom.term = self.__term_transformer.visit(atom.term, False, True, True, self.__max_shift)
            elif atom.term.name == "initial":
                atom = wrap(atom.location, _ast.SymbolicAtom(_ast.Function(atom.location, "__initial", [time(atom.location)], False)))
            elif atom.term.name == "final":
                atom = wrap(atom.location, _ast.SymbolicAtom(_ast.Function(atom.location, "__final", [time(atom.location)], False)))
            elif atom.term.name == "true":
                atom = wrap(atom.location, _ast.BooleanConstant(True))
            elif atom.term.name == "false":
                atom = wrap(atom.location, _ast.BooleanConstant(False))
        return atom
예제 #10
0
파일: head.py 프로젝트: susuhahnml/telingo
    def visit_Symbol(self, x, positive):
        """
        Maps functions to atoms.

        Every other symbol causes a runtime error.

        Arguments:
        x        -- The theory term to translate.
        positive -- The classical sign of the atom.
        """
        symbol = x.symbol
        if x.symbol.type == _clingo.SymbolType.Function and len(
                symbol.name) > 0:
            return self.__atom(
                x.location, positive == symbol.positive, symbol.name,
                [_ast.Symbol(x.location, a) for a in symbol.arguments])
        else:
            raise RuntimeError(
                "invalid temporal formula in rule head: {}".format(
                    _tf.str_location(x.location)))
예제 #11
0
    def _rewrite_tuple(self, element, number):
        """
        Add variables to tuple to ensure multiset semantics.
        """
        if len(element.tuple) != 1:
            raise RuntimeError("Invalid Syntax")

        in_condition = collect_variables(element.condition)
        for name in collect_variables(element.tuple):
            if name in in_condition:
                del in_condition[name]

        element.tuple = list(element.tuple)
        if number is not None:
            element.tuple.append(
                ast.Symbol(element.tuple[0].location, clingo.Number(number)))
        element.tuple.extend(in_condition[name]
                             for name in sorted(in_condition))

        return element
예제 #12
0
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
예제 #13
0
파일: head.py 프로젝트: susuhahnml/telingo
def time_parameter(loc):
    return _ast.Symbol(loc, _clingo.Function(_tf.g_time_parameter_name))
예제 #14
0
파일: term.py 프로젝트: susuhahnml/telingo
    def __get_param(self, name, arity, location, replace_future, fail_future,
                    fail_past, max_shift):
        """
        Strips previous and next operators from function names
        and returns the updated name plus the time arguments to append.
        Furthermore, if the initially operator (_ prefix) is used, then the
        time parameter is replaced with 0. Otherwise, it is treated like a past
        operator.

        If replace_future is set this also introduces a new name for the
        predicate, which is recorded in the list of atoms that have to be made
        redefinable. In this case the name is prefixed with __future_. Such
        dynamic predicates are recorded in the future_predicates list.

        Arguments:
        name           -- The name of the predicate
                          (trailing primes denote previous operators).
        location       -- Location for generated terms.
        replace_future -- Whether atoms referring to the future have to be
                          replaced by a special future atom.
        fail_future    -- Fail if the atom refers to the future.
        fail_past      -- Fail if the atom refers to the past.
        max_shift      -- The maximum number of steps terms look into the
                          future.

        Example for body atoms:

            p(X) :- 'q(X)

        becomes

            p(X,t) :- q(X,t-1)

        Example for head atoms (replace_future=True):

            p''(X) :- q(X).

        becomes

            __future__p(X,2,t) :- q(X,t).

        and future_predicates is extended with (p,1,2) -> False
        """
        n = name.strip("'")
        shift = 0
        for c in name:
            if c == "'":
                shift -= 1
            else:
                break
        shift += len(name) - len(n) + shift

        initially = False
        if n.startswith("_") and not n.startswith("__"):
            n = n[1:]
            if n.startswith("'") or name.startswith("'") or name.endswith("'"):
                raise RuntimeError(
                    "initially operator cannot be used with primes: {}".format(
                        _tf.str_location(location)))
            initially = True

        finally_ = False
        if n.endswith("_") and not n.endswith("__"):
            n = n[:-1]
            if n.endswith("'") or name.startswith("'") or name.endswith("'"):
                raise RuntimeError(
                    "finally operator cannot be used with primes: {}".format(
                        _tf.str_location(location)))
            finally_ = True
            raise RuntimeError("finally operator not yet supported: {}".format(
                _tf.str_location(location)))

        if initially and finally_:
            raise RuntimeError(
                "finally and initially operator cannot used together: {}".
                format(_tf.str_location(location)))

        params = [
            _ast.Symbol(location, _clingo.Function(_tf.g_time_parameter_name))
        ]
        if fail_future and (shift > 0 or finally_):
            raise RuntimeError(
                "future atoms not supported in this context: {}".format(
                    _tf.str_location(location)))
        if fail_past and (shift < 0 or initially):
            raise RuntimeError(
                "past atoms not supported in this context: {}".format(
                    _tf.str_location(location)))
        if shift > 0:
            if replace_future:
                self.__future_predicates.add(
                    (n, arity, self.__positive, shift))
                n = _tf.g_future_prefix + n
                params.insert(0, _ast.Symbol(location, shift))
            else:
                max_shift[0] = max(max_shift[0], shift)
        if shift != 0:
            params[-1] = _ast.BinaryOperation(location,
                                              _ast.BinaryOperator.Plus,
                                              params[-1],
                                              _ast.Symbol(location, shift))
        elif initially:
            params[-1] = _ast.Symbol(location, 0)
        return (n, params)