Skip to content

Commit b48c966

Browse files
author
Zhuoyang Ye
committed
[Test] Density measurement test pass.
1 parent 865b836 commit b48c966

File tree

3 files changed

+67
-66
lines changed

3 files changed

+67
-66
lines changed

test/density/test_density_measure.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_measure_density():
3838
qdev.rx(wires=1, params=1.2) # type: ignore
3939
qdev.cnot(wires=[0, 2]) # type: ignore
4040

41-
tq_counts = tq.measure(qdev, n_shots=n_shots)
41+
tq_counts = tq.measure_density(qdev, n_shots=n_shots)
4242

4343
circ = op_history2qiskit(qdev.n_wires, qdev.op_history)
4444
circ.measure_all()
@@ -58,7 +58,7 @@ def test_measure_density():
5858

5959

6060
if __name__ == "__main__":
61-
import pdb
61+
#import pdb
6262

63-
pdb.set_trace()
64-
test_measure()
63+
#pdb.set_trace()
64+
test_measure_density()

test/density/test_eval_observable_density.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ def test_expval_observable_density():
5757
qdev = tq.NoiseDevice(n_wires=n_wires, bsz=1, record_op=True)
5858
random_layer(qdev)
5959

60-
expval_tq = expval_joint_analytical_density(qdev, observable="".join(obs))[0].item()
60+
expval_tq = expval_joint_analytical_density(qdev, observable="".join(obs))[0].item().real
6161
expval_tq_sampling = expval_joint_sampling_density(
6262
qdev, observable="".join(obs), n_shots=100000
63-
)[0].item()
63+
)[0].item().real
6464

6565
qiskit_circ = op_history2qiskit(qdev.n_wires, qdev.op_history)
6666
operator = pauli_str_op_dict[obs[0]]
@@ -88,9 +88,9 @@ def test_expval_observable_density():
8888

8989

9090
#operator.eval()
91-
expval_qiskit = np.trace(rho_evaled@operator.to_matrix())
91+
expval_qiskit = np.trace(rho_evaled@operator.to_matrix()).real
9292
#print("TWO")
93-
#print(expval_tq, expval_qiskit)
93+
print(expval_tq, expval_qiskit)
9494
assert np.isclose(expval_tq, expval_qiskit, atol=1e-1)
9595
if (
9696
n_wires <= 3

torchquantum/measurement/density_measurements.py

+59-58
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import torchquantum.operator as op
1515
from copy import deepcopy
1616
import matplotlib.pyplot as plt
17-
from .measurements import gen_bitstrings
18-
from .measurements import find_observable_groups
17+
from torchquantum.measurement import gen_bitstrings
18+
from torchquantum.measurement import find_observable_groups
1919

2020
__all__ = [
2121
"expval_joint_sampling_grouping_density",
@@ -181,76 +181,70 @@ def expval_joint_sampling_density(
181181

182182
return torch.tensor(expval_all, dtype=F_DTYPE)
183183

184+
184185
def expval_joint_analytical_density(
185186
noisedev: tq.NoiseDevice,
186187
observable: str,
187188
n_shots=1024
188189
):
189190
"""
190-
Compute the expectation value of a joint observable from sampling
191-
the measurement bistring
192-
Args:
193-
qdev: the quantum device
194-
observable: the joint observable, on the qubit 0, 1, 2, 3, etc in this order
195-
Returns:
196-
the expectation value
197-
Examples:
198-
>>> import torchquantum as tq
199-
>>> import torchquantum.functional as tqf
200-
>>> x = tq.NoiseDevice(n_wires=2)
201-
>>> tqf.hadamard(x, wires=0)
202-
>>> tqf.x(x, wires=1)
203-
>>> tqf.cnot(x, wires=[0, 1])
204-
>>> print(expval_joint_sampling(x, 'II', n_shots=8192))
205-
tensor([[0.9997]])
206-
>>> print(expval_joint_sampling(x, 'XX', n_shots=8192))
207-
tensor([[0.9991]])
208-
>>> print(expval_joint_sampling(x, 'ZZ', n_shots=8192))
209-
tensor([[-0.9980]])
210-
"""
211-
# rotation to the desired basis
212-
n_wires = noisedev.n_wires
213-
paulix = op.op_name_dict["paulix"]
214-
pauliy = op.op_name_dict["pauliy"]
215-
pauliz = op.op_name_dict["pauliz"]
216-
iden = op.op_name_dict["i"]
191+
Compute the expectation value of a joint observable in analytical way, assuming the
192+
density matrix is available.
193+
Args:
194+
qdev: the quantum device
195+
observable: the joint observable, on the qubit 0, 1, 2, 3, etc in this order
196+
Returns:
197+
the expectation value
198+
Examples:
199+
>>> import torchquantum as tq
200+
>>> import torchquantum.functional as tqf
201+
>>> x = tq.QuantumDevice(n_wires=2)
202+
>>> tqf.hadamard(x, wires=0)
203+
>>> tqf.x(x, wires=1)
204+
>>> tqf.cnot(x, wires=[0, 1])
205+
>>> print(expval_joint_analytical(x, 'II'))
206+
tensor([[1.0000]])
207+
>>> print(expval_joint_analytical(x, 'XX'))
208+
tensor([[1.0000]])
209+
>>> print(expval_joint_analytical(x, 'ZZ'))
210+
tensor([[-1.0000]])
211+
"""
212+
# compute the hamiltonian matrix
213+
paulix = mat_dict["paulix"]
214+
pauliy = mat_dict["pauliy"]
215+
pauliz = mat_dict["pauliz"]
216+
iden = mat_dict["i"]
217217
pauli_dict = {"X": paulix, "Y": pauliy, "Z": pauliz, "I": iden}
218218

219-
noisedev_clone = tq.NoiseDevice(n_wires=noisedev.n_wires, bsz=noisedev.bsz, device=noisedev.device)
220-
noisedev_clone.clone_densities(noisedev.densities)
221-
222219
observable = observable.upper()
223-
for wire in range(n_wires):
224-
for rotation in pauli_dict[observable[wire]]().diagonalizing_gates():
225-
rotation(noisedev_clone, wires=wire)
220+
assert len(observable) == noisedev.n_wires
221+
densities = noisedev.get_densities_2d()
226222

227-
mask = np.ones(len(observable), dtype=bool)
228-
mask[np.array([*observable]) == "I"] = False
223+
hamiltonian = pauli_dict[observable[0]].to(densities.device)
224+
for op in observable[1:]:
225+
hamiltonian = torch.kron(hamiltonian, pauli_dict[op].to(densities.device))
229226

230-
expval_all = []
231-
# measure
232-
distributions = measure_density(noisedev_clone, n_shots=n_shots)
233-
for distri in distributions:
234-
n_eigen_one = 0
235-
n_eigen_minus_one = 0
236-
for bitstring, n_count in distri.items():
237-
if np.dot(list(map(lambda x: eval(x), [*bitstring])), mask).sum() % 2 == 0:
238-
n_eigen_one += n_count
239-
else:
240-
n_eigen_minus_one += n_count
227+
batch_size = densities.shape[0]
228+
expanded_hamiltonian = hamiltonian.unsqueeze(0).expand(batch_size, *hamiltonian.shape)
241229

242-
expval = n_eigen_one / n_shots + (-1) * n_eigen_minus_one / n_shots
243-
expval_all.append(expval)
230+
product = torch.bmm(expanded_hamiltonian, densities)
244231

245-
return torch.tensor(expval_all, dtype=F_DTYPE)
232+
# Extract the diagonal elements from each matrix in the batch
233+
diagonals = torch.diagonal(product, dim1=-2, dim2=-1)
234+
235+
# Sum the diagonal elements to get the trace for each batch
236+
trace = torch.sum(diagonals, dim=-1).real
237+
238+
# Should use expectation= Tr(observable \times density matrix)
239+
return trace
246240

247241

248242
def expval_density(
249243
noisedev: tq.NoiseDevice,
250244
wires: Union[int, List[int]],
251245
observables: Union[op.Observable, List[op.Observable]],
252246
):
253-
all_dims = np.arange(noisedev.n_wires+1)
247+
all_dims = np.arange(noisedev.n_wires + 1)
254248
if isinstance(wires, int):
255249
wires = [wires]
256250
observables = [observables]
@@ -314,15 +308,22 @@ def set_v_c_reg_mapping(self, mapping):
314308
qdev = tq.NoiseDevice(n_wires=2, bsz=5, device="cpu", record_op=True) # use device='cuda' for GPU
315309
qdev.h(wires=0)
316310
qdev.cnot(wires=[0, 1])
317-
tqf.h(qdev, wires=1)
318-
tqf.x(qdev, wires=1)
319-
op = tq.RX(has_params=True, trainable=True, init_params=0.5)
320-
op(qdev, wires=0)
311+
#tqf.h(qdev, wires=1)
312+
#tqf.x(qdev, wires=1)
313+
#tqf.y(qdev, wires=1)
314+
#tqf.cnot(qdev,wires=[0, 1])
315+
# op = tq.RX(has_params=True, trainable=True, init_params=0.5)
316+
# op(qdev, wires=0)
321317

322318
# measure the state on z basis
323319
print(tq.measure_density(qdev, n_shots=1024))
324320

325321
# obtain the expval on a observable
326-
expval = expval_joint_sampling_density(qdev, 'II', 100000)
327-
# expval_ana = expval_joint_analytical(qdev, 'II')
322+
expval = expval_joint_sampling_density(qdev, 'XZ', 100000)
323+
324+
print("expval")
328325
print(expval)
326+
327+
expval_ana = expval_joint_analytical_density(qdev, 'XZ')
328+
print("expval_ana")
329+
print(expval_ana)

0 commit comments

Comments
 (0)