Esempio n. 1
0
 def __init__(self, name, *args):
     assert isinstance(name, str)
     assert re.match('[a-zA-Z][a-zA-Z_]*$', name),\
         'invalid name: {0}'.format(name)
     args = list(args)
     arity = signature.get_arity(name)
     assert len(args) == signature.get_nargs(arity)
     for arg in args:
         assert isinstance(arg, Expression), arg
     self._name = name
     self._args = args
     self._arity = arity
     self._polish = ' '.join([name] + [arg._polish for arg in args])
     self._hash = hash(self._polish)
     if arity == 'Variable':
         self._var = self
         self._vars = set([self])
     elif arity == 'NullaryFunction':
         self._var = Expression(name + '_')
         self._vars = set()
     elif arity in [
             'InjectiveFunction',
             'BinaryFunction',
             'SymmetricFunction',
     ]:
         var = re.sub('[ _]+', '_', self.polish).rstrip('_')
         self._var = Expression(var)
         self._vars = union(arg.vars for arg in args)
     else:
         self._var = None
         self._vars = union(arg.vars for arg in args)
Esempio n. 2
0
 def vars(self):
     if self._vars is None:
         if self._arity == 'Variable':
             self._vars = set([self])
         elif self._arity == 'NullaryFunction':
             self._vars = set()
         elif self._arity in signature.FUNCTION_ARITIES:
             self._vars = union(a.vars for a in self._args)
         else:
             self._vars = union(a.vars for a in self._args)
         self._vars = sortedset(self._vars)
     return self._vars
Esempio 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
Esempio n. 4
0
 def terms(self):
     if self._terms is None:
         self._terms = union(a.terms for a in self._args)
         if self.is_term():
             self._terms.add(self)
         self._terms = sortedset(self._terms)
     return self._terms
Esempio n. 5
0
 def consts(self):
     if self._consts is None:
         if self.is_fun() and not self._args:
             self._consts = sortedset([self])
         else:
             self._consts = sortedset(union(a.consts for a in self._args))
     return self._consts
Esempio n. 6
0
def get_events(seq):
    events = set()
    if seq.optional:
        logger('skipped optional rule {}', seq)
        return events
    free_vars = seq.vars
    for sequent in normalize(seq):
        for antecedent in sequent.antecedents:
            if antecedent.name == 'EQUAL':
                lhs, rhs = antecedent.args
                assert lhs.is_var() and rhs.is_var(), antecedent
                # HACK ignore equation antecedents
            else:
                events.add(antecedent)
        # HACK to deal with Equation args
        succedent = iter(sequent.succedents).next()
        for arg in succedent.args:
            if not arg.is_var():
                events.add(arg)
        antecedent_vars = union(a.vars for a in sequent.antecedents)
        for var in succedent.vars & free_vars - antecedent_vars:
            compound_count = sum(1 for arg in succedent.args if arg.args)
            in_count = sum(1 for arg in succedent.args if var in arg.vars)
            # if the var is in a compound in both succedent.args,
            # then succedent.args are sufficient events.
            if in_count < 2 or compound_count < 2:
                events.add(var)
    return events
Esempio n. 7
0
def get_pointed(seq):
    '''
    Return a set of sequents each with a single succedent.
    '''
    result = set()
    if len(seq.succedents) == 1:
        for succedent in seq.succedents:
            if succedent.name != 'OPTIONALLY':
                result.add(seq)
    elif len(seq.succedents) > 1:
        for succedent in seq.succedents:
            remaining = set_without(seq.succedents, succedent)
            negated = union(map(get_negated, remaining))
            # FIXME get_negated is a disjunction; do not union it
            neg_neg = union(map(get_negated, seq.antecedents))
            if not (negated & neg_neg):
                antecedents = seq.antecedents | negated
                result.add(Sequent(antecedents, set([succedent])))
    else:
        TODO('allow empty succedents')
    return result
Esempio n. 8
0
def simplify_step(completed):
    terms = union(p.terms for p in completed)

    def step(fact_sets):
        result = fact_sets.copy()
        for facts in fact_sets:
            for fact in facts:
                for simple in weaken_facts(facts, fact):
                    frozen = frozenset(simple)
                    if frozen not in result:
                        if complete(simple, terms) == completed:
                            result.add(frozen)
        return result

    return step
Esempio n. 9
0
def complete(facts, terms=set()):
    terms = terms | union(p.terms for p in facts) | set([BOT, TOP])
    relevant_facts = set(p for p in basic_facts if p.terms <= terms)
    return close_under(facts, complete_step(terms, relevant_facts))
Esempio n. 10
0
 def vars(self):
     return union(s.vars for s in self.antecedents | self.succedents)
Esempio n. 11
0
 def consts(self):
     return union(s.consts for s in self.antecedents | self.succedents)
Esempio n. 12
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)
Esempio n. 13
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
Esempio n. 14
0
 def consts(self):
     if self.is_fun() and not self.args:
         return set([self])
     else:
         return union([arg.consts for arg in self.args])