예제 #1
0
def int2binlatch(varlist, n):
    net = boolnet.BoolNet(True)
    dividend = n
    power = len(varlist) - 1
    for v in varlist:
        divisor = math.pow(2, power)
        if dividend >= divisor:
            net &= boolnet.BoolNet(v)
            dividend -= divisor
        else:
            net &= ~boolnet.BoolNet(v)
        power -= 1
    return net
예제 #2
0
def label2inputs(inputs, outputs, label, input_map):
    all_signals = inputs + outputs
    labels = label.split("||")
    input_net = boolnet.BoolNet(False)
    for l in labels:
        (props, n_disj) = utils.convert_formula_to_proptab(l, all_signals)
        if props == "T":
            DBG_MSG("Trivial edge")
            input_net |= boolnet.BoolNet(True)
            continue
        props = list(props)
        temp = boolnet.BoolNet(True)
        for p in range(len(all_signals)):
            p_val = props[p]
            if p_val == "1":
                temp &= boolnet.BoolNet(input_map[all_signals[p]])
            elif p_val == "2":
                temp &= ~boolnet.BoolNet(input_map[all_signals[p]])
        input_net |= temp
    return input_net
예제 #3
0
def main(formula_file, part_file, k, args):
    # STEP 0: read partition, ltl formula and create BA
    (inputs, outputs) = read_partition(part_file)
    wring_formulae = read_formulae(formula_file, args.compositional)
    var_offset = None
    latch_net = dict()
    error_net = boolnet.BoolNet(False)
    for wring_formula in wring_formulae:
        ltl2ba_formula = wring_to_ltl2ba(wring_formula, inputs, outputs)
        formula = negate_ltl2ba(ltl2ba_formula)
        DBG_MSG("negated formula: " + str(formula))
        (automata, buchi_states) = construct_automata(formula)
        # STEP 1: translate aig
        (ln, en, var_offset) = translate2aig(inputs, outputs, k,
                                             automata.nodes(), buchi_states,
                                             var_offset,
                                             [(e, automata.edge_label(e))
                                              for e in automata.edges()])
        latch_net.update(ln)
        error_net |= en
    # STEP 2: call Acacia+ to see if this is realizable or not
    arg_list = [
        "--ltl", formula_file, "--part", part_file, "--player", "1",
        "--kbound",
        str(k - 1), "--verb", "0", "--crit", "OFF", "--opt", "none", "--check",
        "REAL"
    ]
    if args.compositional:
        arg_list.extend(["--syn", "COMP", "--nbw", "COMP"])
    (solved, is_real) = acacia_plus.main(arg_list)
    LOG_MSG("acacia+ replied (solved, realizability) = (" + str(solved) +
            ", " + str(is_real) + ")")
    suffix = "comp" + str(k) if args.compositional else str(k)
    if solved and is_real:
        file_name = formula_file[:-4] + "_" + suffix + "_REAL.aag"
        ret = EXIT_STATUS_REALIZABLE
    elif solved and not is_real:
        file_name = formula_file[:-4] + "_" + suffix + "_UNREAL.aag"
        ret = EXIT_STATUS_UNREALIZABLE
    else:
        file_name = formula_file[:-4] + "_" + suffix + "_UNREAL.aag"
        ret = EXIT_STATUS_UNKNOWN
    # FINALLY: dump the AIG
    write_aig(inputs, outputs, latch_net, error_net, file_name)
    return ret
예제 #4
0
def translate2aig(inputs, outputs, k, states, buchi_states, var_offset, edges):
    LOG_MSG("k = " + str(k))
    LOG_MSG(str(len(inputs)) + " inputs")
    DBG_MSG("inputs: " + str(inputs))
    LOG_MSG(str(len(outputs)) + " outputs")
    DBG_MSG("outputs: " + str(outputs))

    # STEP 1: check number of states
    n_nodes = len(states)
    LOG_MSG(str(n_nodes) + " states")
    DBG_MSG("states: " + str(states))

    # STEP 2: assign inputs and outputs a number
    free_var = 2
    input_map = dict()
    input_map["F"] = 0
    input_map["T"] = 1
    for i in inputs:
        input_map[i] = free_var
        free_var += 2
    # reserve outputs and negations
    for o in outputs:
        input_map[o] = free_var
        free_var += 2
    # reserve latches X counters, and negations
    # and get the initial node
    if var_offset is not None:
        assert free_var <= var_offset
        free_var = var_offset
    state_latch_map = dict()
    latch_net = dict()
    init_node = None
    for u in states:
        if u == "initial":
            init_node = u
            DBG_MSG("initial state: " + str(u))
        for i in range(k + 2):
            state_latch_map[(u, i)] = free_var
            latch_net[free_var] = boolnet.BoolNet(False)
            free_var += 2
    LOG_MSG(str(len(buchi_states)) + " buchi states")
    DBG_MSG("buchi states: " + str(buchi_states))
    LOG_MSG(str(len(edges)) + " edges")

    # STEP 3: create the boolean network rep. of automata
    # first transition is to let the 0 config go directly to the initial state
    all_off = boolnet.BoolNet(True)
    for latch in state_latch_map.values():
        all_off &= ~boolnet.BoolNet(latch)
    latch_net[state_latch_map[(init_node, 0)]] |= all_off
    # now add each individual transition,
    # incrementing counters when a state is buchi
    for ((u, v), l) in edges:
        # state u goes to state v
        DBG_MSG("edge: " + str(u) + "->" + str(v) + " (label: " + str(l) + ")")
        # which inputs enable the transition?
        input_net = label2inputs(inputs, outputs, l, input_map)
        # play with the counters
        for i in range(k + 2):
            # if buchi, add value
            if v in buchi_states:
                j = min(i + 1, k + 1)
                latch_net[state_latch_map[(v, j)]] |= (
                    boolnet.BoolNet(state_latch_map[(u, i)]) & input_net)
            else:
                latch_net[state_latch_map[(v, i)]] |= (
                    boolnet.BoolNet(state_latch_map[(u, i)]) & input_net)

    # STEP 4: create the error net
    error_net = boolnet.BoolNet(False)
    for u in states:
        error_net |= boolnet.BoolNet(state_latch_map[(u, k + 1)])
    # RETURN latchnet and errornet
    return (latch_net, error_net, free_var)
예제 #5
0
def write_aig(inputs, outputs, latches, error, file_name):
    f = open(file_name, "w")
    all_signals = inputs + outputs
    n_signals = len(all_signals)
    n_latches = len(latches)
    # STEP 0: Compute the number of gates to be used
    m_vars = boolnet.BoolNet.count_nonterminals()
    # STEP 1: Print header
    f.write("aag " + str(m_vars + n_signals + n_latches) + " " +
            str(n_signals) + " " + str(n_latches) + " " + "1 " + str(m_vars) +
            "\n")
    # STEP 2: Print inputs (and name them)
    var_map = dict()
    for i in range(2, 2 * (n_signals + 1), 2):
        f.write(str(i) + "\n")
        var_map[boolnet.BoolNet(i).index] = i
    # STEP 3: Print latches
    # for this part we need to have numbered/named the gates
    # and assigned a var to True and False
    cur_var = 2 * (n_signals + n_latches + 1)
    var_map[0] = 0
    var_map[1] = 1
    for v in boolnet.BoolNet.iterate_nonterminals():
        var_map[v.index] = cur_var
        cur_var += 2
    # name the latches and print their latch [space] net.index line
    # TECH NOTE
    # =========
    # the boolnet data structure makes sure the following invariant holds:
    # v.neg => v is a literal, therefore v.is_or() != v.neg is equivalent to
    # v.is_or() | v.neg
    for (l, net) in sorted(latches.items()):
        var_map[boolnet.BoolNet(l).index] = l

    for (l, net) in sorted(latches.items()):
        assert ~net.is_or() | ~net.neg
        if net.is_or() != net.neg:
            f.write(str(l) + " " + str(var_map[net.index] ^ 1) + "\n")
        else:
            f.write(str(l) + " " + str(var_map[net.index]) + "\n")
    # STEP 4: Print error
    err = var_map[error.index]
    if error.is_or() != error.neg:
        err ^= 1
    f.write(str(err) + "\n")
    # STEP 5: Print gates
    # we are using deMorgan's Law to have all gates be AND-gates
    for v in boolnet.BoolNet.iterate_nonterminals():
        f.write(str(var_map[v.index]) + " ")
        # the gate might be an or, meaning everyone else will use its
        # negation
        local_neg = v.is_or()
        # we now print the left operand
        left = v.get_left()
        assert ~left.is_or() | ~left.neg
        if local_neg != (left.is_or() != left.neg):
            f.write(str(var_map[left.index] ^ 1) + " ")
        else:
            f.write(str(var_map[left.index]) + " ")
        # same treatment for the right operand
        right = v.get_right()
        assert ~right.is_or() | ~right.neg
        if local_neg != (right.is_or() != right.neg):
            f.write(str(var_map[right.index] ^ 1) + "\n")
        else:
            f.write(str(var_map[right.index]) + "\n")
    # STEP 6: Print symbol table
    cnt = 0
    for i in inputs:
        f.write("i" + str(cnt) + " " + str(i) + "\n")
        cnt += 1
    for i in outputs:
        f.write("i" + str(cnt) + " controllable_" + str(i) + "\n")
        cnt += 1
    cnt = 0
    for l in latches:
        f.write("l" + str(cnt) + " latch" + str(cnt) + "\n")
        cnt += 1
    f.write("o0 error\n")
    # STEP 7: Close the file
    f.close()