Skip to content

Commit

Permalink
Introduce schema for Quantum Volume jobs (#67)
Browse files Browse the repository at this point in the history
* Introduce schema for Quantum Volume jobs

* type hinting in schema validator
  • Loading branch information
cosenal authored Dec 10, 2024
1 parent 9d90ed8 commit 6752e29
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 31 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ _build
# MacOS
.DS_Store

# VSCode
.vscode

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
5 changes: 5 additions & 0 deletions metriq_gym/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ def parse_arguments() -> argparse.Namespace:
Parsed arguments as an argparse.Namespace object.
"""
parser = argparse.ArgumentParser(description="Quantum volume certification")
parser.add_argument(
"input_file",
type=str,
help="Path to the file containing the benchmark parameters",
)
parser.add_argument(
"-n", "--num_qubits", type=int, default=8, help="Number of qubits (default is 8)"
)
Expand Down
11 changes: 6 additions & 5 deletions metriq_gym/dispatch_qv.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,38 @@
import logging
import sys


from metriq_gym.bench import dispatch_bench_job
from metriq_gym.job_manager import JobManager
from metriq_gym.cli import parse_arguments
from metriq_gym.stats import calc_stats
from metriq_gym.schema_validator import load_and_validate


logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")


def main():
args = parse_arguments()
params = load_and_validate(args.input_file)

logging.info(
f"Dispatching Quantum Volume job with n={args.num_qubits}, shots={args.shots}, trials={args.trials}, backend={args.backend}, confidence_level={args.confidence_level}, jobs_file={args.jobs_file}"
f"Dispatching {params['benchmark_name']} job with n={params["num_qubits"]}, shots={params["shots"]}, trials={params["trials"]}, backend={args.backend}, confidence_level={params["confidence_level"]}, jobs_file={args.jobs_file}"
)

job_manager = JobManager(args.jobs_file)

result = dispatch_bench_job(
args.num_qubits, args.backend, args.shots, args.trials, args.provider
params["num_qubits"], args.backend, params["shots"], params["trials"], args.provider
)

if len(result.counts) > 0:
stats = calc_stats([result], args.confidence_level)
stats = calc_stats([result], params["confidence_level"])
logging.info(f"Simulator-only job completed: {stats[0]}.")
print(stats[0])

return 0

logging.info(f"Dispatched {args.trials} trials in 1 job.")
logging.info(f"Dispatched {params["trials"]} trials in 1 job.")

job_manager.add_job(result.to_serializable())

Expand Down
2 changes: 1 addition & 1 deletion metriq_gym/job_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

DEFAULT_FILE_PATH = ".metriq_gym_jobs.jsonl"

# TODO: JobManager is not thread-safe at the moment
# TODO: https://github.com/unitaryfund/metriq-gym/issues/51


class JobManager:
Expand Down
50 changes: 50 additions & 0 deletions metriq_gym/schema_validator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import json
import os
from jsonschema import validate


CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
DEFAULT_SCHEMA_DIR = os.path.join(CURRENT_DIR, "schemas")

SCHEMA_MAPPING = {
"Quantum Volume": "quantum_volume.schema.json",
}


def load_json_file(file_path: str) -> dict:
"""
Load and parse a JSON file.
"""
with open(file_path, "r") as file:
return json.load(file)


def load_schema(benchmark_name: str, schema_dir: str = DEFAULT_SCHEMA_DIR) -> dict:
"""
Load a JSON schema based on the benchmark name.
"""
schema_filename = SCHEMA_MAPPING.get(benchmark_name)
if not schema_filename:
raise ValueError(f"Unsupported benchmark: {benchmark_name}")

schema_path = os.path.join(schema_dir, schema_filename)
return load_json_file(schema_path)


def validate_params(params: dict, schema_dir: str = DEFAULT_SCHEMA_DIR) -> None:
"""
Validate parameters against the corresponding JSON schema.
Raises a ValidationError if the parameters do not match the schema.
"""
schema = load_schema(params.get("benchmark_name"), schema_dir)
validate(instance=params, schema=schema)


def load_and_validate(file_path: str, schema_dir: str = DEFAULT_SCHEMA_DIR) -> dict:
"""
Load parameters from a JSON file and validate them against the corresponding schema.
Raises a ValidationError validation fails.
"""
params = load_json_file(file_path)
validate_params(params, schema_dir)
return params
37 changes: 37 additions & 0 deletions metriq_gym/schemas/quantum_volume.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$id": "metriq-gym/quantum_volume.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Quantum Volume",
"type": "object",
"properties": {
"benchmark_name": {
"type": "string",
"const": "Quantum Volume"
},
"num_qubits": {
"type": "integer",
"minimum": 1,
"examples": [5]
},
"shots": {
"type": "integer",
"default": 1000,
"minimum": 1,
"examples": [1000]
},
"trials": {
"type": "integer",
"default": 100,
"minimum": 1,
"examples": [100]
},
"confidence_level": {
"type": "number",
"minimum": 0,
"maximum": 1,
"default": 0.95,
"examples": [0.95]
}
},
"required": ["benchmark_name", "num_qubits"]
}
Loading

0 comments on commit 6752e29

Please sign in to comment.