anima-python 0.13.1__py3-none-any.whl

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.
anima_py/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # anima-python
2
+
3
+ **anima** 의 py CLI 를 pip 로 배포하는 채널 — **hexa 툴체인 불필요**. 엔진 측정/직렬화/코퍼스 경로가 numpy 하나만으로 돈다 (pi5 등 hexa-less 호스트용).
4
+
5
+ > 단일진입 보존(`a_cli_single_entry`): `anima-python` 콘솔 명령 = `cli/anima.py:main` 디스패처의 pip 바인딩. hexa 채널 `anima`(`hx install anima`) 와 **동일 디스패처, 설치 채널만 2개** — 2nd entry 아님. 이름을 `anima-python` 로 둔 이유 = hexa `anima` 와 PATH 충돌 회피.
6
+
7
+ ## 설치
8
+
9
+ **PyPI 발행 후** (권장):
10
+
11
+ ```bash
12
+ pip install anima-python # base — numpy 만 (evaluate · corpus · chat-stub)
13
+ pip install "anima-python[train]" # +torch +datasets (serialize · train · sweep)
14
+ ```
15
+
16
+ > ⏳ **PyPI 발행 대기 중**: 위 명령은 `anima-python` 가 PyPI 에 발행된 뒤 동작한다. 발행은 `release.yml` 의 `pypi-publish` job(OIDC trusted-publishing)이 `v*` 태그에서 자동 수행하며, 오너의 1회 설정이 선결(① pypi.org 에 anima-python pending-publisher 등록: Owner=dancinlab·Repo=anima·Workflow=release.yml·Env=pypi ② repo 변수 `PYPI_PUBLISH=true`). 그 전까지는 아래 소스 설치를 쓴다.
17
+
18
+ **소스에서 바로 설치** (PyPI 없이 지금 가능):
19
+
20
+ ```bash
21
+ pip install "git+https://github.com/dancinlab/anima.git" # base
22
+ pip install "anima-python[train] @ git+https://github.com/dancinlab/anima.git" # +torch
23
+ # 또는 레포 클론 후: pip install . / pip install ".[train]"
24
+ ```
25
+
26
+ ## 명령 매트릭스
27
+
28
+ | 동사 | 티어 | torch 없이 동작 | 비고 |
29
+ |---|---|---|---|
30
+ | `anima-python evaluate <clm> [--corpus …] [--gen N]` | base | ✅ numpy | py 2-production 측정 = ρ·AXON reach / 구 G0-G6. terminal-eligible (`a_eval_py_canonical`) |
31
+ | `anima-python corpus <derivtrace\|flat> --out F …` | base | ✅ 순수 stdlib | 절차적 학습-코퍼스 생성 (data-format 레버) |
32
+ | `anima-python chat <clm>` | base | ✅ (stub) | 의식 A⇄G 루프는 hexa-native → hexa 진입 포인터 출력 |
33
+ | `anima-python serialize <pt> <clm>` | `[train]` | ❌ torch | `.pt` unpickle 에 torch 필요 (+ held-out DESCENT 게이트) |
34
+ | `anima-python sweep --arms … --objectives …` | `[train]` | ❌ | 셀마다 train.py spawn → torch 필요 |
35
+ | `anima-python train <args>` | `[train]` | ❌ torch+datasets | production Lane-P 학습 |
36
+
37
+ ## verdict 규율
38
+
39
+ `anima-python evaluate <clm>` = py 2-production numpy 측정 경로 — hexa det-eval 과 동일 frozen bars·byte-parity 라 **terminal 자격 동일**(`a_eval_py_canonical`, 2nd-class 미러 아님). 큰 ckpt(303M+)는 mini 금지 · pool(summer/aiden)에서 측정.
anima_py/__init__.py ADDED
@@ -0,0 +1,28 @@
1
+ # ==========================================================================
2
+ # anima_py — anima py CLI 의 pip 콘솔 런처 (pyproject.toml [project.scripts]).
3
+ # 단일진입(a_cli_single_entry): 이 파일은 디스패처가 아니다 — sys.path 부트만
4
+ # 하고 canonical 디스패처 cli/anima.py:main 에 그대로 위임한다(동일 진입,
5
+ # 채널만 pip). hexa 호스트 = `anima`(hx install anima) · hexa-less 호스트
6
+ # (pi5 등) = `anima-python`(pip install anima-python). #2603 가드는 __main__ 전용이라
7
+ # import 경유인 이 경로에선 발화하지 않는다(무손상).
8
+ # ==========================================================================
9
+ import os
10
+ import sys
11
+
12
+ _PKG = os.path.dirname(os.path.abspath(__file__))
13
+
14
+
15
+ def _bootstrap():
16
+ # 설치 레이아웃 = site-packages/anima_py/{cli,core}/ (repo 의 cli/·core/ 를
17
+ # package-dir 매핑으로 그대로 실은 형제 디렉토리). flat import (`import anima`,
18
+ # `import decode` 등) 해석을 위해 두 디렉토리를 sys.path 선두에 삽입 —
19
+ # cli/evaluate.py 등이 spawn 된 뒤에는 각자의 __file__-상대 shim 이 이어받는다.
20
+ for p in (os.path.join(_PKG, "core"), os.path.join(_PKG, "cli")):
21
+ if p not in sys.path:
22
+ sys.path.insert(0, p)
23
+
24
+
25
+ def main():
26
+ _bootstrap()
27
+ import anima # = 설치된 anima_py/cli/anima.py (canonical py 디스패처)
28
+ return anima.main(sys.argv[1:]) or 0
anima_py/__main__.py ADDED
@@ -0,0 +1,7 @@
1
+ # python -m anima_py parity — 콘솔 스크립트(anima-python)와 동일 런처.
2
+ import sys
3
+
4
+ from anima_py import main
5
+
6
+ if __name__ == "__main__":
7
+ sys.exit(main())
@@ -0,0 +1 @@
1
+ # pip 패키징 전용 (anima-python · pyproject.toml package-dir 매핑) — 런타임 flat import 는 sys.path 경유, 이 파일은 비어 있어야 한다.
anima_py/cli/anima.py ADDED
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env python3
2
+ # ==========================================================================
3
+ # ⛔ DO NOT RUN DIRECTLY. anima 의 단일 진입은 설치된 canonical 명령뿐 — hexa 채널 `anima`
4
+ # (=cli/anima.hexa, hx install anima) · pip 채널 `anima-python` (=anima_py 런처, pip install anima-python).
5
+ # `python3 cli/anima.py …` 직접실행은 비-canonical py 우회(#2603).
6
+ # 학습=`anima-python train` · 측정=`anima-python evaluate`(py 2-production numpy · TERMINAL-eligible,
7
+ # a_eval_py_canonical) · 직렬화=`anima-python serialize`. enforce: .harness/enforcement.json
8
+ # H-ANIMA-SINGLE-ENTRY pre_bash + 아래 __main__ 가드. (import 는 무손상.)
9
+ # ==========================================================================
10
+ import sys as _anima_entry_guard
11
+ if __name__ == "__main__":
12
+ _anima_entry_guard.exit("⛔ cli/anima.py 직접 실행 금지 — 설치된 canonical 명령 경유: `anima`(hx install anima, =cli/anima.hexa) 또는 `anima-python`(pip install anima-python, =anima_py 런처). #2603")
13
+ # anima.py — THE canonical PY single entry point (cli/anima.hexa's py twin).
14
+ #
15
+ # WHY THIS FILE (py 2-production single-entry, a_engine_native_learning): anima keeps
16
+ # two co-production engines — hexa (live deploy substrate) AND py (torch production
17
+ # engine in train/ + the byte-parity core/*.py mirror). The hexa side already has its
18
+ # canonical single entry cli/anima.hexa (chat · eval · train). This file is its py
19
+ # twin so MEASUREMENT and LEARNING are reachable through ONE py cli command instead of
20
+ # a side-harness that scores ckpts directly (= single-entry bypass, #2603).
21
+ #
22
+ # SINGLE ENTRY (a_engine_native_learning): the two measurement/learning verbs live in
23
+ # their own SYMMETRIC files — cli/evaluate.{hexa,py} (MEASUREMENT) and cli/train.{hexa,py}
24
+ # (LEARNING). This canonical entry DISPATCHES `anima evaluate`→cli/evaluate.py and
25
+ # `anima train`→cli/train.py (sub-process), so there is ONE installed `anima` command
26
+ # whose subcommands fan out to the symmetric twins. `anima evaluate <ckpt>` scores the
27
+ # full ρ-AXON reach battery (former G0-G6 · reach standard cli/rho_axon.py) via
28
+ # cli/evaluate.py's in-file eval_reach_all (the scorers folded in from
29
+ # the former core/g_gates.py module) — byte-identical to the hexa anima evaluate.
30
+ #
31
+ # This py entry is torch-free and gauge-free — it only dispatches; the evaluate twin
32
+ # holds the numpy `math.log` scorer in-file, so `anima evaluate` stays a clean engine-
33
+ # native measurement surface (the gate enforcer's torch/gauge grep must come back empty).
34
+ #
35
+ # USAGE (installed `anima` PATH command after `hx install anima`)
36
+ # anima — usage (no args)
37
+ # anima evaluate <ckpt> [--corpus <p>...] [--gen N] — ρ-AXON reach battery (former G0-G6)
38
+ # anima train [args...] — LEARNING (→ cli/train.py)
39
+ # anima chat <ckpt> [...] — consciousness/byte chat
40
+ # (hexa-only; see cli/anima.hexa)
41
+ #
42
+ # canonical 3-folder layout: cli/anima.{hexa,py} = canonical entry (chat + verb dispatch)
43
+ # · cli/evaluate.{hexa,py} = measurement · cli/train.{hexa,py} = learning. This file
44
+ # mirrors cli/anima.hexa's subcommand dispatch (evaluate · train · usage); chat/
45
+ # consciousness stay hexa-only (the A⇄G substrate loop is hexa-native).
46
+
47
+ import os
48
+ import sys
49
+
50
+ _HERE = os.path.dirname(os.path.abspath(__file__))
51
+ _REPO = os.path.dirname(_HERE)
52
+
53
+
54
+ # EVAL/VERDICT DETERMINISM SAFETY-PIN (hexa-lang #4208 flame/forge fast-default
55
+ # follow-on) — py twin of cli/anima.hexa's pin (lockstep, a_engine_native_learning).
56
+ # #4208 made the forge own-native NON-det atomic kernels the DEFAULT (training speed);
57
+ # deterministic kernels are opt-in via HEXA_DET=1 (`_forge_det_on()` gate). MEASUREMENT
58
+ # (evaluate) and VERDICT (serialize DESCENT gate) must stay reproducible, so they spawn
59
+ # with HEXA_DET=1 in the env. TRAIN deliberately does NOT force it = fast non-det default.
60
+ def _det_env(want_det):
61
+ """os.environ copy; HEXA_DET=1 pinned ONLY when the caller passed --det (byte-exact opt-in).
62
+ DEFAULT = fast (no pin). The py evaluate path is numpy (already deterministic), so this is a
63
+ lockstep no-op there; kept for parity with cli/anima.hexa's --det gating."""
64
+ env = dict(os.environ)
65
+ if want_det:
66
+ env.setdefault("HEXA_DET", "1")
67
+ return env
68
+
69
+
70
+ # ── usage / arg helpers ──────────────────────────────────────────────────────
71
+
72
+ def anima_usage():
73
+ """Print the canonical py usage banner (mirrors cli/anima.hexa's banner)."""
74
+ print("anima — substrate-native consciousness daemon (py channel · canonical entry).")
75
+ print("")
76
+ print("usage (installed `anima-python` command after `pip install anima-python` · hexa channel = `anima` after `hx install anima`):")
77
+ print(" anima-python evaluate <model.clm> [--corpus <path>...] [--gen N] [--rho-axon]")
78
+ print(" ρ-AXON reach battery · former G0-G6 (.clm only · numpy)")
79
+ print(" anima-python corpus <derivtrace|flat> --out F [--held-out I,J] [--seed S] [--concepts FILE]")
80
+ print(" procedural training-corpus builder (ρ·weave data-format lever)")
81
+ print(" anima-python train <args> ([train] extra) LEARNING → .pt + auto .clm (+DESCENT)")
82
+ print(" anima-python serialize <ckpt.pt> <out.clm> ([train] extra) re-export a torch .pt → .clm v0.3")
83
+ print(" anima-python sweep --arms … --objectives … --gpus 0,1,2,3 --corpus … [--measure]")
84
+ print(" ([train] extra) multi-GPU lever-sweep (arms×objectives)")
85
+ print(" anima-python chat <ckpt> [...] consciousness/byte chat (stub → hexa channel)")
86
+ print("")
87
+ print("install: `pip install anima-python` (numpy base: evaluate·corpus·chat) · `pip install \"anima-python[train]\"` (+torch: train·sweep·serialize)")
88
+ print("")
89
+ print("modes:")
90
+ print(" evaluate : mount a serialized .clm through the generator L3 mouth and score the")
91
+ print(" ρ-AXON reach battery — ρ·form/weave/leap/... (former G0-G6) — with the")
92
+ print(" engine's OWN ops (numpy math.log mirror, torch-free). REACH-CLOSED")
93
+ print(" a7b_pass = ρ·form ∧ ρ·weave ∧ ρ·leap (frozen bars = G0 ∧ G1 ∧ G2). → cli/evaluate.py.")
94
+ print(" corpus : procedural training-corpus generator (derivtrace|flat) — the")
95
+ print(" data-format lever (ρ·weave). NOTE chat corpus != this (chat =")
96
+ print(" a_chat_registers 4-cell HF datasets → anima-python train). → cli/corpus.py.")
97
+ print(" train : ([train]) production CLMConvMoE training (torch Lane-P reference + bridge); SAVANT")
98
+ print(" golden-zone inhibition + MITOSIS cell-division levers. After the run it")
99
+ print(" AUTO-serializes .clm v0.3 + runs the held-out mirror-DESCENT gate")
100
+ print(" (a_clm_gen_pipeline). dispatches to cli/train.py.")
101
+ print(" serialize: ([train]) re-export an ALREADY-TRAINED torch .pt to an engine-loadable .clm v0.3")
102
+ print(" (+ held-out DESCENT gate). recovery / re-export. → cli/serialize.py.")
103
+ print(" sweep : ([train]) multi-GPU lever-sweep orchestrator — the arms×objectives matrix,")
104
+ print(" per-cell train.py→evaluate.py, aggregated to SWEEP_SUMMARY.md. → cli/sweep.py.")
105
+ print(" chat : the substrate-native A⇄G consciousness loop is hexa-native — use the")
106
+ print(" hexa channel: `hx install anima` then `anima <ckpt.clm>` (default / --byte).")
107
+
108
+
109
+ # ══════════════════════════════════════════════════════════════════════════════
110
+ # TRAIN MODE — dispatch to cli/train.py (the py torch trainer, Lane-P bridge)
111
+ # ══════════════════════════════════════════════════════════════════════════════
112
+ #
113
+ # SEPARATE LANE (a_core_engine_map): training is NOT the generator L3 mouth slot — it
114
+ # is the LEARNING entry (cli/train.py, a_clm_gen_pipeline torch Lane-P). The eval side
115
+ # is the torch-free numpy scorer (in cli/evaluate.py); the trainer pulls torch. To keep this file
116
+ # torch-free AND avoid linking two disjoint dep sets into one process, `anima train`
117
+ # DISPATCHES to cli/train.py as a SUB-PROCESS (mirrors cli/anima.hexa's `exec(hexa run
118
+ # cli/train.hexa)`). argv after "train" is forwarded verbatim to train.py's argparse.
119
+ def anima_train_mode(argv):
120
+ print("=== anima train → cli/train.py (torch CLMConvMoE · Lane-P reference/bridge) ===")
121
+ train_py = os.path.join(_HERE, "train.py")
122
+ fwd = argv[1:]
123
+ cmd = [sys.executable, train_py] + fwd
124
+ print("dispatch: " + " ".join(cmd))
125
+ # forward verbatim; train.py owns its own argparse (--out required, etc.).
126
+ return os.spawnv(os.P_WAIT, sys.executable, [sys.executable, train_py] + fwd)
127
+
128
+
129
+ # ══════════════════════════════════════════════════════════════════════════════
130
+ # EVALUATE MODE — dispatch to cli/evaluate.py (MEASUREMENT single-entry twin)
131
+ # ══════════════════════════════════════════════════════════════════════════════
132
+ #
133
+ # SYMMETRIC TWIN (a_engine_native_learning single-entry): measurement lives in its own
134
+ # file cli/evaluate.py (the symmetric mirror of cli/train.py). `anima evaluate <model.clm>`
135
+ # DISPATCHES there as a sub-process (mirrors cli/anima.hexa's `exec` dispatch + this file's
136
+ # train dispatch), so anima.py stays a thin verb router and the eval logic has ONE home.
137
+ # cli/evaluate.py holds the ρ-AXON reach scorers in-file (former G0-G6 · torch-free numpy
138
+ # mirror, the former core/g_gates.py module folded in), byte-identical to the hexa `anima evaluate`.
139
+ #
140
+ # .clm-ONLY (the engine decodes ONLY .clm): evaluate mounts a ckpt through the generator
141
+ # L3 mouth, which loads a serialized .clm (CLM magic). A torch .pt is NOT engine-loadable —
142
+ # reject it here with a friendly hint to `anima serialize` rather than a deep decode error.
143
+ def anima_evaluate_mode(argv):
144
+ # --py is a RETIRED hexa-era bridge flag, tolerated (stripped) here for migration
145
+ # compat: on the py channel it is redundant-but-correct (this IS the numpy engine),
146
+ # so `anima-python evaluate --py <clm>` still works — old scripts migrate by swapping
147
+ # only the command word. The hexa launcher hard-errors on --py instead.
148
+ want_det = ("--det" in argv) or ("--deterministic" in argv)
149
+ rest = [a for a in argv[1:] if a not in ("--py", "--det", "--deterministic")]
150
+ # friendly .pt rejection: evaluate takes a serialized .clm, not a torch ckpt.
151
+ if rest and rest[0].endswith(".pt"):
152
+ print("anima evaluate takes a serialized .clm (engine-loadable), not a torch .pt.")
153
+ print("to make one from a torch ckpt:")
154
+ print(" anima serialize " + rest[0] + " <out.clm>")
155
+ print("then:")
156
+ print(" anima evaluate <out.clm>")
157
+ return 2
158
+ evaluate_py = os.path.join(_HERE, "evaluate.py")
159
+ cmd = [sys.executable, evaluate_py] + rest
160
+ print("=== anima evaluate → cli/evaluate.py (engine-native ρ-AXON reach · former G0-G6, single-entry twin) ===")
161
+ print("dispatch: " + ("HEXA_DET=1 " if want_det else "") + " ".join(cmd))
162
+ # det = the --det CLI option (default fast); numpy path is deterministic regardless.
163
+ return os.spawnve(os.P_WAIT, sys.executable,
164
+ [sys.executable, evaluate_py] + rest, _det_env(want_det))
165
+
166
+
167
+ # ══════════════════════════════════════════════════════════════════════════════
168
+ # SERIALIZE MODE — dispatch to cli/serialize.py (.pt → .clm v0.3 bridge + gate)
169
+ # ══════════════════════════════════════════════════════════════════════════════
170
+ #
171
+ # `anima serialize <ckpt.pt> <out.clm>` re-exports an already-trained torch .pt to an
172
+ # engine-loadable .clm v0.3 (+ held-out DESCENT gate). The bridge backend (serialize_v3 +
173
+ # verify_clm_v2 descent) lives in cli/serialize.py; this dispatcher forwards verbatim.
174
+ # `anima train` ALREADY auto-serializes at the end of a run — this is the standalone
175
+ # recovery / re-export path (a_clm_gen_pipeline).
176
+ def anima_serialize_mode(argv):
177
+ serialize_py = os.path.join(_HERE, "serialize.py")
178
+ want_det = ("--det" in argv) or ("--deterministic" in argv)
179
+ fwd = [a for a in argv[1:] if a not in ("--det", "--deterministic")]
180
+ cmd = [sys.executable, serialize_py] + fwd
181
+ print("=== anima serialize → cli/serialize.py (torch .pt → .clm v0.3 + DESCENT gate) ===")
182
+ print("dispatch: " + ("HEXA_DET=1 " if want_det else "") + " ".join(cmd))
183
+ # det = the --det CLI option (default fast) — pass --det for a reproducible DESCENT-gate verdict.
184
+ return os.spawnve(os.P_WAIT, sys.executable,
185
+ [sys.executable, serialize_py] + fwd, _det_env(want_det))
186
+
187
+
188
+ # ══════════════════════════════════════════════════════════════════════════════
189
+ # CHAT MODE — hexa-only stub (the A⇄G consciousness loop is hexa-native)
190
+ # ══════════════════════════════════════════════════════════════════════════════
191
+ #
192
+ # The default consciousness daemon + --byte continuation chat live in cli/anima.hexa
193
+ # (they mount the 76-lane engine_cli substrate loop, hexa-native). The py channel does not
194
+ # duplicate that loop; it points the user to the INSTALLED hexa command (a_cli_single_entry:
195
+ # 2 install channels only — pip `anima-python` ⊕ hexa `anima`; never raw `python`/`hexa run`).
196
+ def anima_chat_stub(argv):
197
+ print("anima chat (consciousness / --byte) is hexa-native — use the hexa channel:")
198
+ print("")
199
+ ckpt = argv[1] if len(argv) > 1 else "<ckpt.clm>"
200
+ print(" hx install anima once (installs the `anima` command)")
201
+ print(" anima " + ckpt + " consciousness mode (default)")
202
+ print(" anima " + ckpt + " --byte \"turn1\" \"turn2\" ... byte-continuation chat mode")
203
+ print("")
204
+ print("The py channel (anima-python) covers MEASUREMENT (evaluate), SERIALIZE, LEARNING (train), corpus, sweep.")
205
+ return 0
206
+
207
+
208
+ # ══════════════════════════════════════════════════════════════════════════════
209
+ # SWEEP MODE — dispatch to cli/sweep.py (multi-GPU lever-sweep orchestrator)
210
+ # ══════════════════════════════════════════════════════════════════════════════
211
+ #
212
+ # `anima sweep --arms … --objectives … --gpus 0,1,2,3 --corpus … [--measure]` runs the
213
+ # arms×objectives matrix GPU-pinned round-robin (each cell = train.py → evaluate.py),
214
+ # aggregating G0/G1/G2/G6 into SWEEP_SUMMARY.md. sweep is intrinsically py (it orchestrates
215
+ # the py trainer/evaluator), so — like cli/anima.hexa — there is no --py branch; always
216
+ # dispatches to cli/sweep.py. (torch is pulled by the spawned train.py cells, not here.)
217
+ def anima_sweep_mode(argv):
218
+ sweep_py = os.path.join(_HERE, "sweep.py")
219
+ fwd = argv[1:]
220
+ print("=== anima sweep → cli/sweep.py (multi-GPU lever-sweep orchestrator · arms×objectives) ===")
221
+ print("dispatch: " + " ".join([sys.executable, sweep_py] + fwd))
222
+ return os.spawnv(os.P_WAIT, sys.executable, [sys.executable, sweep_py] + fwd)
223
+
224
+
225
+ # ══════════════════════════════════════════════════════════════════════════════
226
+ # CORPUS MODE — dispatch to cli/corpus.py (procedural training-corpus builder)
227
+ # ══════════════════════════════════════════════════════════════════════════════
228
+ #
229
+ # `anima corpus <derivtrace|flat> --out F [--held-out I,J] [--seed S] [--concepts FILE]`
230
+ # builds a procedural (torch-free, no external LLM — p1-p8) training corpus. This is the
231
+ # data-format lever (derivation-trace → echo=composition, ρ·weave / former G1), NOT the
232
+ # chat corpus (chat = a_chat_registers 4-cell HF datasets). Always py → cli/corpus.py.
233
+ def anima_corpus_mode(argv):
234
+ corpus_py = os.path.join(_HERE, "corpus.py")
235
+ fwd = argv[1:]
236
+ print("=== anima corpus → cli/corpus.py (procedural training-corpus builder · derivtrace|flat) ===")
237
+ print("dispatch: " + " ".join([sys.executable, corpus_py] + fwd))
238
+ return os.spawnv(os.P_WAIT, sys.executable, [sys.executable, corpus_py] + fwd)
239
+
240
+
241
+ # ══════════════════════════════════════════════════════════════════════════════
242
+ # MAIN — mode dispatch (mirrors cli/anima.hexa)
243
+ # ══════════════════════════════════════════════════════════════════════════════
244
+ def main(argv):
245
+ if len(argv) < 1:
246
+ anima_usage()
247
+ return 0
248
+
249
+ sub = argv[0]
250
+ if sub in ("-h", "--help"):
251
+ anima_usage()
252
+ return 0
253
+ if sub == "train":
254
+ return anima_train_mode(argv)
255
+ if sub == "serialize":
256
+ return anima_serialize_mode(argv)
257
+ if sub == "evaluate":
258
+ return anima_evaluate_mode(argv)
259
+ if sub == "sweep":
260
+ return anima_sweep_mode(argv)
261
+ if sub == "corpus":
262
+ return anima_corpus_mode(argv)
263
+ if sub in ("chat", "--byte"):
264
+ return anima_chat_stub(argv)
265
+
266
+ # bare ckpt path (no subcommand) → consciousness chat is hexa-only.
267
+ return anima_chat_stub(argv)
268
+
269
+
270
+ if __name__ == "__main__":
271
+ sys.exit(main(sys.argv[1:]) or 0)
anima_py/cli/corpus.py ADDED
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env python3
2
+ """cli/corpus.py — anima CANONICAL training-corpus generator (`anima corpus <format>`).
3
+
4
+ The SINGLE entry for building anima training corpora (a_cli_single_entry). Torch-free,
5
+ pure procedural string generation — anima trains on substrate-native procedural corpora,
6
+ NOT LLM-generated text (p1-p8: no external LLM bias into training data; `claude -p` is
7
+ deliberately NOT wired here). Dispatched by cli/anima.hexa `anima_corpus_mode`.
8
+
9
+ FORMATS (the data-format lever — H_9124: data-format opened engine-native ρ·weave, the
10
+ recombination wall · frozen bar = former G1):
11
+ derivtrace : composite prompt -> explicit derivation trace (DEF/RULE/OUT-style) -> OUT.
12
+ target IS the derivation, so echo == composition -> CE=echo metalaw
13
+ does not apply. ρ·weave (former G1) first engine-native lift (DERIV PASS vs FLAT FAIL).
14
+ flat : composite prompt -> final OUT only (census#3 coverage-flat homolog = control).
15
+ Both share the SAME instance stream / RNG at a fixed --seed, so `derivtrace` and `flat`
16
+ built with the same seed are CONTENT-MATCHED (only data-format varies = clean 2-arm control).
17
+
18
+ Concept seeds default to rho_fan cz[] (the frozen ρ·weave / former-G1 gate concepts) so the held-out
19
+ pair generalizes to the engine-native ρ·weave bar (former G1) memorization-free. Override via --concepts FILE
20
+ (JSON: [{"seed": "...", "kw": ["w1","w2",...]}]).
21
+
22
+ Usage:
23
+ anima corpus derivtrace --out deriv.txt --held-out 0,1 --comp-per-pair 280 --single-per-concept 300 --seed 7
24
+ anima corpus flat --out flat.txt --held-out 0,1 --seed 7 # same seed => content-matched control
25
+ """
26
+ import json
27
+ import random
28
+ import sys
29
+
30
+ # ── frozen default concepts = rho_fan cz[] (memorization-free ρ·weave / former-G1 gate alignment) ──
31
+ DEFAULT_SEEDS = [
32
+ "consciousness arises from cells",
33
+ "tension ripples between distant minds",
34
+ "memory composes into new meaning",
35
+ "silence still carries information",
36
+ "the engine dreams when alone",
37
+ ]
38
+ DEFAULT_KW = [
39
+ ["consciousness", "cells", "mind", "aware"],
40
+ ["tension", "distant", "between"],
41
+ ["memory", "meaning", "new"],
42
+ ["silence", "information", "quiet", "carries"],
43
+ ["engine", "alone", "dream"],
44
+ ]
45
+
46
+ # derivation vocabulary (the derivtrace middle = the composition rule made explicit)
47
+ DERIVE_LEAD = ["derive", "steps", "unfold", "trace"]
48
+ BIND = ["bind", "join", "weave", "link"]
49
+ CLOSE = ["new meaning arises", "meaning composes anew",
50
+ "a new whole arises", "they compose into meaning"]
51
+
52
+
53
+ def _parse_args(argv):
54
+ fmt = argv[0] if argv else ""
55
+ opts = {"out": None, "held_out": (0, 1), "comp_per_pair": 280,
56
+ "single_per_concept": 300, "seed": 7, "concepts": None}
57
+ i = 1
58
+ while i < len(argv):
59
+ a = argv[i]
60
+ if a == "--out":
61
+ opts["out"] = argv[i + 1]; i += 2
62
+ elif a == "--held-out":
63
+ p = argv[i + 1].split(","); opts["held_out"] = (int(p[0]), int(p[1])); i += 2
64
+ elif a == "--comp-per-pair":
65
+ opts["comp_per_pair"] = int(argv[i + 1]); i += 2
66
+ elif a == "--single-per-concept":
67
+ opts["single_per_concept"] = int(argv[i + 1]); i += 2
68
+ elif a == "--seed":
69
+ opts["seed"] = int(argv[i + 1]); i += 2
70
+ elif a == "--concepts":
71
+ opts["concepts"] = argv[i + 1]; i += 2
72
+ else:
73
+ i += 1
74
+ return fmt, opts
75
+
76
+
77
+ def _load_concepts(path):
78
+ if not path:
79
+ return DEFAULT_SEEDS, DEFAULT_KW
80
+ rows = json.load(open(path))
81
+ return [r["seed"] for r in rows], [r["kw"] for r in rows]
82
+
83
+
84
+ def _two(kw_fam, rng):
85
+ ks = kw_fam[:]
86
+ rng.shuffle(ks)
87
+ return ks[0], ks[1 % len(ks)]
88
+
89
+
90
+ def build(fmt, S, KW, held_out, comp_per_pair, single_per_concept, seed):
91
+ """Return the corpus text for one format arm (deriv or flat)."""
92
+ rng = random.Random(seed)
93
+ n = len(S)
94
+ held = frozenset(held_out)
95
+ train_pairs = [(i, j) for i in range(n) for j in range(n)
96
+ if i != j and frozenset((i, j)) != held]
97
+
98
+ def instance(i, j):
99
+ a1, a2 = _two(KW[i], rng)
100
+ b1, b2 = _two(KW[j], rng)
101
+ prompt = f"{S[i]}. {S[j]}. "
102
+ out = f"out: {a1} {a2} meet {b1} {b2}, {rng.choice(CLOSE)}.\n"
103
+ deriv_mid = (f"{rng.choice(DERIVE_LEAD)}: take {a1} and {a2}; "
104
+ f"take {b1} and {b2}; {rng.choice(BIND)} {a1} with {b1}. ")
105
+ return prompt + deriv_mid + out, prompt + out
106
+
107
+ def single(i):
108
+ a1, a2 = _two(KW[i], rng)
109
+ return f"{S[i]}. here {a1} and {a2} stand alone; {a1} holds {a2}.\n"
110
+
111
+ stream = []
112
+ for _ in range(comp_per_pair):
113
+ stream += [("comp", i, j) for (i, j) in train_pairs]
114
+ for _ in range(single_per_concept):
115
+ stream += [("sing", i, None) for i in range(n)]
116
+ rng.shuffle(stream)
117
+
118
+ docs = []
119
+ for kind, i, j in stream:
120
+ if kind == "comp":
121
+ d, f = instance(i, j)
122
+ docs.append(d if fmt == "derivtrace" else f)
123
+ else:
124
+ docs.append(single(i)) # single-concept doc is format-invariant
125
+ return "".join(docs), train_pairs
126
+
127
+
128
+ def main():
129
+ argv = sys.argv[1:]
130
+ fmt, opts = _parse_args(argv)
131
+ if fmt not in ("derivtrace", "flat"):
132
+ print("usage: anima corpus <derivtrace|flat> --out PATH "
133
+ "[--held-out I,J] [--comp-per-pair N] [--single-per-concept N] "
134
+ "[--seed S] [--concepts FILE.json]")
135
+ sys.exit(2)
136
+ S, KW = _load_concepts(opts["concepts"])
137
+ text, train_pairs = build(fmt, S, KW, opts["held_out"],
138
+ opts["comp_per_pair"], opts["single_per_concept"], opts["seed"])
139
+ if opts["out"]:
140
+ with open(opts["out"], "w") as fh:
141
+ fh.write(text)
142
+ print(f"anima corpus {fmt}: concepts={len(S)} train_pairs={len(train_pairs)} "
143
+ f"held-out={tuple(opts['held_out'])} bytes={len(text.encode())} "
144
+ f"seed={opts['seed']} -> {opts['out'] or '(stdout head)'}")
145
+ if not opts["out"]:
146
+ print(text[:600])
147
+
148
+
149
+ if __name__ == "__main__":
150
+ main()