Skip to content
Open
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
9 changes: 8 additions & 1 deletion mqss_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"""MQSS Client package"""

from .job import CircuitJobRequest, HamiltonianJobRequest, JobStatus, Result
from .job import (
CircuitJobRequest,
HamiltonianJobRequest,
JobStatus,
PennylaneJobRequest,
Result,
)
from .mqss_client import MQSSClient
from .resource_info import ResourceInfo

Expand All @@ -11,4 +17,5 @@
"HamiltonianJobRequest",
"JobStatus",
"Result",
"PennylaneJobRequest",
]
21 changes: 21 additions & 0 deletions mqss_client/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ def to_json_dict(self) -> dict:
}


@dataclass
class PennylaneJobRequest(JobRequest):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Bmete7
The PennylaneJobRequest is same as CircuitJobRequest. Why do we need a another class type for it? isn't the Pennylane at the end submit a circuit?
If there is any additional arguments needed that can be added.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

one small comment on the topic @mnfarooqi @annkay108 :
We are planning to change the format of the submitted circuit with the new release of PennylaneAdapter. Therefore, we decided to create a separate class for it, such that the transition to the new format would be smoother.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For any new format, only the value of circuit_format needs to be changed. The circuit itself needs to be serialised for communication purposes, so the circuit type remains the same, i.e. string or stream of bytes.

"""Class to hold Pennylane job information"""

resource_name: str
circuits: str
circuit_format: str
shots: int
no_modify: bool

def to_json_dict(self) -> dict:
"""Convert PennylaneJobRequest to JSON dictionary"""
return {
"resource_name": self.resource_name,
"circuit": self.circuits,
"circuit_format": self.circuit_format,
"shots": self.shots,
"no_modify": self.no_modify,
}


@dataclass
class Result:
"""Result Class to hold counts"""
Expand Down
20 changes: 19 additions & 1 deletion mqss_client/mqss_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
from typing import Dict, Optional, Union

from .hpc_client import HPCOffloadClient
from .job import CircuitJobRequest, HamiltonianJobRequest, JobRequest, JobStatus, Result
from .job import (
CircuitJobRequest,
HamiltonianJobRequest,
JobRequest,
JobStatus,
PennylaneJobRequest,
Result,
)
from .resource_info import ResourceInfo
from .rest_client import RESTClient

Expand Down Expand Up @@ -56,6 +63,11 @@ def submit_job(self, job_request: JobRequest) -> str:
"hamiltonian_job",
job_request.to_json_dict(),
)
elif isinstance(job_request, PennylaneJobRequest):
rsp_json = self.client.post(
"pennylane_job",
job_request.to_json_dict(),
)
else:
raise ValueError("Invalid job request type")

Expand All @@ -73,6 +85,8 @@ def cancel_job(self, uuid: str, job_type: JobRequest) -> None:
self.client.delete(f"job/{uuid}")
elif isinstance(job_type, HamiltonianJobRequest):
self.client.delete(f"hamiltonian_job/{uuid}")
elif isinstance(job_type, PennylaneJobRequest):
self.client.delete(f"pennylane_job/{uuid}")
else:
raise ValueError("Invalid job request type")

Expand All @@ -82,6 +96,8 @@ def job_status(self, uuid: str, job_type: JobRequest) -> JobStatus:
rsp_json = self.client.get(f"job/{uuid}/status")
elif isinstance(job_type, HamiltonianJobRequest):
rsp_json = self.client.get(f"hamiltonian_job/{uuid}/status")
elif isinstance(job_type, PennylaneJobRequest):
rsp_json = self.client.get(f"pennylane_job/{uuid}/status")
else:
raise ValueError("Invalid job request type")

Expand All @@ -98,6 +114,8 @@ def job_result(self, uuid: str, job_type: JobRequest) -> Optional[Result]:
result_json = self.client.get(f"job/{uuid}/result")
elif isinstance(job_type, HamiltonianJobRequest):
result_json = self.client.get(f"hamiltonian_job/{uuid}/result")
elif isinstance(job_type, PennylaneJobRequest):
result_json = self.client.get(f"pennylane_job/{uuid}/result")
else:
raise ValueError("Invalid job request type")

Expand Down
12 changes: 11 additions & 1 deletion test/mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
# For job endpoints
"job": {"jobs": ["mock-uuid-12345"]},
"hamiltonian_job": {"jobs": ["mock-uuid-12345"]},
"pennylane_job": {"jobs": ["mock-uuid-12345"]},
# Status endpoints
"job/mock-uuid-12345/status": {"status": "PENDING"},
"hamiltonian_job/mock-uuid-12345/status": {"status": "PENDING"},
"pennylane_job/mock-uuid-12345/status": {"status": "PENDING"},
# Result endpoints
"job/mock-uuid-12345/result": {
"result": '{"00": 500, "11": 500}',
Expand All @@ -36,6 +38,12 @@
"timestamp_submitted": "2023-04-14 10:00:00.123456",
"timestamp_scheduled": "2023-04-14 10:05:00.123456",
},
"pennylane_job/mock-uuid-12345/result": {
"result": '{"00": 500, "11": 500}',
"timestamp_completed": "2023-04-14 10:15:30.123456",
"timestamp_submitted": "2023-04-14 10:00:00.123456",
"timestamp_scheduled": "2023-04-14 10:05:00.123456",
},
}


Expand Down Expand Up @@ -63,7 +71,9 @@ def mock_receive(queue_name):
method = message_data.get("method", "")

# Handle POST requests for job creation
if (request_path in ["job", "hamiltonian_job"]) and method == "POST":
if (
request_path in ["job", "hamiltonian_job", "pennylane_job"]
) and method == "POST":
return json.dumps({"uuid": "mock-uuid-12345"})

# Handle GET requests using the shared data
Expand Down
21 changes: 21 additions & 0 deletions test/mqss_client_tests_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
HamiltonianJobRequest,
JobStatus,
MQSSClient,
PennylaneJobRequest,
ResourceInfo,
Result,
)
Expand Down Expand Up @@ -44,6 +45,18 @@ def hamiltonian_job_request(resource_name):
)


@pytest.fixture
def pennylane_job_request(resource_name):
"""Fixture to create a pennylane job request"""
return PennylaneJobRequest(
resource_name=resource_name,
circuits=get_qasm(),
circuit_format="qasm",
shots=1000,
no_modify=False,
)


class BaseMQSSClientTests:
"""Base class for MQSS client tests."""

Expand Down Expand Up @@ -105,6 +118,14 @@ def test_submit_hamiltonian_job(
assert job_id is not None
client.cancel_job(job_id, hamiltonian_job_request)

def test_submit_pennylane_job(
self, client: MQSSClient, pennylane_job_request
) -> None:
"""Test submitting a Pennylane job."""
job_id = client.submit_job(pennylane_job_request)
assert job_id is not None
client.cancel_job(job_id, pennylane_job_request)

def test_job_status(
self, client: MQSSClient, circuit_job_request, monkeypatch
) -> None:
Expand Down
7 changes: 7 additions & 0 deletions test/test_mqss_client_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ def test_submit_hamiltonian_job(
hamiltonian_job_request.resource_name = online_resource_name(client)
return super().test_submit_hamiltonian_job(client, hamiltonian_job_request)

def test_submit_pennylane_job(
self, client: MQSSClient, pennylane_job_request
) -> None:
"""Test submitting a Pennylane job."""
pennylane_job_request.resource_name = online_resource_name(client)
return super().test_submit_pennylane_job(client, pennylane_job_request)

def test_job_status(
self, client: MQSSClient, circuit_job_request, monkeypatch
) -> None:
Expand Down
8 changes: 7 additions & 1 deletion test/test_mqss_client_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@
BaseMQSSClientTests,
circuit_job_request,
hamiltonian_job_request,
pennylane_job_request,
resource_name,
)

__all__ = ["circuit_job_request", "hamiltonian_job_request", "resource_name"]
__all__ = [
"circuit_job_request",
"hamiltonian_job_request",
"resource_name",
"pennylane_job_request",
]


@pytest.mark.mock
Expand Down