question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Need to fix the inconsistent part between the base classes and the reference implementations of Primitives

See original GitHub issue

What is the expected enhancement?

There are some different part between the base classes and the reference implementations of Primitives. I think we need to make them consistent. Since removing existing features is more difficult than adding new features, I think it would be good to keep the reference implementation as simple as possible as the first version.

  1. The reference implementation can broadcast parameters only if there are 1 circuit and 1 observable for estimator, 1 circuit for sampler. This is not documented in the base classes. I feel this rule is a bit complicated and this rule is not mentioned in the example of the base classes.
# first example
params = [[0, 0], [1, 1], [2, 2]]
with Estimator(qc, op) as estimator:
  result = estimator(parameter_values=params) # OK with the current impl: result.values = expval(qc, op, [0, 0]), expval(qc, op, [1, 1]), expval(qc, op, [2, 2])
  result = estimator([0] * params.shape[0], [0] * params.shape[0], parameter_values=params)  # equivalent code w/o broadcasting 

with Estimator([qc] * 2, [op] * 2) as estimator:
  result = estimator(parameter_values=params) # Error
  1. circuit_indices and observable_indices are required in the base classes, but the reference implementation allows optional, i.e., they use all circuits or all observables if indices are None.

https://github.com/Qiskit/qiskit-terra/blob/688cf6abe4ec0a2f843a63135cc6c3e9a497b2c3/qiskit/primitives/base_estimator.py#L199-L203 https://github.com/Qiskit/qiskit-terra/blob/688cf6abe4ec0a2f843a63135cc6c3e9a497b2c3/qiskit/primitives/estimator.py#L60-L64

# second example
params = [[0, 1], [2, 3]]
with Estimator([qc1, qc2], [op1, op2]) as estimator:
  result = estimator(parameter_values=params)  # OK with the current impl: result.values = expval(qc1, op1, [0, 1]), expval(qc2, op2, [2, 3])
  # the above code is similar to the broadcasting rule (see the first example), but behaves in a different way
  result = estimator([0, 1], [0, 1], params)  # equivalent code

The combination of these two rules is tricky. According to the first example, estimator(parameter_values=params) in the second example looks broadcasting params, but it actually takes zip of quantum circuits and observables.

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
Cryoriscommented, Sep 6, 2022

I see the advantage of being explicit with the broadcasting: you’re always aware of what’s being calculated and maybe this points out an error if you have lists of differing lengths. However in the algorithms we very often have the setting where we have the same circuit (and observable) and them for different parameter values. Right now this forces us to write something like

def evaluate(parameters: np.ndarray | list[np.ndarray]):
    if not isinstance(parameters, list):
        parameters = [parameters]
    batchsize = np.asarray(parameters).shape[0]
    result = estimator.run(batchsize * [circuit], batchsize * [operator], parameters).result()

which is a bit cumbersome (and the same code get’s repeated a lot). We need to handle a single array of parameters and an arbitrary number of parameter-arrays here, since different optimizers can submit batches of parameters at once.

It would be much nicer if instead we could write something like

def evaluate(parameters: np.ndarray | list[np.ndarray]):
    result = estimator.run(circuit, operator, parameters).result()

Maybe we can also support broadcasting only if the circuit and operator are not a list, that might still be clear enough as behaviour? 🙂

1reaction
levbishopcommented, Apr 1, 2022

My preference is to remove the broadcasting and optional behaviours. I find having to write an explicit [0]*n or [[]] not very painful and makes the nature of the broadcast very explicit and easy to modify eg if you have a second circuit to broadcast over just change to [1]*n

Read more comments on GitHub >

github_iconTop Results From Across the Web

Adds a fake session to primitives · Issue #9139 - GitHub
The idea of FakeSession was discussed when session was introduced in runtime. I said it should not be included in the base class...
Read more >
Never make public members virtual/abstract - really?
Saying. that it is an anti-pattern to make public methods virtual or abstract because of the developer of a derived class that implements ......
Read more >
NotSupportedException Class (System) - Microsoft Learn
This is a common exception when you are calling methods on an object that provides implementations for the methods of an abstract base...
Read more >
MET08-J. Preserve the equality contract when overriding the ...
When the class lacks a customized equals() method (either locally declared or inherited from a parent class), it uses the default Object.equals() implementation...
Read more >
Bug Patterns - Error Prone
Reference equality of boxed primitive types is usually not useful, as they are value objects, and it is bug-prone, as instances are cached...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found