Exemple #1
0
def test_transpose():
    fol = _fol.Context()
    dvars = {'p': (0, 4), 'q': (0, 4), "p_cp": (0, 4)}
    fol.declare(**dvars)
    s = '(p = 1) \/ (p = 2) \/ (p = 4)'
    p_is_prime = fol.add_expr(s)
    s = '(p = 1) \/ (p = 3)'
    p_is_signature = fol.add_expr(s)
    p_to_q = {'p': 'q'}
    p_leq_q = fol.add_expr("p <= q")
    u_leq_p = fol.add_expr("p_cp <= p")
    p_leq_u = fol.add_expr("p <= p_cp")
    prm = lat.Parameters()
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_to_q = p_to_q
    prm.p_vars = {'p'}
    prm.q_vars = {'q'}
    prm.u_vars = {'p_cp'}
    prm.p_to_u = {'p': 'p_cp'}
    bab = cov._BranchAndBound(prm, fol)
    tau = cov._floor(
        p_is_signature, p_is_prime, bab, fol)
    s = 'p = 1 \/ p = 3'
    tau_ = fol.add_expr(s)
    assert tau == tau_
Exemple #2
0
def test_max_transpose():
    fol = _fol.Context()
    # `p'` serves as `u`
    dvars = {'p': (0, 4), 'q': (0, 4), "p_cp": (0, 4)}
    fol.declare(**dvars)
    s = '(p = 2) \/ (p = 4)'
    p_is_prime = fol.add_expr(s)
    s = '(p = 1) \/ (p = 3)'
    p_is_signature = fol.add_expr(s)
    p_to_q = {'p': 'q'}
    # we use intervals `0..p` as literals
    px = dict(p=dict(a='0', b='p'))
    qx = dict(p=dict(a='0', b='q'))
    u_leq_p = fol.add_expr("p_cp <= p")
    p_leq_u = fol.add_expr("p <= p_cp")
    p_leq_q = fol.add_expr("p <= q")
    p_eq_q = fol.add_expr("p = q")  # /\ (0 = 0)
    prm = lat.Parameters()
    prm._px = px
    prm._qx = qx
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_eq_q = p_eq_q
    prm.p_to_q = p_to_q
    prm.p_vars = {'p'}
    prm.q_vars = {'q'}
    prm.u_vars = {'p_cp'}
    prm.p_to_u = {'p': 'p_cp'}
    bab = cov._BranchAndBound(prm, fol)
    max_tau_x = cov._max_transpose(
        p_is_signature, p_is_prime, bab, fol)
    s = 'p = 3'
    max_tau_x_ = fol.add_expr(s)
    assert max_tau_x == max_tau_x_
Exemple #3
0
def test_cyclic_core_fixpoint_recursive():
    fol = _fol.Context()
    p_vars = dict(p=(0, 3))
    q_vars = dict(q=(0, 3))
    u_vars = dict(p_cp=(0, 3))
    fol.declare(**p_vars)
    fol.declare(**q_vars)
    fol.declare(**u_vars)
    p_eq_q = fol.to_bdd(r'p \in 0..3 /\ p = q')
    # 3
    # | |
    # 1 2
    # | |
    # 0
    leq = r'''
    # (* layer 1 *)
    \/ (p = 0  /\  q = 1)
    \/ (p = 0  /\  q = 2)
    # (* layer 2 *)
    \/ (p = 1  /\  q = 3)
    \/ (p = 2  /\  q = 3)
    # transitivity
    \/ (p = 0 /\ q = 3)
    # equality
    \/ (p = q /\ p \in 0..3)
    '''
    p_leq_q = fol.to_bdd(leq)
    u_leq_p = fol.to_bdd(leq.replace('p', 'p_cp').replace('q', 'p'))
    p_leq_u = fol.to_bdd(leq.replace('q', 'p_cp'))
    # bundle
    prm = Parameters()
    prm.p_vars = set(p_vars)
    prm.q_vars = set(q_vars)
    prm.u_vars = set(u_vars)
    #
    prm.p_to_q = dict(p='q')
    prm.q_to_p = dict(q='p')
    prm.p_to_u = dict(p='p_cp')
    #
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_eq_q = p_eq_q
    #
    x = fol.add_expr('p = 0')
    y = fol.add_expr(r'p \in 1..2')
    #
    path_cost = 0.0
    bab = cov._BranchAndBound(prm, fol)
    bab.upper_bound = cov._upper_bound(x, y, prm.p_leq_q, prm.p_to_q, fol)
    path_cost = 0.0
    mincovers = cov_enum._cyclic_core_fixpoint_recursive(
        x, y, path_cost, bab, fol)
    assert len(mincovers) == 2, mincovers
    mincovers_ = {fol.add_expr('p = 1'), fol.add_expr('p = 2')}
    assert mincovers == mincovers_, list(fol.pick_iter(mincovers))
Exemple #4
0
def test_branch_and_bound_class():
    fol = _fol.Context()
    prm = lat.Parameters()
    bab = cov._BranchAndBound(prm, fol)
    bab.lower_bound = 15
    with assert_raises(AssertionError):
        bab.upper_bound = 10
    bab.upper_bound = 20
    # only init for lower bound
    with assert_raises(AssertionError):
        bab.lower_bound = 17
    with assert_raises(AssertionError):
        bab.upper_bound = 10
    bab.upper_bound = 18
Exemple #5
0
def minimize(f, care, fol):
    """Compute minimal DNF of predicate `f` over integers.

    @param f: predicate over integer-valued variables
    @param care: care set as predicate over same variables
    @type f, care: BDD node
    @type fol: `omega.symbolic.fol.Context`

    @return: minimal covers as BDDs over parameters
    @rtype: set of BDD nodes
    """
    # reasons for permisiveness here:
    #
    # - enable inspecting env violations of assumption
    # - make errors visible
    # - use entire instantiation domain
    # - permit computing DNF for care set using same `fol.vars`
    # - tests
    if not cov._care_implies_type_hints(f, care, fol):
        log.warning('care set should imply type hints')
    # could let
    #     f &= care
    # but explicit is better.
    # Also, this permits working outside type hints.
    if not cov._f_implies_care(f, care, fol):
        log.warning('f should imply care set')
    if (f | ~care) == fol.true:
        log.warning('f covers care set, so trivial cover')
    log.info('---- branch and bound search ----')
    prm = lat.setup_aux_vars(f, care, fol)
    lat.setup_lattice(prm, fol)
    # covering problem
    fcare = f | ~care
    x = lat.embed_as_implicants(f, prm, fol)
    y = lat.prime_implicants(fcare, prm, fol)
    bab = cov._BranchAndBound(prm, fol)
    # initialize upper bound
    bab.upper_bound = cov._upper_bound(x, y, prm.p_leq_q, prm.p_to_q, fol)
    path_cost = 0.0
    mincovers = _cyclic_core_fixpoint_recursive(x, y, path_cost, bab, fol)
    # assert
    assert mincovers
    for cover in mincovers:
        cov.assert_is_a_cover_from_y(cover, y, f, prm, fol)
        low = care & ~f
        assert cov._none_covered(cover, low, prm, fol)
    log.info('==== branch and bound search ==== ')
    return mincovers
Exemple #6
0
def test_example_of_strong_reduction():
    """Computing all minimal covers for the counterexample."""
    # For now `cov.minimize` creates the primes etc in
    # a specific way, for a specific basis (orthotopes).
    # This example doesn't fit in that recipe,
    # so we rewrite some of the code in `minimize`.
    fol = _fol.Context()
    fol.to_bdd = fol.add_expr
    x_vars = dict(x=(0, 8))
    p_vars = dict(p=(0, 8))
    q_vars = dict(q=(0, 8))
    u_vars = dict(p_cp=(0, 8))
    fol.declare(**x_vars)
    fol.declare(**p_vars)
    fol.declare(**q_vars)
    fol.declare(**u_vars)
    p_eq_q = fol.to_bdd(r'p \in 0..8  /\  q \in 0..8  /\ p = q')
    leq = r'''
    # (* layer 1 *)
    \/ (p = 0  /\  q = 6)
    \/ (p = 0  /\  q = 7)
    \/ (p = 0  /\  q = 8)
    # (* layer 2 *)
    \/ (p = 6  /\  q = 2)
    \/ (p = 6  /\  q = 3)
    \/ (p = 7  /\  q = 3)
    \/ (p = 7  /\  q = 4)
    \/ (p = 8  /\  q = 4)
    \/ (p = 8  /\  q = 5)
    # (* layer 3 *)
    \/ (p = 2  /\  q = 1)
    \/ (p = 3  /\  q = 1)
    \/ (p = 4  /\  q = 1)
    \/ (p = 5  /\  q = 1)
    # transitivity
    \/ (p = 0 /\ q = 2)
    \/ (p = 0 /\ q = 3)
    \/ (p = 0 /\ q = 4)
    \/ (p = 0 /\ q = 5)
    \/ (p = 0 /\ q = 1)

    \/ (p = 6 /\ q = 1)
    \/ (p = 7 /\ q = 1)
    \/ (p = 8 /\ q = 1)
    # equality
    \/ (p = q /\ p \in 0..8 /\ q \in 0..8)
    '''
    p_leq_q = fol.to_bdd(leq)
    u_leq_p = fol.to_bdd(leq.replace('p', 'p_cp').replace('q', 'p'))
    p_leq_u = fol.to_bdd(leq.replace('q', 'p_cp'))
    # bundle
    prm = Parameters()
    prm.x_vars = set(x_vars)
    prm.p_vars = set(p_vars)
    prm.q_vars = set(q_vars)
    prm.u_vars = set(u_vars)
    #
    prm.p_to_q = dict(p='q')
    prm.q_to_p = dict(q='p')
    prm.p_to_u = dict(p='p_cp')
    #
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_eq_q = p_eq_q
    #
    x = fol.add_expr(r'p \in 6..8')
    y = fol.add_expr(r'p \in 2..5')
    #
    path_cost = 0.0
    bab = cov._BranchAndBound(prm, fol)
    bab.upper_bound = cov._upper_bound(x, y, prm.p_leq_q, prm.p_to_q, fol)
    path_cost = 0.0
    mincovers = cov_enum._cyclic_core_fixpoint_recursive(
        x, y, path_cost, bab, fol)
    # enumerative check
    enumerated_covers(x, y, prm, fol)
    print('all minimal covers:')
    cov_enum._print_mincovers(mincovers, fol)
    # assert set of minimal covers is as expected
    assert len(mincovers) == 3, mincovers
    mincovers_t = set()
    for cover in mincovers:
        c = set()
        for d in fol.pick_iter(cover):
            r, = d.values()
            c.add(r)
        c = tuple(sorted(c))
        mincovers_t.add(c)
    mincovers_t_ = {(2, 4), (3, 4), (3, 5)}
    assert mincovers_t == mincovers_t_, (mincovers_t, mincovers_t_)
def test_counterexample_to_strong_reduction():
    """Not all minimal solutions can be recovered.

    This counterexample shows that the minimal covering
    algorithm does not ensure strong reduction.
    The reason is that the minimal cover before
    unfloors has max floors elements that are
    incomparable to some elements from which we
    could build alternative minimal covers.
    """
    # For now `cov.minimize` creates the primes etc in
    # a specific way, for a specific basis.
    # This example doesn't fit in that recipe,
    # so we rewrite some of the code in `minimize`.
    fol = _fol.Context()
    fol.to_bdd = fol.add_expr
    x_vars = dict(x=(0, 8))
    p_vars = dict(p=(0, 8))
    q_vars = dict(q=(0, 8))
    u_vars = dict(p_cp=(0, 8))
    fol.declare(**x_vars, **p_vars, **q_vars, **u_vars)
    p_eq_q = fol.to_bdd(r'p \in 0..8  /\  q \in 0..8  /\ p = q')
    leq = r'''
    # (* layer 1 *)
    \/ (p = 0  /\  q = 6)
    \/ (p = 0  /\  q = 7)
    \/ (p = 0  /\  q = 8)
    # (* layer 2 *)
    \/ (p = 6  /\  q = 2)
    \/ (p = 6  /\  q = 3)
    \/ (p = 7  /\  q = 3)
    \/ (p = 7  /\  q = 4)
    \/ (p = 8  /\  q = 4)
    \/ (p = 8  /\  q = 5)
    # (* layer 3 *)
    \/ (p = 2  /\  q = 1)
    \/ (p = 3  /\  q = 1)
    \/ (p = 4  /\  q = 1)
    \/ (p = 5  /\  q = 1)
    # transitivity
    \/ (p = 0 /\ q = 2)
    \/ (p = 0 /\ q = 3)
    \/ (p = 0 /\ q = 4)
    \/ (p = 0 /\ q = 5)
    \/ (p = 0 /\ q = 1)

    \/ (p = 6 /\ q = 1)
    \/ (p = 7 /\ q = 1)
    \/ (p = 8 /\ q = 1)
    # equality
    \/ (p = q /\ p \in 0..8 /\ q \in 0..8)
    '''
    p_leq_q = fol.to_bdd(leq)
    u_leq_p = fol.to_bdd(leq.replace('p', 'p_cp').replace('q', 'p'))
    p_leq_u = fol.to_bdd(leq.replace('q', 'p_cp'))
    # bundle
    prm = Parameters()
    prm.x_vars = set(x_vars)
    prm.p_vars = set(p_vars)
    prm.q_vars = set(q_vars)
    prm.u_vars = set(u_vars)
    #
    prm.p_to_q = dict(p='q')
    prm.q_to_p = dict(q='p')
    prm.p_to_u = dict(p='p_cp')
    #
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_eq_q = p_eq_q
    #
    x = fol.add_expr(r'p \in 6..8')
    y = fol.add_expr(r'p \in 2..5')
    #
    path_cost = 0.0
    bab = cov._BranchAndBound(prm, fol)
    bab.upper_bound = cov._upper_bound(x, y, prm.p_leq_q, prm.p_to_q, fol)
    cover, _ = cov._traverse(x, y, path_cost, bab, fol)
    # assert that the result is indeed a cover
    f = x
    assert _covers(cover, f, prm, fol)
    # assert the cover is as expected
    primes = list(fol.pick_iter(cover))
    print(primes)
    primes_ = [dict(p=3), dict(p=4)]
    assert len(primes) == 2, primes
    for p in primes_:
        assert p in primes, (p, primes)
def test_counterexample_to_strong_reduction():
    """Not all minimal solutions can be recovered.

    This counterexample shows that the minimal covering
    algorithm does not ensure strong reduction.
    The reason is that the minimal cover before
    unfloors has max floors elements that are
    incomparable to some elements from which we
    could build alternative minimal covers.
    """
    # For now `cov.minimize` creates the primes etc in
    # a specific way, for a specific basis.
    # This example doesn't fit in that recipe,
    # so we rewrite some of the code in `minimize`.
    fol = _fol.Context()
    fol.to_bdd = fol.add_expr
    x_vars = dict(x=(0, 8))
    p_vars = dict(p=(0, 8))
    q_vars = dict(q=(0, 8))
    u_vars = dict(p_cp=(0, 8))
    fol.declare(**x_vars, **p_vars, **q_vars, **u_vars)
    p_eq_q = fol.to_bdd('p \in 0..8  /\  q \in 0..8  /\ p = q')
    leq = '''
    # (* layer 1 *)
    \/ (p = 0  /\  q = 6)
    \/ (p = 0  /\  q = 7)
    \/ (p = 0  /\  q = 8)
    # (* layer 2 *)
    \/ (p = 6  /\  q = 2)
    \/ (p = 6  /\  q = 3)
    \/ (p = 7  /\  q = 3)
    \/ (p = 7  /\  q = 4)
    \/ (p = 8  /\  q = 4)
    \/ (p = 8  /\  q = 5)
    # (* layer 3 *)
    \/ (p = 2  /\  q = 1)
    \/ (p = 3  /\  q = 1)
    \/ (p = 4  /\  q = 1)
    \/ (p = 5  /\  q = 1)
    \/ (p = q /\ p \in 0..8 /\ q \in 0..8)
    '''
    p_leq_q = fol.to_bdd(leq)
    u_leq_p = fol.to_bdd(leq.replace('p', 'p_cp').replace('q', 'p'))
    p_leq_u = fol.to_bdd(leq.replace('q', 'p_cp'))
    # bundle
    prm = Parameters()
    prm.x_vars = set(x_vars)
    prm.p_vars = set(p_vars)
    prm.q_vars = set(q_vars)
    prm.u_vars = set(u_vars)
    #
    prm.p_to_q = dict(p='q')
    prm.q_to_p = dict(q='p')
    prm.p_to_u = dict(p='p_cp')
    #
    prm.u_leq_p = u_leq_p
    prm.p_leq_u = p_leq_u
    prm.p_leq_q = p_leq_q
    prm.p_eq_q = p_eq_q
    #
    x = fol.add_expr('p \in 6..8')
    y = fol.add_expr('p \in 2..5')
    #
    path_cost = 0.0
    bab = cov._BranchAndBound(prm, fol)
    bab.upper_bound = cov._upper_bound(
        x, y, prm.p_leq_q, prm.p_to_q, fol)
    cover, _ = cov._traverse(x, y, path_cost, bab, fol)
    # assert that the result is indeed a cover
    f = x
    assert _covers(cover, f, prm, fol)
    # assert the cover is as expected
    primes = list(fol.pick_iter(cover))
    print(primes)
    primes_ = [dict(p=3), dict(p=4)]
    assert len(primes) == 2, primes
    for p in primes_:
        assert p in primes, (p, primes)