|
14 | 14 | from collections import defaultdict
|
15 | 15 | from typing import (
|
16 | 16 | AbstractSet,
|
| 17 | + Dict, |
17 | 18 | Iterable,
|
18 | 19 | Mapping,
|
19 | 20 | Optional,
|
|
27 | 28 | import numbers
|
28 | 29 |
|
29 | 30 | import numpy as np
|
| 31 | +from sympy.logic.boolalg import And, Not, Or, Xor |
| 32 | +from sympy.core.expr import Expr |
| 33 | +from sympy.core.symbol import Symbol |
30 | 34 |
|
31 | 35 | from cirq import linalg, protocols, qis, value
|
32 | 36 | from cirq._doc import document
|
@@ -398,6 +402,56 @@ def from_pauli_strings(cls, terms: Union[PauliString, List[PauliString]]) -> 'Pa
|
398 | 402 | termdict[key] += pstring.coefficient
|
399 | 403 | return cls(linear_dict=value.LinearDict(termdict))
|
400 | 404 |
|
| 405 | + @classmethod |
| 406 | + def from_boolean_expression( |
| 407 | + cls, boolean_expr: Expr, qubit_map: Dict[str, 'cirq.Qid'] |
| 408 | + ) -> 'PauliSum': |
| 409 | + """Builds the Hamiltonian representation of a Boolean expression. |
| 410 | +
|
| 411 | + This is based on "On the representation of Boolean and real functions as Hamiltonians for |
| 412 | + quantum computing" by Stuart Hadfield, https://arxiv.org/abs/1804.09130 |
| 413 | +
|
| 414 | + Args: |
| 415 | + boolean_expr: A Sympy expression containing symbols and Boolean operations |
| 416 | + qubit_map: map of string (boolean variable name) to qubit. |
| 417 | +
|
| 418 | + Return: |
| 419 | + The PauliString that represents the Boolean expression. |
| 420 | + """ |
| 421 | + if isinstance(boolean_expr, Symbol): |
| 422 | + # In table 1, the entry for 'x' is '1/2.I - 1/2.Z' |
| 423 | + return cls.from_pauli_strings( |
| 424 | + [ |
| 425 | + PauliString({}, 0.5), |
| 426 | + PauliString({qubit_map[boolean_expr.name]: pauli_gates.Z}, -0.5), |
| 427 | + ] |
| 428 | + ) |
| 429 | + |
| 430 | + if isinstance(boolean_expr, (And, Not, Or, Xor)): |
| 431 | + sub_pauli_sums = [ |
| 432 | + cls.from_boolean_expression(sub_boolean_expr, qubit_map) |
| 433 | + for sub_boolean_expr in boolean_expr.args |
| 434 | + ] |
| 435 | + # We apply the equalities of theorem 1. |
| 436 | + if isinstance(boolean_expr, And): |
| 437 | + pauli_sum = cls.from_pauli_strings(PauliString({}, 1.0)) |
| 438 | + for sub_pauli_sum in sub_pauli_sums: |
| 439 | + pauli_sum = pauli_sum * sub_pauli_sum |
| 440 | + elif isinstance(boolean_expr, Not): |
| 441 | + assert len(sub_pauli_sums) == 1 |
| 442 | + pauli_sum = cls.from_pauli_strings(PauliString({}, 1.0)) - sub_pauli_sums[0] |
| 443 | + elif isinstance(boolean_expr, Or): |
| 444 | + pauli_sum = cls.from_pauli_strings(PauliString({}, 0.0)) |
| 445 | + for sub_pauli_sum in sub_pauli_sums: |
| 446 | + pauli_sum = pauli_sum + sub_pauli_sum - pauli_sum * sub_pauli_sum |
| 447 | + elif isinstance(boolean_expr, Xor): |
| 448 | + pauli_sum = cls.from_pauli_strings(PauliString({}, 0.0)) |
| 449 | + for sub_pauli_sum in sub_pauli_sums: |
| 450 | + pauli_sum = pauli_sum + sub_pauli_sum - 2.0 * pauli_sum * sub_pauli_sum |
| 451 | + return pauli_sum |
| 452 | + |
| 453 | + raise ValueError(f'Unsupported type: {type(boolean_expr)}') |
| 454 | + |
401 | 455 | @property
|
402 | 456 | def qubits(self) -> Tuple[raw_types.Qid, ...]:
|
403 | 457 | qs = {q for k in self._linear_dict.keys() for q, _ in k}
|
|
0 commit comments