diff --git a/README.md b/README.md index d39c532..c181057 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An AI agent that acts as a compiler for computational models. It transpiles between probabilistic programming languages (PyMC, Stan), deep learning frameworks (JAX, PyTorch), and compiles to optimized Rust — with numerical validation at every step. -**[Read the blog post →](https://twiecki.io/blog/2026/03/10/transalchemy/)** +**[Read the blog post →](https://twiecki.io/blog/2026/03/10/alchemize/)** ## How it works @@ -88,7 +88,7 @@ uv sync # or: pip install -e . ```python import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model with pm.Model() as model: mu = pm.Normal("mu", 0, 10) @@ -133,7 +133,7 @@ python examples/mingpt_to_rust.py ## Architecture ``` -transalchemy/ +alchemize/ ├── exporter.py # Extract parameters, transforms, logp graph from pm.Model() ├── compiler.py # Agentic loop: Claude API → Rust code → build → validate ├── stan_exporter.py # Extract Stan model context via BridgeStan @@ -166,7 +166,7 @@ compiled_models/ # Pre-compiled models (normal, linreg, hierarchical, GP, ... The same agentic architecture works for language-to-language translation. Claude generates PyMC code, validates logp against BridgeStan reference values, and iterates until the models match numerically. Used to translate all 120 models from [posteriordb](https://github.com/stan-dev/posteriordb) from Stan to PyMC. ```python -from transalchemy import transpile_stan_to_pymc +from alchemize import transpile_stan_to_pymc stan_code = """ data { int N; array[N] real y; } @@ -188,7 +188,7 @@ The same agentic architecture generalizes to deep learning frameworks. Claude tr ```python import jax.numpy as jnp -from transalchemy import transpile_jax_to_pytorch +from alchemize import transpile_jax_to_pytorch def forward(params, x): x = jax.nn.relu(x @ params["w1"] + params["b1"]) @@ -206,7 +206,7 @@ if result.success: ```python import torch.nn as nn -from transalchemy import transpile_pytorch_to_jax +from alchemize import transpile_pytorch_to_jax class MLP(nn.Module): def __init__(self): @@ -231,7 +231,7 @@ The agent uses the same agentic architecture with tools: `write_code` → `cargo ```python import torch.nn as nn -from transalchemy import transpile_pytorch_to_rust +from alchemize import transpile_pytorch_to_rust class MLP(nn.Module): def __init__(self): diff --git a/transalchemy/__init__.py b/alchemize/__init__.py similarity index 60% rename from transalchemy/__init__.py rename to alchemize/__init__.py index 135c01f..95292d8 100644 --- a/transalchemy/__init__.py +++ b/alchemize/__init__.py @@ -8,94 +8,94 @@ import importlib from typing import TYPE_CHECKING -from transalchemy.jax_exporter import ( +from alchemize.jax_exporter import ( JaxModelExporter, export_jax_model, ) # JAX ↔ PyTorch (no heavy deps at import time) -from transalchemy.jax_pytorch_transpiler import ( +from alchemize.jax_pytorch_transpiler import ( TranspileResult, transpile_jax_to_pytorch, transpile_pytorch_to_jax, ) -from transalchemy.pytorch_exporter import ( +from alchemize.pytorch_exporter import ( PytorchModelExporter, export_pytorch_model, ) -from transalchemy.pytorch_rust_transpiler import ( +from alchemize.pytorch_rust_transpiler import ( RustTranspileResult, transpile_pytorch_to_rust, ) # PyMC/Stan imports are lazy — they pull in heavy deps (pymc, bridgestan) if TYPE_CHECKING: - from transalchemy.analysis import ( + from alchemize.analysis import ( plot_optimization_progress, plot_timeline, plot_waterfall, print_summary, ) - from transalchemy.compiler import ( + from alchemize.compiler import ( OptimizationEvent, compile_model, optimize_model, ) - from transalchemy.exporter import ( + from alchemize.exporter import ( ModelContext, RustModelExporter, export_model, ) - from transalchemy.stan_compiler import ( + from alchemize.stan_compiler import ( StanCompilationResult, compile_stan_model, ) - from transalchemy.stan_exporter import ( + from alchemize.stan_exporter import ( StanModelContext, StanModelExporter, export_stan_model, ) - from transalchemy.stan_to_pymc import StanToPyMCResult, transpile_stan_to_pymc + from alchemize.stan_to_pymc import StanToPyMCResult, transpile_stan_to_pymc def __getattr__(name: str): """Lazy import for PyMC/Stan components.""" _lazy_imports = { - "ModelContext": ("transalchemy.exporter", "ModelContext"), - "RustModelExporter": ("transalchemy.exporter", "RustModelExporter"), - "export_model": ("transalchemy.exporter", "export_model"), - "compile_model": ("transalchemy.compiler", "compile_model"), - "optimize_model": ("transalchemy.compiler", "optimize_model"), - "OptimizationEvent": ("transalchemy.compiler", "OptimizationEvent"), + "ModelContext": ("alchemize.exporter", "ModelContext"), + "RustModelExporter": ("alchemize.exporter", "RustModelExporter"), + "export_model": ("alchemize.exporter", "export_model"), + "compile_model": ("alchemize.compiler", "compile_model"), + "optimize_model": ("alchemize.compiler", "optimize_model"), + "OptimizationEvent": ("alchemize.compiler", "OptimizationEvent"), "plot_optimization_progress": ( - "transalchemy.analysis", + "alchemize.analysis", "plot_optimization_progress", ), - "plot_waterfall": ("transalchemy.analysis", "plot_waterfall"), - "plot_timeline": ("transalchemy.analysis", "plot_timeline"), - "print_summary": ("transalchemy.analysis", "print_summary"), - "StanModelContext": ("transalchemy.stan_exporter", "StanModelContext"), - "StanModelExporter": ("transalchemy.stan_exporter", "StanModelExporter"), - "export_stan_model": ("transalchemy.stan_exporter", "export_stan_model"), + "plot_waterfall": ("alchemize.analysis", "plot_waterfall"), + "plot_timeline": ("alchemize.analysis", "plot_timeline"), + "print_summary": ("alchemize.analysis", "print_summary"), + "StanModelContext": ("alchemize.stan_exporter", "StanModelContext"), + "StanModelExporter": ("alchemize.stan_exporter", "StanModelExporter"), + "export_stan_model": ("alchemize.stan_exporter", "export_stan_model"), "compile_stan_model": ( - "transalchemy.stan_compiler", + "alchemize.stan_compiler", "compile_stan_model", ), "StanCompilationResult": ( - "transalchemy.stan_compiler", + "alchemize.stan_compiler", "StanCompilationResult", ), "transpile_stan_to_pymc": ( - "transalchemy.stan_to_pymc", + "alchemize.stan_to_pymc", "transpile_stan_to_pymc", ), - "StanToPyMCResult": ("transalchemy.stan_to_pymc", "StanToPyMCResult"), + "StanToPyMCResult": ("alchemize.stan_to_pymc", "StanToPyMCResult"), } if name in _lazy_imports: module_path, attr = _lazy_imports[name] module = importlib.import_module(module_path) return getattr(module, attr) - raise AttributeError(f"module 'transalchemy' has no attribute {name!r}") + raise AttributeError(f"module 'alchemize' has no attribute {name!r}") __all__ = [ @@ -137,6 +137,6 @@ def __getattr__(name: str): def to_nutpie(compile_result, model): """Convert a CompilationResult to a nutpie-compatible model. Lazy import.""" - from transalchemy.nutpie_bridge import to_nutpie as _to_nutpie + from alchemize.nutpie_bridge import to_nutpie as _to_nutpie return _to_nutpie(compile_result, model) diff --git a/transalchemy/analysis.py b/alchemize/analysis.py similarity index 99% rename from transalchemy/analysis.py rename to alchemize/analysis.py index 84b370b..219990b 100644 --- a/transalchemy/analysis.py +++ b/alchemize/analysis.py @@ -6,7 +6,7 @@ Usage: # From a CompilationResult: - from transalchemy.analysis import plot_optimization_progress + from alchemize.analysis import plot_optimization_progress fig = plot_optimization_progress(result) # From a results.tsv file: @@ -21,7 +21,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from transalchemy.compiler import CompilationResult + from alchemize.compiler import CompilationResult @dataclass diff --git a/transalchemy/benchmark.py b/alchemize/benchmark.py similarity index 100% rename from transalchemy/benchmark.py rename to alchemize/benchmark.py diff --git a/transalchemy/cli.py b/alchemize/cli.py similarity index 96% rename from transalchemy/cli.py rename to alchemize/cli.py index 31766fa..6f49355 100644 --- a/transalchemy/cli.py +++ b/alchemize/cli.py @@ -165,7 +165,7 @@ def _transpile( @click.group() -@click.version_option(package_name="transalchemy") +@click.version_option(package_name="alchemize") def cli(): """Transalchemy: AI-powered transpilation between computational frameworks.""" @@ -210,10 +210,10 @@ def convert( \b Examples: - transalchemy convert model.stan --to pymc - transalchemy convert train.py --to jax - transalchemy convert model.py --to pytorch - cat model.stan | transalchemy convert --to pymc + alchemize convert model.stan --to pymc + alchemize convert train.py --to jax + alchemize convert model.py --to pytorch + cat model.stan | alchemize convert --to pymc """ # Read input if input_file: @@ -224,7 +224,7 @@ def convert( filename = "stdin" else: raise click.UsageError( - "No input file provided and no data on stdin. Usage: transalchemy convert --to " + "No input file provided and no data on stdin. Usage: alchemize convert --to " ) target = _normalize_framework(target) diff --git a/transalchemy/compiler.py b/alchemize/compiler.py similarity index 99% rename from transalchemy/compiler.py rename to alchemize/compiler.py index af463c7..247b294 100644 --- a/transalchemy/compiler.py +++ b/alchemize/compiler.py @@ -26,7 +26,7 @@ import numpy as np import pymc as pm -from transalchemy.exporter import RustModelExporter +from alchemize.exporter import RustModelExporter _SKILLS_DIR = Path(__file__).parent / "skills" diff --git a/transalchemy/exporter.py b/alchemize/exporter.py similarity index 100% rename from transalchemy/exporter.py rename to alchemize/exporter.py diff --git a/transalchemy/formatting.py b/alchemize/formatting.py similarity index 100% rename from transalchemy/formatting.py rename to alchemize/formatting.py diff --git a/transalchemy/jax_exporter.py b/alchemize/jax_exporter.py similarity index 100% rename from transalchemy/jax_exporter.py rename to alchemize/jax_exporter.py diff --git a/transalchemy/jax_pytorch_transpiler.py b/alchemize/jax_pytorch_transpiler.py similarity index 99% rename from transalchemy/jax_pytorch_transpiler.py rename to alchemize/jax_pytorch_transpiler.py index 5144084..232acbd 100644 --- a/transalchemy/jax_pytorch_transpiler.py +++ b/alchemize/jax_pytorch_transpiler.py @@ -18,8 +18,8 @@ import numpy as np -from transalchemy.formatting import format_python_code as _format_python -from transalchemy.jax_exporter import ModelContext +from alchemize.formatting import format_python_code as _format_python +from alchemize.jax_exporter import ModelContext _SKILLS_DIR = Path(__file__).parent / "skills" @@ -717,7 +717,7 @@ def transpile_jax_to_pytorch( Returns: TranspileResult with generated PyTorch code and validation status. """ - from transalchemy.jax_exporter import JaxModelExporter + from alchemize.jax_exporter import JaxModelExporter api_key = api_key or os.environ.get("ANTHROPIC_API_KEY") if not api_key: @@ -810,7 +810,7 @@ def transpile_pytorch_to_jax( Returns: TranspileResult with generated JAX code and validation status. """ - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter api_key = api_key or os.environ.get("ANTHROPIC_API_KEY") if not api_key: diff --git a/transalchemy/nutpie_bridge.py b/alchemize/nutpie_bridge.py similarity index 98% rename from transalchemy/nutpie_bridge.py rename to alchemize/nutpie_bridge.py index 368965b..ade130d 100644 --- a/transalchemy/nutpie_bridge.py +++ b/alchemize/nutpie_bridge.py @@ -2,8 +2,8 @@ Usage: import pymc as pm - from transalchemy import compile_model - from transalchemy.nutpie_bridge import to_nutpie + from alchemize import compile_model + from alchemize.nutpie_bridge import to_nutpie with pm.Model() as model: ... @@ -24,7 +24,7 @@ import numpy as np import pymc as pm -from transalchemy.compiler import CompilationResult +from alchemize.compiler import CompilationResult def _build_shared_lib(build_dir: Path) -> Path: diff --git a/transalchemy/pytorch_exporter.py b/alchemize/pytorch_exporter.py similarity index 98% rename from transalchemy/pytorch_exporter.py rename to alchemize/pytorch_exporter.py index 9df84a2..c203bab 100644 --- a/transalchemy/pytorch_exporter.py +++ b/alchemize/pytorch_exporter.py @@ -15,7 +15,7 @@ import numpy as np -from transalchemy.jax_exporter import ModelContext, TensorInfo, ValidationPoint +from alchemize.jax_exporter import ModelContext, TensorInfo, ValidationPoint class PytorchModelExporter: diff --git a/transalchemy/pytorch_rust_transpiler.py b/alchemize/pytorch_rust_transpiler.py similarity index 99% rename from transalchemy/pytorch_rust_transpiler.py rename to alchemize/pytorch_rust_transpiler.py index 0a0e35a..e9177bb 100644 --- a/transalchemy/pytorch_rust_transpiler.py +++ b/alchemize/pytorch_rust_transpiler.py @@ -23,7 +23,7 @@ import numpy as np -from transalchemy.jax_exporter import ModelContext, ValidationPoint +from alchemize.jax_exporter import ModelContext, ValidationPoint _SKILLS_DIR = Path(__file__).parent / "skills" @@ -1050,7 +1050,7 @@ def transpile_pytorch_to_rust( if backend not in ("pure", "burn"): raise ValueError(f"backend must be 'pure' or 'burn', got {backend!r}") - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter api_key = api_key or os.environ.get("ANTHROPIC_API_KEY") if not api_key: diff --git a/transalchemy/skills/enzyme.md b/alchemize/skills/enzyme.md similarity index 100% rename from transalchemy/skills/enzyme.md rename to alchemize/skills/enzyme.md diff --git a/transalchemy/skills/gp.md b/alchemize/skills/gp.md similarity index 100% rename from transalchemy/skills/gp.md rename to alchemize/skills/gp.md diff --git a/transalchemy/skills/gp_accelerate.md b/alchemize/skills/gp_accelerate.md similarity index 100% rename from transalchemy/skills/gp_accelerate.md rename to alchemize/skills/gp_accelerate.md diff --git a/transalchemy/skills/gp_cuda.md b/alchemize/skills/gp_cuda.md similarity index 100% rename from transalchemy/skills/gp_cuda.md rename to alchemize/skills/gp_cuda.md diff --git a/transalchemy/skills/jax_to_pytorch.md b/alchemize/skills/jax_to_pytorch.md similarity index 100% rename from transalchemy/skills/jax_to_pytorch.md rename to alchemize/skills/jax_to_pytorch.md diff --git a/transalchemy/skills/pymc_optimization.md b/alchemize/skills/pymc_optimization.md similarity index 100% rename from transalchemy/skills/pymc_optimization.md rename to alchemize/skills/pymc_optimization.md diff --git a/transalchemy/skills/pytorch_to_jax.md b/alchemize/skills/pytorch_to_jax.md similarity index 100% rename from transalchemy/skills/pytorch_to_jax.md rename to alchemize/skills/pytorch_to_jax.md diff --git a/transalchemy/skills/pytorch_to_rust.md b/alchemize/skills/pytorch_to_rust.md similarity index 100% rename from transalchemy/skills/pytorch_to_rust.md rename to alchemize/skills/pytorch_to_rust.md diff --git a/transalchemy/skills/pytorch_to_rust_burn.md b/alchemize/skills/pytorch_to_rust_burn.md similarity index 100% rename from transalchemy/skills/pytorch_to_rust_burn.md rename to alchemize/skills/pytorch_to_rust_burn.md diff --git a/transalchemy/skills/stan.md b/alchemize/skills/stan.md similarity index 100% rename from transalchemy/skills/stan.md rename to alchemize/skills/stan.md diff --git a/transalchemy/skills/stan_to_pymc.md b/alchemize/skills/stan_to_pymc.md similarity index 100% rename from transalchemy/skills/stan_to_pymc.md rename to alchemize/skills/stan_to_pymc.md diff --git a/transalchemy/skills/zerosumnormal.md b/alchemize/skills/zerosumnormal.md similarity index 100% rename from transalchemy/skills/zerosumnormal.md rename to alchemize/skills/zerosumnormal.md diff --git a/transalchemy/stan_compiler.py b/alchemize/stan_compiler.py similarity index 99% rename from transalchemy/stan_compiler.py rename to alchemize/stan_compiler.py index b47a273..b0694cc 100644 --- a/transalchemy/stan_compiler.py +++ b/alchemize/stan_compiler.py @@ -16,7 +16,7 @@ import numpy as np -from transalchemy.stan_exporter import StanModelExporter +from alchemize.stan_exporter import StanModelExporter _SKILLS_DIR = Path(__file__).parent / "skills" diff --git a/transalchemy/stan_exporter.py b/alchemize/stan_exporter.py similarity index 100% rename from transalchemy/stan_exporter.py rename to alchemize/stan_exporter.py diff --git a/transalchemy/stan_to_pymc.py b/alchemize/stan_to_pymc.py similarity index 99% rename from transalchemy/stan_to_pymc.py rename to alchemize/stan_to_pymc.py index c2db299..7067a47 100644 --- a/transalchemy/stan_to_pymc.py +++ b/alchemize/stan_to_pymc.py @@ -16,7 +16,7 @@ import numpy as np -from transalchemy.formatting import format_python_code as _format_python +from alchemize.formatting import format_python_code as _format_python _SKILLS_DIR = Path(__file__).parent / "skills" @@ -294,7 +294,7 @@ def transpile_stan_to_pymc( if verbose: print("Extracting reference values via BridgeStan...") t0 = time.time() - from transalchemy.stan_exporter import StanModelExporter + from alchemize.stan_exporter import StanModelExporter exporter = StanModelExporter(stan_code, data=data) ctx = exporter.context diff --git a/benchmarks/run_benchmarks.py b/benchmarks/run_benchmarks.py index 6057055..f7c7c45 100644 --- a/benchmarks/run_benchmarks.py +++ b/benchmarks/run_benchmarks.py @@ -5,7 +5,7 @@ and stores convergence diagnostics (ESS, Rhat). Usage: - cd /path/to/transalchemy + cd /path/to/alchemize uv run python benchmarks/run_benchmarks.py [--models normal,linreg] [--n-repeats 3] [--output results.json] """ @@ -553,7 +553,7 @@ def benchmark_rust( try: sys.path.insert(0, str(PROJECT_ROOT)) - from transalchemy.nutpie_bridge import _ensure_ffi_setup, _load_logp_fn + from alchemize.nutpie_bridge import _ensure_ffi_setup, _load_logp_fn # Compilation: build the shared library t_compile_start = time.perf_counter() diff --git a/examples/01_normal.py b/examples/01_normal.py index d28208b..7426cfd 100644 --- a/examples/01_normal.py +++ b/examples/01_normal.py @@ -12,7 +12,7 @@ import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # Generate synthetic data np.random.seed(42) diff --git a/examples/02_linear_regression.py b/examples/02_linear_regression.py index 20ca109..b831de8 100644 --- a/examples/02_linear_regression.py +++ b/examples/02_linear_regression.py @@ -12,7 +12,7 @@ import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # Generate synthetic data np.random.seed(42) diff --git a/examples/03_hierarchical.py b/examples/03_hierarchical.py index 38d9fa0..ab9402b 100644 --- a/examples/03_hierarchical.py +++ b/examples/03_hierarchical.py @@ -19,7 +19,7 @@ import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # Generate synthetic hierarchical data np.random.seed(42) @@ -77,7 +77,7 @@ if result.success: print(f"\nCompilation successful in {result.n_attempts} attempt(s)!") print("\nNow you can benchmark:") - print(" python -c 'from transalchemy.benchmark import *; ...'") + print(" python -c 'from alchemize.benchmark import *; ...'") else: print(f"\nCompilation FAILED after {result.n_attempts} attempts") for err in result.validation_errors[:5]: diff --git a/examples/04_zerosumnormal.py b/examples/04_zerosumnormal.py index 74b37bd..8dfb78c 100644 --- a/examples/04_zerosumnormal.py +++ b/examples/04_zerosumnormal.py @@ -30,7 +30,7 @@ import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # --- Synthetic retail sales data --- np.random.seed(314) diff --git a/examples/05_celeri_simplified.py b/examples/05_celeri_simplified.py index eecf907..e9d4648 100644 --- a/examples/05_celeri_simplified.py +++ b/examples/05_celeri_simplified.py @@ -34,7 +34,7 @@ import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # --- Synthetic tectonic data --- np.random.seed(42) diff --git a/examples/bench_logp.py b/examples/bench_logp.py index d47bd8d..db6a69e 100644 --- a/examples/bench_logp.py +++ b/examples/bench_logp.py @@ -5,7 +5,7 @@ what nutpie calls under the hood (pytensor's compiled logp_dlogp_function). Usage: - cd transalchemy + cd alchemize uv run python examples/bench_logp.py """ @@ -14,7 +14,7 @@ import numpy as np import pymc as pm -from transalchemy.benchmark import ( +from alchemize.benchmark import ( _make_test_point, benchmark_logp_numba_cfunc, benchmark_logp_pytensor, diff --git a/examples/generate_blog_plots.py b/examples/generate_blog_plots.py index c980d97..b561cc9 100644 --- a/examples/generate_blog_plots.py +++ b/examples/generate_blog_plots.py @@ -98,8 +98,8 @@ def make_gp_model(): def run_compile_and_optimize(name, make_model_fn, source_code, build_dir): """Compile a PyMC model to Rust, then optimize it.""" - from transalchemy import compile_model, optimize_model - from transalchemy.analysis import ( + from alchemize import compile_model, optimize_model + from alchemize.analysis import ( plot_optimization_progress, plot_timeline, plot_waterfall, @@ -168,7 +168,7 @@ def run_compile_and_optimize(name, make_model_fn, source_code, build_dir): def run_benchmarks_and_plot(): """Run logp benchmarks on compiled models and generate comparison bar chart.""" - from transalchemy.benchmark import ( + from alchemize.benchmark import ( _make_test_point, benchmark_logp_pytensor, benchmark_logp_rust, diff --git a/examples/jax_to_pytorch_mlp.py b/examples/jax_to_pytorch_mlp.py index 396f7ab..bd3242e 100644 --- a/examples/jax_to_pytorch_mlp.py +++ b/examples/jax_to_pytorch_mlp.py @@ -8,7 +8,7 @@ import jax.numpy as jnp import numpy as np -from transalchemy import transpile_jax_to_pytorch +from alchemize import transpile_jax_to_pytorch def mlp_forward(params, x): diff --git a/examples/mingpt_to_rust.py b/examples/mingpt_to_rust.py index 37fbcff..9f299fd 100644 --- a/examples/mingpt_to_rust.py +++ b/examples/mingpt_to_rust.py @@ -1,4 +1,4 @@ -"""Transpile Karpathy's minGPT to Rust using transalchemy. +"""Transpile Karpathy's minGPT to Rust using alchemize. This script: 1. Creates a small GPT model (gpt-nano: 3 layers, 3 heads, 48 embd) @@ -197,7 +197,7 @@ def main(): print() # Step 3: Transpile to Rust - print("Step 3: Transpiling to Rust via transalchemy...") + print("Step 3: Transpiling to Rust via alchemize...") print(" (This will run an agentic Claude loop — may take a few minutes)") print() @@ -285,7 +285,7 @@ def forward(self, x): return logits.view(-1) """ - from transalchemy import transpile_pytorch_to_rust + from alchemize import transpile_pytorch_to_rust # Use "burn" backend for optimized tensors + autodiff, or "pure" for zero-dep backend = sys.argv[1] if len(sys.argv) > 1 else "burn" diff --git a/examples/pytorch_to_jax_mlp.py b/examples/pytorch_to_jax_mlp.py index b7dec8c..30d0dbc 100644 --- a/examples/pytorch_to_jax_mlp.py +++ b/examples/pytorch_to_jax_mlp.py @@ -9,7 +9,7 @@ import torch.nn as nn import torch.nn.functional as F -from transalchemy import transpile_pytorch_to_jax +from alchemize import transpile_pytorch_to_jax class SimpleMLP(nn.Module): diff --git a/examples/pytorch_to_rust_mlp.py b/examples/pytorch_to_rust_mlp.py index 8928f98..370c096 100644 --- a/examples/pytorch_to_rust_mlp.py +++ b/examples/pytorch_to_rust_mlp.py @@ -7,7 +7,7 @@ import torch import torch.nn as nn -from transalchemy import transpile_pytorch_to_rust +from alchemize import transpile_pytorch_to_rust # Define a simple MLP diff --git a/examples/run_benchmark.py b/examples/run_benchmark.py index ba0f183..37af6c4 100644 --- a/examples/run_benchmark.py +++ b/examples/run_benchmark.py @@ -14,8 +14,8 @@ import numpy as np import pymc as pm -from transalchemy import compile_model -from transalchemy.benchmark import ( +from alchemize import compile_model +from alchemize.benchmark import ( benchmark_nutpie, benchmark_rust, print_comparison, diff --git a/examples/stan_01_normal.py b/examples/stan_01_normal.py index 5624a82..d313ca8 100644 --- a/examples/stan_01_normal.py +++ b/examples/stan_01_normal.py @@ -5,7 +5,7 @@ import numpy as np -from transalchemy import compile_stan_model +from alchemize import compile_stan_model STAN_CODE = """ data { diff --git a/examples/stan_02_hierarchical.py b/examples/stan_02_hierarchical.py index 5494500..37c3720 100644 --- a/examples/stan_02_hierarchical.py +++ b/examples/stan_02_hierarchical.py @@ -3,7 +3,7 @@ Classic Eight Schools example — non-centered parameterization. """ -from transalchemy import compile_stan_model +from alchemize import compile_stan_model STAN_CODE = """ data { diff --git a/examples/stan_pymc_01_normal.py b/examples/stan_pymc_01_normal.py index 526cab6..708f62c 100644 --- a/examples/stan_pymc_01_normal.py +++ b/examples/stan_pymc_01_normal.py @@ -6,7 +6,7 @@ import numpy as np -from transalchemy import transpile_stan_to_pymc +from alchemize import transpile_stan_to_pymc STAN_CODE = """ data { diff --git a/examples/stan_pymc_02_hierarchical.py b/examples/stan_pymc_02_hierarchical.py index 46612be..f3f3272 100644 --- a/examples/stan_pymc_02_hierarchical.py +++ b/examples/stan_pymc_02_hierarchical.py @@ -5,7 +5,7 @@ import numpy as np -from transalchemy import transpile_stan_to_pymc +from alchemize import transpile_stan_to_pymc STAN_CODE = """ data { diff --git a/notebooks/overview.py b/notebooks/overview.py index df092b2..1809097 100644 --- a/notebooks/overview.py +++ b/notebooks/overview.py @@ -113,7 +113,7 @@ def _(mo): @app.cell def _(linreg_model): - from transalchemy.exporter import RustModelExporter + from alchemize.exporter import RustModelExporter SOURCE = """alpha ~ Normal(0, 10) beta ~ Normal(0, 10) @@ -419,7 +419,7 @@ def _(mo): ## Architecture ``` - transalchemy/ + alchemize/ ├── exporter.py # Extract: pm.Model() → ModelContext → LLM prompt ├── compiler.py # Generate + Build + Validate loop └── benchmark.py # Compare: nutpie vs AI-compiled Rust @@ -467,7 +467,7 @@ def _(mo): ## Try It ```python - from transalchemy import compile_model + from alchemize import compile_model result = compile_model( model, diff --git a/pyproject.toml b/pyproject.toml index b45e125..3b2e3f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "transalchemy" +name = "alchemize" version = "0.1.0" description = "The Transalchemy: an AI agent that transpiles between any computational framework via LLM" authors = [{name = "Thomas Wiecki", email = "thomas.wiecki@pymc-labs.com"}] @@ -24,14 +24,14 @@ torch = ["torch>=2.0"] dl = ["jax>=0.4", "jaxlib>=0.4", "torch>=2.0"] [project.scripts] -transalchemy = "transalchemy.cli:cli" +alchemize = "alchemize.cli:cli" [build-system] build-backend = "hatchling.build" requires = ["hatchling"] [tool.hatch.build.targets.wheel] -packages = ["transalchemy"] +packages = ["alchemize"] [dependency-groups] dev = [ diff --git a/python b/python index 295d2b8..2677e34 100644 --- a/python +++ b/python @@ -12,7 +12,7 @@ for 2 unconstrained parameters: mu and log(sigma). import numpy as np import pymc as pm -from transalchemy import compile_model +from alchemize import compile_model # Generate synthetic data np.random.seed(42) diff --git a/test_mlx.py b/test_mlx.py index 59d6415..762f8a4 100644 --- a/test_mlx.py +++ b/test_mlx.py @@ -3,13 +3,13 @@ import numpy as np import pymc as pm -from transalchemy import compile_model -from transalchemy.benchmark import ( +from alchemize import compile_model +from alchemize.benchmark import ( benchmark_logp_pytensor, benchmark_logp_rust, print_logp_comparison, ) -from transalchemy.compiler import _mlx_available +from alchemize.compiler import _mlx_available def make_gp_model(N=50): diff --git a/test_mlx_vs_cpu.py b/test_mlx_vs_cpu.py index a2c7be9..5a7cfd8 100644 --- a/test_mlx_vs_cpu.py +++ b/test_mlx_vs_cpu.py @@ -3,8 +3,8 @@ import numpy as np import pymc as pm -from transalchemy import compile_model -from transalchemy.benchmark import ( +from alchemize import compile_model +from alchemize.benchmark import ( benchmark_logp_pytensor, benchmark_logp_rust, ) diff --git a/tests/conftest.py b/tests/conftest.py index 7997dc0..fb3c5f0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -"""Shared fixtures for transalchemy tests.""" +"""Shared fixtures for alchemize tests.""" from __future__ import annotations diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 5e65cad..83f842d 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -1,4 +1,4 @@ -"""Tests for transalchemy.compiler.""" +"""Tests for alchemize.compiler.""" from __future__ import annotations @@ -6,7 +6,7 @@ from pathlib import Path from unittest.mock import MagicMock -from transalchemy.compiler import ( +from alchemize.compiler import ( CompilationResult, _AgentState, _execute_tool, @@ -15,7 +15,7 @@ _tool_read_file, _tool_write_rust_code, ) -from transalchemy.exporter import ( +from alchemize.exporter import ( RustModelExporter, ) @@ -402,7 +402,7 @@ def test_dispatches_read(self): class TestToolDefinitions: def test_tools_list_has_five_tools(self): - from transalchemy.compiler import TOOLS + from alchemize.compiler import TOOLS assert len(TOOLS) == 5 tool_names = {t["name"] for t in TOOLS} @@ -415,7 +415,7 @@ def test_tools_list_has_five_tools(self): } def test_system_prompt_exists(self): - from transalchemy.compiler import SYSTEM_PROMPT + from alchemize.compiler import SYSTEM_PROMPT assert len(SYSTEM_PROMPT) > 100 assert "CpuLogpFunc" in SYSTEM_PROMPT diff --git a/tests/test_exporter.py b/tests/test_exporter.py index ee43ecf..8cbb312 100644 --- a/tests/test_exporter.py +++ b/tests/test_exporter.py @@ -1,4 +1,4 @@ -"""Tests for transalchemy.exporter.""" +"""Tests for alchemize.exporter.""" from __future__ import annotations @@ -8,7 +8,7 @@ import numpy as np -from transalchemy.exporter import ( +from alchemize.exporter import ( ParamInfo, RustModelExporter, ValidationPoint, diff --git a/tests/test_jax_pytorch.py b/tests/test_jax_pytorch.py index fddaaee..e3815cd 100644 --- a/tests/test_jax_pytorch.py +++ b/tests/test_jax_pytorch.py @@ -43,7 +43,7 @@ def forward(params, x): return forward, params, x def test_extract_params(self, simple_model): - from transalchemy.jax_exporter import JaxModelExporter + from alchemize.jax_exporter import JaxModelExporter fn, params, x = simple_model exporter = JaxModelExporter(fn, params, x) @@ -61,7 +61,7 @@ def test_extract_params(self, simple_model): assert b_info.size == 2 def test_extract_validation_points(self, simple_model): - from transalchemy.jax_exporter import JaxModelExporter + from alchemize.jax_exporter import JaxModelExporter fn, params, x = simple_model exporter = JaxModelExporter(fn, params, x, n_extra_points=2) @@ -78,7 +78,7 @@ def test_extract_validation_points(self, simple_model): assert "b" in vp0.grad_params def test_forward_output_matches(self, simple_model): - from transalchemy.jax_exporter import JaxModelExporter + from alchemize.jax_exporter import JaxModelExporter fn, params, x = simple_model exporter = JaxModelExporter(fn, params, x) @@ -89,7 +89,7 @@ def test_forward_output_matches(self, simple_model): np.testing.assert_allclose(got, expected, atol=1e-6) def test_to_dict(self, simple_model): - from transalchemy.jax_exporter import JaxModelExporter + from alchemize.jax_exporter import JaxModelExporter fn, params, x = simple_model exporter = JaxModelExporter(fn, params, x) @@ -127,7 +127,7 @@ def forward(self, x): return model, x def test_extract_params(self, simple_model): - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter model, x = simple_model exporter = PytorchModelExporter(model, x) @@ -141,7 +141,7 @@ def test_extract_params(self, simple_model): assert weight_info.size == 6 def test_extract_validation_points(self, simple_model): - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter model, x = simple_model exporter = PytorchModelExporter(model, x, n_extra_points=2) @@ -158,7 +158,7 @@ def test_extract_validation_points(self, simple_model): def test_forward_output_matches(self, simple_model): import torch - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter model, x = simple_model exporter = PytorchModelExporter(model, x) @@ -177,8 +177,8 @@ class TestTranspilerTools: """Test the transpiler's tool execution logic without API calls.""" def test_write_code_syntax_check(self): - from transalchemy.jax_exporter import ModelContext - from transalchemy.jax_pytorch_transpiler import ( + from alchemize.jax_exporter import ModelContext + from alchemize.jax_pytorch_transpiler import ( _AgentState, _tool_write_code, ) @@ -206,8 +206,8 @@ def test_write_code_syntax_check(self): assert "Syntax error" in result def test_validate_no_code(self): - from transalchemy.jax_exporter import ModelContext - from transalchemy.jax_pytorch_transpiler import ( + from alchemize.jax_exporter import ModelContext + from alchemize.jax_pytorch_transpiler import ( _AgentState, _tool_validate, ) @@ -233,8 +233,8 @@ def test_validate_pytorch_correct_model(self): """Test that validation passes for a correctly transpiled model.""" import jax.numpy as jnp - from transalchemy.jax_exporter import JaxModelExporter - from transalchemy.jax_pytorch_transpiler import ( + from alchemize.jax_exporter import JaxModelExporter + from alchemize.jax_pytorch_transpiler import ( _AgentState, _tool_validate, _tool_write_code, @@ -289,12 +289,12 @@ def test_validate_jax_correct_model(self): import torch import torch.nn as nn - from transalchemy.jax_pytorch_transpiler import ( + from alchemize.jax_pytorch_transpiler import ( _AgentState, _tool_validate, _tool_write_code, ) - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter # Create a simple PyTorch model class Linear(nn.Module): @@ -344,14 +344,14 @@ class TestSkills: """Test that skill files load correctly.""" def test_jax_to_pytorch_skill_exists(self): - from transalchemy.jax_pytorch_transpiler import _load_skill + from alchemize.jax_pytorch_transpiler import _load_skill skill = _load_skill("jax_to_pytorch") assert len(skill) > 0 assert "PyTorch" in skill def test_pytorch_to_jax_skill_exists(self): - from transalchemy.jax_pytorch_transpiler import _load_skill + from alchemize.jax_pytorch_transpiler import _load_skill skill = _load_skill("pytorch_to_jax") assert len(skill) > 0 diff --git a/tests/test_pytorch_rust.py b/tests/test_pytorch_rust.py index b25d9b2..8f9f3d8 100644 --- a/tests/test_pytorch_rust.py +++ b/tests/test_pytorch_rust.py @@ -24,7 +24,7 @@ def simple_context(self): import torch import torch.nn as nn - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter class Linear(nn.Module): def __init__(self): @@ -43,7 +43,7 @@ def forward(self, x): return exporter.context def test_creates_project_structure(self, simple_context): - from transalchemy.pytorch_rust_transpiler import _setup_rust_project + from alchemize.pytorch_rust_transpiler import _setup_rust_project with tempfile.TemporaryDirectory() as tmpdir: build_path = Path(tmpdir) @@ -55,7 +55,7 @@ def test_creates_project_structure(self, simple_context): assert (build_path / "src" / "generated.rs").exists() def test_data_rs_contains_params(self, simple_context): - from transalchemy.pytorch_rust_transpiler import _setup_rust_project + from alchemize.pytorch_rust_transpiler import _setup_rust_project with tempfile.TemporaryDirectory() as tmpdir: build_path = Path(tmpdir) @@ -70,7 +70,7 @@ def test_data_rs_contains_params(self, simple_context): assert "FC_BIAS_SHAPE" in data_rs def test_cargo_toml_valid(self, simple_context): - from transalchemy.pytorch_rust_transpiler import _setup_rust_project + from alchemize.pytorch_rust_transpiler import _setup_rust_project with tempfile.TemporaryDirectory() as tmpdir: build_path = Path(tmpdir) @@ -92,8 +92,8 @@ def agent_state(self): import torch import torch.nn as nn - from transalchemy.pytorch_exporter import PytorchModelExporter - from transalchemy.pytorch_rust_transpiler import ( + from alchemize.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_rust_transpiler import ( _AgentState, _setup_rust_project, ) @@ -123,7 +123,7 @@ def forward(self, x): return state def test_write_code(self, agent_state): - from transalchemy.pytorch_rust_transpiler import _tool_write_code + from alchemize.pytorch_rust_transpiler import _tool_write_code result = _tool_write_code( { @@ -139,33 +139,33 @@ def test_write_code(self, agent_state): assert "forward" in gen def test_write_code_empty(self, agent_state): - from transalchemy.pytorch_rust_transpiler import _tool_write_code + from alchemize.pytorch_rust_transpiler import _tool_write_code result = _tool_write_code({"code": ""}, agent_state, verbose=False) assert "Error" in result def test_read_source(self, agent_state): - from transalchemy.pytorch_rust_transpiler import _tool_read_source + from alchemize.pytorch_rust_transpiler import _tool_read_source result = _tool_read_source(agent_state, verbose=False) # Should return some source code or indication assert len(result) > 0 def test_read_file(self, agent_state): - from transalchemy.pytorch_rust_transpiler import _tool_read_file + from alchemize.pytorch_rust_transpiler import _tool_read_file result = _tool_read_file({"path": "src/data.rs"}, agent_state, verbose=False) assert "W" in result or "WEIGHT" in result or "f32" in result def test_read_file_not_found(self, agent_state): - from transalchemy.pytorch_rust_transpiler import _tool_read_file + from alchemize.pytorch_rust_transpiler import _tool_read_file result = _tool_read_file({"path": "nonexistent.rs"}, agent_state, verbose=False) assert "not found" in result.lower() or "Available" in result def test_cargo_build_placeholder(self, agent_state): """Test that the placeholder generated.rs compiles.""" - from transalchemy.pytorch_rust_transpiler import _tool_cargo_build + from alchemize.pytorch_rust_transpiler import _tool_cargo_build # Check if cargo is available try: @@ -178,7 +178,7 @@ def test_cargo_build_placeholder(self, agent_state): def test_validate_no_binary(self, agent_state): """Test validation when binary doesn't exist.""" - from transalchemy.pytorch_rust_transpiler import _tool_validate + from alchemize.pytorch_rust_transpiler import _tool_validate result = _tool_validate(agent_state, verbose=False) assert "not found" in result.lower() or "Error" in result @@ -196,7 +196,7 @@ def simple_model_context(self): import torch import torch.nn as nn - from transalchemy.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_exporter import PytorchModelExporter class Simple(nn.Module): def __init__(self): @@ -257,8 +257,8 @@ def model_and_state(self): import torch import torch.nn as nn - from transalchemy.pytorch_exporter import PytorchModelExporter - from transalchemy.pytorch_rust_transpiler import ( + from alchemize.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_rust_transpiler import ( _AgentState, _setup_rust_project, ) @@ -289,7 +289,7 @@ def forward(self, x): def test_correct_rust_validates(self, model_and_state): """Write manually correct Rust code and verify it passes validation.""" - from transalchemy.pytorch_rust_transpiler import ( + from alchemize.pytorch_rust_transpiler import ( _tool_cargo_build, _tool_validate, _tool_write_code, @@ -371,7 +371,7 @@ class TestSkills: """Test that the PyTorch→Rust skill file loads correctly.""" def test_pytorch_to_rust_skill_exists(self): - from transalchemy.pytorch_rust_transpiler import _load_skill + from alchemize.pytorch_rust_transpiler import _load_skill skill = _load_skill("pytorch_to_rust") assert len(skill) > 0 @@ -379,14 +379,14 @@ def test_pytorch_to_rust_skill_exists(self): assert "PyTorch" in skill def test_skill_has_matmul_example(self): - from transalchemy.pytorch_rust_transpiler import _load_skill + from alchemize.pytorch_rust_transpiler import _load_skill skill = _load_skill("pytorch_to_rust") assert "linear" in skill.lower() assert "relu" in skill.lower() def test_skill_has_backprop(self): - from transalchemy.pytorch_rust_transpiler import _load_skill + from alchemize.pytorch_rust_transpiler import _load_skill skill = _load_skill("pytorch_to_rust") assert "backward" in skill.lower() or "backprop" in skill.lower() or "gradient" in skill.lower() @@ -399,7 +399,7 @@ class TestRustTranspileResult: """Test the result dataclass.""" def test_success_property(self): - from transalchemy.pytorch_rust_transpiler import RustTranspileResult + from alchemize.pytorch_rust_transpiler import RustTranspileResult result = RustTranspileResult( generated_code="fn forward() {}", @@ -411,7 +411,7 @@ def test_success_property(self): assert result.success is True def test_failure_property(self): - from transalchemy.pytorch_rust_transpiler import RustTranspileResult + from alchemize.pytorch_rust_transpiler import RustTranspileResult result = RustTranspileResult( generated_code="", @@ -423,7 +423,7 @@ def test_failure_property(self): assert result.success is False def test_save(self, tmp_path): - from transalchemy.pytorch_rust_transpiler import RustTranspileResult + from alchemize.pytorch_rust_transpiler import RustTranspileResult result = RustTranspileResult( generated_code="pub fn forward() -> Vec { vec![] }", @@ -446,8 +446,8 @@ class TestPromptBuilding: def test_prompt_contains_model_info(self): import torch.nn as nn - from transalchemy.pytorch_exporter import PytorchModelExporter - from transalchemy.pytorch_rust_transpiler import _build_user_prompt + from alchemize.pytorch_exporter import PytorchModelExporter + from alchemize.pytorch_rust_transpiler import _build_user_prompt class Model(nn.Module): def __init__(self):