def BUFFER(x): """BUFFER. Return the boolean expression for the buffer of ``x``. Parameters ---------- x : hashable object or dict (or subclass of dict). The expression to buffer. Return ------ P : ``qubovert.PUBO`` object or same type as ``type(x)``. If ``x`` is a ``qubovert.QUBO``, ``qubovert.PCBO``, ``qubovert.utils.QUBOMatrix``, or ``qubovert.utils.PUBOMatrix`` object, then ``type(P) == type(x)``. Otherwise, ``type(P) == type(x)``. Example ------- >>> from qubovert.sat import BUFFER >>> P = BUFFER('x') >>> P {('x',): 1} >>> P.value({'x': 1}) 1 >>> P.value({'x': 0}) 0 >>> type(P) qubovert._pubo.PUBO >>> P = BUFFER({(0, 1): 1}) >>> P {(0, 1): 1} >>> P.value({0: 0, 1: 0}) 0 >>> P.value({0: 0, 1: 1}) 0 >>> P.value({0: 1, 1: 0}) 0 >>> P.value({0: 1, 1: 1}) 1 >>> type(P) qubovert._pubo.PUBO >>> from qubovert import boolean_var >>> x = boolean_var('x') >>> P = BUFFER(x) >>> P.value({'x': 1}) 1 >>> P.value({'x': 0}) 0 >>> type(P) qubovert.PCBO """ if isinstance(x, qv.BOOLEAN_MODELS): return x.copy() return qv.PUBO(x) if isinstance(x, dict) else qv.PUBO({(x, ): 1})
def AND(*variables): """AND. Return the boolean expression for the AND of the variables. Parameters ---------- *variables : arguments. ``variables`` can be of arbitrary length. Each variable can be a hashable object, which is the label of the boolean variable, or a dict (or subclass of dict) representing a boolean expression. Return ------ P : ``qubovert.PUBO`` object or same type as ``type(variables[0])``. The boolean expression for the logic operation. If ``variables[0]`` is a ``qubovert.QUBO``, ``qubovert.PCBO``, ``qubovert.utils.QUBOMatrix``, or ``qubovert.utils.PUBOMatrix`` object, then ``type(P) == type(variables[0])``. Otherwise, ``type(P) == type(variables[0])``. Example ------- >>> from qubovert.sat import AND >>> P = AND(0, 1) >>> P {(0, 1): 1} >>> P.value({0: 0, 1: 0}) 0 >>> P.value({0: 0, 1: 1}) 0 >>> P.value({0: 1, 1: 0}) 0 >>> P.value({0: 1, 1: 1}) 1 >>> type(P) qubovert._pubo.PUBO >>> P = AND({(0, 1): 1}, 'x') # and of 0, 1, and 'x'. >>> P {(0, 1, 'x'): 1} >>> type(P) qubovert._pubo.PUBO >>> from qubovert import boolean_var >>> x, y = boolean_var('x'), boolean_var('y') >>> P = AND(x, y) >>> type(P) qubovert.PCBO """ if not variables: P = qv.PUBO() + 1 else: P = 1 for v in variables: P *= BUFFER(v) return P
def OR(*variables): """OR. Return the boolean expression for the OR of the variables. Parameters ---------- *variables : arguments. ``variables`` can be of arbitrary length. Each variable can be a hashable object, which is the label of the boolean variable, or a dict (or subclass of dict) representing a boolean expression. Return ------ P : ``qubovert.PUBO`` object or same type as ``type(variables[0])``. The boolean expression for the logic operation. If ``variables[0]`` is a ``qubovert.QUBO``, ``qubovert.PCBO``, ``qubovert.utils.QUBOMatrix``, or ``qubovert.utils.PUBOMatrix`` object, then ``type(P) == type(variables[0])``. Otherwise, ``type(P) == type(variables[0])``. Example ------- >>> from qubovert.sat import OR >>> P = OR(0, 1) >>> P {(0,): 1, (0, 1): -1, (1,): 1} >>> P.value({0: 0, 1: 0}) 0 >>> P.value({0: 0, 1: 1}) 1 >>> P.value({0: 1, 1: 0}) 1 >>> P.value({0: 1, 1: 1}) 1 >>> type(P) qubovert._pubo.PUBO >>> P = OR({(0, 1): 1}, 'x') # or of 0, 1, and 'x'. >>> P {(0, 1): 1, (0, 1, 'x'): -1, ('x',): 1} >>> type(P) qubovert._pubo.PUBO >>> from qubovert import boolean_var >>> x, y = boolean_var('x'), boolean_var('y') >>> P = OR(x, y) >>> type(P) qubovert.PCBO """ if not variables: return qv.PUBO() + 1 elif len(variables) == 1: return BUFFER(variables[0]) x, v = OR(*variables[:-1]), BUFFER(variables[-1]) return x + v * (1 - x)
def puso_to_pubo(H): """puso_to_pubo. Convert the specified PUSO problem into an upper triangular PUBO problem. Note that PUSO {1, -1} values go to PUBO {0, 1} values in that order! Parameters ---------- H : dictionary or qubovert.utils.PUSOMatrix object. Tuple of spin labels map to PUSO values. See ``help(qubovert.PUSO)`` and ``help(qubovert.utils.PUSOMatrix)`` for info on formatting. Returns ------- P : qubovert.utils.PUBOMatrix object. If ``H`` is a ``qubovert.utils.PUSOMatrix`` object, then ``P`` will be a ``qubovert.utils.PUBOMatrix``, otherwise ``P`` will be a ``qubovert.PUBO`` object. See ``help(qubovert.PUBO)`` and ``help(qubovert.utils.PUBOMatrix)`` for info on formatting. Example ------- >>> H = {(0,): 1, (1,): -1, (0, 1): -1} >>> P = puso_to_pubo(H) >>> isinstance(P, qubovert.utils.PUBOMatrix) True >>> H = {('0',): 1, ('1',): -1, (0, 1): -1} >>> P = puso_to_pubo(H) >>> isinstance(P, qubovert.PUBO) True """ def generate_new_key_value(k): """generate_new_key_value. Recursively generate the PUBO key, value pairs for converting the product ``z[k[0]] * ... * z[k[-1]]``, where each ``z`` is a spin in {1, -1}, to the product ``(1-2*x[k[0]]) * ... * (1-2*x[k[1]])``, where each ``x`` is a boolean variables in {0, 1}. Parameters ---------- k : tuple. Each element of the tuple corresponds to a spin label. Yields ------ res : tuple (key, value) key : tuple. Each element of the tuple corresponds to a binary label. value : float. The value to multiply the value corresponding with ``k`` by. """ if not k: yield k, 1 else: for key, value in generate_new_key_value(k[1:]): yield (k[0],) + key, -2 * value yield key, value # not isinstance! because isinstance(PUSO, PUSOMatrix) is True P = PUBOMatrix() if type(H) == PUSOMatrix else qv.PUBO() for k, v in H.items(): for key, value in generate_new_key_value(k): P[key] += value * v return P
def XOR(*variables): """XOR. Return the boolean expression for the XOR of the variables. XOR(a, b) is 1 if ``a == b``, otherwise it is 0. ``qubovert`` uses the convention that an XOR on > 2 bits is a parity gate. Ie ``XOR(0, 1, 2, 3) == XOR(XOR(XOR(0, 1), 2), 3)``. Parameters ---------- *variables : arguments. ``variables`` can be of arbitrary length. Each variable can be a hashable object, which is the label of the boolean variable, or a dict (or subclass of dict) representing a boolean expression. Return ------ P : ``qubovert.PUBO`` object or same type as ``type(variables[0])``. The boolean expression for the logic operation. If ``variables[0]`` is a ``qubovert.QUBO``, ``qubovert.PCBO``, ``qubovert.utils.QUBOMatrix``, or ``qubovert.utils.PUBOMatrix`` object, then ``type(P) == type(variables[0])``. Otherwise, ``type(P) == type(variables[0])``. Example ------- >>> from qubovert.sat import XOR >>> P = XOR(0, 1) >>> P {(0,): 1, (0, 1): -2, (1,): 1} >>> P.value({0: 0, 1: 0}) 0 >>> P.value({0: 0, 1: 1}) 1 >>> P.value({0: 1, 1: 0}) 1 >>> P.value({0: 1, 1: 1}) 0 >>> type(P) qubovert._pubo.PUBO >>> P = XOR({(0, 1): 1}, 'x') # xor of 0, 1, and 'x'. >>> P {(0, 1): 1, (0, 1, 'x'): -2, ('x',): 1} >>> type(P) qubovert._pubo.PUBO >>> from qubovert import boolean_var >>> x, y = boolean_var('x'), boolean_var('y') >>> P = XOR(x, y) >>> type(P) qubovert.PCBO The following test will pass. >>> for n in range(1, 5): >>> P = XOR(*tuple(range(n))) >>> for i in range(1 << n): >>> sol = decimal_to_boolean(i, n) >>> if sum(sol) % 2 == 1: >>> assert P.value(sol) == 1 >>> else: >>> assert not P.value(sol) """ if not variables: return qv.PUBO() + 1 elif len(variables) == 1: return BUFFER(variables[0]) x, v = XOR(*variables[:-1]), BUFFER(variables[-1]) return (x - v)**2