compmech-reference-pack 0.3.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.
- compmech_reference_pack/__init__.py +22 -0
- compmech_reference_pack/adapters/__init__.py +15 -0
- compmech_reference_pack/adapters/mechdsl_runner.py +321 -0
- compmech_reference_pack/capabilities.py +67 -0
- compmech_reference_pack/domain_pack/domain_pack.yaml +49 -0
- compmech_reference_pack/domain_pack/source_packs/constkit.yaml +28 -0
- compmech_reference_pack/domain_pack/source_packs/mechdsl.yaml +26 -0
- compmech_reference_pack/domain_pack/source_packs/symbolic_fem_workbench.yaml +29 -0
- compmech_reference_pack/normalize.py +192 -0
- compmech_reference_pack/paths.py +30 -0
- compmech_reference_pack-0.3.1.dist-info/METADATA +74 -0
- compmech_reference_pack-0.3.1.dist-info/RECORD +14 -0
- compmech_reference_pack-0.3.1.dist-info/WHEEL +5 -0
- compmech_reference_pack-0.3.1.dist-info/top_level.txt +1 -0
|
@@ -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: []
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
source_pack_schema: akms-learn-source-pack/v1
|
|
2
|
+
source_pack_id: compmech.constkit
|
|
3
|
+
name: ConstKit Concept Helpers
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
companion_role: concept_kit
|
|
6
|
+
# The source is public and obtainable; the adapter that would consume it is
|
|
7
|
+
# not written yet. `planned` describes the adapter, not the availability of
|
|
8
|
+
# the material.
|
|
9
|
+
capability_status: planned
|
|
10
|
+
repo:
|
|
11
|
+
kind: github
|
|
12
|
+
name: SOSOVSKI/Teaching-materials
|
|
13
|
+
ref: main
|
|
14
|
+
roots:
|
|
15
|
+
docs: packages/constkit/docs
|
|
16
|
+
code: packages/constkit/src/constkit
|
|
17
|
+
tests: packages/constkit/tests
|
|
18
|
+
capabilities:
|
|
19
|
+
static_code_mirror: true
|
|
20
|
+
static_lessons: true
|
|
21
|
+
notebook_cells: false
|
|
22
|
+
executable_runner: false
|
|
23
|
+
runtime:
|
|
24
|
+
required_python: ">=3.12,<3.13"
|
|
25
|
+
dependencies: []
|
|
26
|
+
adapter:
|
|
27
|
+
adapter_id: compmech.constkit_adapter
|
|
28
|
+
status: planned
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
source_pack_schema: akms-learn-source-pack/v1
|
|
2
|
+
source_pack_id: compmech.mechdsl
|
|
3
|
+
name: MechDSL Executable Bridge
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
companion_role: executable_bridge
|
|
6
|
+
capability_status: available
|
|
7
|
+
repo:
|
|
8
|
+
kind: github
|
|
9
|
+
name: CEmM2/MechDSL
|
|
10
|
+
ref: main
|
|
11
|
+
roots:
|
|
12
|
+
docs: dev/design_docs
|
|
13
|
+
code: packages/mechdsl-core/src/mechdsl
|
|
14
|
+
examples: dev/examples
|
|
15
|
+
tests: packages/mechdsl-core/tests
|
|
16
|
+
capabilities:
|
|
17
|
+
static_code_mirror: true
|
|
18
|
+
static_lessons: true
|
|
19
|
+
notebook_cells: false
|
|
20
|
+
executable_runner: true
|
|
21
|
+
runtime:
|
|
22
|
+
required_python: ">=3.12,<3.13"
|
|
23
|
+
dependencies: []
|
|
24
|
+
adapter:
|
|
25
|
+
adapter_id: compmech.mechdsl_runner
|
|
26
|
+
status: available
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
source_pack_schema: akms-learn-source-pack/v1
|
|
2
|
+
source_pack_id: compmech.symbolic_fem_workbench
|
|
3
|
+
name: Symbolic FEM Workbench
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
companion_role: pedagogical_workbench
|
|
6
|
+
# The source is public and obtainable; the adapter that would consume it is
|
|
7
|
+
# not written yet. `planned` describes the adapter, not the availability of
|
|
8
|
+
# the material.
|
|
9
|
+
capability_status: planned
|
|
10
|
+
repo:
|
|
11
|
+
kind: github
|
|
12
|
+
name: SOSOVSKI/Teaching-materials
|
|
13
|
+
ref: main
|
|
14
|
+
roots:
|
|
15
|
+
docs: packages/symbolic-fem-workbench/docs
|
|
16
|
+
code: packages/symbolic-fem-workbench/src/symbolic_fem_workbench
|
|
17
|
+
examples: packages/symbolic-fem-workbench/notebooks
|
|
18
|
+
tests: packages/symbolic-fem-workbench/tests
|
|
19
|
+
capabilities:
|
|
20
|
+
static_code_mirror: true
|
|
21
|
+
static_lessons: true
|
|
22
|
+
notebook_cells: true
|
|
23
|
+
executable_runner: false
|
|
24
|
+
runtime:
|
|
25
|
+
required_python: ">=3.12,<3.13"
|
|
26
|
+
dependencies: []
|
|
27
|
+
adapter:
|
|
28
|
+
adapter_id: compmech.symbolic_fem_workbench_adapter
|
|
29
|
+
status: planned
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""normalize.py — rewrite human-authored algpseudocode into algo2code-clean form.
|
|
2
|
+
|
|
3
|
+
The Tier-2 adapter's pre-processing core. An LSP node's
|
|
4
|
+
``extracted["implementation"]`` is human/markdown-authored algpseudocode;
|
|
5
|
+
``algo2code.transpile`` expects an ``algorithmic`` block optionally preceded by
|
|
6
|
+
``% algorithm/backend/args/type`` directive lines.
|
|
7
|
+
|
|
8
|
+
What this pass actually does
|
|
9
|
+
----------------------------
|
|
10
|
+
Empirically, MechDSL's current ``algo2code`` expression grammar already
|
|
11
|
+
subsumes the rewrites the original plan anticipated (``\\sqrt{3/2}``,
|
|
12
|
+
``\\frac{a}{b}``, ``\\cdot``, ``\\left/\\right``, Greek letters, ``^{...}``,
|
|
13
|
+
and ``\\If/\\Else/\\ElsIf/\\While/\\For`` control flow all transpile as-is).
|
|
14
|
+
So the genuinely-useful work here is:
|
|
15
|
+
|
|
16
|
+
1. **Extract** the ``\\begin{algorithmic} … \\end{algorithmic}`` block out of
|
|
17
|
+
surrounding markdown (prose, code fences) so the source is bounded and the
|
|
18
|
+
*absence* of an algorithm is detectable (``algo2code`` silently emits an
|
|
19
|
+
empty function otherwise).
|
|
20
|
+
2. **Synthesise directives** — prepend ``% algorithm <name>`` / ``% backend
|
|
21
|
+
taichi`` when the author didn't, so the emitted function is meaningfully
|
|
22
|
+
named instead of the ``algo2code`` default ``algorithm``; author-supplied
|
|
23
|
+
directives are preserved.
|
|
24
|
+
3. **Surface parser failures as structured warnings, never raise** — per spec
|
|
25
|
+
09 §7 rule 5 (a failed adapter must not invalidate the packet unless
|
|
26
|
+
executable output was explicitly required).
|
|
27
|
+
|
|
28
|
+
The public deliverable is :func:`normalize_algpseudocode` (``str -> str``);
|
|
29
|
+
:func:`normalize` wraps it with a trial parse and the warning report the
|
|
30
|
+
adapter consumes.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import re
|
|
36
|
+
from dataclasses import dataclass
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"NormalizationResult",
|
|
40
|
+
"extract_algorithmic_block",
|
|
41
|
+
"normalize",
|
|
42
|
+
"normalize_algpseudocode",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
_ALGORITHMIC_RE = re.compile(
|
|
46
|
+
r"\\begin\{algorithmic\}(?:\[[^\]]*\])?(?P<body>.*?)\\end\{algorithmic\}",
|
|
47
|
+
re.DOTALL,
|
|
48
|
+
)
|
|
49
|
+
_FENCE_RE = re.compile(r"^[ \t]*```[^\n]*$", re.MULTILINE)
|
|
50
|
+
# ":=" is the only assignment arrow algo2code does not accept; "\gets" and
|
|
51
|
+
# "\leftarrow" parse natively but we canonicalise all three to "=".
|
|
52
|
+
_ARROW_RE = re.compile(r":=|\\gets|\\leftarrow")
|
|
53
|
+
_DIRECTIVE_KEYWORDS = frozenset({"algorithm", "backend", "args", "type"})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class NormalizationResult:
|
|
58
|
+
"""Outcome of normalising one implementation excerpt.
|
|
59
|
+
|
|
60
|
+
Attributes
|
|
61
|
+
----------
|
|
62
|
+
normalized:
|
|
63
|
+
algo2code-ready source (synthesised directives + algorithmic block).
|
|
64
|
+
algorithmic_block_found:
|
|
65
|
+
Whether an ``\\begin{algorithmic}`` block was present in the input.
|
|
66
|
+
parses:
|
|
67
|
+
Whether ``algo2code.parse_algorithm`` accepted the normalised source.
|
|
68
|
+
warnings:
|
|
69
|
+
Structured, human-readable warnings (missing block, parse errors).
|
|
70
|
+
Never empty when ``parses`` is ``False`` or the block was absent.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
normalized: str
|
|
74
|
+
algorithmic_block_found: bool
|
|
75
|
+
parses: bool
|
|
76
|
+
warnings: tuple[str, ...] = ()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def extract_algorithmic_block(impl_md: str) -> str | None:
|
|
80
|
+
"""Return the inner body of the first ``algorithmic`` block, or ``None``.
|
|
81
|
+
|
|
82
|
+
Markdown code fences are stripped first so a fenced ``\\begin{algorithmic}``
|
|
83
|
+
is still found. The returned body excludes the ``\\begin``/``\\end`` markers.
|
|
84
|
+
"""
|
|
85
|
+
if not impl_md:
|
|
86
|
+
return None
|
|
87
|
+
text = _FENCE_RE.sub("", impl_md)
|
|
88
|
+
match = _ALGORITHMIC_RE.search(text)
|
|
89
|
+
if match is None:
|
|
90
|
+
return None
|
|
91
|
+
return match.group("body").strip("\n")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _sanitize_identifier(name: str) -> str:
|
|
95
|
+
"""Coerce an arbitrary string into a safe algo2code algorithm identifier."""
|
|
96
|
+
cleaned = re.sub(r"[^0-9A-Za-z_]", "_", name).strip("_")
|
|
97
|
+
if not cleaned:
|
|
98
|
+
return "algorithm"
|
|
99
|
+
if cleaned[0].isdigit():
|
|
100
|
+
cleaned = f"a_{cleaned}"
|
|
101
|
+
return cleaned
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _collect_directives(impl_md: str) -> list[str]:
|
|
105
|
+
"""Collect author-supplied ``% algorithm/backend/args/type`` directives.
|
|
106
|
+
|
|
107
|
+
Only lines *before* the algorithmic block are considered, so ``%`` lines
|
|
108
|
+
that happen to live inside the block are not mistaken for directives.
|
|
109
|
+
"""
|
|
110
|
+
head = impl_md
|
|
111
|
+
begin = impl_md.find(r"\begin{algorithmic}")
|
|
112
|
+
if begin != -1:
|
|
113
|
+
head = impl_md[:begin]
|
|
114
|
+
directives: list[str] = []
|
|
115
|
+
for raw in head.splitlines():
|
|
116
|
+
stripped = raw.strip()
|
|
117
|
+
if not stripped.startswith("%"):
|
|
118
|
+
continue
|
|
119
|
+
content = stripped[1:].strip()
|
|
120
|
+
first = content.split(None, 1)[0] if content else ""
|
|
121
|
+
if first in _DIRECTIVE_KEYWORDS:
|
|
122
|
+
directives.append(content)
|
|
123
|
+
return directives
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def normalize_algpseudocode(impl_md: str, *, algorithm_name: str | None = None) -> str:
|
|
127
|
+
"""Rewrite a human-authored implementation excerpt into algo2code source.
|
|
128
|
+
|
|
129
|
+
Extracts the ``algorithmic`` block, canonicalises assignment arrows, and
|
|
130
|
+
prepends synthesised ``% algorithm``/``% backend`` directives (preserving
|
|
131
|
+
any the author already supplied). Never raises: a missing block yields an
|
|
132
|
+
empty algorithmic shell, which :func:`normalize` flags as a warning.
|
|
133
|
+
"""
|
|
134
|
+
body = extract_algorithmic_block(impl_md)
|
|
135
|
+
if body is None:
|
|
136
|
+
body = ""
|
|
137
|
+
body = _ARROW_RE.sub("=", body)
|
|
138
|
+
|
|
139
|
+
existing = _collect_directives(impl_md)
|
|
140
|
+
# Match both "algorithm <name>" and a bare "algorithm" directive so a
|
|
141
|
+
# name-less author directive doesn't get a synthesised one appended too.
|
|
142
|
+
has_name = any(d == "algorithm" or d.startswith("algorithm ") for d in existing)
|
|
143
|
+
has_backend = any(d == "backend" or d.startswith("backend ") for d in existing)
|
|
144
|
+
|
|
145
|
+
lines: list[str] = []
|
|
146
|
+
if not has_name:
|
|
147
|
+
lines.append(
|
|
148
|
+
f"% algorithm {_sanitize_identifier(algorithm_name or 'algorithm')}"
|
|
149
|
+
)
|
|
150
|
+
if not has_backend:
|
|
151
|
+
lines.append("% backend taichi")
|
|
152
|
+
lines.extend(f"% {d}" for d in existing)
|
|
153
|
+
lines.append(r"\begin{algorithmic}")
|
|
154
|
+
if body:
|
|
155
|
+
lines.append(body)
|
|
156
|
+
lines.append(r"\end{algorithmic}")
|
|
157
|
+
return "\n".join(lines)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def normalize(
|
|
161
|
+
impl_md: str, *, algorithm_name: str | None = None
|
|
162
|
+
) -> NormalizationResult:
|
|
163
|
+
"""Normalise an excerpt and report parse status + structured warnings.
|
|
164
|
+
|
|
165
|
+
Wraps :func:`normalize_algpseudocode` with a trial ``algo2code`` parse so
|
|
166
|
+
the adapter can attach warnings without ever crashing the packet.
|
|
167
|
+
"""
|
|
168
|
+
found = extract_algorithmic_block(impl_md) is not None
|
|
169
|
+
normalized = normalize_algpseudocode(impl_md, algorithm_name=algorithm_name)
|
|
170
|
+
|
|
171
|
+
warnings: list[str] = []
|
|
172
|
+
if not found:
|
|
173
|
+
warnings.append(
|
|
174
|
+
r"no \begin{algorithmic} block found in implementation excerpt; "
|
|
175
|
+
"emitted source will be an empty function"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
parses = False
|
|
179
|
+
try:
|
|
180
|
+
from algo2code import parse_algorithm
|
|
181
|
+
|
|
182
|
+
parse_algorithm(normalized)
|
|
183
|
+
parses = True
|
|
184
|
+
except Exception as exc:
|
|
185
|
+
warnings.append(f"algo2code parse failed: {type(exc).__name__}: {exc}")
|
|
186
|
+
|
|
187
|
+
return NormalizationResult(
|
|
188
|
+
normalized=normalized,
|
|
189
|
+
algorithmic_block_found=found,
|
|
190
|
+
parses=parses,
|
|
191
|
+
warnings=tuple(warnings),
|
|
192
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Filesystem accessors for the promoted compmech domain pack.
|
|
2
|
+
|
|
3
|
+
The domain pack and its source packs ship as package data under
|
|
4
|
+
``compmech_reference_pack/domain_pack/``. These helpers return concrete
|
|
5
|
+
``Path`` objects so the ``akms_learn`` descriptor loaders — and the
|
|
6
|
+
`CEmM2/Logic-Loom <https://github.com/CEmM2/Logic-Loom>`_ status route — can
|
|
7
|
+
read them without hardcoding the install layout.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from importlib import resources
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
__all__ = ["domain_pack_dir", "domain_pack_path", "source_pack_path"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def domain_pack_dir() -> Path:
|
|
19
|
+
"""Absolute path to the packaged ``domain_pack/`` data directory."""
|
|
20
|
+
return Path(str(resources.files("compmech_reference_pack") / "domain_pack"))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def domain_pack_path() -> Path:
|
|
24
|
+
"""Absolute path to the promoted ``domain_pack.yaml``."""
|
|
25
|
+
return domain_pack_dir() / "domain_pack.yaml"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def source_pack_path(name: str) -> Path:
|
|
29
|
+
"""Absolute path to a source-pack yaml by stem (e.g. ``"mechdsl"``)."""
|
|
30
|
+
return domain_pack_dir() / "source_packs" / f"{name}.yaml"
|
|
@@ -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,14 @@
|
|
|
1
|
+
compmech_reference_pack/__init__.py,sha256=elyoLBFm-eP7OpO4rSDdGr8I85U-I3n3zeYbMDWzdVM,873
|
|
2
|
+
compmech_reference_pack/capabilities.py,sha256=3M-VtSJ08J5DHMsdogVbvdXhjHGG5HackgZUPjsdF-M,2452
|
|
3
|
+
compmech_reference_pack/normalize.py,sha256=ro8aXcVEdGjdT7nvUFdQuvOkOEqmsB2VSaaCaDNN1ew,7084
|
|
4
|
+
compmech_reference_pack/paths.py,sha256=uQxVxnwgBxeSZOyIpP9NzvGqMYWNT2YIbowaz-PInac,1082
|
|
5
|
+
compmech_reference_pack/adapters/__init__.py,sha256=H1MFitiM4TJm7X3JAu4LV3urONw6nP9h5xgeKfejdos,370
|
|
6
|
+
compmech_reference_pack/adapters/mechdsl_runner.py,sha256=MaOKRGIgvtT8kmoqebQuj_kkXXq3aZYNisgmyEHohAk,12759
|
|
7
|
+
compmech_reference_pack/domain_pack/domain_pack.yaml,sha256=1lFR1poc-BmbirLOZBa6MiIFhKIH_sKGUFOhCS6o4Ec,1630
|
|
8
|
+
compmech_reference_pack/domain_pack/source_packs/constkit.yaml,sha256=MTC1nA1SVC63VSlvkRebHouUJ6BkRwJ5lEcgrJXSSyQ,774
|
|
9
|
+
compmech_reference_pack/domain_pack/source_packs/mechdsl.yaml,sha256=iD-woiDkEyHo_5nWDF1a7nUt4c4RWOKRRF1N_HZWQgs,624
|
|
10
|
+
compmech_reference_pack/domain_pack/source_packs/symbolic_fem_workbench.yaml,sha256=UNzr8L5tcXx17qIs1ayCdgRAnVZ7QChK2j-Rv3RM2X4,919
|
|
11
|
+
compmech_reference_pack-0.3.1.dist-info/METADATA,sha256=P0FUlJqk4I0zt-U2FNs-Is1w3jkZDHhCsziEeXqO12E,2726
|
|
12
|
+
compmech_reference_pack-0.3.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
13
|
+
compmech_reference_pack-0.3.1.dist-info/top_level.txt,sha256=riOWv2q4eOyjzwjlSg7oOsCT_jfRzISqSr8V3jECeyk,24
|
|
14
|
+
compmech_reference_pack-0.3.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
compmech_reference_pack
|