qiskit-ibm-runtime
qiskit-ibm-runtime copied to clipboard
Cannot run a set of parameters over a single circuit in Sampler
Describe the bug
I have a simple singe-parameter circuit:
th = Parameter('th')
qc = QuantumCircuit(2, 1)
qc.x(1)
qc.h(0)
qc.cp(th, 0, 1)
qc.h(0)
qc.measure(0, 0)
that I would like to bind to 50 parameters
phases = np.linspace(0, 2*np.pi, 50)
and execute. If I try to do this with the Sampler
there is no combination of circuit_indices
and parameter_values
that works. For example, following the example here: https://qiskit.org/documentation/partners/qiskit_ibm_runtime/tutorials/how-to-getting-started-with-sampler.html#Multiple-parameterized-circuits-example I would expect that I need circuit_indices = [0]*len(phases)
and parameter_values=phases
However this does not work:
sampler = Sampler(circuits=[qc], service=service, options={ "backend": backend })
result = sampler(circuit_indices=[0]*len(phases), parameter_values=phases)
yields:
The number of circuits (50) does not match the number of parameter sets (1)
Ok, then I will just do circuit_indices=[0]
, but that also fails:
sampler = Sampler(circuits=[qc], service=service, options={ "backend": backend })
result = sampler(circuit_indices=[0], parameter_values=phases)
gives:
The number of values (50) does not match the number of parameters (1) for the 0-th circuit.
I can try the other possible permutations of parameters and they both fail as well
sampler = Sampler(circuits=[qc], service=service, options={ "backend": backend })
result = sampler(circuit_indices=[0], parameter_values=[phases])
gives:
The number of values (50) does not match the number of parameters (1) for the 0-th circuit.
and
sampler = Sampler(circuits=[qc], service=service, options={ "backend": backend })
result = sampler(circuit_indices=[0]*len(phases), parameter_values=[phases])
fails with:
The number of circuits (50) does not match the number of parameter sets (1)
Steps to reproduce
Expected behavior I should be able to get distributions from a single circuit over multiple parameters.
Suggested solutions
Additional Information
- qiskit-ibm-runtime version: 0.4.0
- Python version:
- Operating system:
I actually figured this out after writing this. The solution is to put each single parameter in its own list:
phases = np.linspace(0,2*np.pi, 50)
working_phases = [[ph] for ph in phases]
This is not very intuitive nor documented anywhere.
@HuangJunye @tmittal947 @lerongil should we document this on qiskit.org docs?
I will work on this :)
Sorry I don't have time to work on this issue in the near term so I'll unassign myself. If anyone is interested in fixing this, please go ahead!
I believe this is a bug in Terra, and does not require a documentation change. In qiskit/primitives/base/base_sampler
, we have
def run(
self,
circuits: QuantumCircuit | Sequence[QuantumCircuit],
parameter_values: Sequence[float] | Sequence[Sequence[float]] | None = None,
**run_options,
so that a sequence of float should be allowed, as defined in the example above. @jakelishman - can you please have a look?
I'm not on the primitives team, so this would be out of my scope sorry. @ikkoham is either the right person to ask, or knows the right person to ask.
For what it's worth, the behaviour Paul's seeing matches my understanding of the primitives interface. Circuits don't take a single float
as their "parameters"; it's logically always a sequence of floats. It just so happens that in Paul's example, that sequence has a length of 1, which leads to confusion.
The solution Paul found in https://github.com/Qiskit/qiskit-ibm-runtime/issues/339#issuecomment-1137386328 looks like the expected behaviour to me - when there was a flat array of 50 elements, it's interpreted (correctly) as one sequence of parameters, so it needs broadcasting to be many sequences of parameters. The broadcast happens correctly, and then there's a mismatch; each of the 50 circuits wants a sequence of length 1, but a sequence of length 50 was provided. I think the confusion here is just because each circuit wants a sequence of length 1; I think it'd be clear that the original form can't work if each circuit wants 2 parameters.
Closing, in V2 Sampler you can do
phases = np.linspace(0, 2*np.pi, 50)
sampler = SamplerV2(backend)
job = sampler.run([(isa_circuit, phases)], shots=10)