Qiskit / qiskit-aer

Aer is a high performance simulator for quantum circuits that includes noise models
https://qiskit.github.io/qiskit-aer/
Apache License 2.0
502 stars 361 forks source link

Proposed change to the API of SaveAmplitudesSquared instruciton #1470

Open or1426 opened 2 years ago

or1426 commented 2 years ago

Motivation

Given a quantum state of n qubits, an interesting and (sometimes) practically relevant question one can ask is

What is the probability of obtaining a particular measurement outcome when performing a computational-basis measurement on a specified subset of the qubits?

There currently isn't a great way to use qiskit to answer this question. You can technically do it with the SaveExpectationValue instruction, but this isn't a particularly intuitive way to get this information.

What is the expected behavior?

The current definition of SaveAmplitudesSquared is

SaveAmplitudesSquared(num_qubits, params, label='amplitudes_squared', unnormalized=False, pershot=False, conditional=False)

this proposal would change it to

SaveAmplitudesSquared(num_qubits, qubits=None, outcomes=None, label='amplitudes_squared', unnormalized=False, pershot=False, conditional=False)

If not-None the qubits parameter is expected to be a list of k qubits indicating which ones we're measuring. If it is None then assume we measure every qubit.

If not-None the outcomes parameter is expected to be a list of k qubit computational-basis states indicating which outcomes we're interested in. If it is None then assume we are looking for every outcome.

Note that some simulation methods can get pretty significant performance improvements by focussing on specified probabilities - in particular the one I'm implementing in pull request #1273.

Examples

circ = QuantumCircuit(3, 3)
circ.h(1)
circ.h(2)
circ.save_amplitudes_squared(1, qubits=[0], outcome=[0]) # p = 1 
circ.save_amplitudes_squared(1, qubits=[1], outcome=[0]) # p = 0.5
circ.save_amplitudes_squared(2, qubits=[0,1], outcome=[0]) # p = 0.5
circ.save_amplitudes_squared(2, qubits=[0,1], outcome=[1]) # p = 0
circ.save_amplitudes_squared(2, qubits=[1,0], outcome=[1]) # p = 0.5
circ.save_amplitudes_squared(2, qubits=[1,0,2], outcome=[1]) # p = 0.25
circ.save_amplitudes_squared(2, qubits=[1,0,2], outcome=[2]) # p = 0

Problems

  1. Computing every measurement outcome for every qubit can be unintuitively slow/expensive
  2. Computing a single-qubit measurement outcome can also be unintuitively slow/expensive (especially for simulators that have to add up exponentially many probabilities to get marginals)
  3. The new version of SaveAmplitudesSquared will have considerable overlap with SaveProbabilities (if both parameters are None then it will do exactly what SaveProbabilities does)
  4. I'm not sure how the qubits and num_qubits parameters interact, especially if they're inconsistent
  5. It might make sense to change the SaveAmplitudes instruction in the same way, but I don't think there is any physical interpretation/meaning to raw amplitudes on subsets of qubits.
chriseclectic commented 2 years ago

We debated adding this when adding this instruction but ultimately decided against it since as say in 5 it doesn't really make sense for the amplitudes instruction unless you mask/condition on specific states for non specified qubits, this is why we instead defined these as full width instructions.

I think it would make sense to add this to the SaveProbabilities/SaveProbabilitiesDict instruction, so that they have an optional kwarg to specify the probability values you want to save, since these are already intended to be defined on subsets of qubits. The other simulation methods that support save probabilities would need to be updated to respect this kwarg.

I would also suggest that when you specify the list of probabilities that there is some internal conversion so they can be passed in as bitstrings, hexstrings, or ints in python, and then convert to some appropriate fixed format for qobj serialization (probably hex strings since ints would limit prob strings to 64 qubits which would be limiting for the stabilizer method).

or1426 commented 2 years ago

@chriseclectic Yes that all makes sense to me. I think SaveProbabilities and SaveProbabilitiesDict already have the "slicing" behavior I mentioned, i.e. choosing qubits=[1,0] and qubits=[0,1] work as expected.

I can put together a pull request with the change to the instructions (i.e. the python side and as far as decoding the instruction on the c++ side), but updating any of the existing simulators to respect the new argument is probably beyond my expertise. Otherwise if you prefer I'm very happy for you to do it.

or1426 commented 2 years ago

Hi @chriseclectic is there any update on this? It would be good to have some timeline to know when I can get back to working on the integration of the Clifford+T simulator.