pyquil icon indicating copy to clipboard operation
pyquil copied to clipboard

Add support for parameter substitution

Open mhodson-rigetti opened this issue 4 years ago • 3 comments

Pre-Request Checklist

  • [x] I am running the latest versions of pyQuil and the Forest SDK
  • [x] I checked to make sure that this feature has not already been requested

Feature Description

I would like to be able to substitute some or all memory parameters into a parameterized program, returning a program that has evaluated to the fullest extent any expressions involving those parameters.

e.g. RX(1 + 2 * theta) with { "theta": 0.1 } becomes RX(1.2)

This appears not to be supported in the pyquil API, though this type of substitution is done in the back prior to running on QPU.

Proposed Solution

There is a substitute method in pyquil, whichat first glance looks built for this purpose: https://github.com/rigetti/pyquil/blob/master/pyquil/quilatom.py#L384

The first argument it typed to take any expression.

In the pyquil realization of Quil, a Parameter is an Expression, and a MemoryReference is an Expression, but they are otherwise separate. A parameter is denoted %something in text and is used in (at least) the DEFCAL and DEFGATE structures. In the Quil arXiv paper these are referred to as "formal parameters" and this makes sense from a language perspective.

A memory reference is denoted theta or theta[5] in text and is part of an instruction that refers to classical memory; which is always an array though the index can be omitted if it is length 1 and implies the zero index.

With this in mind, the only code path I see to substitute() is through expand_calibrations() (which calls fill_placeholders()). It seems to me in this use case we have a user-defined match-set of specific parameter values for a gate, and these are being filled to effectively return an instantiated calibration (eg. for some particular angle, and so resolving any control expressions such as shift-frequency that apply).

I do not think this code path should encounter a classical memory reference, and this is suggested also by the type of the second argument, which is a parameter to value map.

I therefore recommend expanding the map type to allow memory references, and providing the following implementation of the method _substitute() for MemoryReference so that the substitution is made. Something like the following, but with some adjustments for correct typing, and perhaps alleviating the need to cross-convert a memory reference to a parameter.

def _substitute(self, parameter_memory_map) -> ExpressionDesignator:
    self_as_parameter = Parameter(self.name)
    if self_as_parameter not in parameter_memory_map:
        return self  # cannot substitute; unchanged behavior

    memory = parameter_memory_map[self_as_parameter]
    if self.offset >= len(memory):
        raise RuntimeError(f"memory access {self.name}[{self.offset}] exceeds bounds of parameter value")

    return memory[self.offset]

Additional References

None.

mhodson-rigetti avatar Sep 22 '21 07:09 mhodson-rigetti

:tada: This issue has been resolved in version 3.1.0-rc.1 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

rigetti-githubbot avatar Oct 15 '21 20:10 rigetti-githubbot

:tada: This issue has been resolved in version 3.2.0-rc.1 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

rigetti-githubbot avatar Feb 14 '22 18:02 rigetti-githubbot

:tada: This issue has been resolved in version 3.2.0 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

rigetti-githubbot avatar Aug 03 '22 22:08 rigetti-githubbot

already released

kmunoz-rgti avatar Nov 07 '22 23:11 kmunoz-rgti