compmech-reference-pack 0.3.1__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.
- compmech_reference_pack-0.3.1/PKG-INFO +74 -0
- compmech_reference_pack-0.3.1/README.md +60 -0
- compmech_reference_pack-0.3.1/pyproject.toml +49 -0
- compmech_reference_pack-0.3.1/setup.cfg +4 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/__init__.py +22 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/adapters/__init__.py +15 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/adapters/mechdsl_runner.py +321 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/capabilities.py +67 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/domain_pack/domain_pack.yaml +49 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/domain_pack/source_packs/constkit.yaml +28 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/domain_pack/source_packs/mechdsl.yaml +26 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/domain_pack/source_packs/symbolic_fem_workbench.yaml +29 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/normalize.py +192 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack/paths.py +30 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack.egg-info/PKG-INFO +74 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack.egg-info/SOURCES.txt +23 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack.egg-info/dependency_links.txt +1 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack.egg-info/requires.txt +9 -0
- compmech_reference_pack-0.3.1/src/compmech_reference_pack.egg-info/top_level.txt +1 -0
- compmech_reference_pack-0.3.1/tests/test_capabilities.py +43 -0
- compmech_reference_pack-0.3.1/tests/test_domain_pack.py +67 -0
- compmech_reference_pack-0.3.1/tests/test_import.py +63 -0
- compmech_reference_pack-0.3.1/tests/test_integration.py +128 -0
- compmech_reference_pack-0.3.1/tests/test_mechdsl_runner.py +193 -0
- compmech_reference_pack-0.3.1/tests/test_normalize.py +121 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: compmech-reference-pack
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Computational-mechanics companion adapter — bridges AKMS LSP excerpts to the MechDSL executable backend.
|
|
5
|
+
Requires-Python: <3.14,>=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: akms-learn
|
|
8
|
+
Provides-Extra: mechdsl
|
|
9
|
+
Requires-Dist: mechdsl-core; extra == "mechdsl"
|
|
10
|
+
Requires-Dist: algo2code; extra == "mechdsl"
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=9.0.2; extra == "dev"
|
|
13
|
+
Requires-Dist: compmech-reference-pack[mechdsl]; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# compmech-reference-pack
|
|
16
|
+
|
|
17
|
+
The computational-mechanics companion adapter for
|
|
18
|
+
[AKMS](https://github.com/CEmM2/AKMS). It bridges `akms-learn` Learning Source
|
|
19
|
+
Packet excerpts to the [MechDSL](https://github.com/CEmM2/MechDSL) executable
|
|
20
|
+
backend, so an algorithm described in a knowledge node can be transpiled and
|
|
21
|
+
compiled rather than only read.
|
|
22
|
+
|
|
23
|
+
It ships the `compmech` domain pack — the descriptor and source packs that tell
|
|
24
|
+
`akms-learn` which companions exist and what each can do.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install compmech-reference-pack
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
That gives you the domain pack and the adapter's declared capability surface,
|
|
33
|
+
and pulls in `akms-learn`. It does **not** pull in the MechDSL backend: every
|
|
34
|
+
`mechdsl` and `algo2code` import in this package is function-scoped, so it
|
|
35
|
+
installs and imports cleanly without them.
|
|
36
|
+
|
|
37
|
+
To enable the actual compile, transpile and verify path:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install "compmech-reference-pack[mechdsl]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The extra exists so a downstream consumer can depend on this package without
|
|
44
|
+
dragging the executable backend — and transitively Taichi — into its
|
|
45
|
+
resolution.
|
|
46
|
+
|
|
47
|
+
## What it provides
|
|
48
|
+
|
|
49
|
+
- **`MechDSLRunner`** — the `executable_bridge` adapter. Given an LSP excerpt
|
|
50
|
+
it normalises the algorithmic block, derives a safe algorithm name, and
|
|
51
|
+
delegates to MechDSL's `transpile_algorithm` / `compile_from_sources`.
|
|
52
|
+
Provenance is preserved from node to generated artefact.
|
|
53
|
+
- **`capabilities()`** — a declaration of what the package offers, kept
|
|
54
|
+
deliberately import-light and Taichi-free so a caller can ask without paying
|
|
55
|
+
for a backend it may not use.
|
|
56
|
+
- **The `compmech` domain pack** — `domain_pack.yaml` plus the source packs
|
|
57
|
+
under `domain_pack/source_packs/`, addressed through
|
|
58
|
+
`compmech_reference_pack.paths`.
|
|
59
|
+
|
|
60
|
+
## Companion status
|
|
61
|
+
|
|
62
|
+
| Companion | Role | Status |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `mechdsl` | executable bridge | available |
|
|
65
|
+
| `constkit` | concept kit | planned |
|
|
66
|
+
| `symbolic_fem_workbench` | pedagogical workbench | planned |
|
|
67
|
+
|
|
68
|
+
`planned` describes the adapter, not the source: the material for both planned
|
|
69
|
+
companions is public, in
|
|
70
|
+
[SOSOVSKI/Teaching-materials](https://github.com/SOSOVSKI/Teaching-materials).
|
|
71
|
+
|
|
72
|
+
## Licence
|
|
73
|
+
|
|
74
|
+
Apache-2.0, matching AKMS.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# compmech-reference-pack
|
|
2
|
+
|
|
3
|
+
The computational-mechanics companion adapter for
|
|
4
|
+
[AKMS](https://github.com/CEmM2/AKMS). It bridges `akms-learn` Learning Source
|
|
5
|
+
Packet excerpts to the [MechDSL](https://github.com/CEmM2/MechDSL) executable
|
|
6
|
+
backend, so an algorithm described in a knowledge node can be transpiled and
|
|
7
|
+
compiled rather than only read.
|
|
8
|
+
|
|
9
|
+
It ships the `compmech` domain pack — the descriptor and source packs that tell
|
|
10
|
+
`akms-learn` which companions exist and what each can do.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install compmech-reference-pack
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That gives you the domain pack and the adapter's declared capability surface,
|
|
19
|
+
and pulls in `akms-learn`. It does **not** pull in the MechDSL backend: every
|
|
20
|
+
`mechdsl` and `algo2code` import in this package is function-scoped, so it
|
|
21
|
+
installs and imports cleanly without them.
|
|
22
|
+
|
|
23
|
+
To enable the actual compile, transpile and verify path:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install "compmech-reference-pack[mechdsl]"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The extra exists so a downstream consumer can depend on this package without
|
|
30
|
+
dragging the executable backend — and transitively Taichi — into its
|
|
31
|
+
resolution.
|
|
32
|
+
|
|
33
|
+
## What it provides
|
|
34
|
+
|
|
35
|
+
- **`MechDSLRunner`** — the `executable_bridge` adapter. Given an LSP excerpt
|
|
36
|
+
it normalises the algorithmic block, derives a safe algorithm name, and
|
|
37
|
+
delegates to MechDSL's `transpile_algorithm` / `compile_from_sources`.
|
|
38
|
+
Provenance is preserved from node to generated artefact.
|
|
39
|
+
- **`capabilities()`** — a declaration of what the package offers, kept
|
|
40
|
+
deliberately import-light and Taichi-free so a caller can ask without paying
|
|
41
|
+
for a backend it may not use.
|
|
42
|
+
- **The `compmech` domain pack** — `domain_pack.yaml` plus the source packs
|
|
43
|
+
under `domain_pack/source_packs/`, addressed through
|
|
44
|
+
`compmech_reference_pack.paths`.
|
|
45
|
+
|
|
46
|
+
## Companion status
|
|
47
|
+
|
|
48
|
+
| Companion | Role | Status |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `mechdsl` | executable bridge | available |
|
|
51
|
+
| `constkit` | concept kit | planned |
|
|
52
|
+
| `symbolic_fem_workbench` | pedagogical workbench | planned |
|
|
53
|
+
|
|
54
|
+
`planned` describes the adapter, not the source: the material for both planned
|
|
55
|
+
companions is public, in
|
|
56
|
+
[SOSOVSKI/Teaching-materials](https://github.com/SOSOVSKI/Teaching-materials).
|
|
57
|
+
|
|
58
|
+
## Licence
|
|
59
|
+
|
|
60
|
+
Apache-2.0, matching AKMS.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "compmech-reference-pack"
|
|
3
|
+
version = "0.3.1"
|
|
4
|
+
description = "Computational-mechanics companion adapter — bridges AKMS LSP excerpts to the MechDSL executable backend."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11,<3.14"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"akms-learn",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[project.optional-dependencies]
|
|
12
|
+
# The executable-build path (MechDSLRunner.build_executable / transpile /
|
|
13
|
+
# verify) lazily imports the MechDSL Tier-1 backend — every mechdsl/algo2code
|
|
14
|
+
# import in src/ is function-scoped, so the package installs and imports
|
|
15
|
+
# cleanly without them. They are an optional extra so a downstream consumer
|
|
16
|
+
# (e.g. Logic-Loom's frozen core sidecar) can resolve and install
|
|
17
|
+
# compmech-reference-pack WITHOUT pulling mechdsl-core/algo2code — and
|
|
18
|
+
# transitively Taichi — into its uv lock closure. Install the `mechdsl` extra
|
|
19
|
+
# to enable the actual compile/transpile/verify capability.
|
|
20
|
+
mechdsl = [
|
|
21
|
+
"mechdsl-core",
|
|
22
|
+
"algo2code",
|
|
23
|
+
]
|
|
24
|
+
dev = [
|
|
25
|
+
"pytest>=9.0.2",
|
|
26
|
+
"compmech-reference-pack[mechdsl]",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["setuptools>=68.0"]
|
|
31
|
+
build-backend = "setuptools.build_meta"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
compmech_reference_pack = [
|
|
38
|
+
"domain_pack/*.yaml",
|
|
39
|
+
"domain_pack/source_packs/*.yaml",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
testpaths = ["tests"]
|
|
44
|
+
pythonpath = ["src"]
|
|
45
|
+
markers = [
|
|
46
|
+
"unit: fast unit-level tests",
|
|
47
|
+
"integration: cross-module/integration tests",
|
|
48
|
+
"slow: tests that initialise Taichi (the only Taichi-paying adapter path)",
|
|
49
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""compmech_reference_pack — Tier-2 computational-mechanics companion adapter.
|
|
2
|
+
|
|
3
|
+
Bridges AKMS ``akms_learn`` Learning Source Packet (LSP) excerpts to the
|
|
4
|
+
MechDSL Tier-1 ``mechdsl.integration`` façade: it normalises human-authored
|
|
5
|
+
algpseudocode into algo2code-grammar-clean form, then emits executable Python
|
|
6
|
+
and/or compiled-solver summaries with provenance.
|
|
7
|
+
|
|
8
|
+
This package depends on **both** ``akms-learn`` and ``mechdsl-core`` (plus
|
|
9
|
+
``algo2code``, MechDSL's transpiler backend). It registers the
|
|
10
|
+
``executable_bridge`` adapter so ``akms_learn`` reports
|
|
11
|
+
``executable_bridge_adapter = available``.
|
|
12
|
+
|
|
13
|
+
Companion-adapter pattern: MechDSL stays AKMS-unaware; this package is the only
|
|
14
|
+
place that knows about both sides. The public surface is populated across the
|
|
15
|
+
the executable-bridge tier.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
21
|
+
|
|
22
|
+
__all__: list[str] = []
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""compmech_reference_pack adapters — the executable-bridge runner (Tier 2)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from compmech_reference_pack.adapters.mechdsl_runner import (
|
|
6
|
+
MechDSLRunner,
|
|
7
|
+
adapter_registry_overrides,
|
|
8
|
+
available_adapter_registry,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"MechDSLRunner",
|
|
13
|
+
"adapter_registry_overrides",
|
|
14
|
+
"available_adapter_registry",
|
|
15
|
+
]
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"""mechdsl_runner.py — MechDSLRunner, the executable_bridge adapter.
|
|
2
|
+
|
|
3
|
+
Bridges a bounded AKMS LSP excerpt to the MechDSL Tier-1 façade
|
|
4
|
+
(``mechdsl.integration``) and assembles a provenance-carrying artefact dict.
|
|
5
|
+
|
|
6
|
+
Contract (the real one, NOT the spec's ``build_artifacts``)::
|
|
7
|
+
|
|
8
|
+
build_executable(excerpt: dict, *, options: dict | None = None) -> dict
|
|
9
|
+
|
|
10
|
+
Behaviour
|
|
11
|
+
---------
|
|
12
|
+
- **Emit-only by default.** ``build_executable`` normalises the node's
|
|
13
|
+
``extracted["implementation"]`` (algpseudocode) and calls Tier-1
|
|
14
|
+
``transpile_algorithm``, and — when a ``% mechanics`` problem source plus an
|
|
15
|
+
energy ``derivation`` are present — Tier-1 ``compile_from_sources``. Both are
|
|
16
|
+
Taichi-free.
|
|
17
|
+
- **Taichi only on demand.** Tier-1 ``verify`` is called **only** when
|
|
18
|
+
``options["run_verify"]`` is truthy; that is the single Taichi-paying branch.
|
|
19
|
+
- **Never invalidates the packet** (spec 09 §7 rule 5): a transpile/compile
|
|
20
|
+
failure is captured into ``warnings`` and reported as ``status="error"``
|
|
21
|
+
only when the caller explicitly required executable output
|
|
22
|
+
(``options["require_executable"]``); otherwise ``status`` stays ``"ok"``.
|
|
23
|
+
|
|
24
|
+
No-mutation invariant: this adapter never writes to any AKMS path.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import re
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
32
|
+
from akms_learn.adapters.status import AdapterStatus, adapter_registry
|
|
33
|
+
|
|
34
|
+
ADAPTER_ID = "compmech.mechdsl_runner"
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"ADAPTER_ID",
|
|
38
|
+
"MechDSLRunner",
|
|
39
|
+
"adapter_registry_overrides",
|
|
40
|
+
"available_adapter_registry",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def adapter_registry_overrides() -> dict[str, AdapterStatus]:
|
|
45
|
+
"""Registry override that marks the executable bridge available."""
|
|
46
|
+
return {"executable_bridge_adapter": AdapterStatus.available}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def available_adapter_registry() -> dict[str, AdapterStatus]:
|
|
50
|
+
"""Return the akms_learn adapter registry with this adapter marked available."""
|
|
51
|
+
return adapter_registry(adapter_registry_overrides())
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _algo_name_from_node_id(node_id: str) -> str:
|
|
55
|
+
"""Derive a safe algo2code algorithm name from a node id."""
|
|
56
|
+
tail = node_id.rsplit(".", 1)[-1].rsplit("/", 1)[-1]
|
|
57
|
+
cleaned = re.sub(r"[^0-9A-Za-z_]", "_", tail).strip("_")
|
|
58
|
+
return cleaned or "algorithm"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class MechDSLRunner:
|
|
62
|
+
"""ExecutableBridgeAdapter implementation backed by MechDSL Tier-1.
|
|
63
|
+
|
|
64
|
+
Satisfies ``akms_learn.adapters.protocols.ExecutableBridgeAdapter`` via
|
|
65
|
+
structural subtyping (the protocol is ``@runtime_checkable``).
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
adapter_id = ADAPTER_ID
|
|
69
|
+
|
|
70
|
+
# -- protocol surface ---------------------------------------------------
|
|
71
|
+
|
|
72
|
+
def build_executable(
|
|
73
|
+
self, excerpt: dict[str, Any], *, options: dict[str, Any] | None = None
|
|
74
|
+
) -> dict[str, Any]:
|
|
75
|
+
"""Build an executable artefact from a bounded LSP excerpt.
|
|
76
|
+
|
|
77
|
+
Returns the 8-key contract dict ``{adapter, status, emitted_source,
|
|
78
|
+
transpiled, normalized_input, provenance, vv_plan, warnings}``. When
|
|
79
|
+
``options["run_verify"]`` is truthy a 9th key ``verification`` (the
|
|
80
|
+
Tier-1 ``verify`` result) is added — that opt-in path is the only one
|
|
81
|
+
that pays the Taichi cost. Never raises on a malformed excerpt.
|
|
82
|
+
"""
|
|
83
|
+
options = options or {}
|
|
84
|
+
run_verify = bool(options.get("run_verify", False))
|
|
85
|
+
require_executable = bool(options.get("require_executable", False))
|
|
86
|
+
|
|
87
|
+
node = self._select_node(excerpt)
|
|
88
|
+
node_id = str(node.get("node_id") or excerpt.get("node_id") or "<unknown>")
|
|
89
|
+
extracted = node.get("extracted")
|
|
90
|
+
if not isinstance(extracted, dict):
|
|
91
|
+
extracted = {}
|
|
92
|
+
implementation = extracted.get("implementation")
|
|
93
|
+
derivation = extracted.get("derivation")
|
|
94
|
+
problem = extracted.get("problem")
|
|
95
|
+
|
|
96
|
+
warnings: list[str] = []
|
|
97
|
+
status = "ok"
|
|
98
|
+
normalized_input: str | None = None
|
|
99
|
+
transpiled: dict[str, Any] | None = None
|
|
100
|
+
emitted_source: str | None = None
|
|
101
|
+
|
|
102
|
+
# --- implementation -> normalize -> Tier-1 transpile (Taichi-free) ---
|
|
103
|
+
if implementation:
|
|
104
|
+
from compmech_reference_pack.normalize import normalize
|
|
105
|
+
|
|
106
|
+
norm = normalize(
|
|
107
|
+
implementation, algorithm_name=_algo_name_from_node_id(node_id)
|
|
108
|
+
)
|
|
109
|
+
normalized_input = norm.normalized
|
|
110
|
+
warnings.extend(norm.warnings)
|
|
111
|
+
if norm.algorithmic_block_found:
|
|
112
|
+
try:
|
|
113
|
+
from mechdsl.integration import transpile_algorithm
|
|
114
|
+
except ImportError as exc:
|
|
115
|
+
warnings.append(
|
|
116
|
+
"MechDSL backend unavailable; install "
|
|
117
|
+
'"compmech-reference-pack[mechdsl]" '
|
|
118
|
+
f"({type(exc).__name__}: {exc})"
|
|
119
|
+
)
|
|
120
|
+
if require_executable:
|
|
121
|
+
status = "error"
|
|
122
|
+
else:
|
|
123
|
+
try:
|
|
124
|
+
transpiled = transpile_algorithm(
|
|
125
|
+
norm.normalized, backend="taichi"
|
|
126
|
+
)
|
|
127
|
+
if not transpiled.get("valid_python", False):
|
|
128
|
+
warnings.append(
|
|
129
|
+
"transpiled code did not compile as valid Python"
|
|
130
|
+
)
|
|
131
|
+
if require_executable:
|
|
132
|
+
status = "error"
|
|
133
|
+
except Exception as exc:
|
|
134
|
+
warnings.append(
|
|
135
|
+
f"transpile failed: {type(exc).__name__}: {exc}"
|
|
136
|
+
)
|
|
137
|
+
if require_executable:
|
|
138
|
+
status = "error"
|
|
139
|
+
|
|
140
|
+
# --- derivation (+ problem) -> Tier-1 compile (Taichi-free) ----------
|
|
141
|
+
if derivation and problem:
|
|
142
|
+
try:
|
|
143
|
+
from mechdsl.integration import compile_from_sources
|
|
144
|
+
except ImportError as exc:
|
|
145
|
+
warnings.append(
|
|
146
|
+
"MechDSL backend unavailable; install "
|
|
147
|
+
'"compmech-reference-pack[mechdsl]" '
|
|
148
|
+
f"({type(exc).__name__}: {exc})"
|
|
149
|
+
)
|
|
150
|
+
if require_executable:
|
|
151
|
+
status = "error"
|
|
152
|
+
else:
|
|
153
|
+
try:
|
|
154
|
+
compiled = compile_from_sources(
|
|
155
|
+
problem_source=problem, energy_source=derivation
|
|
156
|
+
)
|
|
157
|
+
emitted_source = compiled["emitted_source"]
|
|
158
|
+
except Exception as exc:
|
|
159
|
+
warnings.append(
|
|
160
|
+
f"compile_from_sources failed: {type(exc).__name__}: {exc}"
|
|
161
|
+
)
|
|
162
|
+
if require_executable:
|
|
163
|
+
status = "error"
|
|
164
|
+
elif derivation and not problem:
|
|
165
|
+
warnings.append(
|
|
166
|
+
"node carries a derivation but no '% mechanics' problem source; "
|
|
167
|
+
"skipping compile_from_sources (provide extracted['problem'] to compile)"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if implementation is None and derivation is None:
|
|
171
|
+
status = "error"
|
|
172
|
+
warnings.append(
|
|
173
|
+
f"excerpt node {node_id!r} carries neither an implementation nor a "
|
|
174
|
+
"derivation; nothing to build"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
result: dict[str, Any] = {
|
|
178
|
+
"adapter": ADAPTER_ID,
|
|
179
|
+
"status": status,
|
|
180
|
+
"emitted_source": emitted_source,
|
|
181
|
+
"transpiled": transpiled,
|
|
182
|
+
"normalized_input": normalized_input,
|
|
183
|
+
"provenance": {
|
|
184
|
+
node_id: {
|
|
185
|
+
"sections": self._sections(node),
|
|
186
|
+
"references": self._references(node_id, node, excerpt),
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"vv_plan": self._vv_plan(node_id, node, excerpt, options),
|
|
190
|
+
"warnings": warnings,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# --- the only Taichi-paying branch ----------------------------------
|
|
194
|
+
if run_verify:
|
|
195
|
+
result["verification"] = self._run_verify(options, warnings)
|
|
196
|
+
|
|
197
|
+
return result
|
|
198
|
+
|
|
199
|
+
# -- extra surface (per plan: status() / can_handle()) ------------------
|
|
200
|
+
|
|
201
|
+
def status(self) -> dict[str, Any]:
|
|
202
|
+
"""Lightweight, Taichi-free availability descriptor for status routes."""
|
|
203
|
+
return {
|
|
204
|
+
"adapter": ADAPTER_ID,
|
|
205
|
+
"available": True,
|
|
206
|
+
"companion_role": "executable_bridge",
|
|
207
|
+
"taichi_required_for": ["verify"],
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
def can_handle(self, excerpt: dict[str, Any]) -> bool:
|
|
211
|
+
"""True when the excerpt has a node carrying implementation/derivation.
|
|
212
|
+
|
|
213
|
+
Total: returns ``False`` (never raises) for any malformed excerpt
|
|
214
|
+
shape — missing ``nodes``, non-dict nodes, non-dict ``extracted``.
|
|
215
|
+
"""
|
|
216
|
+
node = self._select_node(excerpt)
|
|
217
|
+
extracted = node.get("extracted")
|
|
218
|
+
if not isinstance(extracted, dict):
|
|
219
|
+
return False
|
|
220
|
+
return bool(extracted.get("implementation") or extracted.get("derivation"))
|
|
221
|
+
|
|
222
|
+
# -- internals ----------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
@staticmethod
|
|
225
|
+
def _select_node(excerpt: dict[str, Any]) -> dict[str, Any]:
|
|
226
|
+
"""Pick the node dict to build from.
|
|
227
|
+
|
|
228
|
+
Accepts a node-shaped excerpt directly, a ``{"nodes": [...]}`` excerpt
|
|
229
|
+
(first node carrying implementation/derivation, else the first node),
|
|
230
|
+
or any dict (treated as the node).
|
|
231
|
+
"""
|
|
232
|
+
nodes = excerpt.get("nodes")
|
|
233
|
+
if isinstance(nodes, list):
|
|
234
|
+
dict_nodes = [n for n in nodes if isinstance(n, dict)]
|
|
235
|
+
for node in dict_nodes:
|
|
236
|
+
extracted = node.get("extracted")
|
|
237
|
+
if isinstance(extracted, dict) and (
|
|
238
|
+
extracted.get("implementation") or extracted.get("derivation")
|
|
239
|
+
):
|
|
240
|
+
return node
|
|
241
|
+
# No build-bearing node — return the first dict node, or {} so
|
|
242
|
+
# callers never touch a non-dict (None, str, …).
|
|
243
|
+
return dict_nodes[0] if dict_nodes else {}
|
|
244
|
+
return excerpt
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def _sections(node: dict[str, Any]) -> Any:
|
|
248
|
+
return node.get("included_sections") or node.get("sections") or []
|
|
249
|
+
|
|
250
|
+
@staticmethod
|
|
251
|
+
def _references(
|
|
252
|
+
node_id: str, node: dict[str, Any], excerpt: dict[str, Any]
|
|
253
|
+
) -> list[Any]:
|
|
254
|
+
"""Collect references attributable to this node.
|
|
255
|
+
|
|
256
|
+
Prefers node-local references; otherwise filters packet-level
|
|
257
|
+
references by ``source_node_ids`` membership (falling back to all).
|
|
258
|
+
"""
|
|
259
|
+
node_refs = node.get("references")
|
|
260
|
+
if isinstance(node_refs, list) and node_refs:
|
|
261
|
+
return list(node_refs)
|
|
262
|
+
|
|
263
|
+
packet_refs = excerpt.get("references")
|
|
264
|
+
if not isinstance(packet_refs, list):
|
|
265
|
+
return []
|
|
266
|
+
scoped = [
|
|
267
|
+
ref
|
|
268
|
+
for ref in packet_refs
|
|
269
|
+
if isinstance(ref, dict) and node_id in (ref.get("source_node_ids") or [])
|
|
270
|
+
]
|
|
271
|
+
return scoped or list(packet_refs)
|
|
272
|
+
|
|
273
|
+
@classmethod
|
|
274
|
+
def _vv_plan(
|
|
275
|
+
cls,
|
|
276
|
+
node_id: str,
|
|
277
|
+
node: dict[str, Any],
|
|
278
|
+
excerpt: dict[str, Any],
|
|
279
|
+
options: dict[str, Any],
|
|
280
|
+
) -> dict[str, Any]:
|
|
281
|
+
"""Assemble a verification-and-validation plan {benchmark, citation}.
|
|
282
|
+
|
|
283
|
+
The citation is drawn from the same node-scoped reference list used for
|
|
284
|
+
provenance (via :meth:`_references`), so the two never disagree.
|
|
285
|
+
"""
|
|
286
|
+
extracted = node.get("extracted")
|
|
287
|
+
if not isinstance(extracted, dict):
|
|
288
|
+
extracted = {}
|
|
289
|
+
benchmark = (
|
|
290
|
+
options.get("benchmark")
|
|
291
|
+
or extracted.get("benchmark")
|
|
292
|
+
or excerpt.get("benchmark")
|
|
293
|
+
)
|
|
294
|
+
citation: Any = None
|
|
295
|
+
for ref in cls._references(node_id, node, excerpt):
|
|
296
|
+
if isinstance(ref, dict):
|
|
297
|
+
citation = ref.get("citation") or ref.get("title")
|
|
298
|
+
if citation:
|
|
299
|
+
break
|
|
300
|
+
return {"benchmark": benchmark, "citation": citation}
|
|
301
|
+
|
|
302
|
+
@staticmethod
|
|
303
|
+
def _run_verify(options: dict[str, Any], warnings: list[str]) -> dict[str, Any]:
|
|
304
|
+
"""Run the single Taichi-paying Tier-1 verify branch."""
|
|
305
|
+
kind = options.get("verify_kind", "patch_test")
|
|
306
|
+
params = options.get("verify_params", {})
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
from mechdsl.integration import verify
|
|
310
|
+
|
|
311
|
+
return verify(kind, params)
|
|
312
|
+
except ImportError as exc:
|
|
313
|
+
warnings.append(
|
|
314
|
+
"MechDSL backend unavailable; install "
|
|
315
|
+
'"compmech-reference-pack[mechdsl]" '
|
|
316
|
+
f"({type(exc).__name__}: {exc})"
|
|
317
|
+
)
|
|
318
|
+
return {"kind": kind, "passed": False, "details": {"error": str(exc)}}
|
|
319
|
+
except Exception as exc:
|
|
320
|
+
warnings.append(f"verify failed: {type(exc).__name__}: {exc}")
|
|
321
|
+
return {"kind": kind, "passed": False, "details": {"error": str(exc)}}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Capability declarations for compmech_reference_pack.
|
|
2
|
+
|
|
3
|
+
`CEmM2/Logic-Loom <https://github.com/CEmM2/Logic-Loom>`_ imports this package
|
|
4
|
+
from its ``GET /api/mechdsl/status`` route and reads the capability surface to
|
|
5
|
+
decide whether to expose the MechDSL gate.
|
|
6
|
+
This module is deliberately import-light and **Taichi-free**: it declares
|
|
7
|
+
*what* the package offers; it never runs a solve or initialises Taichi.
|
|
8
|
+
|
|
9
|
+
Two capabilities are declared:
|
|
10
|
+
|
|
11
|
+
- ``executable_bridge_adapter`` — the package registers ``MechDSLRunner`` as
|
|
12
|
+
the ``executable_bridge`` adapter (``akms_learn`` reports it available).
|
|
13
|
+
- ``code_mirror_provenance`` — ``build_executable`` attaches per-node
|
|
14
|
+
provenance (source sections + references) to every emitted artefact.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from compmech_reference_pack import __version__
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"ADAPTER_ID",
|
|
23
|
+
"CODE_MIRROR_PROVENANCE",
|
|
24
|
+
"EXECUTABLE_BRIDGE_ADAPTER",
|
|
25
|
+
"capabilities",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
#: Stable id of the executable-bridge adapter this package registers.
|
|
29
|
+
ADAPTER_ID = "compmech.mechdsl_runner"
|
|
30
|
+
|
|
31
|
+
#: Capability keys (also the akms_learn adapter-registry capability names).
|
|
32
|
+
EXECUTABLE_BRIDGE_ADAPTER = "executable_bridge_adapter"
|
|
33
|
+
CODE_MIRROR_PROVENANCE = "code_mirror_provenance"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def capabilities() -> dict:
|
|
37
|
+
"""Return the machine-readable capability surface for status discovery.
|
|
38
|
+
|
|
39
|
+
Shape consumed by Logic-Loom's status route::
|
|
40
|
+
|
|
41
|
+
{package, version, domain_pack, adapter_id, capabilities: {...}}
|
|
42
|
+
|
|
43
|
+
The dict is JSON-serialisable and contains no runtime objects.
|
|
44
|
+
"""
|
|
45
|
+
return {
|
|
46
|
+
"package": "compmech_reference_pack",
|
|
47
|
+
"version": __version__,
|
|
48
|
+
"domain_pack": "compmech.reference",
|
|
49
|
+
"adapter_id": ADAPTER_ID,
|
|
50
|
+
"capabilities": {
|
|
51
|
+
EXECUTABLE_BRIDGE_ADAPTER: {
|
|
52
|
+
"available": True,
|
|
53
|
+
"adapter_id": ADAPTER_ID,
|
|
54
|
+
"companion_role": "executable_bridge",
|
|
55
|
+
"actions": ["emit", "transpile", "verify"],
|
|
56
|
+
# Mirrors the Tier-1 contract: only ``verify`` pays Taichi.
|
|
57
|
+
"taichi_required_for": ["verify"],
|
|
58
|
+
},
|
|
59
|
+
CODE_MIRROR_PROVENANCE: {
|
|
60
|
+
"available": True,
|
|
61
|
+
"source_pack_id": "compmech.mechdsl",
|
|
62
|
+
"repo": "CEmM2/MechDSL",
|
|
63
|
+
# build_executable attaches {node_id: {sections, references}}.
|
|
64
|
+
"provenance_keys": ["sections", "references"],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
domain_pack_schema: akms-learn-domain-pack/v1
|
|
2
|
+
domain_id: compmech
|
|
3
|
+
pack_id: compmech.reference
|
|
4
|
+
name: Computational Mechanics Reference Pack
|
|
5
|
+
version: "0.1.0"
|
|
6
|
+
status: reference
|
|
7
|
+
summary: >-
|
|
8
|
+
Reference computational-mechanics domain pack for AKMS Learn. Promoted from
|
|
9
|
+
the AKMS_learn test fixture by compmech_reference_pack (Tier-2 executable
|
|
10
|
+
bridge); the MechDSL companion is now an available executable runner.
|
|
11
|
+
compatibility:
|
|
12
|
+
akms_learn_schema_min: learn/v0.1
|
|
13
|
+
akms_learn_schema_max: learn/v0.1
|
|
14
|
+
roots:
|
|
15
|
+
nodes: nodes/compmech
|
|
16
|
+
code_mirror: code-mirror/compmech
|
|
17
|
+
examples: learning_examples/compmech
|
|
18
|
+
bundles: lesson_bundles/compmech
|
|
19
|
+
capabilities:
|
|
20
|
+
static_markdown: true
|
|
21
|
+
static_notebook: true
|
|
22
|
+
executable_notebook: false
|
|
23
|
+
external_runner: true
|
|
24
|
+
code_mirror: true
|
|
25
|
+
# `constkit` and `symbolic_fem_workbench` stay `planned`: their adapters are
|
|
26
|
+
# not written. Their source is public — both live under
|
|
27
|
+
# https://github.com/SOSOVSKI/Teaching-materials — so `planned` here describes
|
|
28
|
+
# the adapter, not the availability of the material.
|
|
29
|
+
companion_roles:
|
|
30
|
+
- id: constkit
|
|
31
|
+
package_name: compmech.constkit
|
|
32
|
+
runtime_hint: optional
|
|
33
|
+
capability_status: planned
|
|
34
|
+
- id: symbolic_fem_workbench
|
|
35
|
+
package_name: compmech.symbolic_fem_workbench
|
|
36
|
+
runtime_hint: optional
|
|
37
|
+
capability_status: planned
|
|
38
|
+
- id: mechdsl
|
|
39
|
+
package_name: compmech.mechdsl
|
|
40
|
+
runtime_hint: required
|
|
41
|
+
capability_status: available
|
|
42
|
+
source_packs:
|
|
43
|
+
- source_packs/constkit.yaml
|
|
44
|
+
- source_packs/symbolic_fem_workbench.yaml
|
|
45
|
+
- source_packs/mechdsl.yaml
|
|
46
|
+
provenance:
|
|
47
|
+
source_repos: []
|
|
48
|
+
generated_vault_ref: null
|
|
49
|
+
zotero_collection_refs: []
|