Example #1
0
    def isinstanceo_goal(S):
        nonlocal u, u_type

        u_rf, u_type_rf = reify((u, u_type), S)

        if not isground(u_rf, S) or not isground(u_type_rf, S):

            if not isinstance(S, ConstrainedState):
                S = ConstrainedState(S)

            cs = S.constraints.setdefault(IsinstanceStore, IsinstanceStore())

            try:
                cs.add(u_rf, u_type_rf)
            except TypeError:
                # If the instance object can't be hashed, we can simply use a
                # logic variable to uniquely identify it.
                u_lv = var()
                S[u_lv] = u_rf
                cs.add(u_lv, u_type_rf)

            if cs.post_unify_check(S.data, u_rf, u_type_rf):
                yield S

        # elif isground(u_type, S):
        #     yield from lany(eq(u_type, u_t) for u_t in type(u).mro())(S)
        elif (isinstance(u_type_rf, type)
              # or (
              #     isinstance(u_type, Iterable)
              #     and all(isinstance(t, type) for t in u_type)
              # )
              ) and isinstance(u_rf, u_type_rf):
            yield S
Example #2
0
    def typeo_goal(S):
        nonlocal u, u_type

        u_rf, u_type_rf = reify((u, u_type), S)

        if not isground(u_rf, S) or not isground(u_type_rf, S):

            if not isinstance(S, ConstrainedState):
                S = ConstrainedState(S)

            cs = S.constraints.setdefault(TypeStore, TypeStore())

            try:
                cs.add(u_rf, u_type_rf)
            except TypeError:
                # If the instance object can't be hashed, we can simply use a
                # logic variable to uniquely identify it.
                u_lv = var()
                S[u_lv] = u_rf
                cs.add(u_lv, u_type_rf)

            if cs.post_unify_check(S.data, u_rf, u_type_rf):
                yield S

        elif isinstance(u_type_rf, type) and type(u_rf) == u_type_rf:
            yield S
Example #3
0
    def post_unify_check(self,
                         lvar_map,
                         lvar=None,
                         value=None,
                         old_state=None):

        for lv_key, constraints in list(self.lvar_constraints.items()):

            lv = reify(lv_key, lvar_map)

            is_lv_ground = self.constraint_isground(lv, lvar_map) or isground(
                lv, lvar_map)

            if not is_lv_ground:
                # This constraint isn't ready to be checked
                continue

            # if is_lv_ground and not self.cterm_type_check(lv):
            #     self.lvar_constraints[lv_key]
            #     return False

            constraint_grps = groupby(lambda x: isground(x, lvar_map),
                                      reify(iter(constraints), lvar_map))

            constraints_unground = constraint_grps.get(False, ())
            constraints_ground = constraint_grps.get(True, ())

            if len(constraints_ground) > 0 and not all(
                    self.cparam_type_check(c) for c in constraints_ground):
                # Some constraint parameters aren't the correct type, so fail.
                # del self.lvar_constraints[lv_key]
                return False

            assert constraints_unground or constraints_ground

            if is_lv_ground and len(constraints_unground) == 0:

                if self.require_all_constraints and any(
                        not self.constraint_check(lv, t)
                        for t in constraints_ground):
                    return False
                elif not self.require_all_constraints and not any(
                        self.constraint_check(lv, t)
                        for t in constraints_ground):
                    return False

                # The instance and constraint parameters are all ground and the
                # constraint is satisfied, so, since nothing should change from
                # here on, we can remove the constraint.

                del self.lvar_constraints[lv_key]

        # Some types are unground, so we continue checking until they are
        return True
Example #4
0
def test_unground_lvars():
    a_lv, b_lv = var(), var()

    for ctor in (tuple, list, iter, set, frozenset):

        if ctor not in (set, frozenset):
            sub_ctor = list
        else:
            sub_ctor = tuple

        assert unground_lvars(ctor((1, 2)), {}) == set()
        assert unground_lvars(
            ctor((1, sub_ctor((a_lv, sub_ctor((b_lv, 2)), 3)))),
            {}) == {a_lv, b_lv}
        assert unground_lvars(
            ctor((1, sub_ctor((a_lv, sub_ctor((b_lv, 2)), 3)))),
            {a_lv: 4}) == {b_lv}
        assert (unground_lvars(
            ctor((1, sub_ctor((a_lv, sub_ctor((b_lv, 2)), 3)))), {
                a_lv: 4,
                b_lv: 5
            }) == set())

        assert isground(ctor((1, 2)), {})
        assert isground(ctor((1, a_lv)), {a_lv: 2})
        assert isground(ctor((a_lv, sub_ctor((b_lv, 2)), 3)), {
            a_lv: b_lv,
            b_lv: 1
        })

        assert not isground(ctor((1, a_lv)), {a_lv: b_lv})
        assert not isground(ctor((1, var())), {})
        assert not isground(
            ctor((1, sub_ctor((a_lv, sub_ctor((b_lv, 2)), 3)))), {})
        assert not isground(ctor((a_lv, sub_ctor((b_lv, 2)), 3)), {
            a_lv: b_lv,
            b_lv: var("c")
        })

    # Make sure that no composite elements are constructed within the
    # groundedness checks.
    class CounterList(list):
        constructions = 0

        def __new__(cls, *args, **kwargs):
            cls.constructions += 1
            return super().__new__(cls, *args, **kwargs)

    test_l = CounterList([1, 2, CounterList([a_lv, CounterList([4])])])

    assert CounterList.constructions == 3

    assert not isground(test_l, {})
    assert CounterList.constructions == 3

    assert unground_lvars(test_l, {}) == {a_lv}
Example #5
0
def ground_order_key(S, x):
    if isvar(x):
        return 2
    elif isground(x, S):
        return -1
    elif issubclass(type(x), ConsPair):
        return 1
    else:
        return 0
    def typeo_goal(S: ConstrainedState):
        nonlocal v, t

        v_rf, t_rf = reify((v, t), S)
        isground_all = [
            isground(reified_value, S) for reified_value in [v_rf, t_rf]
        ]
        if not all(isground_all):
            if not isground(t_rf, S):
                g = eq(type(v_rf), t_rf)
                yield from g(S)
            # TODO: What if v_rf is not yet grounded?
            else:
                # g = applyo(isinstance, v_rf, t_rf)
                yield S
        else:
            if type(v_rf) == t_rf:
                yield S
    def binopo_goal(S: ConstrainedState):
        nonlocal x, y, v, op

        uuid = str(uuid4())[:4]
        t = var("type_" + uuid)
        x_rf, y_rf, v_rf, op_rf = reify((x, y, v, op), S)
        isground_all = [
            isground(reified_value, S)
            for reified_value in [x_rf, y_rf, v_rf, op_rf]
        ]
        if not all(isground_all):
            # We can only fix one LV at a time
            if len([uv for uv in isground_all if uv is False]) == 1:
                # TODO: Revop the other vars
                if not isground(v_rf, S):
                    try:
                        g = lall(
                            isinstanceo(x_rf, t),
                            isinstanceo(y_rf, t),
                            isinstanceo(v_rf, t),
                            eq(op_rf(x_rf, y_rf), v_rf),
                        )
                    except Exception as e:
                        logger.debug(
                            "Got exception during binop with args {}: {}".
                            format([x_rf, y_rf, v_rf, op_rf], e))
                        return
                    yield from g(S)
        else:
            # TODO: Why isnt this covered by the `typeo` goal?
            try:
                g = lall(
                    isinstanceo(x_rf, t),
                    isinstanceo(y_rf, t),
                    isinstanceo(v_rf, t),
                    eq(op_rf(x_rf, y_rf), v_rf),
                )
            except Exception as e:
                logger.debug(
                    "Got exception during ungrounded binop with args {}: {}".
                    format([x_rf, y_rf, v_rf, op_rf], e))
                return
            yield from g(S)
Example #8
0
    def permuteo_goal(S):
        nonlocal a, b, default_ConsNull, inner_eq

        a_rf, b_rf = reify((a, b), S)

        # If the lengths differ, then fail
        a_len, b_len = length_hint(a_rf, -1), length_hint(b_rf, -1)
        if a_len > 0 and b_len > 0 and a_len != b_len:
            return

        if isinstance(a_rf, Sequence):

            a_type = type(a_rf)

            a_perms = permutations(a_rf)

            if no_ident:
                next(a_perms)

            if isinstance(b_rf, Sequence):

                b_type = type(b_rf)

                # Fail on mismatched types or straight equality (when
                # `no_ident` is enabled)
                if a_type != b_type or (no_ident and a_rf == b_rf):
                    return

                try:
                    # `a` and `b` are sequences, so let's see if we can pull out
                    # all the (hash-)equivalent elements.
                    # XXX: Use of this requires that the equivalence relation
                    # implied by `inner_eq` be a *superset* of `eq`.

                    cntr_a, cntr_b = Counter(a_rf), Counter(b_rf)
                    rdcd_a, rdcd_b = cntr_a - cntr_b, cntr_b - cntr_a

                    if len(rdcd_a) == len(rdcd_b) == 0:
                        yield S
                        return
                    elif len(rdcd_a) < len(cntr_a):
                        a_rf, b_rf = tuple(rdcd_a.elements()), b_type(
                            rdcd_b.elements())
                        a_perms = permutations(a_rf)

                except TypeError:
                    # TODO: We could probably get more coverage for this case
                    # by using `HashableForm`.
                    pass

                # If they're both ground and we're using basic unification,
                # then simply check that one is a permutation of the other and
                # be done.  No need to create and evaluate a bunch of goals in
                # order to do something that can be done right here.
                # Naturally, this assumes that the `isground` checks aren't
                # nearly as costly as all that other stuff.  If the gains
                # depend on the sizes of `a` and `b`, then we could do
                # `length_hint` checks first.
                if inner_eq == eq and isground(a_rf, S) and isground(b_rf, S):
                    if tuple(b_rf) in a_perms:
                        yield S
                        return
                    else:
                        # This has to be a definitive check, since we can only
                        # use the `a_perms` generator once; plus, we don't want
                        # to iterate over it more than once!
                        return

            yield from lany(inner_eq(b_rf, a_type(i)) for i in a_perms)(S)

        elif isinstance(b_rf, Sequence):

            b_type = type(b_rf)
            b_perms = permutations(b_rf)

            if no_ident:
                next(b_perms)

            yield from lany(inner_eq(a_rf, b_type(i)) for i in b_perms)(S)

        else:

            # None of the arguments are proper sequences, so state that one
            # should be and apply `permuteo` to that.

            a_itero_g = itero(a_rf,
                              nullo_refs=(b_rf, ),
                              default_ConsNull=default_ConsNull)

            for S_new in a_itero_g(S):
                a_new = reify(a_rf, S_new)
                a_type = type(a_new)
                a_perms = permutations(a_new)

                if no_ident:
                    next(a_perms)

                yield from lany(inner_eq(b_rf, a_type(i))
                                for i in a_perms)(S_new)