Source code for boolexpr.misc

# Copyright 2016 Chris Drake
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""
Miscellaneous features not implemented in C++ API
"""


import functools
import itertools
import operator

from .util import clog2
from .util import iter_space
from .wrap import array
from .wrap import not_
from .wrap import or_
from .wrap import and_
from .wrap import _expect_array


[docs]def nhot(n, *args): """ Return a CNF expression that means "exactly N input functions are true". """ if not 0 <= n <= len(args): fstr = "expected 0 <= n <= {}, got {}" raise ValueError(fstr.format(len(args), n)) clauses = list() for xs in itertools.combinations(args, n+1): clauses.append(or_(*[not_(x) for x in xs])) for xs in itertools.combinations(args, (len(args)+1)-n): clauses.append(or_(*xs)) return and_(*clauses)
[docs]def majority(*args): """ Return a CNF expression that means "the majority of input functions are true". """ clauses = list() for xs in itertools.combinations(args, (len(args) + 1) // 2): clauses.append(or_(*xs)) return and_(*clauses)
[docs]def achilles_heel(*args): r""" Return the Achille's Heel function, defined as: :math:`\prod_{i=0}^{n/2-1}{X_{2i} + X_{2i+1}}`. """ num = len(args) if num & 1: fstr = "expected an even number of arguments, got {}" raise ValueError(fstr.format(num)) return and_(*[or_(args[2*i], args[2*i+1]) for i in range(num // 2)])
[docs]def mux(a, sel): """ Return an expression that multiplexes an input array over a select array. """ a = _expect_array(a) sel = _expect_array(sel) if sel.size < clog2(a.size): fstr = "expected at least {} select bits, got {}" raise ValueError(fstr.format(clog2(a.size), sel.size)) terms = (tuple(sel[i] if vertex[i] else ~sel[i] for i in range(sel.size)) for vertex in iter_space(sel.size)) return or_(*[and_(x, *term) for (x, term) in zip(a.flat, terms)])
[docs]def exists(xs, f): """ Return an expression that means "there exists a variable in *xs* such that *f* true." This is identical to ``f.smoothing(xs)``. """ return f.smoothing(xs)
[docs]def forall(xs, f): """ Return an expression that means "for all variables in *xs*, *f* is true." This is identical to ``f.consensus(xs)``. """ return f.consensus(xs)
def cat(*xs): """Concatenate a sequence of expressions.""" return functools.reduce(operator.add, xs, array([]))