Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 136 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ lark = "^0.11.1"
rpcq = "^3.6.0"
networkx = "^2.5"
importlib-metadata = { version = "^3.7.3", python = "<3.8" }
qcs-api-client = "^0.8.0"
qcs-api-client = "0.8.0.dev1451144536"
retry = "^0.9.2"

# latex extra
Expand Down
1 change: 1 addition & 0 deletions pyquil/experimental/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._program import ExperimentalProgram
14 changes: 14 additions & 0 deletions pyquil/experimental/_program.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import Optional
from pyquil.quil import InstructionDesignator, Program


class ExperimentalProgram(Program):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you not update Program itself? Going from non-optional to optional should be backwards compatible

@ameyer-rigetti ameyer-rigetti Jul 27, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I guess could result in a lot of refactoring to satisfy mypy and other use cases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of my intent in this PR is to not have to change anything in the main library for simplicity, with this being almost a "draft" for the next major version (after a long period of iteration & feedback)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes good sense 👍

"""
An ExperimentalProgram is identical to a Program except that ``num_shots`` is optional.
"""

num_shots: Optional[int]

def __init__(self, *instructions: InstructionDesignator):
super().__init__(*instructions)
self.num_shots = None
3 changes: 3 additions & 0 deletions pyquil/experimental/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from ._compiler import ExperimentalQPUCompiler
from ._qpu import ExperimentalQPU
from ._quantum_computer import ExperimentalQuantumComputer, get_experimental_qc
73 changes: 73 additions & 0 deletions pyquil/experimental/api/_compiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from contextlib import contextmanager
from dataclasses import dataclass
import dataclasses
from pyquil.quilbase import Gate
from typing import Dict, Iterator, Optional, cast

from pyquil.api._abstract_compiler import AbstractCompiler, EncryptedProgram, QuantumExecutable
from pyquil.api._compiler import QPUCompiler, rewrite_arithmetic, _collect_memory_descriptors
from pyquil.experimental._program import ExperimentalProgram
from pyquil.quilatom import ExpressionDesignator, MemoryReference
from qcs_api_client.grpc.client import Client as GrpcClient
from qcs_api_client.grpc.models.controller import EncryptedControllerJob
from rpcq.messages import NativeQuilMetadata, ParameterAref, ParameterSpec
from pyquil.parser import parse_program, parse


@dataclass
class ExperimentalExecutable:
job: EncryptedControllerJob

recalculation_table: Dict[ParameterAref, ExpressionDesignator]
"""A mapping from memory references to the original gate arithmetic."""


class ExperimentalQPUCompiler:
quantum_processor_id: str
_timeout: Optional[int] = None

def __init__(self, *, quantum_processor_id: str, timeout: Optional[int] = None):
self.quantum_processor_id = quantum_processor_id
self._timeout = timeout

async def quil_to_native_quil(self, program: ExperimentalProgram):
raise NotImplementedError("compilation of quil to native quil is not yet supported for ExperimentalProgram")

async def native_quil_to_executable(self, native_quil_program: ExperimentalProgram) -> EncryptedControllerJob:
"""
Compile the provided native quil program to an executable suitable for use on the
experimental backend.
"""

# TODO: Expand calibrations within the program, and then remove calibrations and unused frames and waveforms

arithmetic_response = rewrite_arithmetic(native_quil_program)

with self._qcs_client() as client:
job = await client.translate_quil_to_encrypted_controller_job(
quantum_processor_id=self.quantum_processor_id,
quil_program=arithmetic_response.quil,
num_shots=native_quil_program.num_shots,
)

return ExperimentalExecutable(
job=job,
recalculation_table={
mref: _to_expression(rule) for mref, rule in arithmetic_response.recalculation_table.items()
},
)

@contextmanager
def _qcs_client(self) -> Iterator[GrpcClient]:
client = GrpcClient(url="https://grpc.qcs.rigetti.com")
try:
yield client
finally:
client.close()


def _to_expression(rule: str) -> ExpressionDesignator:
# We can only parse complete lines of Quil, so we wrap the arithmetic expression
# in a valid Quil instruction to parse it.
# TODO: This hack should be replaced after #687
return cast(ExpressionDesignator, cast(Gate, parse(f"RZ({rule}) 0")[0]).params[0])
Loading