Ejemplo n.º 1
0
def weaken_facts(facts, fact):
    assert fact in facts
    if fact.is_rel():
        without = set_without(facts, fact)
        yield without
        if fact.name == 'EQUAL':
            lhs, rhs = fact.args
            yield set_with(without, LESS(lhs, rhs))
            yield set_with(without, LESS(rhs, lhs))
Ejemplo n.º 2
0
 def validate(self, bound):
     assert self.value in bound
     if self.lhs_fixed:
         assert_in(self.var1, bound)
         assert_not_in(self.var2, bound)
         self.body.validate(set_with(bound, self.var2))
     else:
         assert_in(self.var2, bound)
         assert_not_in(self.var1, bound)
         self.body.validate(set_with(bound, self.var1))
Ejemplo n.º 3
0
def get_inverses(sequent):
    '''
    Given a sequent A |- B, return set of sequents ~A |- ~B,
    dealing with multiple antecedents and succedents. For example

        A, B |- C, D

    yields the set

        A, ~B |- ~C, ~D
        ~A, B |- ~C, ~D
    '''
    result = set()
    neg_succedents = union(try_get_negated(s) for s in sequent.succedents)
    pos_antecedents = set(sequent.antecedents)
    for pos_antecedent in pos_antecedents:
        try:
            negated = try_get_negated(pos_antecedent)
        except NotNegatable:
            negated = set()
        for neg_antecedent in negated:
            neg_antecedents = set_without(pos_antecedents, pos_antecedent)
            neg_antecedents = set_with(neg_antecedents, neg_antecedent)
            result.add(Sequent(neg_antecedents, neg_succedents))
    return result
Ejemplo n.º 4
0
def normalize_given(seq, atom, bound):
    for normal in normalize(seq):
        if atom in normal.antecedents or atom.is_var():
            yield normal
        # HACK to deal with Equation args
        succedent = iter(normal.succedents).next()
        if succedent.name == 'EQUAL':
            lhs, rhs = succedent.args
            if lhs == atom:
                yield Sequent(
                    set_with(normal.antecedents, lhs),
                    set([Expression('EQUAL', lhs.var, rhs)]))
            elif rhs == atom:
                yield Sequent(
                    set_with(normal.antecedents, rhs),
                    set([Expression('EQUAL', lhs, rhs.var)]))
Ejemplo n.º 5
0
 def validate(self, bound):
     assert_not_in(self.var, bound)
     bound = set_with(bound, self.var)
     for test in self.tests:
         assert_subset(test.vars, bound)
     for var, expr in self.lets.iteritems():
         assert_subset(expr.vars, bound)
         assert_not_in(var, bound)
     self.body.validate(bound)
Ejemplo n.º 6
0
def compile_solver(expr, theory):
    '''
    Produces a set of programs that finds values of term satisfying a theory.
    Inputs:
        expr - string, an expression with free variables
        theory - string representing a theory (in .theory format)
    Outputs:
        a program to be consumed by the virtual machine
    Example:
        expr = 's'
        theory = """
            # 6 constraints = 4 facts + 2 rules
            LESS APP V s s       NLESS x BOT      NLESS x I
            LESS APP s BOT BOT   --------------   ----------------
            EQUAL APP s I I      LESS I APP s x   LESS TOP APP s x
            LESS TOP APP s TOP
            """
    '''
    assert isinstance(expr, basestring), expr
    assert isinstance(theory, basestring), theory
    expr = desugar_expr(parse_string_to_expr(expr))
    assert expr.vars, expr
    theory = parse_theory_string(theory)
    facts = map(desugar_expr, theory['facts'])
    rules = map(desugar_sequent, theory['rules'])
    sequents = []
    can_infer_necessary = not rules and all(f.vars <= expr.vars for f in facts)
    can_infer_possible = expr.is_var()  # TODO generalize to injective exprs
    if can_infer_necessary:
        sequents.append(Sequent(facts, [NONEGATE(RETURN(expr))]))
    if can_infer_possible:
        fail = NONEGATE(NRETURN(expr))
        sequents += [Sequent([], [f, fail]) for f in facts]
        sequents += [
            Sequent(r.antecedents, set_with(r.succedents, fail))
            for r in rules
        ]
    assert sequents, 'Cannot infer anything'
    programs = []
    write_full_programs(programs, sequents, can_parallelize=False)
    program = '\n'.join(programs)
    assert not re.search('FOR_BLOCK', program), 'cannot parallelize'
    return program
Ejemplo n.º 7
0
def get_contrapositives(seq):
    if len(seq.succedents) == 1:
        seq_succedent = iter(seq.succedents).next()
        result = set()
        for antecedent in seq.antecedents:
            if antecedent.name != 'OPTIONALLY':
                antecedents = set_without(seq.antecedents, antecedent)
                succedents = get_negated(antecedent)
                for disjunct in get_negated(seq_succedent):
                    if get_negated(disjunct) & antecedents:
                        pass  # contradiction
                    else:
                        result.add(Sequent(
                            set_with(antecedents, disjunct),
                            succedents))
        return result
    elif len(seq.succedents) > 1:
        TODO('allow multiple succedents')
    else:
        TODO('allow empty succedents')
Ejemplo n.º 8
0
 def validate(self, bound):
     assert_subset(self.expr.vars, bound)
     assert_not_in(self.var, bound)
     self.body.validate(set_with(bound, self.var))
Ejemplo n.º 9
0
 def validate(self, bound):
     assert_in(self.value, bound)
     assert_not_in(self.var1, bound)
     assert_not_in(self.var2, bound)
     self.body.validate(set_with(bound, self.var1, self.var2))
Ejemplo n.º 10
0
def optimize_plan(antecedents, succedent, bound):
    """Iterate through the space of plans, narrowing heuristically."""
    assert isinstance(antecedents, sortedset)
    assert isinstance(succedent.consts, sortedset)

    # ensure
    if not antecedents and succedent.vars <= bound:
        POMAGMA_DEBUG('ensure {}', succedent)
        return Ensure.make(succedent)

    # conditionals
    # HEURISTIC test eagerly in arbitrary order
    for a in antecedents:
        if a.is_rel():
            if a.vars <= bound:
                antecedents_a = sortedset(set_without(antecedents, a))
                POMAGMA_DEBUG('test relation {}', a)
                body = optimize_plan(antecedents_a, succedent, bound)
                return Test.make(a, body)
        else:
            assert a.is_fun(), a
            if a.vars <= bound and a.var in bound:
                antecedents_a = sortedset(set_without(antecedents, a))
                POMAGMA_DEBUG('test function {}', a)
                body = optimize_plan(antecedents_a, succedent, bound)
                return Test.make(a, body)

    # find & bind variable
    # HEURISTIC bind eagerly in arbitrary order
    for a in antecedents:
        if a.is_fun():
            if a.vars <= bound:
                assert a.var not in bound
                antecedents_a = sortedset(set_without(antecedents, a))
                bound_a = set_with(bound, a.var)
                POMAGMA_DEBUG('let {}', a)
                body = optimize_plan(antecedents_a, succedent, bound_a)
                return Let.make(a, body)
            else:
                # TODO find inverse if injective function
                pass

    results = []

    # iterate unknown
    if succedent.is_rel() and succedent.name != 'EQUAL':  # TODO handle EQUAL
        s_free = succedent.vars - bound
        if len(succedent.vars) == len(succedent.args) and len(s_free) == 1:
            v = iter(s_free).next()
            bound_v = set_with(bound, v)
            POMAGMA_DEBUG('iterate unknown {}', v)
            body = optimize_plan(antecedents, succedent, bound_v)
            results.append(Iter.make(v, Test.make(UNKNOWN(succedent), body)))

    # iterate forward
    forward_vars = set()
    for a in antecedents:
        a_free = a.vars - bound
        if len(a_free) == 1:
            forward_vars |= a_free
    for v in forward_vars:
        bound_v = set_with(bound, v)
        POMAGMA_DEBUG('iterate forward {}', v)
        body = optimize_plan(antecedents, succedent, bound_v)
        results.append(Iter.make(v, body))

    # iterate backward
    for a in antecedents:
        if a.is_fun() and a.args and a.var in bound and not (a.vars <= bound):
            nargs = len(a.args)
            a_free = a.vars - bound
            bound_v = bound | a_free
            antecedents_a = sortedset(set_without(antecedents, a))
            assert len(a_free) in [0, 1, 2]
            assert nargs in [0, 1, 2]
            POMAGMA_DEBUG('iterate backward {}', a)
            if nargs == 1 and len(a_free) == 1:
                # TODO injective function inverse need not be iterated
                body = optimize_plan(antecedents_a, succedent, bound_v)
                results.append(IterInvInjective.make(a, body))
            elif nargs == 2 and len(a_free) == 1 and len(a.vars) == 2:
                (fixed,) = list(a.vars - a_free)
                body = optimize_plan(antecedents_a, succedent, bound_v)
                results.append(IterInvBinaryRange.make(a, fixed, body))
            elif nargs == 2 and len(a_free) == 2:
                body = optimize_plan(antecedents_a, succedent, bound_v)
                results.append(IterInvBinary.make(a, body))

    # HEURISTIC iterate locally eagerly
    if results:
        return min(results)

    # iterate anything
    for v in union(a.vars for a in antecedents) | succedent.vars - bound:
        bound_v = set_with(bound, v)
        POMAGMA_DEBUG('iterate non-locally')
        body = optimize_plan(antecedents, succedent, bound_v)
        results.append(Iter.make(v, body))

    return min(results)
Ejemplo n.º 11
0
def get_bound(atom):
    if atom.is_fun():
        return set_with(atom.vars, atom.var)
    else:
        return atom.vars
Ejemplo n.º 12
0
def get_compiled(antecedents, succedent, bound):
    '''
    Iterate through the space of strategies, narrowing heuristically.
    '''
    POMAGMA_DEBUG('{} | {} |- {}', list(bound), list(antecedents), succedent)

    if not antecedents and succedent.vars <= bound:
        POMAGMA_DEBUG('ensure')
        return [Ensure(succedent)]

    results = []

    # bind succedent constants
    for c in succedent.consts:
        if c.var not in bound:
            bound_c = set_with(bound, c.var)
            POMAGMA_DEBUG('bind succedent constant')
            for s in get_compiled(antecedents, succedent, bound_c):
                results.append(Let(c, s))
            return results  # HEURISTIC bind eagerly in arbitrary order

    # bind antecedent constants
    for a in antecedents:
        if not a.args and a.var not in bound:
            assert a.is_fun(), a
            antecedents_a = set_without(antecedents, a)
            bound_a = set_with(bound, a.var)
            POMAGMA_DEBUG('bind antecedent constant')
            for s in get_compiled(antecedents_a, succedent, bound_a):
                results.append(Let(a, s))
            return results  # HEURISTIC bind eagerly in arbitrary order

    # conditionals
    for a in antecedents:
        # if a.name in ['LESS', 'NLESS']:
        if a.is_rel():
            if a.vars <= bound:
                antecedents_a = set_without(antecedents, a)
                POMAGMA_DEBUG('conditional')
                for s in get_compiled(antecedents_a, succedent, bound):
                    results.append(Test(a, s))
        else:
            assert a.is_fun(), a
            if a.vars <= bound and a.var in bound:
                antecedents_a = set_without(antecedents, a)
                POMAGMA_DEBUG('conditional')
                for s in get_compiled(antecedents_a, succedent, bound):
                    results.append(Test(a, s))
        if results:
            return results  # HEURISTIC test eagerly in arbitrary order

    # find & bind variable
    for a in antecedents:
        if a.is_fun():
            if a.vars <= bound:
                assert a.var not in bound
                antecedents_a = set_without(antecedents, a)
                bound_a = set_with(bound, a.var)
                POMAGMA_DEBUG('bind variable')
                for s in get_compiled(antecedents_a, succedent, bound_a):
                    results.append(Let(a, s))
            else:
                # TODO find inverse if injective function
                pass
        if results:
            return results  # HEURISTIC bind eagerly in arbitrary order

    # iterate forward
    for a in antecedents:
        # works for both Relation and Function antecedents
        if a.vars & bound:
            for v in a.vars - bound:
                bound_v = set_with(bound, v)
                POMAGMA_DEBUG('iterate forward')
                for s in get_compiled(antecedents, succedent, bound_v):
                    results.append(Iter(v, s))

    # iterate backward
    for a in antecedents:
        if a.is_fun() and a.var in bound:
            a_vars = a.vars
            a_free = a_vars - bound
            assert len(a_free) in [0, 1, 2]
            nargs = len(a.args)
            assert nargs in [0, 1, 2]
            if nargs and a_free:
                bound_v = bound | a_free
                antecedents_a = set(antecedents)
                antecedents_a.remove(a)
                POMAGMA_DEBUG('iterate backward')
                if nargs == 1 and len(a_free) == 1:
                    # TODO injective function inverse need not be iterated
                    for s in get_compiled(antecedents_a, succedent, bound_v):
                        results.append(IterInvInjective(a, s))
                elif nargs == 2 and len(a_free) == 1 and len(a_vars) == 2:
                    for s in get_compiled(antecedents_a, succedent, bound_v):
                        (fixed,) = list(a.vars - a_free)
                        results.append(IterInvBinaryRange(a, fixed, s))
                elif nargs == 2 and len(a_free) == 2:
                    for s in get_compiled(antecedents_a, succedent, bound_v):
                        results.append(IterInvBinary(a, s))

    if results:
        return results  # HEURISTIC iterate locally eagerly

    # iterate anything
    free = (union([a.vars for a in antecedents]) | succedent.vars - bound)
    for v in free:
        bound_v = set_with(bound, v)
        POMAGMA_DEBUG('iterate non-locally')
        for s in get_compiled(antecedents, succedent, bound_v):
            results.append(Iter(v, s))

    assert results
    return results