-
Notifications
You must be signed in to change notification settings - Fork 13
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
feat: add density matrix simulation via qiskit Aer #380
Conversation
@@ -1,9 +1,13 @@ | |||
Changelog | |||
~~~~~~~~~ | |||
|
|||
.. currentmodule:: pytket.extensions.qiskit |
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.
Is this deliberate? I'm unfamiliar with the syntax
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.
Yeah, basically it means that the refernces to classes and functions don't need to be fully qualified. The link is also generated
i.e.
:py:class:`IBMQBackend`
vs
:py:class:`~pytket.extensions.qiskit.IBMQBackend`
""" | ||
Backend for running simulations on the Qiskit Aer density matrix simulator. | ||
|
||
:param noise_model: Noise model to apply during simulation. Defaults to None. |
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.
Should these be defined here or in the init? I'm not sure what our standard is
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.
Seems to me that we document this in the class docstring rather than the __init__
method. I don't have a strong prefernce either way.
_supports_density_matrix = True | ||
_supports_state = False | ||
_memory = False | ||
_noise_model = None |
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.
type information or all these attributes would be helpful
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.
added in 1d5fd8c
super().__init__() | ||
self._qiskit_backend = qiskit_aer_backend(self._qiskit_backend_name) | ||
self._noise_model = noise_model | ||
gate_set = _tket_gate_set_from_qiskit_backend(self._qiskit_backend).union( |
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.
type for this would be great
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.
added in 1d5fd8c
name=type(self).__name__, | ||
device_name=self._qiskit_backend_name, | ||
version=__extension_version__, | ||
architecture=FullyConnected(n_qubits), |
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.
Should this switch between characterisation.architecture
and FullyConnected
? Though maybe using an architecture with a density matrix is not likely behaviour anyway?
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.
I think you may be right. See 64a3ad8
gate_set=_tket_gate_set_from_qiskit_backend(self._qiskit_backend), | ||
supports_midcircuit_measurement=True, | ||
supports_reset=True, | ||
supports_fast_feedforward=True, |
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.
This is definitely true for the density matrix simulator?
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.
I believe so. I have a test case for this here
return BackendResult( | ||
c_bits=c_bits, | ||
q_bits=q_bits, | ||
shots=shots, | ||
counts=counts, | ||
state=state, | ||
unitary=unitary, | ||
density_matrix=density_matrix, |
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.
BackendResult
already has a density_matrix attribute?
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.
I'm just passing it in as an arg when defining the BackendResult
though right?
tests/backend_test.py
Outdated
result1.get_density_matrix(), np.outer(output_state, output_state.conj()) | ||
) | ||
# Example with resets and conditional gates | ||
# Deterministic if input is a computational basis state |
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.
Don't quite understand this comment. What exactly is deterministic?
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.
So despite the fact that the circuit contains measures and resets it prepares a state deterministically assuming that it starts from the
updated the comment.
tests/backend_test.py
Outdated
assert noisy_density_sim.valid_circuit(circ) | ||
|
||
result = noisy_density_sim.run_circuit(circ) | ||
assert result.get_density_matrix().shape == (8, 8) |
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.
Can we also check that the density matrix differs from what we get with a non-noisy simulation?
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 way I've done this is to check the purity
If
Another option would be to calcluate the expectation value of some observable
if self.supports_state or self.supports_density_matrix: | ||
qc.save_state() |
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.
Shouldn't we be using https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.library.save_density_matrix.html ?
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.
Yes, the QuantumCircuit.save_state
gave equivalent answers but I think you're right. Its more correct to save the density matrix.
Thanks
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.
Couple of small comments.
tests/backend_test.py
Outdated
noisy_dm = result.get_density_matrix() | ||
assert noisy_dm.shape == (8, 8) | ||
# Check purity to verify mixed state | ||
assert np.trace(noisy_dm**2).real < 1 |
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.
Could we change this to "< 0.99" or something so that we rule out the possibility of rounding errors causing the test to pass when it shouldn't?
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.
Thanks, done.
tests/backend_test.py
Outdated
noiseless_dm2 = result2.get_density_matrix() | ||
assert np.allclose(noiseless_dm2, np.outer(statevector, statevector.conj())) | ||
# Check purity to verify that we have a pure state | ||
assert np.trace(noiseless_dm2**2).real == 1 |
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.
Better to use np.isclose()
for floating-point comparison, to account for rounding error.
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.
Good point, done in ff91d0a
Description
Adding a new
AerDensityMatrixBackend
class. Unlike other density matrix simulators available through the pytket extensions this emulator should support an optionalNoiseModel
in the constructor.There's a decent amount of duplication from the
AerBackend
implementation forBackendInfo
. Maybe there's a smarter and less error prone way to do it.Related issues
closes #231
Checklist