Example #1
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
Example #2
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
Example #3
0
def _translate_to_fired_holds(rule_ast, control, builder, t_option):
    """
    Translate the different possible xclingo rules their clingo version making use of 'fired_' and 'holds_' prefixes,
    then it adds them to the base program using the given builder object.
    Also it keep trace (inside the given control object) of the rule information that is necessary for computing the
    causes after the solving phase.

    @param ast.AST rule_ast: the AST from which the rules will be generated
    @param clingo.ProgramBuilder builder: builder of the clingo control object that will receive the generated rules.
    @param bool t_option: if enabled, the function will print the translated sentences but they will not be added to the
    builder.
    @return: None
    """
    rule_ast = XClingoAST(rule_ast)

    if rule_ast.type == ast.ASTType.Rule:

        # show_all rules, trace_all rules and constraints rules.
        if rule_ast.is_show_all_rule() or rule_ast.is_trace_all_rule(
        ) or rule_ast.is_constraint():
            if rule_ast['body']:
                rule_ast.add_prefix("holds_")
                translated_rule = str(rule_ast)
            else:
                translated_rule = str(rule_ast['head']) + "."

            generated_rules = translated_rule + "\n"
        else:  # Other cases
            rule_counter = control.count_rule()

            # Separates the &label literals in the body from the rest
            label_body, rest_body = _separate_labels_from_body(
                rule_ast['body'])
            # Binds the function in the head to a variable to simplify following code
            head_function = rule_ast['head'].get_function()

            # Keep trace of head, arguments and body of the rules using rule_counter
            fired_head_variables = list(map(str, head_function['arguments'])) + \
                                   list(set(map(str, body_variables(rule_ast['body']))) - set(map(str, head_function['arguments'])))

            control.traces[rule_counter] = {
                'head':
                (rule_ast['head']['atom']['term'].type !=
                 ast.ASTType.UnaryOperation, str(head_function['name']),
                 head_function['arguments']),
                'arguments':
                fired_head_variables,
                # 'body' contains pairs of function names and arguments found in the body
                'body':
                [(lit['atom']['term'].type != ast.ASTType.UnaryOperation,
                  lit.get_function()['name'], lit.get_function()['arguments'])
                 for lit in rest_body
                 if lit.type == ast.ASTType.Literal and lit['atom'].type ==
                 ast.ASTType.SymbolicAtom and lit['sign'] == ast.Sign.NoSign]
            }

            # Generates fired rule
            fired_head = "fired_{counter}({arguments})".format(
                counter=str(rule_counter),
                arguments=",".join(fired_head_variables))

            if rest_body:
                for a in rest_body:
                    a.add_prefix('holds_')
                fired_rule = "{fired_head} :- {body}.".format(
                    fired_head=fired_head, body=",".join(map(str, rest_body)))
            else:
                fired_rule = fired_head + "."

            # Generates label rules
            label_rules = ""
            for label_ast in label_body:
                label_rules += "&trace{{{fired_id},{original_head},{label_parameters}}} :- {body}.\n".format(
                    fired_id=str(rule_counter),
                    original_head=str(rule_ast['head']),
                    label_parameters=",".join(
                        [str(e) for e in label_ast['atom']['elements']]),
                    body=fired_head)

            # Generates holds rule
            rule_ast['head'].add_prefix('holds_')
            head_function['arguments'] = [
                ast.Variable(
                    v['location'], "Aux" +
                    str(head_function['arguments'].index(v._internal_ast)))
                for v in head_function['arguments']
            ]
            holds_rule = "{head} :- fired_{rule_counter}({fired_arguments}).".format(
                head=rule_ast['head'],
                rule_counter=rule_counter,
                fired_arguments=",".join([
                    "Aux" + str(i) for i in range(0, len(fired_head_variables))
                ]))

            # Generates a comment
            comment = "%" + str(rule_ast)

            generated_rules = comment + "\n" + fired_rule + "\n" + holds_rule + "\n" + label_rules

        _add_to_base(generated_rules, builder, t_option)