sudo pip install git+https://github.com/tpircher/quine-mccluskey.git
    sudo pip uninstall quine_mccluskey
    pip uninstall quine_mccluskey

    pip install git+https://github.com/tpircher/quine-mccluskey.git


    Args:
        varnames (?):

    Returns:
        ?:

    CommandLine:
        python -m utool.util_alg solve_boolexpr --show

    Example:
        >>> # DISABLE_DOCTEST
        >>> from utool.util_alg import *  # NOQA
        >>> import utool as ut
        >>> varnames = ['sa', 'said', 'aid']
        >>> result = solve_boolexpr()
        >>> print(result)

def solve_boolexpr():
    """
    sudo pip install git+https://github.com/tpircher/quine-mccluskey.git
    sudo pip uninstall quine_mccluskey
    pip uninstall quine_mccluskey

    pip install git+https://github.com/tpircher/quine-mccluskey.git


    Args:
        varnames (?):

    Returns:
        ?:

    CommandLine:
        python -m utool.util_alg solve_boolexpr --show

    Example:
        >>> # DISABLE_DOCTEST
        >>> from utool.util_alg import *  # NOQA
        >>> import utool as ut
        >>> varnames = ['sa', 'said', 'aid']
        >>> result = solve_boolexpr()
        >>> print(result)

    """
    #false_cases = [
    #    int('111', 2),
    #    int('011', 2),
    #    int('001', 2),
    #]
    #true_cases = list(set(range(2 ** 3)) - set(false_cases))
    varnames = ['sa', 'said', 'aid']

    #import utool as ut
    truth_table = [
        dict(sa=True,  said=True,  aid=True,  output=False),
        dict(sa=True,  said=True,  aid=False, output=True),
        dict(sa=True,  said=False, aid=True,  output=True),
        dict(sa=True,  said=False, aid=False, output=True),
        dict(sa=False, said=True,  aid=True,  output=False),
        dict(sa=False, said=True,  aid=False, output=True),
        dict(sa=False, said=False, aid=True,  output=False),
        dict(sa=False, said=False, aid=False, output=True),
    ]
    truth_tuples = [ut.dict_take(d, varnames) for d in truth_table]
    outputs = [d['output'] for d in truth_table]
    true_tuples = ut.compress(truth_tuples, outputs)
    #false_tuples = ut.compress(truth_tuples, ut.not_list(outputs))
    true_cases = [''.join([str(int(t)) for t in tup]) for tup in true_tuples]
    true_cases = [''.join([str(int(t)) for t in tup]) for tup in true_tuples]
    #truth_nums = [int(s, 2) for s in true_cases]

    from quine_mccluskey.qm import QuineMcCluskey
    qm = QuineMcCluskey(use_xor=False)
    result = qm.simplify_los(true_cases, num_bits=len(varnames))
    print(result)
    #ut.chr_range(3)

    #symbol_map = {
    #    '-': '',
    #    '1': '{v}',
    #    '0': 'not {v}',
    #    '^': '^',
    #}

    #'-' don't care: this bit can be either zero or one.
    #'1' the bit must be one.
    #'0' the bit must be zero.
    #'^' all bits with the caret are XOR-ed together.
    #'~' all bits with the tilde are XNOR-ed together.

    #formulas = [[symbol_map[r].format(v=v) for v, r in zip(varnames, rs)] for rs in result]
    grouped_terms = [dict(ut.group_items(varnames, rs)) for rs in result]
    def parenjoin(char, list_):
        if len(list_) == 0:
            return ''
        else:
            return '(' + char.join(list_) + ')'

    expanded_terms = [
        (
            term.get('1', []) +
            ['(not ' + b + ')' for b in term.get('0', [])] +
            [
                parenjoin(' ^ ', term.get('^', [])),
                parenjoin(' ~ ', term.get('~', [])),
            ]
        ) for term in grouped_terms
    ]

    final_terms = [[t for t in term if t] for term in expanded_terms]

    products = [parenjoin(' and ', [f for f in form if f]) for form in final_terms]
    final_expr = ' or '.join(products)
    print(final_expr)