refractal 0.1.0a1__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.
- refractal-0.1.0a1/.gitignore +20 -0
- refractal-0.1.0a1/CHANGELOG.md +66 -0
- refractal-0.1.0a1/LICENSE +202 -0
- refractal-0.1.0a1/NOTICE +23 -0
- refractal-0.1.0a1/PKG-INFO +314 -0
- refractal-0.1.0a1/README.md +268 -0
- refractal-0.1.0a1/docs/README.md +68 -0
- refractal-0.1.0a1/docs/adapter-contract.md +109 -0
- refractal-0.1.0a1/docs/adapter-example.md +208 -0
- refractal-0.1.0a1/docs/backend-compose.md +220 -0
- refractal-0.1.0a1/docs/backend-vla-eval.md +166 -0
- refractal-0.1.0a1/docs/catalog-reference.md +251 -0
- refractal-0.1.0a1/docs/execution-mode.md +99 -0
- refractal-0.1.0a1/docs/getting-started.md +195 -0
- refractal-0.1.0a1/docs/perturbations/adapters.md +310 -0
- refractal-0.1.0a1/docs/perturbations/declaring.md +415 -0
- refractal-0.1.0a1/docs/perturbations/index.md +93 -0
- refractal-0.1.0a1/docs/perturbations/sweeps.md +173 -0
- refractal-0.1.0a1/docs/reading-a-comparison.md +159 -0
- refractal-0.1.0a1/docs/releasing.md +71 -0
- refractal-0.1.0a1/docs/writing-a-catalog.md +272 -0
- refractal-0.1.0a1/examples/catalog/assets/cube_bowl.xml +13 -0
- refractal-0.1.0a1/examples/catalog/assets/vial_rack.xml +14 -0
- refractal-0.1.0a1/examples/catalog/hardware.yaml +23 -0
- refractal-0.1.0a1/examples/catalog/run.yaml +19 -0
- refractal-0.1.0a1/examples/catalog/scenarios.yaml +64 -0
- refractal-0.1.0a1/examples/catalog/scenes.yaml +30 -0
- refractal-0.1.0a1/examples/catalog/tasks.yaml +29 -0
- refractal-0.1.0a1/examples/mjx-panda/assets/panda_pick_cube.xml +300 -0
- refractal-0.1.0a1/examples/mjx-panda/hardware.yaml +23 -0
- refractal-0.1.0a1/examples/mjx-panda/run.yaml +9 -0
- refractal-0.1.0a1/examples/mjx-panda/scenarios.yaml +20 -0
- refractal-0.1.0a1/examples/mjx-panda/scenes.yaml +62 -0
- refractal-0.1.0a1/examples/mjx-panda/tasks.yaml +7 -0
- refractal-0.1.0a1/pyproject.toml +83 -0
- refractal-0.1.0a1/src/refractal/__init__.py +109 -0
- refractal-0.1.0a1/src/refractal/build/__init__.py +479 -0
- refractal-0.1.0a1/src/refractal/cli.py +719 -0
- refractal-0.1.0a1/src/refractal/compare/__init__.py +66 -0
- refractal-0.1.0a1/src/refractal/compare/pairing.py +377 -0
- refractal-0.1.0a1/src/refractal/compare/stats.py +364 -0
- refractal-0.1.0a1/src/refractal/compare/variance.py +196 -0
- refractal-0.1.0a1/src/refractal/compare/verdict.py +589 -0
- refractal-0.1.0a1/src/refractal/example.py +98 -0
- refractal-0.1.0a1/src/refractal/execute/__init__.py +42 -0
- refractal-0.1.0a1/src/refractal/execute/fake.py +151 -0
- refractal-0.1.0a1/src/refractal/execute/harness.py +220 -0
- refractal-0.1.0a1/src/refractal/execute/local.py +163 -0
- refractal-0.1.0a1/src/refractal/execute/physics.py +126 -0
- refractal-0.1.0a1/src/refractal/execute/resources.py +122 -0
- refractal-0.1.0a1/src/refractal/execute/results.py +884 -0
- refractal-0.1.0a1/src/refractal/execute/vla_eval.py +940 -0
- refractal-0.1.0a1/src/refractal/execute/vla_eval_runner.py +694 -0
- refractal-0.1.0a1/src/refractal/expect.py +159 -0
- refractal-0.1.0a1/src/refractal/generators.py +24 -0
- refractal-0.1.0a1/src/refractal/init.py +236 -0
- refractal-0.1.0a1/src/refractal/perturbations/__init__.py +1056 -0
- refractal-0.1.0a1/src/refractal/predicates.py +34 -0
- refractal-0.1.0a1/src/refractal/promote.py +151 -0
- refractal-0.1.0a1/src/refractal/render/__init__.py +564 -0
- refractal-0.1.0a1/src/refractal/resolve/__init__.py +356 -0
- refractal-0.1.0a1/src/refractal/resolve/expand.py +432 -0
- refractal-0.1.0a1/src/refractal/resolve/fit.py +390 -0
- refractal-0.1.0a1/src/refractal/resolve/lock.py +314 -0
- refractal-0.1.0a1/src/refractal/schema/__init__.py +99 -0
- refractal-0.1.0a1/src/refractal/schema/canonical.py +212 -0
- refractal-0.1.0a1/src/refractal/schema/errors.py +57 -0
- refractal-0.1.0a1/src/refractal/schema/generators.py +258 -0
- refractal-0.1.0a1/src/refractal/schema/identity.py +428 -0
- refractal-0.1.0a1/src/refractal/schema/importstr.py +119 -0
- refractal-0.1.0a1/src/refractal/schema/loader.py +337 -0
- refractal-0.1.0a1/src/refractal/schema/models.py +767 -0
- refractal-0.1.0a1/src/refractal/schema/plan.py +349 -0
- refractal-0.1.0a1/src/refractal/sweep.py +180 -0
- refractal-0.1.0a1/tests/__init__.py +0 -0
- refractal-0.1.0a1/tests/fixture_filters.py +19 -0
- refractal-0.1.0a1/tests/test_boundaries.py +308 -0
- refractal-0.1.0a1/tests/test_bridge.py +723 -0
- refractal-0.1.0a1/tests/test_build.py +765 -0
- refractal-0.1.0a1/tests/test_canonical.py +142 -0
- refractal-0.1.0a1/tests/test_compare.py +1162 -0
- refractal-0.1.0a1/tests/test_encoding.py +123 -0
- refractal-0.1.0a1/tests/test_execute.py +934 -0
- refractal-0.1.0a1/tests/test_expect.py +186 -0
- refractal-0.1.0a1/tests/test_generators.py +177 -0
- refractal-0.1.0a1/tests/test_identity.py +309 -0
- refractal-0.1.0a1/tests/test_init.py +105 -0
- refractal-0.1.0a1/tests/test_loader.py +149 -0
- refractal-0.1.0a1/tests/test_models.py +259 -0
- refractal-0.1.0a1/tests/test_mutate.py +187 -0
- refractal-0.1.0a1/tests/test_perturbations.py +1235 -0
- refractal-0.1.0a1/tests/test_physics.py +119 -0
- refractal-0.1.0a1/tests/test_promote.py +210 -0
- refractal-0.1.0a1/tests/test_render.py +556 -0
- refractal-0.1.0a1/tests/test_resolve.py +1370 -0
- refractal-0.1.0a1/tests/test_rewrite.py +172 -0
- refractal-0.1.0a1/tests/test_sweep.py +129 -0
- refractal-0.1.0a1/tests/test_vla_eval_loop.py +1372 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Anchored to the repo root. An unanchored `build/` also matches
|
|
2
|
+
# src/refractal/build/, which silently kept the whole `refractal build` package
|
|
3
|
+
# out of git -- `git status` stayed clean, the tests passed against the working
|
|
4
|
+
# tree, and the wheel shipped without it. Anchor these.
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.venv/
|
|
9
|
+
/build/
|
|
10
|
+
/dist/
|
|
11
|
+
/results/
|
|
12
|
+
/plan.json
|
|
13
|
+
|
|
14
|
+
# mkdocs build output. Regenerable from docs/ + mkdocs.yml, and when it was
|
|
15
|
+
# tracked it went stale: a wording fix in docs/ left the built HTML asserting
|
|
16
|
+
# the old text.
|
|
17
|
+
site/
|
|
18
|
+
.mutation-in-progress
|
|
19
|
+
.coverage.json
|
|
20
|
+
.coverage
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
What changed in each released version. Newest first.
|
|
4
|
+
|
|
5
|
+
This is not the commit history. The history records why a decision was made;
|
|
6
|
+
this records what a user gets in a version they can install. Different
|
|
7
|
+
audiences, and the history is the better read for the first question.
|
|
8
|
+
|
|
9
|
+
## 0.1.0a1 (unreleased)
|
|
10
|
+
|
|
11
|
+
First alpha. Every stage is implemented and tested against real model servers
|
|
12
|
+
as well as the synthetic backend.
|
|
13
|
+
|
|
14
|
+
**`plan_id` may move between alpha versions.** Episode identity is a hash of
|
|
15
|
+
the catalog's content, and the fields that feed it are still settling: they
|
|
16
|
+
changed three times this month. Results written by `0.1.0a1` may therefore fail
|
|
17
|
+
to join with results from a later alpha, and `refractal compare` will refuse
|
|
18
|
+
the join rather than pool them, which is the intended behaviour and not a bug.
|
|
19
|
+
If you are about to spend GPU hours, this is the sentence to read first. The
|
|
20
|
+
`a` in the version is doing real work.
|
|
21
|
+
|
|
22
|
+
`plan_schema` is 3. It is deliberately not part of `plan_id`: a format bump
|
|
23
|
+
does not make an experiment a different experiment.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- `refractal init`, write a working example catalog that runs end to end with
|
|
28
|
+
no GPU, no simulator and no checkpoints.
|
|
29
|
+
- `refractal build`, compute scene hashes, evaluate filters and record resource
|
|
30
|
+
shapes into `catalog/build.lock`.
|
|
31
|
+
- `refractal plan`, compile a catalog into `plan.json`. Runs with none of the
|
|
32
|
+
optional dependencies installed, which is enforced by a test rather than by
|
|
33
|
+
convention.
|
|
34
|
+
- `refractal run`, execute a plan. Backends: `local` (simulates outcomes, no
|
|
35
|
+
infrastructure), `vla-eval` (drives the harness against running model
|
|
36
|
+
servers), `compose` (one container per worker).
|
|
37
|
+
- `refractal render`, write a deployment description from a plan without Docker
|
|
38
|
+
or a cluster installed. Targets: `compose` and `k8s`.
|
|
39
|
+
- `refractal compare`, compare checkpoints in a results directory. Paired
|
|
40
|
+
McNemar on scenario-level outcomes, a clustered bootstrap that resamples
|
|
41
|
+
whole scenarios, Cochran's Q as a screen across three or more checkpoints,
|
|
42
|
+
and Holm correction across the whole contrast family.
|
|
43
|
+
- `refractal explain`, why two plans are different experiments.
|
|
44
|
+
- Perturbations: timed changes to the world, the observation or the action
|
|
45
|
+
during an episode, hashed into `scenario_hash` so a perturbed episode is a
|
|
46
|
+
different experiment from its unperturbed counterpart.
|
|
47
|
+
- Exit codes for CI: 0 no regression, 1 regression, 2 cannot be answered.
|
|
48
|
+
The third is never reported as the second.
|
|
49
|
+
- Optional extras: `execute`, `compare`, `video`, `vla-eval`, `all`, `test`.
|
|
50
|
+
Comparison needs no numerical stack.
|
|
51
|
+
|
|
52
|
+
### Not built yet
|
|
53
|
+
|
|
54
|
+
Stated because a gap a user discovers is worse than one they were told about.
|
|
55
|
+
|
|
56
|
+
- **Trajectory quality metrics.** The `steps.parquet` schema is declared and
|
|
57
|
+
nothing writes it. Writing it against synthetic data would bake in guesses
|
|
58
|
+
about what a real adapter can record.
|
|
59
|
+
- **`refractal run --backend k8s`.** Kubernetes is reached through `render`:
|
|
60
|
+
Refractal writes one Job per worker and your cluster schedules them. Nothing
|
|
61
|
+
submits them, watches them or collects their exit codes.
|
|
62
|
+
- **Resource-shape probing.** `refractal build` carries hand-declared shapes
|
|
63
|
+
forward and records whether they were measured. A lint refuses a comment
|
|
64
|
+
claiming a measurement when nothing recorded one.
|
|
65
|
+
- **Partial credit.** `phase_outcomes` exists in the schema and the LIBERO
|
|
66
|
+
adapter never populates it, so success is binary.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright 2026 Nalin Raut
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
refractal-0.1.0a1/NOTICE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Refractal
|
|
2
|
+
Copyright 2026 Nalin Raut
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
5
|
+
|
|
6
|
+
This product depends on software from the following projects.
|
|
7
|
+
No source from them is included in this distribution.
|
|
8
|
+
|
|
9
|
+
-------------------------------------------------------------------------------
|
|
10
|
+
vla-evaluation-harness
|
|
11
|
+
https://github.com/allenai/vla-evaluation-harness
|
|
12
|
+
Copyright The Allen Institute for Artificial Intelligence
|
|
13
|
+
Licensed under the Apache License, Version 2.0
|
|
14
|
+
|
|
15
|
+
Refractal's `--backend vla-eval` runs every episode through this harness. It
|
|
16
|
+
provides the model-server protocol, the benchmark adapters, the observation and
|
|
17
|
+
action specifications, and the episode loop. Refractal subclasses two of its
|
|
18
|
+
classes (`Orchestrator` and `EpisodeRecorder`) and adds no copies of its source.
|
|
19
|
+
-------------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
Benchmark suites and model servers loaded through the harness at run time are
|
|
22
|
+
the work of their own authors and carry their own licences. Refractal neither
|
|
23
|
+
distributes nor modifies them.
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: refractal
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Scene-coherent placement and paired comparison for policy evaluation
|
|
5
|
+
Project-URL: Homepage, https://github.com/nalinraut/refractal
|
|
6
|
+
Project-URL: Repository, https://github.com/nalinraut/refractal
|
|
7
|
+
Project-URL: Issues, https://github.com/nalinraut/refractal/issues
|
|
8
|
+
Author: Nalin Raut
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: benchmark,evaluation,reproducibility,robotics,simulation,statistics,vla
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Testing
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: pydantic>=2.6
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: fsspec>=2024.2.0; extra == 'all'
|
|
28
|
+
Requires-Dist: pillow>=10.0; extra == 'all'
|
|
29
|
+
Requires-Dist: pyarrow>=15.0; extra == 'all'
|
|
30
|
+
Provides-Extra: compare
|
|
31
|
+
Requires-Dist: fsspec>=2024.2.0; extra == 'compare'
|
|
32
|
+
Requires-Dist: pyarrow>=15.0; extra == 'compare'
|
|
33
|
+
Provides-Extra: execute
|
|
34
|
+
Requires-Dist: fsspec>=2024.2.0; extra == 'execute'
|
|
35
|
+
Requires-Dist: pyarrow>=15.0; extra == 'execute'
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: numpy>=1.24; extra == 'test'
|
|
38
|
+
Requires-Dist: pillow>=10.0; extra == 'test'
|
|
39
|
+
Provides-Extra: video
|
|
40
|
+
Requires-Dist: pillow>=10.0; extra == 'video'
|
|
41
|
+
Provides-Extra: vla-eval
|
|
42
|
+
Requires-Dist: fsspec>=2024.2.0; extra == 'vla-eval'
|
|
43
|
+
Requires-Dist: pyarrow>=15.0; extra == 'vla-eval'
|
|
44
|
+
Requires-Dist: vla-eval>=0.6.0; extra == 'vla-eval'
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# Refractal
|
|
48
|
+
|
|
49
|
+
[](https://pypi.org/project/refractal/)
|
|
50
|
+
[](https://pypi.org/project/refractal/)
|
|
51
|
+
[](https://github.com/nalinraut/refractal/blob/main/LICENSE)
|
|
52
|
+
[](https://github.com/nalinraut/refractal/actions/workflows/ci.yml)
|
|
53
|
+
|
|
54
|
+
**A closed-loop evaluation compiler.**
|
|
55
|
+
|
|
56
|
+
Refractal turns a declared set of scenarios into a plan you can inspect before running,
|
|
57
|
+
executes it on your chosen backend with the policy acting in simulation, and tells you
|
|
58
|
+
whether the difference between two checkpoints is real.
|
|
59
|
+
|
|
60
|
+
Backends: local, Docker Compose, Kubernetes.
|
|
61
|
+
|
|
62
|
+
Run the same evaluation twice and know whether the difference is real.
|
|
63
|
+
|
|
64
|
+
You have a policy. You changed something. You want to know if the new version is
|
|
65
|
+
better.
|
|
66
|
+
|
|
67
|
+
Today you run a benchmark, get 78%, run the old one, get 74%, and guess. That
|
|
68
|
+
number hides everything that matters: *which* situations got better, whether four
|
|
69
|
+
points is real or noise, whether some of those "failures" were your container
|
|
70
|
+
crashing, and whether the new version got worse at something while getting better
|
|
71
|
+
overall.
|
|
72
|
+
|
|
73
|
+
Refractal turns "run a benchmark" into "run an experiment."
|
|
74
|
+
|
|
75
|
+
```console
|
|
76
|
+
$ pip install "refractal[execute,compare]"
|
|
77
|
+
$ mkdir demo && cd demo
|
|
78
|
+
$ refractal init .
|
|
79
|
+
$ refractal plan catalog --hardware laptop -o plan.json
|
|
80
|
+
cube-bowl-v1 30 scenarios 360 episodes 2 worker(s) <=37 min
|
|
81
|
+
------------------------------------------------------------------
|
|
82
|
+
360 episodes across 1 scene(s), 2 worker(s), at most 37 min
|
|
83
|
+
that is an upper bound: every episode is costed at its full step limit,
|
|
84
|
+
and episodes that succeed finish sooner.
|
|
85
|
+
wrote plan.json (plan_schema 3, plan_id sha256:82b73f180a7a...)
|
|
86
|
+
|
|
87
|
+
$ refractal run plan.json -o results --catalog catalog
|
|
88
|
+
$ refractal compare results $(python -c "import json;print(json.load(open('plan.json'))['plan_id'])")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
About a minute end to end, with no GPU, no simulator and no checkpoints: the
|
|
92
|
+
example runs against a built-in fake benchmark, so the machinery is real and only
|
|
93
|
+
the robot is not.
|
|
94
|
+
|
|
95
|
+
**[Start here →](https://github.com/nalinraut/refractal/blob/main/docs/getting-started.md)**
|
|
96
|
+
|
|
97
|
+
## Documentation
|
|
98
|
+
|
|
99
|
+
| | |
|
|
100
|
+
|---|---|
|
|
101
|
+
| [Getting started](https://github.com/nalinraut/refractal/blob/main/docs/getting-started.md) | Install to verdict, start to finish. |
|
|
102
|
+
| [Writing a catalog](https://github.com/nalinraut/refractal/blob/main/docs/writing-a-catalog.md) | Describing your own experiment, and which edits invalidate existing results. |
|
|
103
|
+
| [Catalog reference](https://github.com/nalinraut/refractal/blob/main/docs/catalog-reference.md) | Every file and every field, for looking things up. A key not listed there is rejected. |
|
|
104
|
+
| [Reading a comparison](https://github.com/nalinraut/refractal/blob/main/docs/reading-a-comparison.md) | Every number in the output and when not to trust it. |
|
|
105
|
+
| [Perturbations](https://github.com/nalinraut/refractal/blob/main/docs/perturbations/index.md) · [declaring](https://github.com/nalinraut/refractal/blob/main/docs/perturbations/declaring.md) · [adapters](https://github.com/nalinraut/refractal/blob/main/docs/perturbations/adapters.md) · [sweeps](https://github.com/nalinraut/refractal/blob/main/docs/perturbations/sweeps.md) | Changing the world mid-episode, when success rates alone cannot separate two checkpoints. |
|
|
106
|
+
| [Adapter contract](https://github.com/nalinraut/refractal/blob/main/docs/adapter-contract.md) · [example](https://github.com/nalinraut/refractal/blob/main/docs/adapter-example.md) | Connecting your own simulator. |
|
|
107
|
+
| [Against vla-eval](https://github.com/nalinraut/refractal/blob/main/docs/backend-vla-eval.md) · [In containers](https://github.com/nalinraut/refractal/blob/main/docs/backend-compose.md) | Running at scale. |
|
|
108
|
+
| [Execution modes](https://github.com/nalinraut/refractal/blob/main/docs/execution-mode.md) · [Releasing](https://github.com/nalinraut/refractal/blob/main/docs/releasing.md) | |
|
|
109
|
+
|
|
110
|
+
## What it does
|
|
111
|
+
|
|
112
|
+
**Declares experiments, not benchmark invocations.** You describe scenes, tasks
|
|
113
|
+
and scenario grids in YAML. Refractal expands that into a concrete list of
|
|
114
|
+
episodes, each with a content-addressed identity, works out how many workers the
|
|
115
|
+
run needs and whether they fit in memory, and writes a plan you can read, diff and
|
|
116
|
+
commit before spending anything.
|
|
117
|
+
|
|
118
|
+
**Compares episode by episode, with statistics that fit the design.** The same
|
|
119
|
+
scenarios face every checkpoint, so the data is *paired*. Refractal reports the
|
|
120
|
+
full 2×2 per task, runs McNemar on scenario-level outcomes, and gates on a
|
|
121
|
+
clustered bootstrap that resamples whole scenarios, because five seeds at one
|
|
122
|
+
pose are one observation of that pose rather than five.
|
|
123
|
+
|
|
124
|
+
**Refuses rather than guessing.** A plan that oversubscribes VRAM is not emitted.
|
|
125
|
+
A comparison across two scene geometries is blocked, not reported. A worker
|
|
126
|
+
assignment the backend cannot execute is refused at planning time rather than
|
|
127
|
+
discovered forty minutes in.
|
|
128
|
+
|
|
129
|
+
## Three things it gets right that aggregate scores cannot
|
|
130
|
+
|
|
131
|
+
**Identity is content, never position.** An episode is a hash of
|
|
132
|
+
`(scene, task, scenario, seed, checkpoint)`. Rename a task and results still
|
|
133
|
+
join; change what the task *means* and they correctly stop. Reordering a list
|
|
134
|
+
cannot silently change what an attempt was.
|
|
135
|
+
|
|
136
|
+
**Infra failures leave the denominator.** A crashed worker is its own column, not
|
|
137
|
+
a policy failure. And because dropping it breaks the pairing a paired test needs,
|
|
138
|
+
the seed is dropped from *every* checkpoint, with the loss reported rather than
|
|
139
|
+
absorbed.
|
|
140
|
+
|
|
141
|
+
**Multiplicity is corrected across the whole family.** The gate fires if any
|
|
142
|
+
contrast trips, so every contrast is one family. Three tasks at a nominal 5% is a
|
|
143
|
+
family-wise error rate near 14%; four checkpoints across three tasks is eighteen
|
|
144
|
+
contrasts and about 60%. Holm-adjusted, with the uncorrected number printed so
|
|
145
|
+
the correction does not read as pedantry.
|
|
146
|
+
|
|
147
|
+
## Comparing more than two checkpoints
|
|
148
|
+
|
|
149
|
+
Two is the common case, not a special one. A single checkpoint is a comparison of
|
|
150
|
+
size one; three is a training sweep, and produces something a leaderboard cannot:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
scene-v1 / task-4 (119 scenarios)
|
|
154
|
+
rates: ckpt-46: 49.4% ckpt-47: 49.8% ckpt-48: 37.5% (baseline ckpt-46)
|
|
155
|
+
outcome patterns:
|
|
156
|
+
35 none solve
|
|
157
|
+
18 only ckpt-46, ckpt-47 <- what ckpt-48 lost
|
|
158
|
+
18 all solve
|
|
159
|
+
17 only ckpt-47
|
|
160
|
+
3 only ckpt-48
|
|
161
|
+
Cochran Q (screen): Q=19.73 p=0.0005 (66 of 119 scenarios disagree)
|
|
162
|
+
ckpt-46 -> ckpt-47: +0.005 [-0.059, +0.066] p=0.8874 holm=1.0000 -> no change
|
|
163
|
+
ckpt-46 -> ckpt-48: -0.118 [-0.179, -0.059] p=0.0008 holm=0.0040 -> REGRESSED
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
"Eighteen scenarios that ckpt-46 and ckpt-47 both solve and ckpt-48 lost" is a
|
|
167
|
+
hypothesis you can go replay. Three lost scenarios would be noise.
|
|
168
|
+
|
|
169
|
+
## Exit codes
|
|
170
|
+
|
|
171
|
+
`refractal compare` is meant for CI:
|
|
172
|
+
|
|
173
|
+
| code | meaning |
|
|
174
|
+
|---|---|
|
|
175
|
+
| 0 | no regression |
|
|
176
|
+
| 1 | regression detected |
|
|
177
|
+
| 2 | **cannot be answered**: different scene geometry, duplicated episodes, or a change to the code that ran them |
|
|
178
|
+
|
|
179
|
+
The third is not a regression and is never reported as one. "The two runs used
|
|
180
|
+
different geometry" is a different sentence from "the policy got worse", and
|
|
181
|
+
conflating them teaches people to ignore the gate.
|
|
182
|
+
|
|
183
|
+
## Architecture
|
|
184
|
+
|
|
185
|
+
Refractal is a compiler, not a runtime. A catalog goes in, a `plan.json` comes
|
|
186
|
+
out, and the plan executes. The schedule is decided once and recorded, which makes
|
|
187
|
+
placement part of the provenance rather than an accident of the day.
|
|
188
|
+
|
|
189
|
+
| package | does | needs infrastructure? |
|
|
190
|
+
|---|---|---|
|
|
191
|
+
| `refractal.schema` | catalog, validation, identity | no |
|
|
192
|
+
| `refractal.resolve` | catalog → `plan.json` | no |
|
|
193
|
+
| `refractal.build` | facts that need the engine → `build.lock` | yes |
|
|
194
|
+
| `refractal.execute` | runs a plan; three backends | yes |
|
|
195
|
+
| `refractal.perturbations` | timed changes to world, observation or action | no |
|
|
196
|
+
| `refractal.render` | plan → deployment file | no |
|
|
197
|
+
| `refractal.compare` | Parquet → verdict | no |
|
|
198
|
+
|
|
199
|
+
`refractal plan` runs on a laptop with no simulator, no GPU and no Docker. That is
|
|
200
|
+
enforced by a test rather than by convention: it is the property that lets you
|
|
201
|
+
inspect a plan and its cost before committing to it.
|
|
202
|
+
|
|
203
|
+
Results are Parquet at an fsspec URI, so `./results` and `s3://bucket/results` are
|
|
204
|
+
the same code path. Every write is atomic, which is what makes resume safe, and
|
|
205
|
+
resume works by episode identity rather than by a counter.
|
|
206
|
+
|
|
207
|
+
## Backends
|
|
208
|
+
|
|
209
|
+
Two things are called a backend and it is worth keeping them apart. `refractal
|
|
210
|
+
run --backend X` executes a plan. `refractal render --target Y` writes a
|
|
211
|
+
deployment file that something else executes.
|
|
212
|
+
|
|
213
|
+
| `refractal run --backend` | |
|
|
214
|
+
|---|---|
|
|
215
|
+
| `local` | simulates outcomes; no infrastructure |
|
|
216
|
+
| `vla-eval` | drives the harness against running model servers |
|
|
217
|
+
| `compose` | one container per worker, over the same entrypoint |
|
|
218
|
+
|
|
219
|
+
| `refractal render --target` | |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `compose` | a Compose file; `docker compose up` runs it |
|
|
222
|
+
| `k8s` | one Job per worker; `kubectl apply` runs it |
|
|
223
|
+
|
|
224
|
+
Kubernetes is reached through `render`, not through `run`: Refractal writes the
|
|
225
|
+
Jobs and your cluster schedules them. Both targets render **without Docker or a
|
|
226
|
+
cluster installed**, so you can read the file before running it.
|
|
227
|
+
|
|
228
|
+
## Install
|
|
229
|
+
|
|
230
|
+
```console
|
|
231
|
+
pip install refractal # plan and build
|
|
232
|
+
pip install "refractal[execute]" # + run
|
|
233
|
+
pip install "refractal[compare]" # + compare
|
|
234
|
+
pip install "refractal[vla-eval]" # + the harness backend
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Comparison needs no numerical stack: exact McNemar is a binomial tail, the
|
|
238
|
+
bootstrap is resampling, and Cochran's Q is a permutation test.
|
|
239
|
+
|
|
240
|
+
## Status
|
|
241
|
+
|
|
242
|
+
Alpha. Every stage is implemented and tested, and the identity-bearing fields are
|
|
243
|
+
still able to move between versions, which is what the `a` in `0.1.0a1` is for.
|
|
244
|
+
|
|
245
|
+
Validated against real model servers as well as the synthetic backend: **15,490
|
|
246
|
+
episodes across 13 runs**, including a 600-episode comparison whose success rate
|
|
247
|
+
was predicted from an earlier run's data before it was run and came back within
|
|
248
|
+
two points.
|
|
249
|
+
|
|
250
|
+
The largest is a 2,700-episode comparison of three checkpoints across three
|
|
251
|
+
LIBERO suites, executed twice under one `plan_id` — once locally, once as one
|
|
252
|
+
container per worker:
|
|
253
|
+
|
|
254
|
+
| | wall clock | episode work | overall success |
|
|
255
|
+
|---|---|---|---|
|
|
256
|
+
| local, workers in sequence | 317 min | 314 min | 72.6% |
|
|
257
|
+
| compose, workers in parallel | **171 min** | 462 min | 72.0% |
|
|
258
|
+
|
|
259
|
+
Placement moved the wall clock by 1.86× and the result by 0.6 points. The two
|
|
260
|
+
placements agreed on **92.0%** of episodes — while re-running a *single*
|
|
261
|
+
placement against itself agreed on only **89.7%**, so two deployments differ
|
|
262
|
+
less than one deployment differs from its own rerun. That is the claim the
|
|
263
|
+
content-addressed identity exists to support, and it is measured rather than
|
|
264
|
+
asserted.
|
|
265
|
+
|
|
266
|
+
The 462 minutes of episode work against 314 is the honest other half:
|
|
267
|
+
parallelism bought real wall clock and was not free, because four workers
|
|
268
|
+
contend where one had the machine to itself.
|
|
269
|
+
|
|
270
|
+
## What is not here yet
|
|
271
|
+
|
|
272
|
+
- **Trajectory quality metrics.** The `steps.parquet` schema is declared and
|
|
273
|
+
nothing writes it, deliberately: writing it against synthetic data would bake in
|
|
274
|
+
guesses about what a real adapter can record.
|
|
275
|
+
- **`--backend k8s`.** `refractal render --target k8s` writes the Jobs and they
|
|
276
|
+
run against the same `--worker` entrypoint Compose uses, but nothing supervises
|
|
277
|
+
them from inside Refractal: no `run` subcommand submits them, watches them, or
|
|
278
|
+
collects their exit codes. Rendered and applied, not driven.
|
|
279
|
+
- **Resource-shape probing.** `refractal build` carries hand-declared shapes
|
|
280
|
+
forward and records whether they were measured. A lint refuses a comment
|
|
281
|
+
claiming a measurement when nothing recorded one.
|
|
282
|
+
|
|
283
|
+
## Built on vla-evaluation-harness
|
|
284
|
+
|
|
285
|
+
Refractal is a layer over
|
|
286
|
+
[**`allenai/vla-evaluation-harness`**](https://github.com/allenai/vla-evaluation-harness),
|
|
287
|
+
from the Allen Institute for AI, and does not fork it. The harness runs the
|
|
288
|
+
episodes: it owns the model-server protocol, the benchmark adapters, the
|
|
289
|
+
observation and action specs, and the episode loop. Refractal decides which
|
|
290
|
+
episodes to run, gives them content-addressed identities, and compares the
|
|
291
|
+
results.
|
|
292
|
+
|
|
293
|
+
Everything `--backend vla-eval` does is the harness doing it. Refractal subclasses
|
|
294
|
+
two of its classes and otherwise stays out of the way, which is why the
|
|
295
|
+
integration is a pinned dependency rather than a vendored copy, and why
|
|
296
|
+
`scripts/verify_harness_claims.py` exists: the assumptions Refractal makes about
|
|
297
|
+
someone else's code are checked rather than assumed.
|
|
298
|
+
|
|
299
|
+
The harness is Apache-2.0, as is Refractal. No code is copied from it.
|
|
300
|
+
|
|
301
|
+
If you use Refractal for published work, cite the harness as well. The evaluation
|
|
302
|
+
is theirs; the comparison is ours.
|
|
303
|
+
|
|
304
|
+
## Acknowledgements
|
|
305
|
+
|
|
306
|
+
- [`allenai/vla-evaluation-harness`](https://github.com/allenai/vla-evaluation-harness)
|
|
307
|
+
(Allen Institute for AI, Apache-2.0), which runs every episode.
|
|
308
|
+
- The benchmark suites and model servers it wraps, each under its own licence and
|
|
309
|
+
each the work of its own authors.
|
|
310
|
+
|
|
311
|
+
## Licence
|
|
312
|
+
|
|
313
|
+
Apache-2.0. See [LICENSE](https://github.com/nalinraut/refractal/blob/main/LICENSE)
|
|
314
|
+
and [NOTICE](https://github.com/nalinraut/refractal/blob/main/NOTICE).
|