Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: use qcs-sdk-python implementation of conjugate_pauli_by_clifford and generate_randomized_benchmarking_sequence #1557

Merged
merged 6 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 14 additions & 14 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 @@ -27,7 +27,7 @@ rpcq = "^3.10.0"
pydantic = "^1.10.7"
networkx = "^2.5"
importlib-metadata = { version = ">=3.7.3,<5", python = "<3.8" }
qcs-sdk-python = "0.5.0rc.17"
qcs-sdk-python = "0.5.0rc.20"
retry = "^0.9.2"
types-python-dateutil = "^2.8.19"
types-retry = "^0.9.9"
Expand Down
25 changes: 14 additions & 11 deletions pyquil/api/_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
from typing import List, Optional, Sequence, cast

from qcs_sdk import QCSClient
from qcs_sdk.compiler.quilc import (
PauliTerm as QuilcPauliTerm,
RandomizedBenchmarkingRequest,
ConjugateByCliffordRequest,
)

from pyquil.api._abstract_compiler import AbstractBenchmarker
from pyquil.api._compiler_client import (
GenerateRandomizedBenchmarkingSequenceRequest,
ConjugatePauliByCliffordRequest,
CompilerClient,
)
from pyquil.api._compiler_client import CompilerClient

from pyquil.paulis import PauliTerm, is_identity
from pyquil.quil import address_qubits, Program
Expand Down Expand Up @@ -65,14 +66,16 @@ def apply_clifford_to_pauli(self, clifford: Program, pauli_in: PauliTerm) -> Pau

indices_and_terms = list(zip(*list(pauli_in.operations_as_set())))

request = ConjugatePauliByCliffordRequest(
pauli_indices=list(indices_and_terms[0]),
pauli_symbols=list(indices_and_terms[1]),
request = ConjugateByCliffordRequest(
pauli=QuilcPauliTerm(
indices=list(indices_and_terms[0]),
symbols=list(indices_and_terms[1]),
),
clifford=clifford.out(calibrations=False),
)
response = self._compiler_client.conjugate_pauli_by_clifford(request)

phase_factor, paulis = response.phase_factor, response.pauli
phase_factor, paulis = response.phase, response.pauli

pauli_out = PauliTerm("I", 0, 1.0j**phase_factor)
clifford_qubits = clifford.get_qubits()
Expand Down Expand Up @@ -133,9 +136,9 @@ def generate_rb_sequence(

depth = int(depth) # needs to be jsonable, no np.int64 please!

request = GenerateRandomizedBenchmarkingSequenceRequest(
request = RandomizedBenchmarkingRequest(
depth=depth,
num_qubits=qubits,
qubits=qubits,
gateset=gateset_for_api,
seed=seed,
interleaver=interleaver_out,
Expand Down
118 changes: 17 additions & 101 deletions pyquil/api/_compiler_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################
from contextlib import contextmanager
from dataclasses import dataclass
import json
from typing import Iterator, List, Optional
from typing import List, Optional

from qcs_sdk import QCSClient
from qcs_sdk.compiler.quilc import get_version_info, compile_program, CompilerOpts, TargetDevice
import rpcq
from qcs_sdk.compiler.quilc import (
get_version_info,
compile_program,
CompilerOpts,
TargetDevice,
conjugate_pauli_by_clifford,
generate_randomized_benchmarking_sequence,
ConjugateByCliffordRequest,
ConjugatePauliByCliffordResponse,
RandomizedBenchmarkingRequest,
GenerateRandomizedBenchmarkingSequenceResponse,
)
from rpcq.messages import TargetDevice as TargetQuantumProcessor


Expand Down Expand Up @@ -87,67 +96,6 @@ class CompileToNativeQuilResponse:
"""Metadata for the returned Native Quil."""


@dataclass
class ConjugatePauliByCliffordRequest:
"""
Request to conjugate a Pauli element by a Clifford element.
"""

pauli_indices: List[int]
"""Qubit indices onto which the factors of the Pauli term are applied."""

pauli_symbols: List[str]
"""Ordered factors of the Pauli term."""

clifford: str
"""Clifford element."""


@dataclass
class ConjugatePauliByCliffordResponse:
"""
Conjugate Pauli by Clifford response.
"""

phase_factor: int
"""Encoded global phase factor on the emitted Pauli."""

pauli: str
"""Description of the encoded Pauli."""


@dataclass
class GenerateRandomizedBenchmarkingSequenceRequest:
"""
Request to generate a randomized benchmarking sequence.
"""

depth: int
"""Depth of the benchmarking sequence."""

num_qubits: int
"""Number of qubits involved in the benchmarking sequence."""

gateset: List[str]
"""List of Quil programs, each describing a Clifford."""

seed: Optional[int]
"""PRNG seed. Set this to guarantee repeatable results."""

interleaver: Optional[str]
"""Fixed Clifford, specified as a Quil string, to interleave through an RB sequence."""


@dataclass
class GenerateRandomizedBenchmarkingSequenceResponse:
"""
Randomly generated benchmarking sequence response.
"""

sequence: List[List[int]]
"""List of Cliffords, each expressed as a list of generator indices."""


class CompilerClient:
"""
Client for making requests to a Quil compiler.
Expand Down Expand Up @@ -197,48 +145,16 @@ def compile_to_native_quil(self, request: CompileToNativeQuilRequest) -> Compile
)
return CompileToNativeQuilResponse(native_program=native_program, metadata=None)

def conjugate_pauli_by_clifford(self, request: ConjugatePauliByCliffordRequest) -> ConjugatePauliByCliffordResponse:
def conjugate_pauli_by_clifford(self, request: ConjugateByCliffordRequest) -> ConjugatePauliByCliffordResponse:
"""
Conjugate a Pauli element by a Clifford element.
"""
rpcq_request = rpcq.messages.ConjugateByCliffordRequest(
pauli=rpcq.messages.PauliTerm(indices=request.pauli_indices, symbols=request.pauli_symbols),
clifford=request.clifford,
)
with self._rpcq_client() as rpcq_client: # type: rpcq.Client
response: rpcq.messages.ConjugateByCliffordResponse = rpcq_client.call(
"conjugate_pauli_by_clifford",
rpcq_request,
)
return ConjugatePauliByCliffordResponse(phase_factor=response.phase, pauli=response.pauli)
return conjugate_pauli_by_clifford(request=request, client=self._client_configuration)

def generate_randomized_benchmarking_sequence(
self, request: GenerateRandomizedBenchmarkingSequenceRequest
self, request: RandomizedBenchmarkingRequest
) -> GenerateRandomizedBenchmarkingSequenceResponse:
"""
Generate a randomized benchmarking sequence.
"""
rpcq_request = rpcq.messages.RandomizedBenchmarkingRequest(
depth=request.depth,
qubits=request.num_qubits,
gateset=request.gateset,
seed=request.seed,
interleaver=request.interleaver,
)
with self._rpcq_client() as rpcq_client: # type: rpcq.Client
response: rpcq.messages.RandomizedBenchmarkingResponse = rpcq_client.call(
"generate_rb_sequence",
rpcq_request,
)
return GenerateRandomizedBenchmarkingSequenceResponse(sequence=response.sequence)

@contextmanager
def _rpcq_client(self) -> Iterator[rpcq.Client]:
client = rpcq.Client(
endpoint=self.base_url,
timeout=self.timeout,
)
try:
yield client
finally:
client.close() # type: ignore
return generate_randomized_benchmarking_sequence(request=request, client=self._client_configuration)
73 changes: 0 additions & 73 deletions test/unit/test_compiler_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from mock import AsyncMock

from qcs_sdk import QCSClient
import rpcq
from _pytest.monkeypatch import MonkeyPatch
import pytest
from pytest import raises
Expand All @@ -32,11 +31,6 @@
CompilerClient,
CompileToNativeQuilRequest,
CompileToNativeQuilResponse,
ConjugatePauliByCliffordRequest,
ConjugatePauliByCliffordResponse,
GenerateRandomizedBenchmarkingSequenceRequest,
GenerateRandomizedBenchmarkingSequenceResponse,
NativeQuilMetadataResponse,
)
from pyquil.external.rpcq import CompilerISA, compiler_isa_to_target_quantum_processor

Expand All @@ -63,16 +57,6 @@ def test_init__validates_compiler_url(monkeypatch: MonkeyPatch):
CompilerClient(client_configuration=client_configuration)


def test_sets_timeout_on_requests(mocker: MockerFixture):
client_configuration = QCSClient.load()
compiler_client = CompilerClient(client_configuration=client_configuration, request_timeout=0.1)

patch_rpcq_client(mocker=mocker, return_value={})

with compiler_client._rpcq_client() as client:
assert client.timeout == compiler_client.timeout


@pytest.mark.skip # cannot mock `qcs_sdk` here
def test_get_version__returns_version(mocker: MockerFixture):
client_configuration = QCSClient.load()
Expand Down Expand Up @@ -102,60 +86,3 @@ def test_compile_to_native_quil__returns_native_quil(
native_program="DECLARE ro BIT[1]\n",
metadata=None,
)


def test_conjugate_pauli_by_clifford__returns_conjugation_result(mocker: MockerFixture):
client_configuration = QCSClient.load()
compiler_client = CompilerClient(client_configuration=client_configuration)
rpcq_client = patch_rpcq_client(
mocker=mocker, return_value=rpcq.messages.ConjugateByCliffordResponse(phase=42, pauli="pauli")
)

request = ConjugatePauliByCliffordRequest(
pauli_indices=[0, 1, 2],
pauli_symbols=["x", "y", "z"],
clifford="cliff",
)
assert compiler_client.conjugate_pauli_by_clifford(request) == ConjugatePauliByCliffordResponse(
phase_factor=42,
pauli="pauli",
)
rpcq_client.call.assert_called_once_with(
"conjugate_pauli_by_clifford",
rpcq.messages.ConjugateByCliffordRequest(
pauli=rpcq.messages.PauliTerm(indices=[0, 1, 2], symbols=["x", "y", "z"]),
clifford="cliff",
),
)


def test_generate_randomized_benchmarking_sequence__returns_benchmarking_sequence(
mocker: MockerFixture,
):
client_configuration = QCSClient.load()
compiler_client = CompilerClient(client_configuration=client_configuration)

rpcq_client = patch_rpcq_client(
mocker=mocker, return_value=rpcq.messages.RandomizedBenchmarkingResponse(sequence=[[3, 1, 4], [1, 6, 1]])
)

request = GenerateRandomizedBenchmarkingSequenceRequest(
depth=42,
num_qubits=3,
gateset=["some", "gate", "set"],
seed=314,
interleaver="some-interleaver",
)
assert compiler_client.generate_randomized_benchmarking_sequence(
request
) == GenerateRandomizedBenchmarkingSequenceResponse(sequence=[[3, 1, 4], [1, 6, 1]])
rpcq_client.call.assert_called_once_with(
"generate_rb_sequence",
rpcq.messages.RandomizedBenchmarkingRequest(
depth=42,
qubits=3,
gateset=["some", "gate", "set"],
seed=314,
interleaver="some-interleaver",
),
)