Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Fixed — runtime resources ship inside the wheels

- **Canonical algorithm sources are package data**: the six `algpseudocode` sources (`jacobi`, `newmark`, `pcg`, `radial_return_j2`, `radial_return_j2_kinematic`, `radial_return_j2_mixed`) moved from the repository-only `dev/algorithms/` to `algo2code/library/algorithms/` and are read via `importlib.resources`. Installed from PyPI, `mechdsl.lib.plasticity{,_kinematic,_mixed}` and `algo2code.library.radial_return_j2{,_kinematic,_mixed}` previously raised `FileNotFoundError` at import time (they walked up from `__file__` looking for the repo checkout); `mechdsl.solver.seam_solve` / `seam_integrate` had the same latent defect behind their Taichi import.
- **`algo2code.library.algorithm_source(name)` / `algorithm_source_path(name)` / `ALGORITHM_SOURCES`**: new accessors for the bundled sources; `mechdsl.solver.pcg_tex_path()` / `newmark_tex_path()` now resolve through them.
- **Regression test**: `packages/mechdsl-core/tests/test_wheel_import.py` builds both wheels, installs them into a fresh venv without the `[verify]` extra, and imports every module (missing `taichi` / `ti_runtime` is the only accepted skip); `packages/algo2code/tests/test_library_sources.py` checks the bundled sources in-process.

### Changed — shipped source no longer carries internal planning references

- Comments, docstrings, error messages and emitted-code comments in `mechdsl-core` and `algo2code` (and the bundled `.tex` algorithm sources) no longer cite internal plan/phase/task identifiers or cross-repo planning notes; the reasoning behind each comment is kept. Error messages keep their actionable content. No identifiers, behaviour or public API changed. Golden codegen snapshots were regenerated for the affected comment lines only. The benchmark registry's `task_id` values (`"P10-1"`..`"P10-9"`) are data keys matched by the committed perf baseline and are unchanged.

## [0.2.1] - 2026-08-31

### Changed — packaging for PyPI
Expand Down
8 changes: 5 additions & 3 deletions docs/algo2code/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ individual stages are exported too (`parse_algorithm`, `infer_types`, `generate_

## The algorithm library

Canonical algorithms live in `algo2code.library`, each backed by a `.tex` source under
`dev/algorithms/`. Every module exposes the verbatim LaTeX as a constant, a getter, and a
convenience transpile wrapper.
Canonical algorithms live in `algo2code.library`, each backed by a `.tex` source bundled
as package data under `algo2code/library/algorithms/` (so they are available from an
installed wheel). Every module exposes the verbatim LaTeX as a constant, a getter, and a
convenience transpile wrapper; `algo2code.library.algorithm_source("pcg.tex")` reads any
bundled source by name.

| Algorithm | Module | LaTeX constant | Wrapper |
|---|---|---|---|
Expand Down
17 changes: 9 additions & 8 deletions packages/algo2code/src/algo2code/backends/taichi_codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
each generated file — backward-compatible, no runtime dependency.
- ``"ti_runtime"``: emit ``from ti_runtime import vector_ops as _v`` and call
the shared primitives for ``dot``/``norm``/``copy``/``vec_add``; only
``_matvec`` remains inlined (the matrix-free operator seam is P2-2's
concern). algo2code itself never imports ``ti_runtime`` — it only *emits*
the import line.
``_matvec`` remains inlined (the matrix-free operator is injected through
the seam by the consumer). algo2code itself never imports ``ti_runtime`` —
it only *emits* the import line.

Compatibility note (``"ti_runtime"`` mode):
``ti_runtime.vector_ops.dot`` uses ``x[I].dot(y[I])`` which requires
Expand All @@ -29,7 +29,7 @@
the consumer passes scalar fields. Callers that use vector fields (e.g.
mechdsl FEM drivers) are unaffected. This is a known field-model mismatch;
resolving it (either by changing the emitted field model to ``ti.Vector.field``
or by adding scalar variants to ti_runtime) is out of scope for P2-1.
or by adding scalar variants to ti_runtime) is out of scope for this backend.
"""

from __future__ import annotations
Expand Down Expand Up @@ -177,7 +177,7 @@ def emit_kernels(self, runtime: str = RUNTIME_INLINE) -> str:
In ``"ti_runtime"`` mode the shared primitives (dot/norm/copy/vec_add)
are called via the ``_v`` alias imported from ``ti_runtime.vector_ops``.
Only ``_matvec`` has no ti_runtime equivalent and remains inlined
(the matrix-free operator seam is P2-2's concern).
(the matrix-free operator is injected through the seam by the consumer).
"""
lines = []
if runtime == RUNTIME_TI_RUNTIME:
Expand Down Expand Up @@ -394,8 +394,8 @@ def _vector_field_alloc(self, vec_arg: str | None) -> str:
locals matching the *vector argument's* component layout (``<arg>.n``):
the ``ti_runtime`` ``dot``/``norm2`` primitives use ``x[I].dot(y[I])``,
which requires vector fields. This is what lets the matrix-free seam
(P2-2) run end-to-end against ``ti_runtime`` (resolving the field-model
mismatch P2-1 documented). With no vector argument the component count
run end-to-end against ``ti_runtime`` (resolving the field-model
mismatch documented above). With no vector argument the component count
is unknown, so fall back to the scalar layout.
"""
if self.runtime == RUNTIME_TI_RUNTIME and vec_arg is not None:
Expand Down Expand Up @@ -847,7 +847,8 @@ def generate_taichi(algo: Algorithm, runtime: str = RUNTIME_INLINE) -> str:
``"ti_runtime"``
Emit ``from ti_runtime import vector_ops as _v`` and call the
shared primitives for dot/norm/copy/vec_add. Only ``_matvec``
remains inlined (the matrix-free operator seam is P2-2's concern).
remains inlined (the matrix-free operator is injected through the
seam by the consumer).
algo2code itself never imports ti_runtime — it only emits the
import line.

Expand Down
3 changes: 1 addition & 2 deletions packages/algo2code/src/algo2code/expr_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,7 @@ def parse_term(self) -> Expr:

Division at the term level shares precedence with multiplication
(left-associative) so ``a + b / c`` parses as ``a + (b / c)``
rather than dropping the divisor. post_recovery_plan Phase 5
parser fix.
rather than dropping the divisor.
"""
left = self.parse_signed_factor()
while True:
Expand Down
11 changes: 11 additions & 0 deletions packages/algo2code/src/algo2code/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@
here instead of re-typing or re-inventing the algorithm text — this is the
canonical hand-off seam between ``algo2code`` and any consumer that wants a
reference implementation of a textbook iterative solver.

The verbatim ``.tex`` sources live in ``algo2code/library/algorithms/`` and
ship as package data; :func:`algorithm_source` reads any of them by name.
"""

from algo2code.library.pcg import (
PCG_ALGORITHM_LATEX,
get_pcg_algorithm_latex,
)
from algo2code.library.sources import (
ALGORITHM_SOURCES,
algorithm_source,
algorithm_source_path,
)

__all__ = [
"ALGORITHM_SOURCES",
"PCG_ALGORITHM_LATEX",
"algorithm_source",
"algorithm_source_path",
"get_pcg_algorithm_latex",
]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% Point-Jacobi preconditioner apply (PlanJune14 P4-1).
% Point-Jacobi preconditioner apply.
%
% Computes the Jacobi (diagonal) preconditioned vector:
%
Expand All @@ -9,16 +9,16 @@
% small positive guard against near-zero diagonal entries. All operands are
% degree-of-freedom vectors (one value per node or per component).
%
% Grammar note (2026-06-15, P4-1):
% -----------------------------------
% Grammar note:
% -------------
% algo2code currently lowers vector/vector division (`z = r / d`) to the Python
% expression `z = (r / d)`, which is not runnable for `ti.Vector.field` operands
% (Taichi raises TypeError: unsupported operand type(s) for /: MatrixField /
% MatrixField). The grammar supports scalar operations and vector +/-/scale/
% callable-matvec, but has no `vec_ediv` (elementwise divide) primitive.
%
% The clean fix is a new `vec_ediv(z, r, d, eps)` primitive in ti_runtime
% vector_ops — exactly what P4-1 adds. The generated body below is therefore
% vector_ops. The generated body below is therefore
% realised as a thin `@ti.data_oriented` adapter
% (`mechdsl.solver.jacobi_preconditioner.GeneratedJacobiPreconditioner`) whose
% `_apply` kernel calls `ti_runtime.vector_ops.ediv(z, r, d, eps)` — a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% Newmark-beta implicit time integration — single step (PlanJune14 P6-1).
% Newmark-beta implicit time integration — single step.
%
% The canonical Newmark-beta step authored for the **all-Taichi on-device
% time-integration seam path** (the temporal analogue of the matrix-free PCG in
Expand Down Expand Up @@ -32,7 +32,7 @@
% average-acceleration / trapezoidal rule — unconditionally stable, no numerical
% damping. HHT-alpha is a one-parameter generalisation (alpha-weighted residual);
% it reuses the same predictor/corrector skeleton and is intentionally NOT
% authored here — Newmark-beta is the P6-1 deliverable, HHT is optional/next.
% authored here — Newmark-beta is the deliverable, HHT is optional/next.
%
% Seam contract (mirrors ti_runtime.seams.TimeIntegrationContext)
% ---------------------------------------------------------------
Expand All @@ -42,8 +42,8 @@
% The callable owns the mass / damping / stiffness / external-force data; the box
% is mass-/material-agnostic, exactly like ``pcg.tex`` is operator-agnostic.
%
% Grammar note (2026-06-15, P6-1)
% -------------------------------
% Grammar note
% ------------
% This box transpiles **directly** through algo2code in ``runtime='ti_runtime'``
% mode with no grammar gap: the predictor/corrector updates are all
% ``scalar*vector`` and ``vector +/- vector`` (fused ``_v.vec_add`` AXPBY calls),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
% Matrix-free Preconditioned Conjugate Gradient (PCG) — PlanJune14 P4-2.
% Matrix-free Preconditioned Conjugate Gradient (PCG).
%
% The canonical PCG algorithm authored for the **all-Taichi on-device seam path**
% (Option 1): the operator ``A`` and the preconditioner ``M_inv`` are both
% The canonical PCG algorithm authored for the **all-Taichi on-device seam path**:
% the operator ``A`` and the preconditioner ``M_inv`` are both
% *callables* (matrix-free), so this box transpiles via
% ``algo2code.transpile(..., runtime='ti_runtime')`` into a body that solves
% ``A x = b`` over ``ti.Vector.field`` DOF vectors without ever forming or storing
Expand All @@ -12,7 +12,7 @@
% Identical in algorithm to the canonical PCG LaTeX
% (``algo2code.library.pcg.PCG_ALGORITHM_LATEX`` / the hand twin
% ``mechdsl.solver.import_adapter.Algo2CodePCGSolver``) and to the matrix-free
% ``_CALLABLE_PCG_LATEX`` proven runnable in P2-2. The *only* surface change vs
% ``_CALLABLE_PCG_LATEX`` proven runnable in runtime mode. The *only* surface change vs
% the canonical box is the operator type:
%
% canonical: ``% args A:matrix, ... apply_M_inv:callable, ...``
Expand All @@ -21,15 +21,15 @@
% A matrix ``A`` lowers to a dense scalar-indexed ``_matvec`` (incompatible with
% the ``ti.Vector.field`` layout the seam uses); a callable ``A`` lowers to the
% in-place ``A(out, p)`` operator call — the ``ti_runtime`` ``apply_A(out, x)``
% seam contract. The P2-2 runtime-mode guard requires exactly this: a callable
% seam contract. The runtime-mode guard requires exactly this: a callable
% operator + a vector argument.
%
% Seam contract (mirrors ti_runtime.seams.LinearSolveContext)
% -----------------------------------------------------------
% A(out, x) — operator: out = A @ x (out FIRST)
% M_inv(r, z) — preconditioner: z = M^{-1} r (out LAST)
%
% This box productionizes the PJ-1 spike's hand-written ``pcg`` body
% This box productionizes the spike's hand-written ``pcg`` body
% (``packages/mechdsl-core/tests/spike/svk_hex8_taichi.py``): the generated body
% maps line-for-line to that hand-written PCG, but is *derived from LaTeX* rather
% than hand-coded.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% post_recovery_plan Phase 5 (P5-1): J2 radial-return algpseudocode source.
% J2 radial-return algpseudocode source.
%
% Scalar Newton inner loop for J2 plasticity with power-law isotropic
% hardening. Solves for the plastic multiplier increment dl given the
Expand All @@ -14,11 +14,10 @@
%
% This is the production algo2code source consumed by
% ``mechdsl.lib.plasticity.radial_return`` via ``algo2code.transpile``
% (post_recovery_plan Phase 5 P5-3 — algo2code expr_parser bugs that
% previously deferred direct emission landed in the same phase under
% P5-1's parser fix). Bit-equality with the imported reference path is
% asserted by
% ``packages/mechdsl-core/tests/test_j2_radial_return_parity.py`` (P5-4).
% (the algo2code expr_parser bugs that previously deferred direct emission
% were fixed alongside this source). Bit-equality with the imported reference
% path is asserted by
% ``packages/mechdsl-core/tests/test_j2_radial_return_parity.py``.
%
% Inputs
% ------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
% constitutive_latex Phase 6 (P6-2): J2 kinematic linear-hardening
% radial-return algpseudocode source.
% J2 kinematic linear-hardening radial-return algpseudocode source.
%
% Scalar return-map inner solve for J2 plasticity with LINEAR KINEMATIC
% hardening (Prager). The yield surface translates (back-stress beta)
Expand All @@ -19,14 +18,14 @@
%
% This scalar source is authored as the SAME fixed-iteration loop
% structure as the isotropic power-law variant
% (``dev/algorithms/radial_return_j2.tex``) for transpile-pattern
% (``algo2code/library/algorithms/radial_return_j2.tex``) for transpile-pattern
% consistency: the residual ``res = xi_eq - (3*mu + H_kin)*dl - sigy0``
% is linear in dl, so the Newton update (denominator ``3*mu + H_kin``)
% converges in a single step and every subsequent iteration leaves dl
% unchanged at the exact root (res = 0 => the closed form above).
% Authoring it as a loop
% keeps P6-1/P6-2/P6-3 on one structural pattern that algo2code already
% transpiles end-to-end.
% keeps the isotropic, kinematic and mixed variants on one structural
% pattern that algo2code already transpiles end-to-end.
%
% Back-stress update (Prager, discrete) is performed in TENSOR space by
% the mechdsl-core wrapper:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
% constitutive_latex Phase 6 (P6-3): J2 MIXED-hardening radial-return
% algpseudocode source.
% J2 MIXED-hardening radial-return algpseudocode source.
%
% Scalar return-map inner solve for J2 plasticity with MIXED hardening:
% the yield surface BOTH translates (linear kinematic back-stress beta,
% Prager — from P6-2) AND expands (power-law isotropic radius growth
% sigma_y(alpha) = sigy0 + K*alpha^n — from P6-1), simultaneously. Yield
% Prager — as in the kinematic variant) AND expands (power-law isotropic
% radius growth sigma_y(alpha) = sigy0 + K*alpha^n — as in the isotropic
% variant), simultaneously. Yield
% is measured on the RELATIVE (shifted) stress xi = dev(S) - beta against
% the EXPANDING radius sigma_y(alpha):
%
Expand All @@ -14,10 +14,11 @@
% Because the isotropic part is a NONLINEAR power law in
% alpha = alpha_old + dl, the discrete consistency condition is NONLINEAR
% in the plastic-multiplier increment dl, so — unlike the pure-linear
% kinematic variant (P6-2, closed form) — this needs the scalar NEWTON
% loop of the isotropic variant (P6-1). The kinematic part contributes a
% LINEAR term (3*mu + H_kin)*dl exactly as in P6-2; the isotropic part
% contributes the nonlinear sigma_y(alpha_old + dl) exactly as in P6-1.
% kinematic variant (closed form) — this needs the scalar NEWTON
% loop of the isotropic variant. The kinematic part contributes a
% LINEAR term (3*mu + H_kin)*dl exactly as in the kinematic variant; the
% isotropic part contributes the nonlinear sigma_y(alpha_old + dl) exactly
% as in the isotropic variant.
%
% Consistency residual (root in dl):
%
Expand All @@ -29,7 +30,8 @@
%
% so the Newton update is dl <- dl + r / (3*mu + H_kin + Hp) with
% Hp = K*n*ap^(n-1) the isotropic slope d(sigma_y)/d(alpha). This reduces
% to P6-1 when H_kin = 0 (xi_eq == sigma_eq, beta == 0) and to P6-2 when
% to the isotropic variant when H_kin = 0 (xi_eq == sigma_eq, beta == 0)
% and to the kinematic variant when
% K = 0 (sigma_y(alpha) == sigy0, constant radius, linear residual).
%
% The alpha->0 guard mirrors j2_power_law.py / radial_return_j2.tex: for
Expand All @@ -44,7 +46,7 @@
% Python by ``mechdsl.lib.plasticity_mixed`` — the same division of labour
% as the isotropic (``mechdsl.lib.plasticity``) and kinematic
% (``mechdsl.lib.plasticity_kinematic``) variants. The flow normal and
% back-stress factors are identical to P6-2:
% back-stress factors are identical to the kinematic variant:
%
% nf = (3/2) * xi / ||xi||_eq (von Mises gradient)
% dEp = dl * nf (plastic strain increment)
Expand Down
9 changes: 3 additions & 6 deletions packages/algo2code/src/algo2code/library/pcg.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
r"""Canonical Preconditioned Conjugate Gradient (PCG) algorithm in algpseudocode.

This module is the **algo2code interface hook** consumed by
``mechdsl-core``'s ``Algo2CodePCGSolver`` adapter (Plan recovery task P6-1).
``mechdsl-core``'s ``Algo2CodePCGSolver`` adapter.
It exposes:

* :data:`PCG_ALGORITHM_LATEX` — the verbatim LaTeX source of the canonical
PCG algorithm, mirrored from
``dev/tasks/recovery_plan_latex_contract/json/P6-1.json`` field
``pcg_algorithm_latex.latex``.
PCG algorithm.
* :func:`get_pcg_algorithm_latex` — accessor returning that text.

Runtime invariant
-----------------

This module imports **only stdlib**. ``algo2code`` is the runtime-free
sibling package of ``mechdsl-core`` (see ``.claude/CLAUDE.md`` /
``dev/design_docs/11-ALGO2CODE.md``); nothing here imports — directly or
sibling package of ``mechdsl-core``; nothing here imports — directly or
transitively — ``mechdsl``. Consumers that want a runnable implementation
own the translation step.

Expand Down
Loading
Loading