|
1 | 1 | from qforte import build_circuit, Computer, QubitOperator
|
2 | 2 | import numpy as np
|
| 3 | +import qforte as qf |
| 4 | +import random |
| 5 | +from copy import deepcopy |
3 | 6 |
|
4 | 7 |
|
5 | 8 | class TestSparseOp:
|
@@ -102,3 +105,169 @@ def test_sparse_operator(self):
|
102 | 105 | print("Operator used for sparse matrix operator test: \n", qubit_op)
|
103 | 106 | print("||∆||: ", diff_val)
|
104 | 107 | assert diff_val < 1.0e-15
|
| 108 | + |
| 109 | + def test_sparse_gates(self): |
| 110 | + """ |
| 111 | + This test ensures that the sparse matrix representations of various |
| 112 | + gates agrees with those obtained using the kronecker product with |
| 113 | + the identity matrix |
| 114 | + """ |
| 115 | + |
| 116 | + def sparse_matrix_to_numpy_array(sp_mat: dict, dim: int) -> np.array: |
| 117 | + mat = np.zeros((dim, dim), dtype=complex) |
| 118 | + for row in sp_mat: |
| 119 | + for column in sp_mat[row]: |
| 120 | + mat[row, column] = sp_mat[row][column] |
| 121 | + return mat |
| 122 | + |
| 123 | + one_qubit_gate_pool = [ |
| 124 | + "X", |
| 125 | + "Y", |
| 126 | + "Z", |
| 127 | + "Rx", |
| 128 | + "Ry", |
| 129 | + "Rz", |
| 130 | + "H", |
| 131 | + "S", |
| 132 | + "T", |
| 133 | + "R", |
| 134 | + "V", |
| 135 | + "adj(V)", |
| 136 | + ] |
| 137 | + |
| 138 | + two_qubit_gate_pool = [ |
| 139 | + "CNOT", |
| 140 | + "aCNOT", |
| 141 | + "cY", |
| 142 | + "cZ", |
| 143 | + "cV", |
| 144 | + "SWAP", |
| 145 | + "cRz", |
| 146 | + "cR", |
| 147 | + "A", |
| 148 | + "adj(cV)", |
| 149 | + ] |
| 150 | + |
| 151 | + parametrized_gate_periods = { |
| 152 | + "Rx": 4 * np.pi, |
| 153 | + "Ry": 4 * np.pi, |
| 154 | + "Rz": 4 * np.pi, |
| 155 | + "R": 2 * np.pi, |
| 156 | + "cR": 2 * np.pi, |
| 157 | + "cRz": 4 * np.pi, |
| 158 | + "A": 2 * np.pi, |
| 159 | + } |
| 160 | + |
| 161 | + dim = 2 |
| 162 | + identity = np.eye(2) |
| 163 | + for gatetype in one_qubit_gate_pool: |
| 164 | + if gatetype in parametrized_gate_periods: |
| 165 | + period = parametrized_gate_periods[gatetype] |
| 166 | + parameter = random.uniform(-period / 2, period / 2) |
| 167 | + gate_0 = qf.gate(gatetype, 0, parameter) |
| 168 | + gate_1 = qf.gate(gatetype, 1, parameter) |
| 169 | + else: |
| 170 | + if gatetype == "adj(V)": |
| 171 | + gate_0 = qf.gate("V", 0) |
| 172 | + gate_0 = gate_0.adjoint() |
| 173 | + gate_1 = qf.gate("V", 1) |
| 174 | + gate_1 = gate_1.adjoint() |
| 175 | + else: |
| 176 | + gate_0 = qf.gate(gatetype, 0) |
| 177 | + gate_1 = qf.gate(gatetype, 1) |
| 178 | + sparse_mat_0 = gate_0.sparse_matrix(2) |
| 179 | + sparse_mat_1 = gate_1.sparse_matrix(2) |
| 180 | + mat = sparse_matrix_to_numpy_array(gate_0.sparse_matrix(1).to_map(), dim) |
| 181 | + mat_0 = sparse_matrix_to_numpy_array(sparse_mat_0.to_map(), dim * 2) |
| 182 | + mat_1 = sparse_matrix_to_numpy_array(sparse_mat_1.to_map(), dim * 2) |
| 183 | + mat_0_kron = np.kron(identity, mat) |
| 184 | + mat_1_kron = np.kron(mat, identity) |
| 185 | + assert np.all(mat_0 == mat_0_kron) |
| 186 | + assert np.all(mat_1 == mat_1_kron) |
| 187 | + |
| 188 | + dim = 4 |
| 189 | + for gatetype in two_qubit_gate_pool: |
| 190 | + if gatetype in parametrized_gate_periods: |
| 191 | + period = parametrized_gate_periods[gatetype] |
| 192 | + parameter = random.uniform(-period / 2, period / 2) |
| 193 | + gate_01 = qf.gate(gatetype, 0, 1, parameter) |
| 194 | + gate_10 = qf.gate(gatetype, 1, 0, parameter) |
| 195 | + gate_12 = qf.gate(gatetype, 1, 2, parameter) |
| 196 | + gate_21 = qf.gate(gatetype, 2, 1, parameter) |
| 197 | + else: |
| 198 | + if gatetype == "adj(cV)": |
| 199 | + gate_01 = qf.gate("cV", 0, 1) |
| 200 | + gate_01 = gate_01.adjoint() |
| 201 | + gate_10 = qf.gate("cV", 1, 0) |
| 202 | + gate_10 = gate_10.adjoint() |
| 203 | + gate_12 = qf.gate("cV", 1, 2) |
| 204 | + gate_12 = gate_12.adjoint() |
| 205 | + gate_21 = qf.gate("cV", 2, 1) |
| 206 | + gate_21 = gate_21.adjoint() |
| 207 | + else: |
| 208 | + gate_01 = qf.gate(gatetype, 0, 1) |
| 209 | + gate_10 = qf.gate(gatetype, 1, 0) |
| 210 | + gate_12 = qf.gate(gatetype, 1, 2) |
| 211 | + gate_21 = qf.gate(gatetype, 2, 1) |
| 212 | + sparse_mat_01 = gate_01.sparse_matrix(3) |
| 213 | + sparse_mat_10 = gate_10.sparse_matrix(3) |
| 214 | + sparse_mat_12 = gate_12.sparse_matrix(3) |
| 215 | + sparse_mat_21 = gate_21.sparse_matrix(3) |
| 216 | + mat1 = sparse_matrix_to_numpy_array(gate_01.sparse_matrix(2).to_map(), dim) |
| 217 | + mat2 = sparse_matrix_to_numpy_array(gate_10.sparse_matrix(2).to_map(), dim) |
| 218 | + mat_01 = sparse_matrix_to_numpy_array(sparse_mat_01.to_map(), dim * 2) |
| 219 | + mat_10 = sparse_matrix_to_numpy_array(sparse_mat_10.to_map(), dim * 2) |
| 220 | + mat_12 = sparse_matrix_to_numpy_array(sparse_mat_12.to_map(), dim * 2) |
| 221 | + mat_21 = sparse_matrix_to_numpy_array(sparse_mat_21.to_map(), dim * 2) |
| 222 | + mat_01_kron = np.kron(identity, mat1) |
| 223 | + mat_10_kron = np.kron(identity, mat2) |
| 224 | + mat_12_kron = np.kron(mat1, identity) |
| 225 | + mat_21_kron = np.kron(mat2, identity) |
| 226 | + assert np.all(mat_01 == mat_01_kron) |
| 227 | + assert np.all(mat_10 == mat_10_kron) |
| 228 | + assert np.all(mat_12 == mat_12_kron) |
| 229 | + assert np.all(mat_21 == mat_21_kron) |
| 230 | + |
| 231 | + def test_circuit_sparse_matrix(self): |
| 232 | + Rhh = 1.5 |
| 233 | + |
| 234 | + mol = qf.system_factory( |
| 235 | + system_type="molecule", |
| 236 | + build_type="psi4", |
| 237 | + basis="sto-6g", |
| 238 | + mol_geometry=[ |
| 239 | + ("H", (0, 0, -3 * Rhh / 2)), |
| 240 | + ("H", (0, 0, -Rhh / 2)), |
| 241 | + ("H", (0, 0, Rhh / 2)), |
| 242 | + ("H", (0, 0, 3 * Rhh / 2)), |
| 243 | + ], |
| 244 | + symmetry="d2h", |
| 245 | + multiplicity=1, |
| 246 | + charge=0, |
| 247 | + num_frozen_docc=0, |
| 248 | + num_frozen_uocc=0, |
| 249 | + run_mp2=0, |
| 250 | + run_ccsd=0, |
| 251 | + run_cisd=0, |
| 252 | + run_fci=0, |
| 253 | + ) |
| 254 | + |
| 255 | + for compact in [False, True]: |
| 256 | + uccsd = qf.UCCNVQE( |
| 257 | + mol, compact_excitations=compact, qubit_excitations=False |
| 258 | + ) |
| 259 | + uccsd.run( |
| 260 | + pool_type="SD", opt_maxiter=200, optimizer="bfgs", opt_thresh=1.0e-5 |
| 261 | + ) |
| 262 | + |
| 263 | + qc1 = qf.Computer(mol.hamiltonian.num_qubits()) |
| 264 | + qc1.apply_circuit(uccsd.build_Uvqc()) |
| 265 | + coeff_vec1 = deepcopy(qc1.get_coeff_vec()) |
| 266 | + |
| 267 | + Uvqc = uccsd.build_Uvqc() |
| 268 | + sparse_Uvqc = Uvqc.sparse_matrix(mol.hamiltonian.num_qubits()) |
| 269 | + qc2 = qf.Computer(mol.hamiltonian.num_qubits()) |
| 270 | + qc2.apply_sparse_matrix(sparse_Uvqc) |
| 271 | + coeff_vec2 = qc2.get_coeff_vec() |
| 272 | + |
| 273 | + assert np.linalg.norm(np.array(coeff_vec2) - np.array(coeff_vec1)) < 1.0e-14 |
0 commit comments