-
Notifications
You must be signed in to change notification settings - Fork 368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix snapshot density matrix #374
Changes from all commits
17b3554
2fed9ca
3422e50
8a8ccff
9fd75ce
09d5e29
03af651
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -468,6 +468,18 @@ QasmController::simulation_method(const Circuit &circ, | |||||
bool validate) const { | ||||||
// Check simulation method and validate state | ||||||
switch(simulation_method_) { | ||||||
case Method::statevector: { | ||||||
if (validate) { | ||||||
if (simulation_precision_ == Precision::single_precision) { | ||||||
Statevector::State<QV::QubitVector<float>> state; | ||||||
validate_state(state, circ, noise_model, true); | ||||||
} else { | ||||||
Statevector::State<QV::QubitVector<>> state; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's clearer if we explicitily say:
Suggested change
|
||||||
validate_state(state, circ, noise_model, true); | ||||||
} | ||||||
} | ||||||
return Method::statevector; | ||||||
} | ||||||
case Method::density_matrix: { | ||||||
if (validate) | ||||||
validate_state(DensityMatrix::State<>(), circ, noise_model, true); | ||||||
|
@@ -504,7 +516,7 @@ QasmController::simulation_method(const Circuit &circ, | |||||
validate_state(DensityMatrix::State<>(), circ, noise_model, false) && | ||||||
check_measure_sampling_opt(circ, Method::density_matrix).first) { | ||||||
return Method::density_matrix; | ||||||
} | ||||||
} | ||||||
// Finally we check the statevector memory requirement for the | ||||||
// current number of qubits. If it fits in available memory we | ||||||
// default to the Statevector method. Otherwise we attempt to use | ||||||
|
@@ -527,10 +539,16 @@ QasmController::simulation_method(const Circuit &circ, | |||||
} | ||||||
// If we didn't select extended stabilizer above proceed to the default switch clause | ||||||
default: { | ||||||
// Default method is statevector | ||||||
// For default we use statevector followed by density matrix (for the case | ||||||
// when the circuit contains invalid instructions for statevector) | ||||||
if (validate_state(Statevector::State<>(), circ, noise_model, false)) { | ||||||
return Method::statevector; | ||||||
} | ||||||
// If circuit contains invalid instructions for statevector throw a hail | ||||||
// mary and try for density matrix. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ave María!! |
||||||
if (validate) | ||||||
validate_state(Statevector::State<>(), circ, noise_model, true); | ||||||
return Method::statevector; | ||||||
validate_state(DensityMatrix::State<>(), circ, noise_model, true); | ||||||
return Method::density_matrix; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,10 @@ | |
snapshot_state_pre_measure_statevector_nondeterministic, | ||
snapshot_state_post_measure_statevector_nondeterministic) | ||
|
||
def get_snapshots(data, label, snapshot_type): | ||
"""Format snapshots as list of Numpy arrays""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this has one more level of indentation, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indeed! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will merge here and fix in #380 |
||
return data.get("snapshots", {}).get(snapshot_type, {}).get(label, []) | ||
|
||
|
||
class QasmSnapshotStatevectorTests: | ||
"""QasmSimulator snapshot statevector tests.""" | ||
|
@@ -40,14 +44,10 @@ class QasmSnapshotStatevectorTests: | |
] | ||
BACKEND_OPTS = {} | ||
|
||
def statevector_snapshots(self, data, label): | ||
@staticmethod | ||
def statevector_snapshots(data, label): | ||
"""Format snapshots as list of Numpy arrays""" | ||
# Check snapshot entry exists in data | ||
self.assertIn("snapshots", data) | ||
self.assertIn("statevector", data["snapshots"]) | ||
self.assertIn(label, data["snapshots"]["statevector"]) | ||
# Format output as list of numpy array | ||
snaps = data["snapshots"]["statevector"][label] | ||
snaps = data.get("snapshots", {}).get("statevector", {}).get(label, []) | ||
statevecs = [] | ||
for snap in snaps: | ||
svec = np.array(snap) | ||
|
@@ -188,14 +188,10 @@ class QasmSnapshotStabilizerTests: | |
SUPPORTED_QASM_METHODS = ['automatic', 'stabilizer'] | ||
BACKEND_OPTS = {} | ||
|
||
def stabilizer_snapshots(self, data, label): | ||
"""Format snapshots as list of Numpy arrays""" | ||
# Check snapshot entry exists in data | ||
self.assertIn("snapshots", data) | ||
self.assertIn("stabilizer", data["snapshots"]) | ||
self.assertIn(label, data["snapshots"]["stabilizer"]) | ||
# Format output as list of numpy array | ||
return data["snapshots"]["stabilizer"][label] | ||
@staticmethod | ||
def stabilizer_snapshots(data, label): | ||
"""Get stabilizer snapshots""" | ||
return data.get("snapshots", {}).get("stabilizer", {}).get(label, []) | ||
|
||
@staticmethod | ||
def stabilizes_statevector(stabilizer, statevector): | ||
|
@@ -340,3 +336,151 @@ def test_snapshot_stabilizer_post_measure_nondet(self): | |
stabilizer = snaps[j] | ||
self.assertTrue( | ||
self.stabilizes_statevector(stabilizer, statevec)) | ||
|
||
|
||
class QasmSnapshotDensityMatrixTests: | ||
"""QasmSimulator snapshot density matrix tests.""" | ||
|
||
SIMULATOR = QasmSimulator() | ||
SUPPORTED_QASM_METHODS = [ | ||
'automatic', 'density_matrix' | ||
] | ||
BACKEND_OPTS = {} | ||
|
||
@staticmethod | ||
def density_snapshots(data, label): | ||
"""Format snapshots as list of Numpy arrays""" | ||
# Check snapshot entry exists in data | ||
snaps = data.get("snapshots", {}).get("density_matrix", {}).get(label, []) | ||
# Convert nested lists to numpy arrays | ||
output = {} | ||
for snap_dict in snaps: | ||
memory = snap_dict['memory'] | ||
mat = np.array(snap_dict['value']) | ||
output[memory] = mat[:, :, 0] + 1j * mat[:, :, 1] | ||
return output | ||
|
||
def test_snapshot_density_matrix_pre_measure_det(self): | ||
"""Test snapshot density matrix before deterministic final measurement""" | ||
shots = 10 | ||
label = "snap" | ||
counts_targets = snapshot_state_counts_deterministic(shots) | ||
statevec_targets = snapshot_state_pre_measure_statevector_deterministic( | ||
) | ||
circuits = snapshot_state_circuits_deterministic(label, | ||
'density_matrix', | ||
post_measure=False) | ||
|
||
qobj = assemble(circuits, self.SIMULATOR, shots=shots) | ||
job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) | ||
method = self.BACKEND_OPTS.get('method', 'automatic') | ||
if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS: | ||
self.assertRaises(AerError, job.result) | ||
else: | ||
result = job.result() | ||
self.is_completed(result) | ||
self.compare_counts(result, circuits, counts_targets, delta=0) | ||
# Check snapshots | ||
for j, circuit in enumerate(circuits): | ||
data = result.data(circuit) | ||
snaps = self.density_snapshots(data, label) | ||
self.assertTrue(len(snaps), 1) | ||
target = np.outer(statevec_targets[j], statevec_targets[j].conj()) | ||
# Pre-measurement all memory bits should be 0 | ||
value = snaps.get('0x0') | ||
self.assertTrue(np.allclose(value, target)) | ||
|
||
def test_snapshot_density_matrix_pre_measure_nondet(self): | ||
"""Test snapshot density matrix before non-deterministic final measurement""" | ||
shots = 100 | ||
label = "snap" | ||
counts_targets = snapshot_state_counts_nondeterministic(shots) | ||
statevec_targets = snapshot_state_pre_measure_statevector_nondeterministic( | ||
) | ||
circuits = snapshot_state_circuits_nondeterministic(label, | ||
'density_matrix', | ||
post_measure=False) | ||
|
||
qobj = assemble(circuits, self.SIMULATOR, shots=shots) | ||
job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) | ||
method = self.BACKEND_OPTS.get('method', 'automatic') | ||
if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS: | ||
self.assertRaises(AerError, job.result) | ||
else: | ||
result = job.result() | ||
self.is_completed(result) | ||
self.compare_counts(result, | ||
circuits, | ||
counts_targets, | ||
delta=0.2 * shots) | ||
# Check snapshots | ||
for j, circuit in enumerate(circuits): | ||
data = result.data(circuit) | ||
snaps = self.density_snapshots(data, label) | ||
self.assertTrue(len(snaps), 1) | ||
target = np.outer(statevec_targets[j], statevec_targets[j].conj()) | ||
value = snaps.get('0x0') | ||
self.assertTrue(np.allclose(value, target)) | ||
|
||
def test_snapshot_density_matrix_post_measure_det(self): | ||
"""Test snapshot density matrix after deterministic final measurement""" | ||
shots = 10 | ||
label = "snap" | ||
counts_targets = snapshot_state_counts_deterministic(shots) | ||
statevec_targets = snapshot_state_post_measure_statevector_deterministic( | ||
) | ||
circuits = snapshot_state_circuits_deterministic(label, | ||
'density_matrix', | ||
post_measure=True) | ||
|
||
qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) | ||
job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) | ||
method = self.BACKEND_OPTS.get('method', 'automatic') | ||
if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS: | ||
self.assertRaises(AerError, job.result) | ||
else: | ||
result = job.result() | ||
self.is_completed(result) | ||
self.compare_counts(result, circuits, counts_targets, delta=0) | ||
# Check snapshots | ||
for i, circuit in enumerate(circuits): | ||
data = result.data(circuit) | ||
snaps = self.density_snapshots(data, label) | ||
for j, mem in enumerate(data['memory']): | ||
target = statevec_targets[i].get(mem) | ||
target = np.outer(target, target.conj()) | ||
value = snaps.get(mem) | ||
self.assertTrue(np.allclose(value, target)) | ||
|
||
def test_snapshot_density_matrix_post_measure_nondet(self): | ||
"""Test snapshot density matrix after non-deterministic final measurement""" | ||
shots = 100 | ||
label = "snap" | ||
counts_targets = snapshot_state_counts_nondeterministic(shots) | ||
statevec_targets = snapshot_state_post_measure_statevector_nondeterministic( | ||
) | ||
circuits = snapshot_state_circuits_nondeterministic(label, | ||
'density_matrix', | ||
post_measure=True) | ||
|
||
qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) | ||
job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) | ||
method = self.BACKEND_OPTS.get('method', 'automatic') | ||
if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS: | ||
self.assertRaises(AerError, job.result) | ||
else: | ||
result = job.result() | ||
self.is_completed(result) | ||
self.compare_counts(result, | ||
circuits, | ||
counts_targets, | ||
delta=0.2 * shots) | ||
# Check snapshots | ||
for i, circuit in enumerate(circuits): | ||
data = result.data(circuit) | ||
snaps = self.density_snapshots(data, label) | ||
for j, mem in enumerate(data['memory']): | ||
target = statevec_targets[i].get(mem) | ||
target = np.outer(target, target.conj()) | ||
value = snaps.get(mem) | ||
self.assertTrue(np.allclose(value, target)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can move this
validate_state()
right after the en of the conditional, because both branches of the conditional call the same function with the same args.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the state arg is actually different (template param
<float>
or<double>
);