Пример #1
0
def test_validity(sentence: nnf.NNF):
    if sentence.valid():
        event("Valid sentence")
        assert all(
            sentence.satisfied_by(model)
            for model in nnf.all_models(sentence.vars()))
    else:
        event("Invalid sentence")
        assert any(not sentence.satisfied_by(model)
                   for model in nnf.all_models(sentence.vars()))
Пример #2
0
def test_models(sentence: nnf.NNF):
    real_models = [
        model for model in all_models(sentence.vars())
        if sentence.satisfied_by(model)
    ]
    models = list(sentence.models())
    assert len(real_models) == len(models)
    assert model_set(real_models) == model_set(models)
Пример #3
0
def test_all_models(names):
    result = list(nnf.all_models(names))
    # Proper result size
    assert len(result) == 2**len(names)
    # Only real names, only booleans
    assert all(name in names and isinstance(value, bool) for model in result
               for name, value in model.items())
    # Only complete models
    assert all(len(model) == len(names) for model in result)
    # No duplicate models
    assert len({tuple(model.items()) for model in result}) == len(result)
Пример #4
0
def test_iff(a: nnf.NNF, b: nnf.NNF):
    c = operators.iff(a, b)
    for model in nnf.all_models(c.vars()):
        assert ((a.satisfied_by(model) == b.satisfied_by(model)
                 ) == c.satisfied_by(model))
Пример #5
0
def test_implied_by(a: nnf.NNF, b: nnf.NNF):
    c = operators.implied_by(a, b)
    for model in nnf.all_models(c.vars()):
        assert ((b.satisfied_by(model) and not a.satisfied_by(model)) !=
                c.satisfied_by(model))
Пример #6
0
def test_nor(a: nnf.NNF, b: nnf.NNF):
    c = operators.nor(a, b)
    for model in nnf.all_models(c.vars()):
        assert ((a.satisfied_by(model) or b.satisfied_by(model)) !=
                c.satisfied_by(model))
Пример #7
0
def test_all_models_basic():
    assert list(nnf.all_models([])) == [{}]
    assert list(nnf.all_models([1])) == [{1: False}, {1: True}]
    assert len(list(nnf.all_models(range(10)))) == 1024
Пример #8
0
def test_satisfiable(sentence: nnf.NNF):
    assert sentence.satisfiable() == any(
        sentence.satisfied_by(model) for model in all_models(sentence.vars()))
Пример #9
0
def encode_circuit_search(original_theory, num_gates, models=[]):

    ########
    # Vars #
    ########

    # Inputs to the circuit are the variables of the input theory
    inputs = [Var(v) for v in original_theory.vars()]
    if models:
        input_clones = clone_varset(models, inputs, inputs)
    else:
        input_clones = {}

    # Gates are either & | or ~
    gates = []
    gate_modalities = {}
    for i in range(num_gates):
        gates.append(Var(Gate(i)))
        gate_modalities[gates[-1]] = {}
        for m in ['and', 'or', 'not']:
            gate_modalities[gates[-1]][m] = Var(GateType(gates[-1], m))

    if models:
        gate_clones = clone_varset(models, inputs, gates)
    else:
        gate_clones = {}

    # Single (arbitrary) gate is the circuit output
    output = gates[0]

    # Connections between inputs/gates to gates, and transitivity
    connections = {}
    unconnections = {}
    for src in inputs + gates[1:]:
        connections[src] = {}
        for dst in gates:
            if src != dst:
                connections[src][dst] = Var(Connection(src, dst))
                if dst not in unconnections:
                    unconnections[dst] = {}
                unconnections[dst][src] = connections[src][dst]
    C = connections # convenience

    orders = {}
    for src in gates:
        orders[src] = {}
        for dst in gates:
            orders[src][dst] = Var(Order(src,dst))



    ###############
    # Constraints #
    ###############

    ''' add decorators for simplifying adding constraints (i.e. a conjunct)'''
    conjuncts = []

    # Orderings (to forbid cycles in the circuit)
    for g1 in gates:
        # Connection implies orders
        for src in connections:
            for dst in connections[src]:
                if isinstance(src.name, Gate) and isinstance(dst.name, Gate):
                    conjuncts.append(~connections[src][dst] | orders[src][dst])
        # Can't order before yourself
        conjuncts.append(~orders[g1][g1])
        # Transitive closure
        for g2 in gates:
            for g3 in gates:
                conjuncts.append(~orders[g1][g2] | ~orders[g2][g3] | orders[g1][g3])

    if FORCE_TREE:
        # At max one outgoing connection on a gate
        for src in gates[1:]:
            for dst1 in connections[src]:
                for dst2 in connections[src]:
                    if dst1 != dst2:
                        conjuncts.append(~connections[src][dst1] | ~connections[src][dst2])

    # Every gate has at least one input
    for dst in unconnections:
        conjuncts.append(Or(unconnections[dst].values()))

    # Every gate has at most two inputs and negation gates have at most one
    for j in gates:
        for i1 in inputs+gates[1:]:
            for i2 in inputs+gates[1:]:
                if not unique([j,i1,i2]):
                    continue
                conjuncts.append(~gate_modalities[j]['not'] | ~C[i1][j] | ~C[i2][j])
                for i3 in inputs+gates[1:]:
                    if not unique([j,i1,i2,i3]):
                        continue
                    conjuncts.append(~C[i1][j] | ~C[i2][j] | ~C[i3][j])

    # Every gate has exactly one modality
    for g in gates:
        # At least one
        conjuncts.append(Or(gate_modalities[g].values()))

        # At most one
        for m1 in ['and', 'or', 'not']:
            remaining = set(['and', 'or', 'not']) - set([m1])
            conjuncts.append(Or([~gate_modalities[g][m2] for m2 in remaining]))

    # Re-usable theories
    notneg_cache = {}
    def notneg(src, dst, cloned_src=None):
        if not cloned_src:
            cloned_src = src
        if (cloned_src,dst) not in notneg_cache:
            notneg_cache[(cloned_src,dst)] = ~C[src][dst] | cloned_src
        return notneg_cache[(cloned_src,dst)]

    notpos_cache = {}
    def notpos(src, dst, cloned_src=None):
        if not cloned_src:
            cloned_src = src
        if (cloned_src,dst) not in notpos_cache:
            notpos_cache[(cloned_src,dst)] = ~C[src][dst] | ~cloned_src
        return notpos_cache[(cloned_src,dst)]

    # Implement the gates
    for g in gates:

        ins = [i for i in inputs+gates[1:] if i != g]

        conjuncts.append(~gate_modalities[g]['and'] | iff(g, And([notneg(src,g) for src in ins])))

        t = Or([notpos(src,g).negate() for src in ins])
        conjuncts.append(~gate_modalities[g]['or'] | iff(g, t))

        conjuncts.append(~gate_modalities[g]['not'] | iff(g, t.negate()))

        for m in models:
            bitvec = model_to_bitvec(m, inputs)
            orig_mapping = {**{input_clones[bitvec][i]: i for i in inputs if i != g},
                            **{gate_clones[bitvec][i]: i for i in gates[1:] if i != g}}
            ins = orig_mapping.keys()

            conjuncts.append(~gate_modalities[g]['and'] | iff(gate_clones[bitvec][g],
                     And([notneg(orig_mapping[src],g,src) for src in ins])))

            t = Or([notpos(orig_mapping[src],g,src).negate() for src in ins])
            conjuncts.append(~gate_modalities[g]['or'] | iff(gate_clones[bitvec][g], t))

            conjuncts.append(~gate_modalities[g]['not'] | iff(gate_clones[bitvec][g], t.negate()))


    # Finally, lock in the models
    if models:
        for m in models:
            bitvec = model_to_bitvec(m, inputs)
            for var in m:
                if m[var]:
                    conjuncts.append(input_clones[bitvec][Var(var)])
                else:
                    conjuncts.append(~input_clones[bitvec][Var(var)])
            if original_theory.satisfied_by(m):
                conjuncts.append(gate_clones[bitvec][output])
            else:
                conjuncts.append(~gate_clones[bitvec][output])
    else:
        for model in all_models(original_theory.vars()):

            t = false # negating the conjunction because of the implication: flips the signs
            for var,val in model.items():
                if val:
                    t |= ~Var(var)
                else:
                    t |= Var(var)
            if original_theory.satisfied_by(model):
                t |= output
            else:
                t |= ~output
            conjuncts.append(t)


    versions = {}
    example = {}
    for c in conjuncts:
        cn = c.simplify().to_CNF()
        stats = "(%d / %d / %d) > (%d / %d / %d)" % (c.simplify().size(), c.simplify().height(), len(c.simplify().vars()),
                                                     cn.size(), cn.height(), len(cn.vars()))
        example[stats] = str(c.simplify())
        versions[stats] = versions.get(stats, 0) + 1
    print("Conjunct stats:")
    for k in versions:
        print("\n - (%d) %s: %s" % (versions[k], k, example[k]))

    T = And(conjuncts)
    return T.simplify(), inputs, gates, output, connections, unconnections, gate_modalities
Пример #10
0
def solve_and_output(theory, bound):
    encoded, inputs, gates, output, connections, unconnections, gate_modalities = encode_circuit_search(theory, bound, list(all_models(theory.vars())))
    print("  Size: %d" % encoded.size())
    print("Height: %d" % encoded.height())
    print("  Vars: %d" % len(encoded.vars()))
    with open('encoded.cnf', 'w') as f:
        th = encoded.to_CNF()
        print("Compiled Vars: %d" % len(th.vars()))
        print("Compiled Clauses: %d" % len(th.children))
        print ("AxVars: %d" % len(list(filter(lambda x: isinstance(x, Aux), th.vars()))))
        var_labels = dict(enumerate(th.vars(), start=1))
        var_labels_inverse = {v: k for k, v in var_labels.items()}
        dimacs.dump(th, f, mode='cnf', var_labels=var_labels_inverse)

    with config(sat_backend="kissat"):
        t0 = time.time()
        model = encoded.solve()
        print("\nSolver complete in %.2fsec" % (time.time()-t0))
        if not model:
            print("No solution for bound %d\n" % bound)
            return

    print("\nGates:")
    for var in model:
        if isinstance(var, GateType) and model[var]:
            print(var)
    print("\nConnections:")
    for var in model:
        if isinstance(var, Connection) and model[var]:
            print(var)
    print("\nOutput: %s" % output)

    print("\nConfig for 1110:")
    for var in model:
        if '1110' in str(var):
            print("%s: %s" % (str(var), str(model[var])))

    print("\n  %s" % build_solution(inputs, gates, gate_modalities, model, output, unconnections))

    print()