qiskit-ibm-runtime icon indicating copy to clipboard operation
qiskit-ibm-runtime copied to clipboard

Cannot run a set of parameters over a single circuit in Sampler

Open nonhermitian opened this issue 2 years ago • 6 comments

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:

nonhermitian avatar May 25 '22 14:05 nonhermitian

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.

nonhermitian avatar May 25 '22 14:05 nonhermitian

@HuangJunye @tmittal947 @lerongil should we document this on qiskit.org docs?

rathishcholarajan avatar May 25 '22 17:05 rathishcholarajan

I will work on this :)

HuangJunye avatar May 30 '22 08:05 HuangJunye

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!

HuangJunye avatar Jul 07 '22 07:07 HuangJunye

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?

merav-aharoni avatar Aug 15 '23 12:08 merav-aharoni

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.

jakelishman avatar Aug 21 '23 11:08 jakelishman

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)

jyu00 avatar Jul 03 '24 20:07 jyu00