marqov 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. marqov-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  2. marqov-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  3. marqov-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +28 -0
  4. marqov-0.2.0/.github/workflows/ci.yml +24 -0
  5. marqov-0.2.0/.github/workflows/release.yml +46 -0
  6. marqov-0.2.0/.gitignore +19 -0
  7. marqov-0.2.0/CHANGELOG.md +34 -0
  8. marqov-0.2.0/CODE_OF_CONDUCT.md +54 -0
  9. marqov-0.2.0/CONTRIBUTING.md +204 -0
  10. marqov-0.2.0/LICENSE +184 -0
  11. marqov-0.2.0/PKG-INFO +240 -0
  12. marqov-0.2.0/README.md +159 -0
  13. marqov-0.2.0/SECURITY.md +20 -0
  14. marqov-0.2.0/benchmarks/__init__.py +1 -0
  15. marqov-0.2.0/benchmarks/harness.py +124 -0
  16. marqov-0.2.0/benchmarks/raw_sdk/bell_state_dm1.py +249 -0
  17. marqov-0.2.0/benchmarks/raw_sdk/bell_state_ionq.py +251 -0
  18. marqov-0.2.0/benchmarks/raw_sdk/bell_state_ionq_aria.py +238 -0
  19. marqov-0.2.0/benchmarks/raw_sdk/bell_state_iqm.py +261 -0
  20. marqov-0.2.0/benchmarks/raw_sdk/bell_state_iqm_emerald.py +261 -0
  21. marqov-0.2.0/benchmarks/raw_sdk/bell_state_rigetti.py +236 -0
  22. marqov-0.2.0/benchmarks/raw_sdk/bell_state_sv1.py +128 -0
  23. marqov-0.2.0/benchmarks/raw_sdk/bell_state_tn1.py +152 -0
  24. marqov-0.2.0/benchmarks/raw_sdk/harness.py +122 -0
  25. marqov-0.2.0/benchmarks/raw_sdk/mis_quera_aquila.py +322 -0
  26. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_dm1.py +126 -0
  27. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_ionq.py +126 -0
  28. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_ionq_aria.py +126 -0
  29. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_iqm.py +126 -0
  30. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_iqm_emerald.py +126 -0
  31. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_local.py +264 -0
  32. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_rigetti.py +126 -0
  33. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_sv1.py +126 -0
  34. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_sv1_raw.py +274 -0
  35. marqov-0.2.0/benchmarks/raw_sdk/vqe_h2_tn1.py +126 -0
  36. marqov-0.2.0/benchmarks/shared/__init__.py +25 -0
  37. marqov-0.2.0/benchmarks/shared/vqe_h2.py +311 -0
  38. marqov-0.2.0/benchmarks/shared/vqe_h2_chemistry.py +369 -0
  39. marqov-0.2.0/benchmarks/suite.py +294 -0
  40. marqov-0.2.0/marqov/__init__.py +63 -0
  41. marqov-0.2.0/marqov/backends.py +23 -0
  42. marqov-0.2.0/marqov/benchmarking/__init__.py +21 -0
  43. marqov-0.2.0/marqov/benchmarking/spam.py +240 -0
  44. marqov-0.2.0/marqov/circuits.py +955 -0
  45. marqov-0.2.0/marqov/cli/__init__.py +365 -0
  46. marqov-0.2.0/marqov/device.py +303 -0
  47. marqov-0.2.0/marqov/executors/__init__.py +53 -0
  48. marqov-0.2.0/marqov/executors/azure.py +485 -0
  49. marqov-0.2.0/marqov/executors/base.py +155 -0
  50. marqov-0.2.0/marqov/executors/braket.py +342 -0
  51. marqov-0.2.0/marqov/executors/factory.py +427 -0
  52. marqov-0.2.0/marqov/executors/ibm.py +316 -0
  53. marqov-0.2.0/marqov/executors/ionq.py +428 -0
  54. marqov-0.2.0/marqov/executors/local.py +119 -0
  55. marqov-0.2.0/marqov/executors/quantinuum.py +245 -0
  56. marqov-0.2.0/marqov/executors/rigetti.py +319 -0
  57. marqov-0.2.0/marqov/experiments/__init__.py +5 -0
  58. marqov-0.2.0/marqov/experiments/preflight.py +163 -0
  59. marqov-0.2.0/marqov/simulation/__init__.py +21 -0
  60. marqov-0.2.0/marqov/simulation/backends.py +67 -0
  61. marqov-0.2.0/marqov/simulation/circuit_converter.py +71 -0
  62. marqov-0.2.0/marqov/simulation/config.py +56 -0
  63. marqov-0.2.0/marqov/simulation/executor.py +176 -0
  64. marqov-0.2.0/marqov/simulation/noise.py +162 -0
  65. marqov-0.2.0/marqov/workflows/__init__.py +75 -0
  66. marqov-0.2.0/marqov/workflows/activity.py +195 -0
  67. marqov-0.2.0/marqov/workflows/decorators.py +476 -0
  68. marqov-0.2.0/marqov/workflows/graph.py +302 -0
  69. marqov-0.2.0/marqov/workflows/runner.py +73 -0
  70. marqov-0.2.0/marqov/workflows/temporal_workflow.py +189 -0
  71. marqov-0.2.0/pyproject.toml +135 -0
  72. marqov-0.2.0/tests/__init__.py +1 -0
  73. marqov-0.2.0/tests/conftest.py +1 -0
  74. marqov-0.2.0/tests/experiments/__init__.py +0 -0
  75. marqov-0.2.0/tests/experiments/test_preflight.py +146 -0
  76. marqov-0.2.0/tests/integration/__init__.py +0 -0
  77. marqov-0.2.0/tests/integration/test_qristal_spike.py +230 -0
  78. marqov-0.2.0/tests/integration/test_rigetti_qvm.py +71 -0
  79. marqov-0.2.0/tests/test_activity_heartbeat.py +116 -0
  80. marqov-0.2.0/tests/test_azure_bitorder.py +80 -0
  81. marqov-0.2.0/tests/test_benchmark_suite.py +366 -0
  82. marqov-0.2.0/tests/test_circuits.py +726 -0
  83. marqov-0.2.0/tests/test_decorators.py +239 -0
  84. marqov-0.2.0/tests/test_device_integration.py +167 -0
  85. marqov-0.2.0/tests/test_executors.py +824 -0
  86. marqov-0.2.0/tests/test_ionq_executor.py +524 -0
  87. marqov-0.2.0/tests/test_noise.py +455 -0
  88. marqov-0.2.0/tests/test_rigetti_executor.py +257 -0
  89. marqov-0.2.0/tests/test_simulation.py +436 -0
  90. marqov-0.2.0/tests/test_spam.py +189 -0
  91. marqov-0.2.0/tests/test_spam_correction.py +147 -0
  92. marqov-0.2.0/tests/test_temporal_activities.py +608 -0
  93. marqov-0.2.0/tests/test_temporal_runner.py +135 -0
  94. marqov-0.2.0/tests/test_temporal_workflow.py +504 -0
  95. marqov-0.2.0/tests/test_version.py +18 -0
  96. marqov-0.2.0/tests/test_workflow_dispatch_start.py +57 -0
  97. marqov-0.2.0/tests/test_workflows.py +33 -0
  98. marqov-0.2.0/tools/check_no_url_deps.py +35 -0
  99. marqov-0.2.0/tools/verify_marqov_wheel.py +15 -0
  100. marqov-0.2.0/tools/verify_sdk_against_fork.py +33 -0
  101. marqov-0.2.0/uv.lock +3367 -0
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug in the Marqov SDK
4
+ labels: bug
5
+ ---
6
+
7
+ **Describe the bug**
8
+ A clear description of what the bug is.
9
+
10
+ **To reproduce**
11
+ Minimal code example that reproduces the issue:
12
+
13
+ ```python
14
+ from marqov.circuits import Circuit
15
+ from marqov.executors.local import LocalExecutor
16
+ # ...
17
+ ```
18
+
19
+ **Expected behavior**
20
+ What you expected to happen.
21
+
22
+ **Actual behavior**
23
+ What actually happened, including any error messages or tracebacks.
24
+
25
+ **Environment**
26
+ - marqov version: (run `pip show marqov`)
27
+ - Python version: (run `python --version`)
28
+ - OS:
29
+ - Provider/executor:
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a new feature or improvement
4
+ labels: enhancement
5
+ ---
6
+
7
+ **What problem does this solve?**
8
+ Describe the use case or limitation you're running into.
9
+
10
+ **Proposed solution**
11
+ Describe what you'd like to see added or changed.
12
+
13
+ **Alternatives considered**
14
+ Any alternative solutions or workarounds you've considered.
15
+
16
+ **Additional context**
17
+ Links to provider documentation, related issues, or examples.
@@ -0,0 +1,28 @@
1
+ ## Summary
2
+
3
+ Brief description of what this PR does.
4
+
5
+ ## Type of change
6
+
7
+ - [ ] Bug fix
8
+ - [ ] New executor
9
+ - [ ] Circuit format converter
10
+ - [ ] Documentation
11
+ - [ ] Other (describe):
12
+
13
+ ## Testing
14
+
15
+ - [ ] I ran `pytest tests/ -v` and tests pass
16
+ - [ ] For new executors: tested against local simulator or QVM (describe below)
17
+ - [ ] For circuit converters: roundtrip test passes with known-correct reference circuit
18
+
19
+ **Test details:**
20
+
21
+ ## Checklist
22
+
23
+ - [ ] No hardcoded credentials or API keys
24
+ - [ ] Handles the canonical gate set from `CONTRIBUTING.md §1` (if adding a circuit converter)
25
+
26
+ **For new executors only:**
27
+ - [ ] Registered in `ExecutorFactory` per `CONTRIBUTING.md §3`
28
+ - [ ] `get_status()` returns device-level availability (`"online"/"offline"/"maintenance"`), not job-level status
@@ -0,0 +1,24 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: ["**"]
5
+ pull_request:
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: actions/setup-python@v5
12
+ with: { python-version: "3.12" }
13
+ - name: Install uv
14
+ run: pip install uv
15
+ # Install the [all] backend extras (qiskit/cirq/pennylane/pytket/quantinuum/
16
+ # pyquil): the circuit-interop / device / executor tests import these at
17
+ # module load and HARD-FAIL (ModuleNotFoundError) rather than skip when
18
+ # absent. Installing them is what makes the full suite green.
19
+ - name: Install (with all backend extras + dev)
20
+ run: uv pip install --system -e ".[all,dev]"
21
+ - name: No-URL-deps guard
22
+ run: python tools/check_no_url_deps.py
23
+ - name: Test suite
24
+ run: pytest tests/ -q
@@ -0,0 +1,46 @@
1
+ name: release
2
+ on:
3
+ push:
4
+ tags: ["v*"]
5
+ workflow_dispatch: # manual TestPyPI dry-run
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: actions/setup-python@v5
12
+ with: { python-version: "3.12" }
13
+ - run: pip install uv && uv build
14
+ - name: Assert built version matches the tag (tag pushes only)
15
+ if: startsWith(github.ref, 'refs/tags/v')
16
+ run: |
17
+ TAG="${GITHUB_REF_NAME#v}"
18
+ test -f "dist/marqov-${TAG}-py3-none-any.whl" \
19
+ || { echo "FAIL: built wheel is not version ${TAG} (check pyproject version)"; ls dist/; exit 1; }
20
+ echo "version OK: ${TAG}"
21
+ - uses: actions/upload-artifact@v4
22
+ with: { name: dist, path: dist/ }
23
+
24
+ publish-testpypi:
25
+ needs: build
26
+ if: github.event_name == 'workflow_dispatch'
27
+ runs-on: ubuntu-latest
28
+ environment: testpypi
29
+ permissions: { id-token: write }
30
+ steps:
31
+ - uses: actions/download-artifact@v4
32
+ with: { name: dist, path: dist/ }
33
+ - uses: pypa/gh-action-pypi-publish@release/v1
34
+ with:
35
+ repository-url: https://test.pypi.org/legacy/
36
+
37
+ publish-pypi:
38
+ needs: build
39
+ if: startsWith(github.ref, 'refs/tags/v')
40
+ runs-on: ubuntu-latest
41
+ environment: pypi
42
+ permissions: { id-token: write }
43
+ steps:
44
+ - uses: actions/download-artifact@v4
45
+ with: { name: dist, path: dist/ }
46
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,19 @@
1
+ .venv/
2
+ .venv-gate/
3
+ # Any virtualenv (e.g. .verify-venv) — excluded so the hatchling sdist build does
4
+ # not try to bundle venv symlinks.
5
+ *-venv/
6
+ .*-venv/
7
+ # Claude Code local tooling / worktrees — never ship in the sdist.
8
+ .claude/
9
+ __pycache__/
10
+ *.pyc
11
+ *.pyo
12
+ .pytest_cache/
13
+ .mypy_cache/
14
+ .ruff_cache/
15
+ dist/
16
+ build/
17
+ *.egg-info/
18
+ .env
19
+ .env.local
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `marqov` SDK are documented here. This project follows
4
+ [Semantic Versioning](https://semver.org/). While on `0.x`, the public API may
5
+ still change between minor versions; `1.0.0` is reserved for the first API-stable
6
+ release.
7
+
8
+ ## [0.2.0] — 2026-06-29
9
+
10
+ First public release on PyPI.
11
+
12
+ ### Added
13
+ - Public release of the `marqov` SDK: build quantum circuits and run them across
14
+ multiple hardware backends (AWS Braket, IBM Quantum, Azure Quantum, IonQ,
15
+ Rigetti, Quantinuum, and local simulation) behind one API.
16
+ - Circuit interop helpers (import/export with Qiskit, Cirq, PennyLane, pytket,
17
+ and pyQuil) and workflow/task decorators for composing multi-step programs.
18
+
19
+ ### Changed
20
+ - The circuit IR / transpilation dependency is now the published
21
+ [`marqov-quantumflow`](https://pypi.org/project/marqov-quantumflow/) package
22
+ instead of a git URL, which is what makes `pip install marqov` possible.
23
+ - The package version is single-sourced from `marqov/__init__.py` (`__version__`)
24
+ via hatchling, so the distribution metadata, `marqov.__version__`, and
25
+ `marqov --version` always agree.
26
+
27
+ ### Known limitations
28
+ - `@task`/`@workflow` serialize the decorated function with `cloudpickle` at
29
+ decoration time. When the function is a local/closure (not module-level) and a
30
+ large set of heavy backends is imported in the same process, this can overflow
31
+ into a `RecursionError`. Module-level task functions are unaffected. A fix that
32
+ defers/removes the function serialization is planned.
33
+
34
+ [0.2.0]: https://pypi.org/project/marqov/0.2.0/
@@ -0,0 +1,54 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our mistakes
23
+ - Focusing on what is best not just for us as individuals, but for the overall community
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
28
+ - Trolling, insulting or derogatory comments, and personal or political attacks
29
+ - Public or private harassment
30
+ - Publishing others' private information without their explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
32
+
33
+ ## Enforcement Responsibilities
34
+
35
+ Community leaders are responsible for clarifying and enforcing our standards of
36
+ acceptable behavior and will take appropriate and fair corrective action in
37
+ response to any behavior that they deem inappropriate, threatening, offensive,
38
+ or harmful.
39
+
40
+ ## Scope
41
+
42
+ This Code of Conduct applies within all community spaces, and also applies when
43
+ an individual is officially representing the community in public spaces.
44
+
45
+ ## Enforcement
46
+
47
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
48
+ reported to the community leaders at ops@marqov.ai. All complaints will be
49
+ reviewed and investigated promptly and fairly.
50
+
51
+ ## Attribution
52
+
53
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
54
+ version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
@@ -0,0 +1,204 @@
1
+ # Contributing to Marqov SDK
2
+
3
+ Thank you for contributing. This guide covers everything you need to add a new
4
+ executor, circuit converter, or other contribution to the Marqov SDK.
5
+
6
+ ## Development Setup
7
+
8
+ ```bash
9
+ git clone https://github.com/marqov-dev/marqov-sdk
10
+ cd marqov-sdk
11
+ python3.12 -m venv .venv
12
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
13
+ pip install -e ".[all,dev]"
14
+ pytest tests/ -v
15
+ ```
16
+
17
+ ## §1 — Canonical Gate Set
18
+
19
+ All executor and circuit converter contributions must support the following
20
+ gates and raise `NotImplementedError` for anything outside this set. This list
21
+ is derived from `marqov/circuits.py` (`_QISKIT_GATE_MAP`) and represents what
22
+ the SDK can round-trip today.
23
+
24
+ | Category | Gates |
25
+ |---------------|------------------------------|
26
+ | Single-qubit | H, X, Y, Z, S, T |
27
+ | Rotation | Rx(θ), Ry(θ), Rz(θ) |
28
+ | Two-qubit | CNOT/CX, CZ, SWAP |
29
+
30
+ ## §2 — Executor Interface
31
+
32
+ All executors inherit from `BaseExecutor` in `marqov/executors/base.py`.
33
+
34
+ ### Required methods
35
+
36
+ **`async execute(circuit: Circuit, shots: int = 1000, **kwargs) -> ExecutionResult`**
37
+
38
+ Submit the circuit to the backend and return results. `ExecutionResult` fields
39
+ you must populate:
40
+
41
+ | Field | Type | Required | Description |
42
+ |-------|------|----------|-------------|
43
+ | `counts` | `dict[str, int]` | Yes | Measurement outcomes e.g. `{"00": 512, "11": 488}` |
44
+ | `backend` | `str` | Yes | Name or identifier of the backend |
45
+ | `execution_time_ms` | `float` | Yes | Wall time in milliseconds |
46
+ | `shots` | `int` | Yes | Number of shots executed |
47
+ | `raw_result` | `Any` | No | Provider-specific result object, for debugging |
48
+ | `metadata` | `dict` | No | Additional provider metadata |
49
+
50
+ **`async cancel(job_id: str) -> bool`**
51
+
52
+ Cancel a running job. Return `True` if successful, `False` otherwise. If the
53
+ provider does not support cancellation, the default `BaseExecutor` implementation
54
+ returns `False` — do not override it unless the provider supports cancellation.
55
+
56
+ `job_id` is the provider's job or task identifier. Callers obtain it from
57
+ `ExecutionResult.metadata` (e.g. `result.metadata["task_arn"]` for Braket).
58
+ Executors that support cancellation should store the active job ID as instance
59
+ state (e.g. `self._current_job_id`) and include it in `ExecutionResult.metadata`
60
+ under a documented key. Job polling (queued → running → completed) happens
61
+ internally inside `execute()` and is not related to this method.
62
+
63
+ **`async get_status() -> DeviceStatus`**
64
+
65
+ Return the QPU's **operational availability** — whether the device is currently
66
+ accepting new job submissions. This is **device-level status**, not job-level
67
+ status. Job polling (queued → running → completed) is handled internally inside
68
+ `execute()` and is not exposed via `get_status()`.
69
+
70
+ `DeviceStatus` fields:
71
+
72
+ | Field | Type | Values |
73
+ |-------|------|--------|
74
+ | `status` | `str` | `"online"`, `"offline"`, `"maintenance"` |
75
+ | `queue_depth` | `int \| None` | Number of queued tasks, or `None` if unknown |
76
+ | `queue_time_seconds` | `int \| None` | Estimated queue wait, or `None` if unknown |
77
+
78
+ The default `BaseExecutor.get_status()` returns `DeviceStatus.always_online()`.
79
+ Cloud backends should override this to query the provider's device status endpoint.
80
+
81
+ ## §3 — Adding a New Executor
82
+
83
+ 1. Create `marqov/executors/<name>.py` with a config dataclass and executor class:
84
+
85
+ ```python
86
+ from dataclasses import dataclass
87
+ from typing import Any
88
+ from marqov.executors.base import BaseExecutor, DeviceStatus, ExecutionResult
89
+ from marqov.circuits import Circuit
90
+
91
+ @dataclass
92
+ class MyProviderExecutorConfig:
93
+ api_key: str
94
+ device_name: str
95
+ shots: int = 1000
96
+
97
+ class MyProviderExecutor(BaseExecutor):
98
+ def __init__(self, config: MyProviderExecutorConfig) -> None:
99
+ self.config = config
100
+
101
+ async def execute(self, circuit: Circuit, shots: int = 1000, **kwargs: Any) -> ExecutionResult:
102
+ # convert circuit, submit, poll, return ExecutionResult
103
+ ...
104
+
105
+ async def get_status(self) -> DeviceStatus:
106
+ # query provider device status endpoint
107
+ ...
108
+ ```
109
+
110
+ 2. Register in `marqov/executors/factory.py`:
111
+ - Add import at top: `from marqov.executors.<name> import MyProviderExecutor, MyProviderExecutorConfig`
112
+ - Add branch in `create_executor()`:
113
+ ```python
114
+ if provider == "My Provider":
115
+ return cls._create_myprovider_executor(backend_slug, backend_config)
116
+ ```
117
+ - Add `_create_myprovider_executor()` classmethod following the pattern of `_create_ibm_executor()`
118
+ - Add `"My Provider"` to the list in `get_supported_providers()`
119
+
120
+ 3. Add the provider package to `pyproject.toml` as an optional dependency:
121
+ ```toml
122
+ [project.optional-dependencies]
123
+ myprovider = ["my-provider-sdk>=1.0.0"]
124
+ ```
125
+
126
+ 4. Export from `marqov/executors/__init__.py`.
127
+
128
+ ## §4 — Local QVM Setup (Rigetti executor development)
129
+
130
+ The Rigetti QCS executor tests run against a local QVM instance. QVM requires
131
+ `quilc` running alongside it.
132
+
133
+ ```bash
134
+ docker pull rigetti/quilc
135
+ docker pull rigetti/qvm
136
+ docker run -d -p 5555:5555 rigetti/quilc -server
137
+ docker run -d -p 5000:5000 rigetti/qvm -server
138
+ ```
139
+
140
+ Verify:
141
+ ```bash
142
+ python -c "from pyquil import get_qc; qc = get_qc('2q-qvm'); print(qc)"
143
+ ```
144
+
145
+ Expected output: `<QVM 2q-qvm>` or similar. If you see a connection error,
146
+ check both containers are running with `docker ps`.
147
+
148
+ ## §5 — Running Benchmarks
149
+
150
+ `benchmarks/suite.py` runs a fixed set of reference circuits — Bell, 3-qubit
151
+ GHZ, and a deterministic depth-5 random circuit — against any configured
152
+ executor and prints a comparison table. It works out of the box with
153
+ `LocalExecutor`, so no credentials are required:
154
+
155
+ ```bash
156
+ python benchmarks/suite.py --executor local --shots 1000 --seed 1234
157
+ ```
158
+
159
+ Output format — one row per (backend × circuit) combination:
160
+
161
+ | backend | circuit | shots | exec_time_ms | top_3_outcomes |
162
+ |---------|-----------|-------|--------------|--------------------------------------|
163
+ | local | bell | 1000 | 0.4 | {"11": 502, "00": 498} |
164
+ | local | ghz | 1000 | 0.4 | {"111": 524, "000": 476} |
165
+ | local | random_d5 | 1000 | 0.4 | {"010": 262, "100": 254, "110": 243} |
166
+
167
+ Columns:
168
+ - `backend`: executor name
169
+ - `circuit`: circuit name (`bell`, `ghz`, `random_d5`)
170
+ - `shots`: number of shots
171
+ - `exec_time_ms`: wall time in milliseconds (varies per run and machine)
172
+ - `top_3_outcomes`: counts of the 3 most frequent measurement outcomes, ordered
173
+ by count descending
174
+
175
+ The measurement outcomes above are reproducible for a fixed `--seed` (it seeds
176
+ both the random circuit and the local sampler); `exec_time_ms` is wall time and
177
+ will differ on your machine.
178
+
179
+ **Scope.** The suite compares execution time and outcome distribution only.
180
+ Shot-fidelity and queue-overhead metrics are out of scope for this harness;
181
+ device-level queue status is available separately via `BaseExecutor.get_status()`.
182
+
183
+ **Error handling.** If a backend errors on any circuit, the suite skips that
184
+ *entire* backend (it emits no partial rows for it), logs the backend and the
185
+ failing circuit to stderr, and continues with the next backend — it never
186
+ aborts. If every backend fails the command exits non-zero, so CI can flag a
187
+ fully broken run.
188
+
189
+ **Benchmarking other backends.** The CLI only constructs the zero-credential
190
+ `local` executor, but `run_suite()` is executor-agnostic — pass a mapping of
191
+ name → `BaseExecutor` to benchmark cloud backends programmatically:
192
+
193
+ ```python
194
+ import asyncio
195
+ from benchmarks.suite import run_suite, format_table
196
+ from marqov.executors import ExecutorFactory, LocalExecutor
197
+
198
+ executors = {
199
+ "local": LocalExecutor(),
200
+ "sv1": ExecutorFactory.create_executor("sv1", braket_config),
201
+ }
202
+ rows = asyncio.run(run_suite(executors, shots=1000))
203
+ print(format_table(rows))
204
+ ```
marqov-0.2.0/LICENSE ADDED
@@ -0,0 +1,184 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship made available under
36
+ the License, as indicated by a copyright notice that is included in
37
+ or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object
40
+ form, that is based on (or derived from) the Work and for which the
41
+ editorial revisions, annotations, elaborations, or other modifications
42
+ represent, as a whole, an original work of authorship. For the purposes
43
+ of this License, Derivative Works shall not include works that remain
44
+ separable from, or merely link (or bind by name) to the interfaces of,
45
+ the Work and Derivative Works thereof.
46
+
47
+ "Contribution" shall mean, as submitted to the Licensor for inclusion
48
+ in the Work by the copyright owner or by an individual or Legal Entity
49
+ authorized to submit on behalf of the copyright owner. For the purposes
50
+ of this definition, "submitted" means any form of electronic, verbal,
51
+ or written communication sent to the Licensor or its representatives,
52
+ including but not limited to communication on electronic mailing lists,
53
+ source code control systems, and issue tracking systems that are managed
54
+ by, or on behalf of, the Licensor for the purpose of discussing and
55
+ improving the Work, but excluding communication that is conspicuously
56
+ marked or designated in writing by the copyright owner as "Not a
57
+ Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
60
+ whom a Contribution has been received by the Licensor and included
61
+ within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of
64
+ this License, each Contributor hereby grants to You a perpetual,
65
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
66
+ copyright license to reproduce, prepare Derivative Works of,
67
+ publicly display, publicly perform, sublicense, and distribute the
68
+ Work and such Derivative Works in Source or Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of
71
+ this License, each Contributor hereby grants to You a perpetual,
72
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73
+ (except as stated in this section) patent license to make, have made,
74
+ use, offer to sell, sell, import, and otherwise transfer the Work,
75
+ where such license applies only to those patent claims licensable
76
+ by such Contributor that are necessarily infringed by their
77
+ Contribution(s) alone or by the combination of their Contribution(s)
78
+ with the Work to which such Contribution(s) was submitted. If You
79
+ institute patent litigation against any entity (including a cross-claim
80
+ or counterclaim in a lawsuit) alleging that the Work or any
81
+ Contributor's Contribution(s) constitutes direct or contributory
82
+ patent infringement, then any patent rights granted to You under
83
+ this License for that Work shall terminate as of the date such
84
+ litigation is filed.
85
+
86
+ 4. Redistribution. You may reproduce and distribute copies of the
87
+ Work or Derivative Works thereof in any medium, with or without
88
+ modifications, and in Source or Object form, provided that You
89
+ meet the following conditions:
90
+
91
+ (a) You must give any other recipients of the Work or Derivative
92
+ Works a copy of this License; and
93
+
94
+ (b) You must cause any modified files to carry prominent notices
95
+ stating that You changed the files; and
96
+
97
+ (c) You must retain, in the Source form of any Derivative Works
98
+ that You distribute, all copyright, patent, trademark, and
99
+ attribution notices from the Source form of the Work,
100
+ excluding those notices that do not pertain to any part of
101
+ the Derivative Works; and
102
+
103
+ (d) If the Work includes a "NOTICE" text file as part of its
104
+ distribution, You must include a readable copy of the
105
+ attribution notices contained within such NOTICE file, in
106
+ at least one of the following places: within a NOTICE text
107
+ file distributed as part of the Derivative Works; within
108
+ the Source form or documentation, if provided along with the
109
+ Derivative Works; or, within a display generated by the
110
+ Derivative Works, if and wherever such third-party notices
111
+ normally appear. The contents of the NOTICE file are for
112
+ informational purposes only and do not modify the License.
113
+ You may add Your own attribution notices within Derivative
114
+ Works that You distribute, alongside or in addition to the
115
+ NOTICE text from the Work, provided that such additional
116
+ attribution notices cannot be construed as modifying the License.
117
+
118
+ You may add Your own license statement for Your modifications and
119
+ may provide additional grant of rights to use, copy, modify, merge,
120
+ publish, distribute, sublicense, and/or sell copies of the
121
+ Contribution, either on an unrestrictive basis or under the terms of
122
+ this License.
123
+
124
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
125
+ any Contribution intentionally submitted for inclusion in the Work
126
+ by You to the Licensor shall be under the terms and conditions of
127
+ this License, without any additional terms or conditions.
128
+ Notwithstanding the above, nothing herein shall supersede or modify
129
+ the terms of any separate license agreement you may have executed
130
+ with Licensor regarding such Contributions.
131
+
132
+ 6. Trademarks. This License does not grant permission to use the trade
133
+ names, trademarks, service marks, or product names of the Licensor,
134
+ except as required for reasonable and customary use in describing the
135
+ origin of the Work and reproducing the content of the NOTICE file.
136
+
137
+ 7. Disclaimer of Warranty. Unless required by applicable law or
138
+ agreed to in writing, Licensor provides the Work (and each
139
+ Contributor provides its Contributions) on an "AS IS" BASIS,
140
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
141
+ implied, including, without limitation, any warranties or conditions
142
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
143
+ PARTICULAR PURPOSE. You are solely responsible for determining the
144
+ appropriateness of using or reproducing the Work and assume any
145
+ risks associated with Your exercise of permissions under this License.
146
+
147
+ 8. Limitation of Liability. In no event and under no legal theory,
148
+ whether in tort (including negligence), contract, or otherwise,
149
+ unless required by applicable law (such as deliberate and grossly
150
+ negligent acts) or agreed to in writing, shall any Contributor be
151
+ liable to You for damages, including any direct, indirect, special,
152
+ incidental, or exemplary damages of any character arising as a
153
+ result of this License or out of the use or inability to use the
154
+ Work (including but not limited to damages for loss of goodwill,
155
+ work stoppage, computer failure or malfunction, or all other
156
+ commercial damages or losses), even if such Contributor has been
157
+ advised of the possibility of such damages.
158
+
159
+ 9. Accepting Warranty or Additional Liability. While redistributing
160
+ the Work or Derivative Works thereof, You may choose to offer,
161
+ and charge a fee for, acceptance of support, warranty, indemnity,
162
+ or other liability obligations and/or rights consistent with this
163
+ License. However, in accepting such obligations, You may offer such
164
+ obligations only on Your own behalf and on Your sole responsibility,
165
+ not on behalf of any other Contributor, and only if You agree to
166
+ indemnify, defend, and hold each Contributor harmless for any
167
+ liability incurred by, or claims asserted against, such Contributor
168
+ by reason of your accepting any such warranty or additional liability.
169
+
170
+ END OF TERMS AND CONDITIONS
171
+
172
+ Copyright 2026 Marqov
173
+
174
+ Licensed under the Apache License, Version 2.0 (the "License");
175
+ you may not use this file except in compliance with the License.
176
+ You may obtain a copy of the License at
177
+
178
+ http://www.apache.org/licenses/LICENSE-2.0
179
+
180
+ Unless required by applicable law or agreed to in writing, software
181
+ distributed under the License is distributed on an "AS IS" BASIS,
182
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
183
+ See the License for the specific language governing permissions and
184
+ limitations under the License.