def flow_checker(module: Module):
    module.reset_delay()
    net_names = module.nets
    passed = True
    for net_name in net_names:
        net = module.get_net(net_name)
        if len(net.get_parents()) >= 1:
            delays = {module.get_delay(pre.name) for pre in net.get_parents()}
            if len(delays) == 1:
                continue
            else:
                passed = False
                print("\nUnequal path found at node {}".format(net_name))
    delays = {module.delays.values()}
    if len(delays) != 1:
        print("\nOutputs delay not equal")
        passed = False
    if passed:
        print("\nEven data path test passed.")
def majority_picking(target: Module, lib: Library):
    maj_mod = target.interface_copy()
    dfs = list(target.outputs)
    rev = False
    dfs.sort(key=lambda x: target.get_delay(x.name), reverse=rev)
    visited = set()
    while len(dfs) != 0:
        cur = dfs.pop()
        if isinstance(cur, PortIn) or isinstance(cur, Constant):
            continue
        if cur in visited:
            continue
        if maj_mod.get_net(cur.name) is None:
            maj_mod.add_wire(cur.name)
        border = majority_feasible_checker(cur, maj_mod)
        feasible = False

        if len(border) == 3:
            l = LogicCut(cur, list(border), target)
            selection = majority_seperation(l.truth)
            if selection is not None:
                feasible = True
                border_sorted = list(border)
                border_sorted.sort(key=lambda x: target.get_delay(x.name),
                                   reverse=rev)
                for b in border_sorted:
                    if maj_mod.get_net(b.name) is None:
                        maj_mod.add_wire(b.name)
                    if b not in visited:
                        dfs.append(b)
                if len(selection) == 1:
                    sela = set(selection).pop()
                    if len(sela) == 1:
                        t_truth = majority_primary_gates[sela[0]]
                        gate_mapping(maj_mod, cur,
                                     [maj_mod.get_net(b.name) for b in border],
                                     t_truth, lib)
                        # print(l.truth, cur.name, [b.name for b in border])
                else:
                    majority_blocks[cur.name] = tuple(
                        [[maj_mod.get_net(b.name) for b in border], selection])
                    # print(l.truth, cur.name, [b.name for b in border])
        if not feasible:
            parents = cur.get_parents()
            parents_sorted = list(parents)
            parents_sorted.sort(key=lambda x: target.get_delay(x.name),
                                reverse=rev)
            for parent in parents_sorted:
                if maj_mod.get_net(parent.name) is None:
                    maj_mod.add_wire(parent.name)
                if parent not in visited:
                    dfs.append(parent)
            inst = cur.source_instance
            if inst is not None:
                if isinstance(inst, Alias):
                    maj_mod.add_alias(inst.wire_in.name, inst.wire_out.name)
                else:
                    mapping = {
                        x: inst.pins.get(x).connection.name
                        for x in inst.model.interface
                    }
                    maj_mod.add_instance(inst.name, inst.model, mapping)
        if cur.name in skipped:
            skipped.remove(cur.name)
        visited.add(cur)
    return maj_mod