|
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | 14 | """Function for building a walk operator for the THC hamiltonian.""" |
| 15 | +import attrs |
| 16 | +import numpy as np |
15 | 17 | from numpy.typing import NDArray |
| 18 | +from openfermion.resource_estimates.utils import QI |
16 | 19 |
|
17 | 20 | from qualtran.bloqs.block_encoding.lcu_block_encoding import SelectBlockEncoding |
18 | 21 | from qualtran.bloqs.chemistry.thc import PrepareTHC, SelectTHC |
@@ -51,3 +54,59 @@ def get_walk_operator_for_thc_ham( |
51 | 54 | block_encoding = SelectBlockEncoding(select=sel, prepare=prep) |
52 | 55 | walk_op = QubitizationWalkOperator(block_encoding=block_encoding) |
53 | 56 | return walk_op |
| 57 | + |
| 58 | + |
| 59 | +def get_reiher_thc_walk_operator( |
| 60 | + num_bits_theta: int = 16, num_bits_state_prep: int = 10 |
| 61 | +) -> QubitizationWalkOperator: |
| 62 | + """Build the THC walk operator for the Reiher hamiltoninan |
| 63 | +
|
| 64 | + Note currently we spoof the Hamiltonian by over writing prepare's 1-norm |
| 65 | + value with the correct value and use random THC factors for expediency. |
| 66 | +
|
| 67 | + Parameters are taken from openfermion compute_cost_thc_test.py. |
| 68 | +
|
| 69 | + Args: |
| 70 | + num_bits_theta: the number of bits of precision for the givens rotations |
| 71 | + num_bits_state_prep: The number of bits of precision for the preparation |
| 72 | + of the LCU coefficients using alias sampling. |
| 73 | +
|
| 74 | + Returns: |
| 75 | + walk_op: A constructed Reiher Hamiltonian walk operator. |
| 76 | + """ |
| 77 | + # Let's just generate some random coefficients for the moment with parameters |
| 78 | + # corresponding to the FeMoCo model complex. |
| 79 | + num_spin_orb = 108 |
| 80 | + num_mu = 350 |
| 81 | + num_bits_theta = 16 |
| 82 | + num_bits_state_prep = 10 |
| 83 | + tpq = np.random.normal(0, 1, size=(num_spin_orb // 2, num_spin_orb // 2)) |
| 84 | + zeta = np.random.normal(0, 1, size=(num_mu, num_mu)) |
| 85 | + zeta = 0.5 * (zeta + zeta.T) |
| 86 | + eta = np.random.normal(0, 1, size=(num_mu, num_spin_orb // 2)) |
| 87 | + eri_thc = np.einsum("Pp,Pr,Qq,Qs,PQ->prqs", eta, eta, eta, eta, zeta, optimize=True) |
| 88 | + # In practice one typically uses the exact ERI tensor instead of that from |
| 89 | + # THC, but that's a minor detail. |
| 90 | + tpq_prime = ( |
| 91 | + tpq |
| 92 | + - 0.5 * np.einsum("illj->ij", eri_thc, optimize=True) |
| 93 | + + np.einsum("llij->ij", eri_thc, optimize=True) |
| 94 | + ) |
| 95 | + t_l = np.linalg.eigvalsh(tpq_prime) |
| 96 | + qroam_blocking_factor = QI(num_mu + num_spin_orb // 2)[0] |
| 97 | + walk_op = get_walk_operator_for_thc_ham( |
| 98 | + t_l, |
| 99 | + eta, |
| 100 | + zeta, |
| 101 | + num_bits_state_prep=num_bits_state_prep, |
| 102 | + num_bits_theta=num_bits_theta, |
| 103 | + kr1=qroam_blocking_factor, |
| 104 | + kr2=qroam_blocking_factor, |
| 105 | + ) |
| 106 | + # GIANT HACK: overwrite the lambda value directly |
| 107 | + # TODO: maybe parse THC hamiltonian files from openfermion directly |
| 108 | + block_encoding = attrs.evolve( |
| 109 | + walk_op.block_encoding, prepare=attrs.evolve(walk_op.prepare, sum_of_l1_coeffs=306.3) |
| 110 | + ) |
| 111 | + walk_op = attrs.evolve(walk_op, block_encoding=block_encoding) |
| 112 | + return walk_op |
0 commit comments