intelloptim 0.1.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.
- intelloptim-0.1.0/.github/CODEOWNERS +1 -0
- intelloptim-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +29 -0
- intelloptim-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- intelloptim-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +14 -0
- intelloptim-0.1.0/.github/dependabot.yml +21 -0
- intelloptim-0.1.0/.github/pull_request_template.md +11 -0
- intelloptim-0.1.0/.github/workflows/ci.yml +126 -0
- intelloptim-0.1.0/.github/workflows/release.yml +114 -0
- intelloptim-0.1.0/.github/workflows/scheduled.yml +45 -0
- intelloptim-0.1.0/.gitignore +59 -0
- intelloptim-0.1.0/.pre-commit-config.yaml +34 -0
- intelloptim-0.1.0/CHANGELOG.md +36 -0
- intelloptim-0.1.0/CLAUDE.md +178 -0
- intelloptim-0.1.0/CODE_OF_CONDUCT.md +9 -0
- intelloptim-0.1.0/CONTRIBUTING.md +76 -0
- intelloptim-0.1.0/LICENSE +201 -0
- intelloptim-0.1.0/MANIFEST.in +4 -0
- intelloptim-0.1.0/NOTICE +8 -0
- intelloptim-0.1.0/PKG-INFO +188 -0
- intelloptim-0.1.0/README.md +124 -0
- intelloptim-0.1.0/SECURITY.md +21 -0
- intelloptim-0.1.0/noxfile.py +79 -0
- intelloptim-0.1.0/pyproject.toml +190 -0
- intelloptim-0.1.0/scripts/release.sh +44 -0
- intelloptim-0.1.0/scripts/release_tools.py +171 -0
- intelloptim-0.1.0/setup.cfg +4 -0
- intelloptim-0.1.0/src/intelloptim/__init__.py +51 -0
- intelloptim-0.1.0/src/intelloptim/_internal/__init__.py +19 -0
- intelloptim-0.1.0/src/intelloptim/_internal/audit.py +349 -0
- intelloptim-0.1.0/src/intelloptim/_internal/hashing.py +255 -0
- intelloptim-0.1.0/src/intelloptim/_internal/logging.py +352 -0
- intelloptim-0.1.0/src/intelloptim/_internal/schemas.py +300 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/__init__.py +22 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/__init__.py +19 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/builtin/__init__.py +25 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/builtin/_common.py +41 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/builtin/owg.py +454 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/builtin/sa.py +317 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/__init__.py +31 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/__init__.py +0 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/base.py +348 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/config.py +115 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/distributions.py +319 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/executor.py +149 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/learner.py +225 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/measurement.py +86 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/policy.py +248 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/ppo.py +135 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/resources.py +60 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/serialization.py +25 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/snapshot.py +104 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/commons/space.py +230 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/gaus.py +47 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/mixture.py +49 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/qiskit/__init__.py +15 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/qiskit/circuit.py +33 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/qiskit/ibm_runtime.py +88 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/backend/quantum/qiskit/simulator.py +62 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/errors.py +33 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/protocols.py +71 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/pruners.py +88 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/samplers.py +235 -0
- intelloptim-0.1.0/src/intelloptim/algorithms/space.py +53 -0
- intelloptim-0.1.0/src/intelloptim/client/__init__.py +30 -0
- intelloptim-0.1.0/src/intelloptim/client/api.py +364 -0
- intelloptim-0.1.0/src/intelloptim/client/auth.py +88 -0
- intelloptim-0.1.0/src/intelloptim/client/errors.py +170 -0
- intelloptim-0.1.0/src/intelloptim/client/study.py +388 -0
- intelloptim-0.1.0/src/intelloptim/client/trial.py +250 -0
- intelloptim-0.1.0/src/intelloptim/core/__init__.py +27 -0
- intelloptim-0.1.0/src/intelloptim/core/objective.py +146 -0
- intelloptim-0.1.0/src/intelloptim/core/parameters.py +301 -0
- intelloptim-0.1.0/src/intelloptim/core/pruners/__init__.py +63 -0
- intelloptim-0.1.0/src/intelloptim/core/pruners/base.py +56 -0
- intelloptim-0.1.0/src/intelloptim/core/pruners/optuna.py +176 -0
- intelloptim-0.1.0/src/intelloptim/core/samplers/__init__.py +97 -0
- intelloptim-0.1.0/src/intelloptim/core/samplers/base.py +141 -0
- intelloptim-0.1.0/src/intelloptim/core/samplers/builtin.py +138 -0
- intelloptim-0.1.0/src/intelloptim/core/samplers/optuna.py +215 -0
- intelloptim-0.1.0/src/intelloptim/core/samplers/quantum.py +332 -0
- intelloptim-0.1.0/src/intelloptim/params.py +24 -0
- intelloptim-0.1.0/src/intelloptim/py.typed +0 -0
- intelloptim-0.1.0/src/intelloptim/version.py +10 -0
- intelloptim-0.1.0/src/intelloptim/worker/__init__.py +14 -0
- intelloptim-0.1.0/src/intelloptim/worker/cli.py +134 -0
- intelloptim-0.1.0/src/intelloptim/worker/evaluator_cli.py +223 -0
- intelloptim-0.1.0/src/intelloptim/worker/registry.py +130 -0
- intelloptim-0.1.0/src/intelloptim/worker/slurm.py +72 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/PKG-INFO +188 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/SOURCES.txt +146 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/dependency_links.txt +1 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/entry_points.txt +2 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/requires.txt +35 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/scm_file_list.json +147 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/scm_version.json +8 -0
- intelloptim-0.1.0/src/intelloptim.egg-info/top_level.txt +1 -0
- intelloptim-0.1.0/tests/__init__.py +0 -0
- intelloptim-0.1.0/tests/integration/__init__.py +0 -0
- intelloptim-0.1.0/tests/integration/quantum/__init__.py +0 -0
- intelloptim-0.1.0/tests/integration/quantum/test_hardware_smoke.py +41 -0
- intelloptim-0.1.0/tests/integration/quantum/test_ibm_runtime.py +141 -0
- intelloptim-0.1.0/tests/integration/quantum/test_qiskit_simulator.py +95 -0
- intelloptim-0.1.0/tests/integration/quantum/test_sim_samplers.py +200 -0
- intelloptim-0.1.0/tests/support/__init__.py +0 -0
- intelloptim-0.1.0/tests/support/numpy_executor.py +76 -0
- intelloptim-0.1.0/tests/unit/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/algorithms/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_distributions.py +307 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_learner.py +205 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_measurement_and_executor.py +145 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_policy.py +210 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_ppo.py +127 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_samplers.py +443 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_snapshot.py +81 -0
- intelloptim-0.1.0/tests/unit/algorithms/quantum/test_space.py +176 -0
- intelloptim-0.1.0/tests/unit/algorithms/test_owg_sampler.py +627 -0
- intelloptim-0.1.0/tests/unit/algorithms/test_plugin_loading.py +125 -0
- intelloptim-0.1.0/tests/unit/algorithms/test_sa_sampler.py +358 -0
- intelloptim-0.1.0/tests/unit/algorithms/test_sampler_dependencies.py +155 -0
- intelloptim-0.1.0/tests/unit/client/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/client/conftest.py +58 -0
- intelloptim-0.1.0/tests/unit/client/test_auth.py +139 -0
- intelloptim-0.1.0/tests/unit/client/test_client.py +226 -0
- intelloptim-0.1.0/tests/unit/client/test_enqueue.py +40 -0
- intelloptim-0.1.0/tests/unit/client/test_error_mapping.py +123 -0
- intelloptim-0.1.0/tests/unit/client/test_optimize_worker_id.py +47 -0
- intelloptim-0.1.0/tests/unit/client/test_pruning.py +297 -0
- intelloptim-0.1.0/tests/unit/client/test_public_surface.py +21 -0
- intelloptim-0.1.0/tests/unit/client/test_trial.py +105 -0
- intelloptim-0.1.0/tests/unit/core/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/core/test_hashing.py +254 -0
- intelloptim-0.1.0/tests/unit/core/test_objective.py +137 -0
- intelloptim-0.1.0/tests/unit/core/test_parameters.py +161 -0
- intelloptim-0.1.0/tests/unit/core/test_pruners.py +107 -0
- intelloptim-0.1.0/tests/unit/core/test_quantum_specs.py +226 -0
- intelloptim-0.1.0/tests/unit/core/test_samplers.py +61 -0
- intelloptim-0.1.0/tests/unit/core/test_schemas.py +212 -0
- intelloptim-0.1.0/tests/unit/core/test_top_level_imports.py +137 -0
- intelloptim-0.1.0/tests/unit/internal/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/internal/test_audit.py +162 -0
- intelloptim-0.1.0/tests/unit/internal/test_logging.py +210 -0
- intelloptim-0.1.0/tests/unit/test_release_tools.py +193 -0
- intelloptim-0.1.0/tests/unit/worker/__init__.py +0 -0
- intelloptim-0.1.0/tests/unit/worker/test_cli.py +109 -0
- intelloptim-0.1.0/tests/unit/worker/test_evaluator_cli.py +261 -0
- intelloptim-0.1.0/tests/unit/worker/test_registry.py +94 -0
- intelloptim-0.1.0/tests/unit/worker/test_slurm_identity.py +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @mbarbetti
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something does not work as documented
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened, and what did you expect?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: repro
|
|
13
|
+
attributes:
|
|
14
|
+
label: Minimal example
|
|
15
|
+
description: Code that reproduces the problem. Remove tokens and private URLs.
|
|
16
|
+
render: python
|
|
17
|
+
- type: input
|
|
18
|
+
id: version
|
|
19
|
+
attributes:
|
|
20
|
+
label: intelloptim version
|
|
21
|
+
placeholder: "python -c 'import intelloptim; print(intelloptim.__version__)'"
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
- type: input
|
|
25
|
+
id: python
|
|
26
|
+
attributes:
|
|
27
|
+
label: Python version and operating system
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an improvement
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem would this solve?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: idea
|
|
13
|
+
attributes:
|
|
14
|
+
label: What would you like to see?
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: github-actions
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
groups:
|
|
8
|
+
actions:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
commit-message:
|
|
11
|
+
prefix: "ci"
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: pip
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
17
|
+
groups:
|
|
18
|
+
python-dependencies:
|
|
19
|
+
patterns: ["*"]
|
|
20
|
+
commit-message:
|
|
21
|
+
prefix: "build"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## What and why
|
|
2
|
+
|
|
3
|
+
<!-- What changes, and why. Link the issue if there is one. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] The PR title follows Conventional Commits (`feat(scope): ...`, `fix: ...`, `docs: ...`)
|
|
8
|
+
- [ ] Tests added or updated, and `nox` passes locally
|
|
9
|
+
- [ ] `CHANGELOG.md` has an entry under `[Unreleased]` (or the PR is labelled `skip-changelog`)
|
|
10
|
+
- [ ] Public API, docstrings and README updated if behaviour changed
|
|
11
|
+
- [ ] No credentials, tokens or private data in code, tests or logs
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_call:
|
|
8
|
+
inputs:
|
|
9
|
+
full:
|
|
10
|
+
description: "Run every supported Python version"
|
|
11
|
+
type: boolean
|
|
12
|
+
default: false
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
plan:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
outputs:
|
|
25
|
+
python: ${{ steps.pick.outputs.python }}
|
|
26
|
+
steps:
|
|
27
|
+
- id: pick
|
|
28
|
+
env:
|
|
29
|
+
FULL: ${{ inputs.full || github.event_name == 'push' }}
|
|
30
|
+
run: |
|
|
31
|
+
if [ "$FULL" = "true" ]; then
|
|
32
|
+
echo 'python=["3.11","3.12","3.13","3.14","3.15"]' >> "$GITHUB_OUTPUT"
|
|
33
|
+
else
|
|
34
|
+
echo 'python=["3.11","3.15"]' >> "$GITHUB_OUTPUT"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
lint:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
41
|
+
with:
|
|
42
|
+
fetch-depth: 0
|
|
43
|
+
persist-credentials: false
|
|
44
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.12"
|
|
47
|
+
- run: python -m pip install nox
|
|
48
|
+
- run: nox -s lint --default-venv-backend virtualenv
|
|
49
|
+
|
|
50
|
+
typecheck:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
54
|
+
with:
|
|
55
|
+
fetch-depth: 0
|
|
56
|
+
persist-credentials: false
|
|
57
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
58
|
+
with:
|
|
59
|
+
python-version: "3.12"
|
|
60
|
+
- run: python -m pip install nox
|
|
61
|
+
- run: nox -s typecheck --default-venv-backend virtualenv
|
|
62
|
+
|
|
63
|
+
test:
|
|
64
|
+
needs: plan
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
strategy:
|
|
67
|
+
fail-fast: false
|
|
68
|
+
matrix:
|
|
69
|
+
python: ${{ fromJSON(needs.plan.outputs.python) }}
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
72
|
+
with:
|
|
73
|
+
fetch-depth: 0
|
|
74
|
+
persist-credentials: false
|
|
75
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
76
|
+
with:
|
|
77
|
+
python-version: ${{ matrix.python }}
|
|
78
|
+
- run: python -m pip install nox
|
|
79
|
+
- run: nox -s "tests-${{ matrix.python }}" --default-venv-backend virtualenv
|
|
80
|
+
|
|
81
|
+
build:
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
85
|
+
with:
|
|
86
|
+
fetch-depth: 0
|
|
87
|
+
persist-credentials: false
|
|
88
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
89
|
+
with:
|
|
90
|
+
python-version: "3.12"
|
|
91
|
+
- run: python -m pip install nox
|
|
92
|
+
- run: nox -s build --default-venv-backend virtualenv
|
|
93
|
+
|
|
94
|
+
changelog:
|
|
95
|
+
if: github.event_name == 'pull_request'
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
99
|
+
with:
|
|
100
|
+
fetch-depth: 0
|
|
101
|
+
persist-credentials: false
|
|
102
|
+
- name: CHANGELOG.md must change unless the PR is labelled skip-changelog
|
|
103
|
+
if: >-
|
|
104
|
+
!contains(github.event.pull_request.labels.*.name, 'skip-changelog')
|
|
105
|
+
&& github.actor != 'dependabot[bot]'
|
|
106
|
+
env:
|
|
107
|
+
BASE_REF: ${{ github.base_ref }}
|
|
108
|
+
run: |
|
|
109
|
+
if ! git diff --name-only "origin/${BASE_REF}...HEAD" | grep -qx CHANGELOG.md; then
|
|
110
|
+
echo "::error::Add an entry under [Unreleased] in CHANGELOG.md, or label the PR skip-changelog."
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# The only status check that branch protection needs to require.
|
|
115
|
+
ci-ok:
|
|
116
|
+
if: always()
|
|
117
|
+
needs: [plan, lint, typecheck, test, build, changelog]
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- env:
|
|
121
|
+
RESULTS: ${{ join(needs.*.result, ' ') }}
|
|
122
|
+
run: |
|
|
123
|
+
echo "job results: $RESULTS"
|
|
124
|
+
case " $RESULTS " in
|
|
125
|
+
*" failure "*|*" cancelled "*) exit 1 ;;
|
|
126
|
+
esac
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Pushing a tag vX.Y.Z (or vX.Y.ZrcN) from main builds the distributions and
|
|
4
|
+
# publishes them: pre-releases to TestPyPI, final releases to PyPI after the
|
|
5
|
+
# `pypi` environment is approved. No token is stored: PyPI trusts this workflow
|
|
6
|
+
# (Trusted Publishing).
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags: ["v*"]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
outputs:
|
|
18
|
+
prerelease: ${{ steps.kind.outputs.prerelease }}
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- name: The tagged commit must be on main
|
|
25
|
+
run: |
|
|
26
|
+
git fetch --no-tags origin main
|
|
27
|
+
git merge-base --is-ancestor "$GITHUB_SHA" origin/main
|
|
28
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.12"
|
|
31
|
+
- run: python -m pip install build twine packaging
|
|
32
|
+
- id: kind
|
|
33
|
+
env:
|
|
34
|
+
TAG: ${{ github.ref_name }}
|
|
35
|
+
run: |
|
|
36
|
+
echo "prerelease=$(python scripts/release_tools.py prerelease "$TAG")" >> "$GITHUB_OUTPUT"
|
|
37
|
+
python scripts/release_tools.py notes "$TAG" > /dev/null
|
|
38
|
+
- run: python -m build --outdir dist
|
|
39
|
+
- run: twine check --strict dist/*
|
|
40
|
+
- env:
|
|
41
|
+
TAG: ${{ github.ref_name }}
|
|
42
|
+
run: |
|
|
43
|
+
python scripts/release_tools.py check-dist dist "$TAG"
|
|
44
|
+
python scripts/release_tools.py check-contents dist
|
|
45
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
if-no-files-found: error
|
|
50
|
+
|
|
51
|
+
publish-testpypi:
|
|
52
|
+
needs: build
|
|
53
|
+
if: needs.build.outputs.prerelease == 'true'
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
environment:
|
|
56
|
+
name: testpypi
|
|
57
|
+
url: https://test.pypi.org/project/intelloptim/
|
|
58
|
+
permissions:
|
|
59
|
+
id-token: write
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
|
62
|
+
with:
|
|
63
|
+
name: dist
|
|
64
|
+
path: dist/
|
|
65
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
66
|
+
with:
|
|
67
|
+
repository-url: https://test.pypi.org/legacy/
|
|
68
|
+
|
|
69
|
+
publish-pypi:
|
|
70
|
+
needs: build
|
|
71
|
+
if: needs.build.outputs.prerelease == 'false'
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
environment:
|
|
74
|
+
name: pypi
|
|
75
|
+
url: https://pypi.org/project/intelloptim/
|
|
76
|
+
permissions:
|
|
77
|
+
id-token: write
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
|
80
|
+
with:
|
|
81
|
+
name: dist
|
|
82
|
+
path: dist/
|
|
83
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
84
|
+
|
|
85
|
+
github-release:
|
|
86
|
+
needs: [build, publish-testpypi, publish-pypi]
|
|
87
|
+
if: >-
|
|
88
|
+
always() && needs.build.result == 'success'
|
|
89
|
+
&& (needs.publish-testpypi.result == 'success' || needs.publish-pypi.result == 'success')
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
permissions:
|
|
92
|
+
contents: write
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
95
|
+
with:
|
|
96
|
+
persist-credentials: false
|
|
97
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
|
98
|
+
with:
|
|
99
|
+
name: dist
|
|
100
|
+
path: dist/
|
|
101
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
102
|
+
with:
|
|
103
|
+
python-version: "3.12"
|
|
104
|
+
- run: python -m pip install packaging
|
|
105
|
+
- name: Create the GitHub release
|
|
106
|
+
env:
|
|
107
|
+
GH_TOKEN: ${{ github.token }}
|
|
108
|
+
TAG: ${{ github.ref_name }}
|
|
109
|
+
PRERELEASE: ${{ needs.build.outputs.prerelease }}
|
|
110
|
+
run: |
|
|
111
|
+
python scripts/release_tools.py notes "$TAG" > notes.md
|
|
112
|
+
flag=""
|
|
113
|
+
if [ "$PRERELEASE" = "true" ]; then flag="--prerelease"; fi
|
|
114
|
+
gh release create "$TAG" dist/* --title "$TAG" --notes-file notes.md $flag
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Scheduled
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 5 * * 1"
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
ci:
|
|
13
|
+
uses: ./.github/workflows/ci.yml
|
|
14
|
+
with:
|
|
15
|
+
full: true
|
|
16
|
+
|
|
17
|
+
extras-installable:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
python: ["3.11", "3.12", "3.13", "3.14", "3.15"]
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
25
|
+
with:
|
|
26
|
+
fetch-depth: 0
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python }}
|
|
31
|
+
- name: Every extra can still be resolved on this Python
|
|
32
|
+
run: python -m pip install --dry-run ".[samplers,quantum-ibm]"
|
|
33
|
+
|
|
34
|
+
audit:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
38
|
+
with:
|
|
39
|
+
fetch-depth: 0
|
|
40
|
+
persist-credentials: false
|
|
41
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
- run: python -m pip install ".[samplers,quantum-ibm]" pip-audit
|
|
45
|
+
- run: pip-audit
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# GenAI tools
|
|
2
|
+
.claude/
|
|
3
|
+
AGENTS.md
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
*.so
|
|
10
|
+
.Python
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.nox/
|
|
13
|
+
*.egg
|
|
14
|
+
.eggs/
|
|
15
|
+
build/
|
|
16
|
+
dist/
|
|
17
|
+
wheels/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.mypy_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
.tox/
|
|
22
|
+
.coverage
|
|
23
|
+
.coverage.*
|
|
24
|
+
htmlcov/
|
|
25
|
+
coverage.xml
|
|
26
|
+
|
|
27
|
+
# Virtual envs (we use conda envs outside the repo, but keep these out anyway)
|
|
28
|
+
.venv/
|
|
29
|
+
venv/
|
|
30
|
+
env/
|
|
31
|
+
|
|
32
|
+
# Local dev
|
|
33
|
+
*.db
|
|
34
|
+
*.db-journal
|
|
35
|
+
*.sqlite
|
|
36
|
+
*.sqlite3
|
|
37
|
+
dev.db*
|
|
38
|
+
|
|
39
|
+
# OS / editors
|
|
40
|
+
.DS_Store
|
|
41
|
+
.idea/
|
|
42
|
+
.vscode/
|
|
43
|
+
*.swp
|
|
44
|
+
*~
|
|
45
|
+
|
|
46
|
+
# Frontend
|
|
47
|
+
node_modules/
|
|
48
|
+
frontend/dist/
|
|
49
|
+
frontend/.vite/
|
|
50
|
+
frontend/coverage/
|
|
51
|
+
|
|
52
|
+
# Docker / runtime
|
|
53
|
+
.env
|
|
54
|
+
.env.local
|
|
55
|
+
*.pid
|
|
56
|
+
|
|
57
|
+
# Logs
|
|
58
|
+
*.log
|
|
59
|
+
logs/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Hooks for local use: `pre-commit install`. The formatters and the type checker
|
|
2
|
+
# are the ones installed with the `dev` extra (`language: system`), so the
|
|
3
|
+
# versions and the dependencies are the same as in `nox` and in CI.
|
|
4
|
+
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
6
|
+
rev: v5.0.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: trailing-whitespace
|
|
9
|
+
- id: end-of-file-fixer
|
|
10
|
+
- id: check-yaml
|
|
11
|
+
- id: check-toml
|
|
12
|
+
- id: check-added-large-files
|
|
13
|
+
args: ["--maxkb=512"]
|
|
14
|
+
- id: check-merge-conflict
|
|
15
|
+
- id: debug-statements
|
|
16
|
+
|
|
17
|
+
- repo: local
|
|
18
|
+
hooks:
|
|
19
|
+
- id: black
|
|
20
|
+
name: black
|
|
21
|
+
entry: black
|
|
22
|
+
language: system
|
|
23
|
+
types: [python]
|
|
24
|
+
- id: ruff
|
|
25
|
+
name: ruff
|
|
26
|
+
entry: ruff check --fix
|
|
27
|
+
language: system
|
|
28
|
+
types: [python]
|
|
29
|
+
- id: mypy
|
|
30
|
+
name: mypy
|
|
31
|
+
entry: mypy src/intelloptim
|
|
32
|
+
language: system
|
|
33
|
+
pass_filenames: false
|
|
34
|
+
files: ^src/intelloptim/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file. The format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
|
5
|
+
uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html); while the
|
|
6
|
+
version is below 1.0, minor releases may contain breaking changes.
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-10-30
|
|
11
|
+
|
|
12
|
+
First public release.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Client SDK in `intelloptim.client` (`Client`, `StudyHandle`, `Trial`,
|
|
17
|
+
`TrialState` and the `errors` module) for an intelloptim server: ask/tell,
|
|
18
|
+
enqueue, early stopping with `Trial.report` and `Trial.should_prune`
|
|
19
|
+
(`TrialPruned` ends a pruned trial). `intelloptim.client` and
|
|
20
|
+
`intelloptim.algorithms` are loaded on first access, so `import intelloptim`
|
|
21
|
+
stays light.
|
|
22
|
+
- Declarative search spaces (`intelloptim.params`) with float, int and
|
|
23
|
+
categorical parameters.
|
|
24
|
+
- Sampler and pruner specifications backed by Optuna (Random, TPE, GP, NSGA-II,
|
|
25
|
+
QMC; Median, Percentile, Threshold, Nop) and the built-in samplers SA and OWG.
|
|
26
|
+
- Quantum policy samplers (Gaussian and mixture variants) with a simulated
|
|
27
|
+
version and a hardware version, an executor plugin mechanism
|
|
28
|
+
(`intelloptim.quantum_executors`) and an IBM Runtime executor.
|
|
29
|
+
- `intelloptim-worker evaluator` command, which runs an objective registered with
|
|
30
|
+
`@intopt.objective` against a server, for example as a SLURM array job. Each
|
|
31
|
+
worker sends its worker and site ids (`StudyHandle.optimize(...,
|
|
32
|
+
worker_id=...)`), derived from the SLURM environment.
|
|
33
|
+
- Optional extras: `gp`, `qmc`, `quantum`, `quantum-ibm`, `samplers`.
|
|
34
|
+
|
|
35
|
+
[Unreleased]: https://github.com/mbarbetti/intelloptim/compare/v0.1.0...HEAD
|
|
36
|
+
[0.1.0]: https://github.com/mbarbetti/intelloptim/releases/tag/v0.1.0
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# intelloptim — project guidance
|
|
2
|
+
|
|
3
|
+
## What this repo is
|
|
4
|
+
|
|
5
|
+
The client SDK and the algorithm layer of **intelloptim**, a general black-box
|
|
6
|
+
optimization framework built on Optuna's ask/tell API (an evolution of
|
|
7
|
+
**Hopaas**, Barbetti & Anderlini, 2023,
|
|
8
|
+
[arXiv:2301.05522](https://arxiv.org/abs/2301.05522)). It contains the user-facing
|
|
9
|
+
client, the pure domain types, the wire protocol, and the sampler/pruner
|
|
10
|
+
resolution including the in-repo sampler runtimes. Imported as
|
|
11
|
+
`import intelloptim as intopt`.
|
|
12
|
+
|
|
13
|
+
Users install it to talk to a running intelloptim server and to write
|
|
14
|
+
objectives. The server and the dashboard are separate projects that depend on
|
|
15
|
+
this package for its domain types, wire schemas, hashing and algorithms.
|
|
16
|
+
|
|
17
|
+
## Mental map
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
src/intelloptim/
|
|
21
|
+
_internal/ wire schemas (incl. TrialState), hashing (study identity),
|
|
22
|
+
logging, audit helpers
|
|
23
|
+
core/ pure domain types — no I/O, only pydantic
|
|
24
|
+
samplers/ base.py (SamplerKind, rebuild policy, base specs),
|
|
25
|
+
optuna.py (Random/TPE/GP/NSGA-II/QMC specs),
|
|
26
|
+
builtin.py (SA/OWG specs), quantum.py (quantum policy
|
|
27
|
+
specs: Gaus/Mixture, simulated "Sim" and hardware)
|
|
28
|
+
pruners/ base.py (PrunerKind), optuna.py (Median/Percentile/
|
|
29
|
+
Threshold/Nop specs)
|
|
30
|
+
parameters.py, objective.py
|
|
31
|
+
algorithms/ spec -> optuna resolvers (samplers.py, pruners.py) and
|
|
32
|
+
load_sampler_plugins() entry-point discovery
|
|
33
|
+
backend/ runtime for non-Optuna samplers (builtin/: sa.py, owg.py;
|
|
34
|
+
quantum/: gaus.py, mixture.py, commons/ for the
|
|
35
|
+
vendor-neutral policy, learner and executors, qiskit/ for
|
|
36
|
+
the only Qiskit code)
|
|
37
|
+
protocols.py, errors.py, space.py
|
|
38
|
+
client/ REST/WS SDK (Client, StudyHandle, Trial, errors) — httpx
|
|
39
|
+
worker/ `intelloptim-worker` CLI (evaluator subcommand, worker and site
|
|
40
|
+
identity from the SLURM environment)
|
|
41
|
+
params.py public facade over core/parameters (`intopt.params.Float`)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Hard layering rules
|
|
45
|
+
|
|
46
|
+
1. **`core/` is pure**: stdlib and pydantic only; no `httpx`, `optuna`, I/O or
|
|
47
|
+
networking.
|
|
48
|
+
2. **`algorithms/` is the only place Optuna's sampler/pruner classes are
|
|
49
|
+
imported.** `core/` holds specs; `algorithms/` resolves them.
|
|
50
|
+
3. **`_internal/schemas.py` is the only place wire models are defined.**
|
|
51
|
+
4. **`_internal/hashing.py` output is byte-stable.** Golden tests pin it;
|
|
52
|
+
changing the hashed payload changes every study id.
|
|
53
|
+
5. **`client/` is the only module that talks to a server over HTTP.**
|
|
54
|
+
6. **Quantum samplers** (`SimQuantumGaus`, `QuantumGaus`, `SimQuantumMixture`,
|
|
55
|
+
`QuantumMixture`) live in-repo: specs in `core/samplers/quantum.py`, runtime
|
|
56
|
+
in `algorithms/backend/quantum/`. The `Sim` samplers are ideal; the others
|
|
57
|
+
run on hardware and are separate kinds on purpose. Specs never carry
|
|
58
|
+
credentials, and only `algorithms/backend/quantum/qiskit/` imports Qiskit.
|
|
59
|
+
|
|
60
|
+
## Wire protocol and stability
|
|
61
|
+
|
|
62
|
+
- The wire models and `API_VERSION` live in `_internal/schemas.py`; the sampler
|
|
63
|
+
and pruner unions are `SamplerSpec` and `PrunerSpec`. Changing any of them is
|
|
64
|
+
a versioned event that the server and the dashboard must follow.
|
|
65
|
+
- Study-scoped requests carry `study_id` in the URL and `config_digest` in the
|
|
66
|
+
body; **409** on mismatch (`ConfigDigestMismatchError`).
|
|
67
|
+
- **503 + `Retry-After`** from `/ask` while a sampler rebuilds
|
|
68
|
+
(`StudyRebuildingError`). **410** from `/ask` and `/enqueue` when the study is
|
|
69
|
+
stopped (`StudyStoppedError`). **429** from `/ask` or `/tell` when the quota is
|
|
70
|
+
exhausted.
|
|
71
|
+
- `POST /studies/{id}/trials/{tid}/should_prune` takes the intermediate values
|
|
72
|
+
not yet sent and returns `{"should_prune": bool}`; it is not quota-counted.
|
|
73
|
+
- Study identity: `study_id = sha256(study_key, study_name, direction,
|
|
74
|
+
canonicalized_params, sampler_spec, pruner_spec)`, always computed with
|
|
75
|
+
`study_identity(study_key, request)`; `study_key` is an opaque per-user or
|
|
76
|
+
per-group key resolved by the server, never the API token.
|
|
77
|
+
- `trial_id` is an opaque handle; `number` is the position in the study.
|
|
78
|
+
|
|
79
|
+
## Samplers
|
|
80
|
+
|
|
81
|
+
To add a **built-in** sampler: add a spec class in `core/samplers/`, add its
|
|
82
|
+
`kind` to `SamplerKind`, add it to the `SamplerSpec` union, and register a
|
|
83
|
+
resolver in `algorithms/samplers.py:_RESOLVERS`. If it is not a thin wrapper
|
|
84
|
+
over an Optuna sampler, put its runtime in `algorithms/backend/`. Pruners follow
|
|
85
|
+
the same pattern.
|
|
86
|
+
|
|
87
|
+
Built-in samplers must be **stateless**: the server builds a fresh sampler on
|
|
88
|
+
every ask, so anything an in-memory sampler would remember must be rebuilt from
|
|
89
|
+
the study history (with RNGs derived from the seed and trial number) or from a
|
|
90
|
+
model persisted in the study by `rebuild(study)` (see `OWG`, `SA` and the
|
|
91
|
+
quantum samplers).
|
|
92
|
+
|
|
93
|
+
External packages can override the resolver of an existing kind through the
|
|
94
|
+
`intelloptim.samplers` entry-point group, and add a quantum provider through
|
|
95
|
+
`intelloptim.quantum_executors`.
|
|
96
|
+
|
|
97
|
+
Ships in-repo: `Random`, `TPE`, `GP`, `NSGA-II`, `QMC` (Optuna-backed; `GP`
|
|
98
|
+
needs the `gp` extra, `QMC` the `qmc` extra), `SA`, `OWG`, and the quantum
|
|
99
|
+
policy samplers (extras `quantum`, `quantum-ibm`). A missing optional package
|
|
100
|
+
raises `SamplerDependencyError` naming the extra to install.
|
|
101
|
+
|
|
102
|
+
## SDK contract
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import intelloptim as intopt
|
|
106
|
+
with intopt.client.Client(url="...", token=...) as client:
|
|
107
|
+
study = client.create_study(
|
|
108
|
+
study_name="...", direction="minimize",
|
|
109
|
+
sampler_spec=intopt.samplers.TPESamplerSpec(seed=42),
|
|
110
|
+
parameters=[intopt.params.Float("x", -10, 10)],
|
|
111
|
+
)
|
|
112
|
+
study.optimize(my_objective, n_trials=50, catch=Exception)
|
|
113
|
+
best = study.best_trial
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- The search space is declared once, in `create_study(parameters=[...])`.
|
|
117
|
+
Objectives read the sampled values by name: `trial.sampled_float("x")`,
|
|
118
|
+
`sampled_int`, `sampled_categorical`. There is no `suggest_*`.
|
|
119
|
+
- `tell(state=COMPLETE)` requires `value`; `PRUNED`/`FAILED` accept `None`.
|
|
120
|
+
- Early stopping: `trial.report(value, step)` buffers locally,
|
|
121
|
+
`trial.should_prune()` sends the new values, and the objective raises
|
|
122
|
+
`intopt.client.errors.TrialPruned`, which `optimize` records as `PRUNED`.
|
|
123
|
+
- `create_study` is idempotent and parallel-safe; `best_trial` is `None` until
|
|
124
|
+
one trial completes. `optimize(n_trials=N)` raises `InsufficientQuotaError`
|
|
125
|
+
before any call if `N` exceeds the remaining calls.
|
|
126
|
+
|
|
127
|
+
Client errors: `ConfigDigestMismatchError` (409), `StudyRebuildingError` (503),
|
|
128
|
+
`StudyStoppedError` (410), `MissingTokenError`, `InsufficientQuotaError`,
|
|
129
|
+
`StudyLimitExceededError`.
|
|
130
|
+
|
|
131
|
+
## Testing
|
|
132
|
+
|
|
133
|
+
- `tests/unit/` tests pure logic and never imports third-party quantum SDKs; the
|
|
134
|
+
quantum samplers run against a numpy executor in `tests/support/`.
|
|
135
|
+
`tests/integration/` (marker `qiskit`) uses real Qiskit and a stubbed IBM
|
|
136
|
+
runtime. Tests marked `hardware` hit a real device, are opt-in, and must never
|
|
137
|
+
run in automation.
|
|
138
|
+
- `client/` tests use `httpx.MockTransport`; there is no dependency on a server.
|
|
139
|
+
- Every feature or fix ships with `pytest` tests (happy path and edge cases).
|
|
140
|
+
|
|
141
|
+
## Style
|
|
142
|
+
|
|
143
|
+
Black (88 columns, double quotes), Ruff, `mypy --strict`. Type hints with
|
|
144
|
+
`typing.List/Dict/Optional/Union`, `os.path` instead of `pathlib`, Google-style
|
|
145
|
+
docstrings with typed `Args:`, `Returns:`, `Raises:`. Comments only for a
|
|
146
|
+
non-obvious *why*. Docstrings describe behaviour for users, not development
|
|
147
|
+
rules.
|
|
148
|
+
|
|
149
|
+
## Do not modify without explicit instruction
|
|
150
|
+
|
|
151
|
+
- `_internal/hashing.py` and `study_identity` (study ids and digests depend on
|
|
152
|
+
the exact bytes hashed).
|
|
153
|
+
- The wire models in `_internal/schemas.py` (versioned change, bump
|
|
154
|
+
`API_VERSION`).
|
|
155
|
+
|
|
156
|
+
## Commands
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pip install -e ".[dev]"
|
|
160
|
+
pytest tests/unit -q
|
|
161
|
+
pytest tests/integration -q # needs the quantum extra
|
|
162
|
+
ruff check src/ tests/
|
|
163
|
+
black --check src/ tests/
|
|
164
|
+
mypy src/intelloptim/
|
|
165
|
+
nox # the same checks, across Python versions
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Development notes
|
|
169
|
+
|
|
170
|
+
The maintainer keeps additional design notes in `.claude/notes/`. They are not
|
|
171
|
+
part of the repository; ask for them when working in these areas:
|
|
172
|
+
|
|
173
|
+
- samplers and benchmarking (statelessness rules, sampler choice, honest
|
|
174
|
+
benchmarking)
|
|
175
|
+
- quantum samplers (design, cohort/snapshot mechanics, hardware guards, limits)
|
|
176
|
+
- sampler plugins (entry-point contract, adding a built-in sampler kind)
|
|
177
|
+
- documentation conventions (docstring style, checklist after public-surface
|
|
178
|
+
changes)
|