Skip to content

Tutorials - #4

Open
r-fedorov wants to merge 18 commits into
mainfrom
tutorials
Open

Tutorials#4
r-fedorov wants to merge 18 commits into
mainfrom
tutorials

Conversation

@r-fedorov

@r-fedorov r-fedorov commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary by Sourcery

Refine performance evaluation and numerical parity infrastructure while tightening tensor product and Linear semantics and Metal kernel dispatch, adding three-way Torch CPU/MLX benchmark reporting and randomized cross-framework parity suites.

New Features:

  • Introduce three-way Torch CPU, general MLX, and kernel-enabled MLX benchmark harness with compact SVG/CSV/HTML reporting and per-result dispatch metadata.
  • Add randomized TensorProduct, core-operation, and high-level operation parity harnesses that compare Torch/e3nn and MLX using seeded NumPy inputs in isolated workers.

Bug Fixes:

  • Align Linear default instruction ordering and external weight semantics with upstream e3nn, preserving grouped execution gradients for repeated irrep blocks.
  • Harden tensor product validation and execution by rejecting invalid instructions, enforcing dtype and shape rules on weights, and correctly accumulating repeated paths into shared outputs.
  • Avoid materializing shared tensor-product weights per batch item and route large dense scalar-path contractions through general MLX at their measured crossover for stability and performance.
  • Ensure generated Metal kernels and general MLX paths produce numerically consistent outputs and derivatives across dispatch boundaries and rank/dtype fallbacks.

Enhancements:

  • Simplify MLX and Torch benchmark cases to a compact workload set, add model-level gate-points and v2106 network benchmarks, and record the actual execution path used by each MLX measurement.
  • Tighten scatter_sum, tensor product, and Linear implementations with better broadcasting rules, shared/unshared weight handling, and more efficient grouped contractions.
  • Extend documentation with detailed kernel limitations, Linear weight layout guidance, and updated performance and compatibility guarantees linked to the new evaluation suites.

Tests:

  • Expand Metal-kernel tests to cover tensor-product dispatch boundaries, nested derivatives, stability, and mixed ownership cases.
  • Add unit tests that lock in the new evaluation harness behavior, workload surface, and worker orchestration, including dispatch labels and fixed case sets.
  • Introduce comprehensive tests for tensor-product validation edge cases, Linear weight-path ordering, grouped external-weight VJPs, and the new randomized parity harnesses.
  • Update documentation-contract tests to assert the newly documented behavioral guarantees and evaluation workflows.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Linear weight-path ordering and grouped execution to preserve gradients and correct external-weight interpretation.
    • Enhanced TensorProduct validation, dtype consistency, shared/per-sample broadcasting, and instruction accumulation for repeated/unweighted cases.
    • Tightened Metal dispatch boundaries and fallback behavior; added TensorSquare use_custom_kernel propagation.
  • Documentation

    • Expanded Linear semantics/compatibility and clarified migration, kernel limitations, and benchmark/evaluation workflow.
    • Updated randomized parity and evaluation-suite docs/navigation.
  • Testing

    • Added/expanded seeded, replayable parity and randomized qualification harnesses with strict contracts across Torch CPU and all MLX variants.
    • Strengthened Metal kernel correctness, dispatch, and stability coverage.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @r-fedorov, your pull request is larger than the review limit of 300000 diff characters

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6862dab4-32a5-46e0-841c-b1bea89f681c

📥 Commits

Reviewing files that changed from the base of the PR and between 8db6939 and 1de1b88.

📒 Files selected for processing (13)
  • e3nn_mlx/ops_tp.py
  • evals/mlx_cases.py
  • evals/randomized_core_parity.py
  • evals/torch_cases.py
  • tests/test_evals.py
  • tests/test_metal_kernels.py
  • tests/test_randomized_tensor_product_parity_harness.py
  • tests/test_tensor_product_compatibility_qualification.py
  • tests/test_tensor_product_wrappers.py
  • tests/test_tutorial_tensor_helpers.py
  • tests/test_upstream_o3_linear_norm.py
  • tutorials/README.md
  • tutorials/tensor_helpers.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • tests/test_upstream_o3_linear_norm.py
  • tests/test_randomized_tensor_product_parity_harness.py
  • tests/test_metal_kernels.py
  • e3nn_mlx/ops_tp.py
  • evals/randomized_core_parity.py
  • tests/test_evals.py
  • evals/torch_cases.py
  • tests/test_tensor_product_compatibility_qualification.py
  • evals/mlx_cases.py

📝 Walkthrough

Walkthrough

This change corrects tensor-product and Linear semantics, strengthens validation and dispatch handling, adds seeded Torch/MLX parity harnesses, and consolidates performance evaluation into a fixed three-worker benchmark with compact reports and expanded documentation.

Changes

Tensor semantics and validation

Layer / File(s) Summary
Instruction, weight, and dispatch semantics
e3nn_core/instructions.py, e3nn_mlx/ops_tp.py, e3nn_mlx/nn_linear.py
Original-irrep instruction mapping, dtype and shape validation, repeated-output accumulation, Linear input-major ordering, grouped matrix construction, and Metal dispatch thresholds are updated.
Compatibility and regression coverage
tests/test_tensor_product_compatibility_qualification.py, tests/test_metal_kernels.py, tests/test_upstream_o3_linear_norm.py, tests/test_tensor_product*.py
Tests cover zero multiplicities, weight broadcasting and gradients, repeated instructions, kernel fallbacks, nested derivatives, Linear ordering, and grouped external-weight VJPs.

Three-way benchmark runner

Layer / File(s) Summary
Worker and workload model
evals/common.py, evals/mlx_cases.py, evals/torch_cases.py, evals/workloads.py
Benchmark tasks target Torch CPU, general MLX, and kernel MLX with explicit execution and dispatch metadata, reduced workload registries, and smoke/full presets.
Runner and reports
evals/run.py, evals/run_backend.py, evals/plot_results.py, tests/test_evals.py
The runner launches fixed isolated workers and emits compact latency, speedup, CSV, and HTML artifacts containing selected dispatch paths.

Randomized parity qualification

Layer / File(s) Summary
Parity harnesses
evals/randomized_*_parity.py, evals/RANDOMIZED_*.md
Seeded core-operation, operation/VJP, and tensor-product harnesses generate replayable cases, compare Torch and MLX variants, and save structured reports and failures.
Parity contract tests
tests/test_randomized_*_parity_harness.py
Tests verify deterministic generation, finite replayable arrays, comparison failure retention, and successful execution across MLX variants.

Compatibility and evaluation documentation

Layer / File(s) Summary
Public behavior and migration guides
docs/COMPATIBILITY.md, docs/HIGH_LEVEL_API.md, docs/guide/*, README.md
Documentation describes Linear layouts, tensor-product instruction rules, shared and unshared weights, generated-kernel boundaries, migration procedures, tutorial tensor compatibility, and the revised evaluation workflow.
Documentation contracts and release notes
tests/test_documentation_contract.py, docs/UPSTREAM_O3_TEST_MATRIX.md, CHANGELOG.md
Documentation evidence mappings, Linear test coverage references, and Unreleased changelog sections are updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • lamalab-org/e3nn_mlx#1: Adds the generated Metal-kernel framework and use_custom_kernel gating that this change further integrates with tensor-product dispatch.
  • lamalab-org/e3nn_mlx#3: Updates the tutorial tensor helper implementation that this change further aligns with IrrepsArray behavior.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too generic and does not convey the main changes in benchmarking, parity, docs, and tensor-product semantics. Use a concise, specific title that summarizes the primary change, such as compact benchmarks, parity harnesses, and tutorial tensor updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tutorials

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors the evaluation and benchmarking suite into a compact three‑way Torch‑CPU vs MLX vs MLX‑kernel benchmark, tightens tensor product and Linear semantics and validation, adds randomized cross‑framework numerical parity harnesses, and augments Metal kernel dispatch logic and tests, while simplifying plots, workloads, and documentation accordingly.

Sequence diagram for MLX TensorProduct Metal dispatch vs general path

sequenceDiagram
    participant Caller
    participant TP as TensorProduct
    participant MDK as TensorProduct__metal_dispatch_kind
    participant TM as TensorProduct__try_metal
    participant Metal as _metal_operation
    participant Num as _numerical_tensor_product

    Caller->>TP: _apply_arrays(left_array, right_array, weight)
    TP->>TP: _get_weight(weight)

    alt use_custom_kernel enabled
        TP->>TM: _try_metal(left_array, right_array, weight)
        TM->>MDK: _metal_dispatch_kind(left_array, right_array, weight)
        MDK-->>TM: kind or None

        alt kind is not None
            TM->>Metal: _metal_operation(left_array, right_array, metal_weight)
            Metal-->>TP: output_array
        else kind is None
            TM-->>TP: None
            TP->>Num: _numerical_tensor_product(left, right, weights)
            Num-->>TP: output_array
        end
    else use_custom_kernel disabled
        TP->>Num: _numerical_tensor_product(left, right, weights)
        Num-->>TP: output_array
    end

    TP-->>Caller: output_array
Loading

File-Level Changes

Change Details Files
Refactor MLX benchmark cases to support dispatch metadata, kernel-aware tensor products, new model workloads, and removal of legacy v2106 microbenchmarks.
  • Expose and propagate a configurable use_custom_kernels flag, add dispatch strings to Task and benchmark rows, and introduce helpers for compiled functions and tensor-product dispatch decisions.
  • Rewrite spherical_harmonics, tensor product, linear, scatter, and new weighted_tensor_product_uvu builders to use the o3 API directly, compiled wrappers, and finer-grained dispatch labels (general-mlx, metal-* kernels, and fallbacks).
  • Replace legacy v2106 convolution/message-passing/network cases with gate_points_2102, v2106_simple_network, and v2106_attributed_network model tasks built on a shared graph constructor that report kernel support scope via dispatch.
  • Adjust BUILDERS order and remove unused build_tasks helper to match the streamlined case set.
evals/mlx_cases.py
evals/common.py
evals/workloads.py
tests/test_evals.py
Redesign the plotting, CSV, and HTML reporting pipeline around three fixed backends and simplified latency/speedup views.
  • Define a fixed BACKENDS tuple (torch-cpu, mlx, mlx-kernel), simplify color mapping, and implement helpers to pick successful rows and derive latency and speedup entries with torch-cpu as the reference.
  • Remove aggregation, kernel-speedup, compile, memory, and scaling-plot logic; simplify horizontal_bars layout, labeling, and value formatting.
  • Extend CSV summaries with dispatch and sort rows deterministically by phase/case/backend.
  • Replace the previous HTML report with a compact table-oriented report that embeds only latency and speedup SVGs and shows selected path, median, compile time, and status per row.
evals/plot_results.py
evals/README.md
tests/test_evals.py
Simplify the Torch benchmark backend to a single CPU-only, eager, multi-threaded worker with updated workloads matching the MLX cases.
  • Drop device selection, compile support, and v2106 microbenchmarks; configure Torch to use all CPU and interop threads and report them in backend metadata.
  • Rework all case builders (spherical harmonics, tensor products, linear, scatter, and model cases) to use CPU tensors, eager-only execution, and the new gate_points_2102/v2106_simple_network/v2106_attributed_network models on fixed graph topology.
  • Align Task construction semantics with the MLX side (no compile_* functions, eager-only forward/train, and a fixed torch-eager dispatch string).
evals/torch_cases.py
evals/workloads.py
tests/test_evals.py
Refactor the backend runner/orchestrator to always run exactly three isolated workers and record actual execution dispatch instead of synthetic backend labels.
  • Change run_backend CLI to backend choices (torch-cpu, mlx, mlx-kernel), remove device/compile/mlx-kernels flags, and compute backend metadata and result rows using a single backend identifier and Task.dispatch.
  • Rename benchmark_mode to _benchmark, infer execution (eager vs compiled) from presence of compiler, and simplify timing metadata to warmup/samples only.
  • Update the top-level run orchestrator to use a WORKERS tuple of the three backends, build worker commands without device/kernel flags, and pass E3NN_MLX_REQUIRE_RUNTIME for MLX workers.
  • Adjust tests to assert the fixed worker set, new CLI semantics, and presence of dispatch in CSV/HTML outputs and model tasks.
evals/run_backend.py
evals/run.py
evals/common.py
tests/test_evals.py
Tighten TensorProduct construction, broadcasting, and weight semantics, and add scalar-path Metal dispatch guards.
  • Enhance make_tensor_product_instructions to track original irreps, remap indices after zero-multiplicity removal, allow variance lists for either original or compact irreps, forbid mode 'uvw' without weights, and reject instructions referencing zero-multiplicity irreps.
  • In _numerical_tensor_product, enforce weight dtype equality, treat rank-1 weights as shared, broadcast unshared weights across leading dimensions only when compatible, and always accumulate per-instruction contributions directly into output blocks instead of concatenating separately for the unweighted case.
  • Expose a _metal_dispatch_kind helper on TensorProduct to gate scalar-path kernels by both batch size and total work (path_count * batch), and reuse it from _try_metal.
  • Validate unshared weight rank and trailing dimension in _get_weight, and improve error messaging paths.
e3nn_core/instructions.py
e3nn_mlx/ops_tp.py
tests/test_metal_kernels.py
tests/test_tensor_product.py
tests/test_p0_equivariance.py
tests/test_tensor_product_correctness.py
tests/test_tensor_product_compatibility_qualification.py
docs/guide/tensor_products.md
docs/COMPATIBILITY.md
docs/guide/performance.md
docs/guide/index.md
docs/HIGH_LEVEL_API.md
tests/test_documentation_contract.py
Fix Linear default path ordering and grouped external-weight execution to match upstream semantics and preserve VJPs.
  • Change default Linear instruction enumeration to be input-major then output index (matching upstream), and rework grouped weight application to build the full block matrix via path-wise block accumulation rather than relying on flat offsets.
  • Add tests that check default instruction order against upstream, derive the grouped external-weight gradient formula via explicit einsum, and assert MLX matches it.
  • Document Linear path order, weight layout, and grouped-gradient guarantees in the migration, high-level API, linear guide, and compatibility docs, and link new tests into the documentation contract matrix.
e3nn_mlx/nn_linear.py
tests/test_upstream_o3_linear_norm.py
docs/guide/linear.md
docs/HIGH_LEVEL_API.md
docs/COMPATIBILITY.md
docs/guide/migration.md
docs/UPSTREAM_O3_TEST_MATRIX.md
tests/test_documentation_contract.py
Extend Metal kernel tests to cover new channel_uvu kernels, scalar-path dispatch boundaries, dtype/rank fallbacks, and stable repeated derivatives.
  • Add a helper to build a channel_uvu TensorProduct and tests that compare its forward, VJP, JVP (via differentiable_arrays), and second-order mixed derivatives to the general path within tolerances.
  • Test that repeated VJP evaluations are numerically stable, that scalar-path kernels respect both batch and work guards, that rank/dtype mismatches fall back to general MLX but preserve outputs, and that mixed-weight ownership configurations bypass custom kernels entirely while matching general results.
  • Update the performance guide and documentation contract to reference the new dispatch and work-guard behavior.
tests/test_metal_kernels.py
docs/guide/performance.md
tests/test_documentation_contract.py
Introduce seeded cross-framework randomized parity harnesses and tests for tensor products and core operations.
  • Add randomized_tensor_product_parity with a seeded TensorProduct case generator that covers all modes, layouts, and weight semantics, plus isolated Torch/MLX workers and a comparison/reporting pipeline that emits JSON, Markdown, and per-case failure fixtures.
  • Add randomized_core_parity and randomized_operation_parity harnesses that generate cases for Wigner coefficients, rotations, SH, Linear, Gate, Norm, BatchNorm, radial functions, scatter, tensor-product wrappers, and spherical activations, and compare forward outputs and VJPs against upstream Torch/e3nn.
  • Add README-style docs describing these harnesses, wire their guarantees into the documentation contract, and add tests that assert generation reproducibility, structural breadth, finite replayable values, and successful MLX execution across all variants.
evals/randomized_tensor_product_parity.py
evals/randomized_core_parity.py
evals/randomized_operation_parity.py
evals/RANDOMIZED_PARITY.md
evals/RANDOMIZED_OPERATION_PARITY.md
tests/test_randomized_tensor_product_parity_harness.py
tests/test_randomized_operation_parity_harness.py
tests/test_randomized_core_parity_harness.py
tests/test_documentation_contract.py
Refresh top-level docs and changelog to describe the new benchmark, kernels, and parity guarantees.
  • Add an Unreleased section to the changelog summarizing tensor-product/Linear fixes, randomized parity harnesses, evaluation refactor, and Metal dispatch guards.
  • Update README and performance guide to reference the new compact three-way evaluation, kernel limitations, and operation-level parity docs instead of the removed kernel evaluation guide.
  • Adjust documentation contract tests to assert the presence of new statements and anchors across the updated guides.
CHANGELOG.md
README.md
docs/guide/performance.md
evals/README.md
tests/test_documentation_contract.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
tests/test_metal_kernels.py (1)

214-221: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Matching on an MLX-internal error message is brittle.

"Not implemented for CustomKernel" is MLX's own wording for the missing JVP rule, not this project's contract, so an upstream rewording breaks the test for reasons unrelated to e3nn_mlx. Consider asserting only the exception type, or relaxing the pattern to a stable fragment such as "CustomKernel".

♻️ Suggested relaxation
-    with pytest.raises(ValueError, match="Not implemented for CustomKernel"):
+    with pytest.raises(ValueError, match="CustomKernel"):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_metal_kernels.py` around lines 214 - 221, Relax the ValueError
assertion in the mx.jvp test around apply so it does not depend on MLX’s exact
internal message wording. Assert only ValueError, or match the stable
“CustomKernel” fragment while preserving the test’s validation of the
unsupported JVP behavior.
tests/test_tensor_product_compatibility_qualification.py (1)

278-304: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This test can pass vacuously.

record_broadcast only records when array is shared_weight. If MLX ever returns a distinct array object from product.weight, the identity check never fires and materialized_shapes == [] holds regardless of whether the weight was materialized per item — silently losing the performance contract being guarded. Consider matching on shape instead (any broadcast whose trailing dim is weight_numel), and/or asserting the recorder observed at least one call so the hook is proven live.

♻️ Suggested strengthening
     materialized_shapes = []
+    all_broadcasts = []
     original_broadcast_to = mx.broadcast_to
 
     def record_broadcast(array, shape, *args, **kwargs):
-        if array is shared_weight:
+        all_broadcasts.append(tuple(shape))
+        if tuple(shape)[-1:] == (product.weight_numel,) and len(shape) > 1:
             materialized_shapes.append(tuple(shape))
         return original_broadcast_to(array, shape, *args, **kwargs)
 
     monkeypatch.setattr(mx, "broadcast_to", record_broadcast)
     output = product(left, right)
     mx.eval(output.array)
 
     assert output.shape == (8, product.irreps_out.dim)
     assert materialized_shapes == []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_tensor_product_compatibility_qualification.py` around lines 278 -
304, Strengthen test_shared_tensor_product_weights_are_not_materialized_per_item
so the broadcast recorder cannot pass vacuously when product.weight is
represented by a different array object. Match relevant broadcasts using the
shared weight shape or trailing weight_numel dimension, and assert the recorder
observed the expected hook activity before verifying that no per-item
materialization occurred.
tests/test_upstream_o3_linear_norm.py (1)

156-196: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a sparse-group case to cover the zero-block branch.

With 3x2e + 3x3e + 2x2e3x2e + 3x3e + 3x2e and default instructions, the 2e group has all four (input, output) pairs present, so the new mx.zeros(...) fallback in nn_linear.py (lines 294-302) is never taken. That branch is exactly where a wrong block shape or ordering would silently corrupt the assembled matrix. Passing explicit instructions that omit one pair within the 2e group (e.g. [(0, 0), (1, 1), (2, 2)]) would exercise it alongside this VJP formula.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_upstream_o3_linear_norm.py` around lines 156 - 196, Update
test_grouped_linear_external_weight_vjp_matches_blockwise_formula to pass
explicit instructions omitting one 2e input/output pair, such as the diagonal
pairs (0, 0), (1, 1), and (2, 2), when constructing o3.Linear. Keep the existing
VJP-versus-blockwise gradient assertions unchanged so the test exercises the
zero-block fallback while preserving the formula coverage.
tests/test_randomized_tensor_product_parity_harness.py (1)

77-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Select the perturbed variant by its kernel flag instead of index == 2.

MLX_VARIANTS entries are (name, compile_left_right, use_custom_kernel); keying off position 2 breaks whenever the variant list is reordered or extended.

♻️ Proposed tweak
-    for index, (name, _, _) in enumerate(MLX_VARIANTS):
+    for name, _compile, use_custom_kernel in MLX_VARIANTS:
         output = reference.copy()
-        if index == 2:
+        if use_custom_kernel:
             output[0, 0] += 0.1
         variants.append(
             {
                 "name": name,
                 "status": "ok",
                 "shape": [1, 2],
                 "output": output.tolist(),
-                "custom_eligible": index == 2,
-                "kernel_kind": "scalar_paths" if index == 2 else None,
+                "custom_eligible": use_custom_kernel,
+                "kernel_kind": "scalar_paths" if use_custom_kernel else None,
             }
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_randomized_tensor_product_parity_harness.py` around lines 77 - 90,
Update the variant-generation loop to select the perturbed and custom-kernel
variant using each MLX_VARIANTS entry’s use_custom_kernel flag rather than index
== 2. Unpack the tuple accordingly and derive both custom_eligible and
kernel_kind from that flag, preserving the existing scalar_paths and default
behavior.
evals/torch_cases.py (2)

144-144: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Ruff flags these lambda assignments as E731 errors; convert to def.

Same pattern at Lines 144, 215, 307, 339, 385. Ruff also reports the unpacked-but-unused torch at Lines 270, 318, 350 (RUF059) — use _torch or _, o3 = _imports() there.

♻️ Example
-    forward = lambda: module(left, right)
+    def forward():
+        return module(left, right)

Also applies to: 215-215, 307-307, 339-339, 385-385

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@evals/torch_cases.py` at line 144, Replace the lambda assignments at the
`forward` definitions on lines 144, 215, 307, 339, and 385 with local `def`
functions preserving each callable’s arguments and behavior. In the affected
cases at lines 270, 318, and 350, rename the unused unpacked `torch` binding to
`_torch` or discard it with `_` while retaining the `o3` value.

Source: Linters/SAST tools


300-300: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Global monkeypatch of model_module.radius_graph leaks across builders.

Each builder permanently rebinds the attribute on the imported upstream module with a closure over its edge_index. It works only because run_backend.main constructs and benchmarks one case at a time; any future change that builds all tasks up front (or reuses a task after a later build) would silently benchmark the wrong topology. Consider patching within a context manager around the measured calls, or passing precomputed edges via the data dict where the upstream API allows it.

Also applies to: 337-337

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@evals/torch_cases.py` at line 300, Replace the permanent assignments to
model_module.radius_graph in each builder with scoped patching that is active
only during that builder’s measured model calls, then restores the original
function afterward. Ensure closures use the current builder’s edge_index and
cannot affect later builders or reused tasks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@evals/mlx_cases.py`:
- Around line 126-134: The dispatch labels in evals/mlx_cases.py at lines
126-134 and 303-305 must reflect runtime kernel eligibility, not
_USE_CUSTOM_KERNELS alone. Update the spherical-harmonics label near the
dispatch expression to also require the same Metal availability conditions used
by ops_sh.spherical_harmonics, and update the scatter-sum label to require the
scatter kernel’s actual eligibility/availability; otherwise retain the existing
fallback labels.

In `@evals/randomized_core_parity.py`:
- Around line 890-913: Pass the use_custom_kernel value through the TensorSquare
construction in the wrapper branch, ensuring the inherited _try_metal probe and
_metal_kernel_kind metadata use the requested custom-kernel setting rather than
the constructor default.

In `@tests/test_documentation_contract.py`:
- Around line 282-341: Update the DOCUMENTED_SOURCE_CONTRACTS entries in
test_documentation_contract.py so every quoted excerpt exactly matches the
current wording and punctuation in its referenced documentation file. Inspect
the corresponding sections of tensor_products.md, linear.md, performance.md, and
evals/README.md, then replace only the stale literal substrings while preserving
each associated test reference and contract intent.

---

Nitpick comments:
In `@evals/torch_cases.py`:
- Line 144: Replace the lambda assignments at the `forward` definitions on lines
144, 215, 307, 339, and 385 with local `def` functions preserving each
callable’s arguments and behavior. In the affected cases at lines 270, 318, and
350, rename the unused unpacked `torch` binding to `_torch` or discard it with
`_` while retaining the `o3` value.
- Line 300: Replace the permanent assignments to model_module.radius_graph in
each builder with scoped patching that is active only during that builder’s
measured model calls, then restores the original function afterward. Ensure
closures use the current builder’s edge_index and cannot affect later builders
or reused tasks.

In `@tests/test_metal_kernels.py`:
- Around line 214-221: Relax the ValueError assertion in the mx.jvp test around
apply so it does not depend on MLX’s exact internal message wording. Assert only
ValueError, or match the stable “CustomKernel” fragment while preserving the
test’s validation of the unsupported JVP behavior.

In `@tests/test_randomized_tensor_product_parity_harness.py`:
- Around line 77-90: Update the variant-generation loop to select the perturbed
and custom-kernel variant using each MLX_VARIANTS entry’s use_custom_kernel flag
rather than index == 2. Unpack the tuple accordingly and derive both
custom_eligible and kernel_kind from that flag, preserving the existing
scalar_paths and default behavior.

In `@tests/test_tensor_product_compatibility_qualification.py`:
- Around line 278-304: Strengthen
test_shared_tensor_product_weights_are_not_materialized_per_item so the
broadcast recorder cannot pass vacuously when product.weight is represented by a
different array object. Match relevant broadcasts using the shared weight shape
or trailing weight_numel dimension, and assert the recorder observed the
expected hook activity before verifying that no per-item materialization
occurred.

In `@tests/test_upstream_o3_linear_norm.py`:
- Around line 156-196: Update
test_grouped_linear_external_weight_vjp_matches_blockwise_formula to pass
explicit instructions omitting one 2e input/output pair, such as the diagonal
pairs (0, 0), (1, 1), and (2, 2), when constructing o3.Linear. Keep the existing
VJP-versus-blockwise gradient assertions unchanged so the test exercises the
zero-block fallback while preserving the formula coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e4e964ac-cb61-4a61-9528-77e89bf0330d

📥 Commits

Reviewing files that changed from the base of the PR and between 007b6f6 and 9b312e2.

📒 Files selected for processing (39)
  • CHANGELOG.md
  • README.md
  • docs/COMPATIBILITY.md
  • docs/HIGH_LEVEL_API.md
  • docs/UPSTREAM_O3_TEST_MATRIX.md
  • docs/guide/index.md
  • docs/guide/linear.md
  • docs/guide/migration.md
  • docs/guide/performance.md
  • docs/guide/tensor_products.md
  • e3nn_core/instructions.py
  • e3nn_mlx/nn_linear.py
  • e3nn_mlx/ops_tp.py
  • evals/KERNEL_EVALUATION.md
  • evals/OPTIMIZATION_REPORT.md
  • evals/RANDOMIZED_OPERATION_PARITY.md
  • evals/RANDOMIZED_PARITY.md
  • evals/README.md
  • evals/common.py
  • evals/mlx_cases.py
  • evals/plot_results.py
  • evals/randomized_core_parity.py
  • evals/randomized_operation_parity.py
  • evals/randomized_tensor_product_parity.py
  • evals/run.py
  • evals/run_backend.py
  • evals/torch_cases.py
  • evals/workloads.py
  • tests/test_documentation_contract.py
  • tests/test_evals.py
  • tests/test_metal_kernels.py
  • tests/test_p0_equivariance.py
  • tests/test_randomized_core_parity_harness.py
  • tests/test_randomized_operation_parity_harness.py
  • tests/test_randomized_tensor_product_parity_harness.py
  • tests/test_tensor_product.py
  • tests/test_tensor_product_compatibility_qualification.py
  • tests/test_tensor_product_correctness.py
  • tests/test_upstream_o3_linear_norm.py
💤 Files with no reviewable changes (2)
  • evals/KERNEL_EVALUATION.md
  • evals/OPTIMIZATION_REPORT.md

Comment thread evals/mlx_cases.py
Comment thread evals/randomized_core_parity.py
Comment on lines +282 to +341
(
"docs/guide/tensor_products.md",
"Shared weights remain one-dimensional during execution.",
"tests/test_tensor_product_compatibility_qualification.py::test_shared_tensor_product_weights_are_not_materialized_per_item",
),
(
"docs/guide/tensor_products.md",
"Scalar-path kernel selection considers both the static contraction size and the batch size.",
"tests/test_metal_kernels.py::test_dense_scalar_tensor_product_dispatch_uses_work_guard",
),
(
"docs/guide/tensor_products.md",
"Both paths implement the same contraction and normalization conventions.",
"tests/test_tensor_product_correctness.py::test_optimized_full_tensor_product_matches_fallback_outputs_and_gradients",
),
(
"docs/guide/linear.md",
"Without explicit instructions, `Linear` enumerates compatible paths in input-major, then output-index order, matching upstream e3nn.",
"tests/test_upstream_o3_linear_norm.py::test_linear_default_weight_paths_follow_upstream_input_major_order",
),
(
"docs/guide/linear.md",
"The grouped execution path preserves derivatives with respect to external weights, including repeated input and output irrep blocks.",
"tests/test_upstream_o3_linear_norm.py::test_grouped_linear_external_weight_vjp_matches_blockwise_formula",
),
(
"docs/COMPATIBILITY.md",
"Mode `uvw` always requires weights",
"tests/test_tensor_product_compatibility_qualification.py::test_constructor_rejects_upstream_invalid_uvw_and_static_configurations",
),
(
"docs/guide/equivariance.md",
"actual = layer(x @ D_in.T)",
"tests/test_documentation_contract.py::test_documented_linear_and_gate_examples_are_equivariant",
),
(
"docs/guide/performance.md",
"The repository's `evals/` harness does this consistently across MLX, PyTorch CPU, and PyTorch MPS.",
"The repository's `evals/` harness does this consistently across Torch CPU, general MLX, and kernel-enabled MLX.",
"tests/test_documentation_contract.py::test_documentation_metadata_workflow_and_timing_contracts",
),
(
"docs/guide/performance.md",
"Disabling a kernel changes execution, not the mathematical operation.",
"tests/test_metal_kernels.py::test_spherical_harmonics_kernel_matches_general_forward_gradient_and_hessian",
),
(
"docs/guide/performance.md",
"Dense shared-weight tensor products deliberately keep their parameter vector compact.",
"tests/test_tensor_product_compatibility_qualification.py::test_shared_tensor_product_weights_are_not_materialized_per_item",
),
(
"docs/guide/performance.md",
"The shipped `gate_points_2102` model currently has no model-level kernel toggle",
"tests/test_evals.py::test_model_benchmarks_report_kernel_scope",
),
(
"evals/README.md",
"Every result row also records the selected execution path.",
"tests/test_evals.py::test_mlx_benchmark_reports_actual_tensor_product_dispatch",
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'Shared weights remain one-dimensional during execution.' docs/guide/tensor_products.md
rg -n 'Scalar-path kernel selection considers both the static contraction size and the batch size.' docs/guide/tensor_products.md
rg -n 'Both paths implement the same contraction and normalization conventions.' docs/guide/tensor_products.md
rg -n 'Without explicit instructions, .Linear. enumerates compatible paths in input-major' docs/guide/linear.md
rg -n 'The grouped execution path preserves derivatives with respect to external weights' docs/guide/linear.md
rg -n "The repository's .evals/. harness does this consistently across Torch CPU" docs/guide/performance.md
rg -n 'Dense shared-weight tensor products deliberately keep their parameter vector compact.' docs/guide/performance.md
rg -n 'The shipped .gate_points_2102. model currently has no model-level kernel toggle' docs/guide/performance.md
rg -n 'Every result row also records the selected execution path.' evals/README.md

Repository: lamalab-org/e3nn_mlx

Length of output: 317


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact referenced lines plus surrounding context.
printf 'docs/guide/tensor_products.md lines 65-80 and 108-124:\n'
sed -n '65,80p;108,124p' docs/guide/tensor_products.md

printf '\nSearch exact quoted excerpts (Python literal compare):\n'
python3 - <<'PY'
from pathlib import Path
target_refs = [
    ("docs/guide/tensor_products.md", "Shared weights remain one-dimensional during execution."),
    ("docs/guide/tensor_products.md", "Scalar-path kernel selection considers both the static contraction size and the batch size."),
    ("docs/guide/tensor_products.md", "Both paths implement the same contraction and normalization conventions."),
    ("docs/guide/linear.md", "Without explicit instructions, `Linear` enumerates compatible paths in input-major, then output-index order, matching upstream e3nn."),
    ("docs/guide/linear.md", "The grouped execution path preserves derivatives with respect to external weights, including repeated input and output irrep blocks."),
    ("docs/guide/performance.md", "The repository's `evals/` harness does this consistently across Torch CPU, general MLX, and kernel-enabled MLX."),
    ("docs/guide/performance.md", "Disabling a kernel changes execution, not the mathematical operation."),
    ("docs/guide/performance.md", "Dense shared-weight tensor products deliberately keep their parameter vector compact."),
    ("docs/guide/performance.md", "The shipped `gate_points_2102` model currently has no model-level kernel toggle"),
    ("evals/README.md", "Every result row also records the selected execution path."),
]
for path, excerpt in target_refs:
    text = Path(path).read_text()
    print(f"{path}:{path}:{excerpt!r}: FOUND" if excerpt in text else f"{path}:{path}:{excerpt!r}: MISSING")
PY

Repository: lamalab-org/e3nn_mlx

Length of output: 2517


Fix the verbatim documentation contract excerpts.

DOCUMENTED_SOURCE_CONTRACTS currently contains literal substrings that do not exist in the referenced docs, so the test will fail under the exact-substring contract. For example, docs/guide/tensor_products.md only contains Shared weights remain one-dimensional during execution. before mentioning MLX broadcasting; several docs/guide/linear.md, docs/guide/performance.md, and evals/README.md quoted excerpts also need to match the actual wording/punctuation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_documentation_contract.py` around lines 282 - 341, Update the
DOCUMENTED_SOURCE_CONTRACTS entries in test_documentation_contract.py so every
quoted excerpt exactly matches the current wording and punctuation in its
referenced documentation file. Inspect the corresponding sections of
tensor_products.md, linear.md, performance.md, and evals/README.md, then replace
only the stale literal substrings while preserving each associated test
reference and contract intent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant