Esempio n. 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
Esempio n. 2
0
    def transform(self, atom):
        loc          = atom.location
        false        = self.__false_atom(loc)
        atom, ranges = transform_theory_atom(atom)
        variables    = get_variables(atom)
        param        = time_parameter(loc)
        shift        = _ast.Variable(loc, g_tel_shift_variable)
        aux          = self.__aux_atom(loc, variables + [param])
        saux         = self.__aux_atom(loc, variables + [shift], inc=0)
        rules        = []

        if self.__false_external is None:
            rules.append(_tf.External(loc, false.atom, []))

        rules.append(_ast.Rule(loc, atom, [aux]))

        if ranges:
            elems = []
            for (lhs, rhs), heads in ranges:
                cond = []
                diff = _ast.BinaryOperation(loc, _ast.BinaryOperator.Minus, param, shift)
                if lhs.ast_type != _ast.ASTType.SymbolicTerm or lhs.symbol.type != _clingo.SymbolType.Number or lhs.symbol.number > 0:
                    cond.append(_ast.Literal(loc, _ast.Sign.NoSign, _ast.Comparison(_ast.ComparisonOperator.LessEqual, lhs, diff)))

                if rhs.ast_type != _ast.ASTType.SymbolicTerm or rhs.symbol.type != _clingo.SymbolType.Supremum:
                    cond.append(_ast.Literal(loc, _ast.Sign.NoSign, _ast.Comparison(_ast.ComparisonOperator.LessEqual, diff, rhs)))

                elems.extend([_ast.ConditionalLiteral(loc, _ast.Literal(loc, _ast.Sign.NoSign, head), cond) for head in heads])

            rules.append(_ast.Rule(loc, _ast.Disjunction(loc, elems), [saux, false]))

        return aux, rules
Esempio n. 3
0
    def visit_Rule(self, rule):
        """
        Sets the state flags when visiting a rule.

        After that the head and body of the rule are visited in the right context.
        """
        try:
            self.__head = True
            self.__max_shift = [0]
            self.__constraint = _tf.is_constraint(rule)
            self.__normal = _tf.is_normal(rule)
            rule.head = self.visit(rule.head)
            self.__head = False
            rule.body = self.visit(rule.body)
            if self.__max_shift[0] > 0 and not self.__final:
                last = _ast.Rule(rule.location, rule.head, rule.body[:])
                self.__append_final(rule, _clingo.Function(_tf.g_time_parameter_name_alt))
                self.__constraint_parts.setdefault((self.__part, self.__max_shift[0]), []).append((rule, last))
                return None
        finally:
            self.__head        = False
            self.__max_shift   = [0]
            self.__constraint  = False
            self.__normal = False
        return rule
Esempio n. 4
0
    def visit_Rule(self, rule):
        """
        Shift constraints in integrity constraints and visit head/body
        literals.
        """
        # Note: This implements clingcon's don't care propagation. We can shift
        # one constraint from the body of an integrity constraint to the head
        # of a rule. This way the constraint is no longer strict and can be
        # represented internally with less constraints.
        head = rule.head
        body = rule.body
        if self._shift and head.type == ast.ASTType.Literal and head.atom.type == ast.ASTType.BooleanConstant and not head.atom.value:
            for literal in body:
                if literal.type == ast.ASTType.Literal and literal.atom.type == ast.ASTType.TheoryAtom:
                    atom = literal.atom
                    term = atom.term
                    if term.name in [
                            "sum", "diff", "in", "max", "min", "count"
                    ] and not term.arguments:
                        body = copy(body)
                        body.remove(literal)
                        if literal.sign != ast.Sign.Negation:
                            atom = copy(atom)
                            atom.guard = copy(atom.guard)
                            atom.guard.operator_name = _negate_relation(
                                atom.guard.operator_name)
                        head = atom
                        break

        # tag heads and bodies
        head = self.visit(head, loc="head")
        body = self.visit(body, loc="body")

        return ast.Rule(rule.location, head, body)
Esempio n. 5
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
Esempio n. 6
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
Esempio n. 7
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
Esempio n. 8
0
    def _convert_rule(self, head, body):
        """
        Converts the LPMLN rule using either the unsat atoms
        or the simplified approach without them (default setting)
        """
        loc = head.location
        idx, constraint_weight, priority = self._get_constraint_parameters(loc)

        # Choice rules without bound can be skipped
        if str(head.ast_type) == 'ASTType.Aggregate':
            if head.left_guard is None and head.right_guard is None:
                return [ast.Rule(loc, head, body)]
            else:
                not_head = ast.Literal(loc, ast.Sign.Negation, head)

        else:
            not_head = ast.Literal(loc, ast.Sign.Negation, head.atom)

        # Create ASP rules
        # TODO: Better way to insert and delete items from body?
        if self.use_unsat:
            unsat, not_unsat = self._get_unsat_atoms(loc, idx)
            # Rule 1 (unsat :- Body, not Head)
            body.insert(0, not_head)
            asp_rule1 = ast.Rule(loc, unsat, body)

            # Rule 2 (Head :- Body, not unsat)
            del body[0]
            body.insert(0, not_unsat)
            asp_rule2 = ast.Rule(loc, head, body)

            # Rule 3 (weak constraint unsat)
            asp_rule3 = ast.Minimize(loc, constraint_weight, priority,
                                     [idx, self.global_variables], [unsat])
            return [asp_rule1, asp_rule2, asp_rule3]
        else:
            asp_rules = []
            # Choice rules with bounds, e.g. 'w : { a; b } = 1 :- B.'
            # get converted to two rules:
            # w : { a ; b } :- B.       --> { a ; b } :- B.
            # w : :- not { a ; b } = 1. --> :~ B, not {a ; b} = 1. [w,id, X]
            if str(head.ast_type) == 'ASTType.Aggregate':
                agg1 = ast.Aggregate(loc, None, head.elements, None)
                asp_rules.append(ast.Rule(loc, agg1, body))
                body.insert(0, not_head)
            # Convert integrity constraint 'w: #false :- B.' to weak constraint
            # of form: ':~ B. [w, idx, X]'
            elif str(head.atom.ast_type
                     ) == 'ASTType.BooleanConstant' and not head.atom.value:
                pass
            # Convert normal rule 'w: H :- B.' to choice rule and weak
            # constraint of form: '{H} :- B.' and ':~ B, not H. [w, idx, X]'
            else:
                cond_head = ast.ConditionalLiteral(loc, head, [])
                choice_head = ast.Aggregate(loc, None, [cond_head], None)
                asp_rules.append(ast.Rule(loc, choice_head, body))
                body.insert(0, not_head)

            # TODO: Should the two solve calls work with unsat as well?
            if self.two_solve_calls and str(priority) == '0':
                ext_helper_atom = ast.SymbolicAtom(
                    ast.Function(loc, 'ext_helper', [], False))
                ext_helper_atom = ast.Literal(loc, ast.Sign.NoSign,
                                              ext_helper_atom)
                body.insert(0, ext_helper_atom)

            weak_constraint = ast.Minimize(loc, constraint_weight, priority,
                                           [idx, self.global_variables], body)
            asp_rules.append(weak_constraint)
            return asp_rules