Skip to content

Add MultiModalSymplecticAutoencoder, multimodal losses, and HRedSys reference shift and VJP - #370

Merged
michakraus merged 8 commits into
mainfrom
multimodal-symplectic-ae/part-f
Oct 30, 2026
Merged

michakraus merged 8 commits into
mainfrom
multimodal-symplectic-ae/part-f

Conversation

@michakraus

@michakraus michakraus commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

Implements Part F of the multi-modal symplectic autoencoders plan in GeometricMachineLearning:

  • MultiModalSymplecticAutoencoder, encode, decode, and translate:
    • MultiModalSymplecticAutoencoder(frontends::NamedTuple, core::SymplecticCompression) <: SymplecticCompression combines a non-empty NamedTuple of modality frontends (individual layers or Chains of symplectic particle layers) whose canonical output dimension 2n_m matches core.full_dim with a shared SymplecticCompression core (SymplecticAutoencoder, WeightTiedSymplecticAutoencoder, or SymmetricSymplecticAutoencoder).
    • encode(nn, modality, x) (with modality a Symbol or Val(modality)) applies frontends[modality] followed by encoder(core), decode(nn, modality, ξ) applies decoder(core) followed by inverse_layer(frontends[modality]), and translate(nn, from, to, x) computes decode(nn, to, encode(nn, from, x)).
    • ChainRulesCore.rrule methods for encode and decode (each for a Symbol and a Val modality) differentiate the active frontend and the core with rrule_via_ad and give zero tangents for the other frontends, so Zygote.gradient with respect to network parameters works across all modalities, Chain frontends included.
  • Multi-modal training losses (CharbonnierRelativeLoss, IsometricRolloutLoss, CrossModalCycleLoss):
    • CharbonnierRelativeLoss(; ε = 1e-3, λ_lat = 1e-2) evaluates the exact-zero Charbonnier relative reconstruction loss plus latent consistency penalty, dispatching low-rank (X, S, V) inputs through FastDLRATraceLoss without forming dense Nx × Nv arrays.
    • IsometricRolloutLoss(integrator; α_lat = 1.0, α_rec = 1.0, α_H = 0.1, H = nothing) evaluates multi-step latent rollout error, decoded trajectory error, and latent Hamiltonian conservation penalty.
    • CrossModalCycleLoss(mod_a, mod_b; β_align = 1.0, β_cycle = 0.1) evaluates paired latent alignment plus cross-modal cycle consistency.
  • HRedSys reference-state shifting, :vjp pullback mode, and preallocated buffers:
    • Extends HRedSys, build_v_reduced, and build_f_reduced with optional reference states q_ref and p_ref (converted to Vector{eltype(ics.q)}) and pullback_mode::Symbol = :jacobian | :vjp.
    • :vjp evaluates $(\nabla_\xi \Psi^{\mathrm{dec}}(\xi))^T \mathbb{J}_{2N}^T [v(z); f(z)]$ in a single reverse-mode pullback Zygote.pullback(decoder, ξ) and falls back to ForwardDiff.jacobian! when state vectors carry ForwardDiff.Dual elements during implicit integrator Newton iterations.
    • Preallocates work buffers (ξ_buf, v_intermediate, f_intermediate, z_bar_buf, jac_result) and a per-element-type IdDict{DataType, Any} cache (ReducedVFCache) for ForwardDiff.Dual evaluations.

Pre-PR verification

Fixed in this pass

# point file:line what was wrong what changed
— — — none —

Unresolved

# point file:line claim evidence
— — — none —

Pre-existing, adjacent

# severity file:line claim evidence

Checked and clean

  • 1 · correctness, quality, concision: run-tests.jl passed 645 of 645 across the six files (test/reduced_system/reference_shift_and_vjp.jl, test/reduced_system/reduced_system.jl, test/architectures/multimodal_symplectic_autoencoder.jl, test/quality/aqua.jl, test/quality/exports.jl, test/quality/reachability.jl), from one run of run-tests.jl on Julia 1.13.3. JuliaFormatter (style = "sciml") and fatou lint are clean on the changed source files, and test-layout.jl --check reports no violation. Two mutants are caught by test/reduced_system/reference_shift_and_vjp.jl: evaluate_vf_and_compute_∇Ψ returning its cache buffers instead of copies, and a floating-point state of another element type than the cache's taking the per-type cache instead of raising an ArgumentError. A one-sided _add_ref! that shifts the wrong component is caught by the same file, and the original _check_eltype (which promoted the components of a mixed state) is caught by test/architectures/multimodal_symplectic_autoencoder.jl.
  • 2 · functionality duplicated from dependencies: The code reuses FastDLRATraceLoss, tensor_transpose_tensor_mul, tensor_tensor_mul, inverse_layer, DiffResults.JacobianResult, ForwardDiff.jacobian!, and Zygote.pullback.
  • 3 · type piracy: The Aqua checks and the ExplicitImports checks of test/quality/aqua.jl pass (17/17).
  • 4 · type instability: The test files assert @inferred for encode, decode, translate, and the three losses in Float32 and Float64. Base.return_types of evaluate_vf_and_compute_∇Ψ is concrete for Float64 and for ForwardDiff.Dual input.
  • 5 · avoidable allocations: One warm call of v_reduced with 2n = 4 allocates, as the minimum of 5 calls, in two fresh processes with --check-bounds=auto on Julia 1.13.3: 4448 / 8160 / 29728 bytes with :jacobian and 27968 / 29376 / 37248 bytes with :vjp, at 2N = 12 / 40 / 200. The allocations grow with N. evaluate_vf_and_compute_∇Ψ returns copies of its cache buffers, so that no caller holds memory of the cache. The batched _frob_sq_norm allocates 316.01 MiB before and 3.01 MiB after for Float32 with Nx = Nv = 10000, rank 32 and 128 slices (minimum of 7 warm calls, fresh process, --check-bounds=auto, Julia 1.13.3).
  • 6 · stale comments, present tense: No added line in src/, test/, or docs/src/ matches previously, originally, no longer, used to, now , or formerly.
  • 7 · history only in CHANGELOG.md: The same search finds no historical phrase; the CHANGELOG.md entry is under ## [Unreleased].

Not checked

  • No Documenter build and no run on Julia 1.12 in the local checks (CI covers both); no full Pkg.test(); no mutant for the batched _frob_sq_norm copy change, whose test checks value, gradient and non-mutation.

Release: minor bump — adds MultiModalSymplecticAutoencoder, encode, decode, translate, CharbonnierRelativeLoss, IsometricRolloutLoss, CrossModalCycleLoss, and HRedSys reference-state shifting and :vjp pullback support prior to 1.0.

Critic

The builder-critic loop passed a436a12 (Round: verify 3 on 7f21517..a436a12, base 9ef9680). The review of this pull request and the fix commits after it changed the code. The table gives the state of each earlier defect at this head.

Earlier defects

# defect status at this head evidence
B1 (R1) Zygote.gradient with respect to network parameters failed on MultiModalSymplecticAutoencoder when any frontend was a Chain, and CharbonnierRelativeLoss, IsometricRolloutLoss, and CrossModalCycleLoss accepted only NeuralNetwork and failed under Zygote.gradient(ps -> loss(nn.architecture, ps, ...), nn.params) fixed encode and decode on a MultiModalSymplecticLayer have ChainRulesCore.rrule methods that differentiate the active frontend and the core with rrule_via_ad and give zero tangents for the other frontends. The three losses have methods for (model, ps::NamedTuple, ...). The testset "Analytical Zygote gradients match central finite differences in Float64" and the Chain-frontend testset of test/architectures/multimodal_symplectic_autoencoder.jl pass.
B2 (R1) HRedSys did not convert q_ref and p_ref to the state element type eltype(ics.q) fixed The HRedSys constructor converts with Vector{T_state}(q_ref) and Vector{T_state}(p_ref). test/reduced_system/reference_shift_and_vjp.jl checks that Float64 references give Float32 fields for Float32 states.
B3 (R1) HRedSys allocation test in test/reduced_system/reference_shift_and_vjp.jl ran inside @safetestset rather than in a cold julia --startup-file=no --check-bounds=yes subprocess not at this head Neither new test file has an allocation test. The figures in "Checked and clean" come from a separate cold script.
B1 (verify 1) MultiModalSymplecticAutoencoder used ChainRulesCore.@non_differentiable _core_layer_keys(Any) and @non_differentiable _frontend_inverse_layer(Any), violating the spec's ban on custom ChainRules rules not at this head src/architectures/multimodal_symplectic_autoencoder.jl has four ChainRulesCore.rrule methods (encode and decode, each for a Symbol and a Val modality) and one @non_differentiable (_check_modality). src/loss/multimodal_losses.jl has two @non_differentiable (_check_traj_len and _check_eltype).

Known issues added

K40, K41

Decisions taken without the user

  • Decided (arbitrator, 2026-10-30, high): Replace the ad-hoc _apply_frontend(fe::Chain, ...) pre-flattening and runtime keys(ps_core)[1:M] slicing with compositional helper functions that preserve Chain's nested parameter NamedTuple structure and split MultiModalSymplecticAutoencoder encoder/decoder parameter NamedTuple keys via Val(M) and Base.structdiff, so that Zygote reverse-mode AD produces well-typed non-nothing parameter cotangents for Chain frontends and all three loss types on both NamedTuple and NeuralNetwork wrappers without custom ChainRulesCore.@non_differentiable rules.
  • Decided (arbitrator, 2026-10-26): The direct (I - A)\(I + A) Cayley retraction and its analytical differential and pullback are implemented for AbstractMatrix and AbstractVecOrMat via standard lu(I - A) without scalar indexing. On CPU arrays, this runs natively without fallback. On GPU arrays whose backend does not support batch-less lu(I - A) or where a caller prefers the series, the retraction dispatches or falls back to the truncated Neumann series. Because the Vlasov–Poisson training uses small reduced Stiefel dimensions ($n \le 32$, $m_x, m_v \le 16$), Stiefel retraction steps run on CPU or small device matrices where lu is fast.
  • Decided (arbitrator, 2026-10-26; user, 2026-10-26): Each part adds its own new test file(s) and includes them in test/runtests.jl, and runs only the new and directly touched test files during the builder-critic loop.
  • Unmet clauses: none

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fcbb4554-cd54-452b-bcaf-d0ed385e448d
Commits

Reviewing files that changed from the base of the PR and between 775e13f and 1dd2238.

Files selected for processing: 4
  • src/architectures/multimodal_symplectic_autoencoder.jl
  • src/reduced_system/reduced_system.jl
  • test/architectures/multimodal_symplectic_autoencoder.jl
  • test/reduced_system/reference_shift_and_vjp.jl
Files skipped from review as they are similar to previous changes: 2
  • test/architectures/multimodal_symplectic_autoencoder.jl
  • src/architectures/multimodal_symplectic_autoencoder.jl

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Summary

Summary by CodeRabbit

  • New Features
    • Added multimodal symplectic autoencoders with encode, decode, and translate operations across modalities.
    • Added reconstruction, rollout, and cross-modal cycle losses for training and evaluation.
    • Reduced-system modeling now supports reference-state shifts in encoding, decoding, and reduced evaluations, with selectable Jacobian or VJP pullbacks.
  • Documentation
    • Expanded library documentation to cover multimodal autoencoder operations and losses, and updated the changelog to reflect these additions.

The pull request adds a multimodal symplectic autoencoder with modality-specific operations and three losses. It also extends HRedSys with reference-state shifts, Jacobian and VJP pullback modes, and reusable typed caches.

Changes: Multimodal symplectic compression

Layer / File(s) Summary
Architecture contract and construction
src/architectures/multimodal_symplectic_autoencoder.jl, src/GeometricMachineLearning.jl, docs/src/architectures/symplectic_autoencoder.md, test/architectures/multimodal_symplectic_autoencoder.jl
Adds the multimodal architecture, validates frontends against the shared core, initializes frontend and core paths, and exports and documents the API.
Modality operations and gradients
src/architectures/multimodal_symplectic_autoencoder.jl, test/architectures/multimodal_symplectic_autoencoder.jl
Adds modality-specific encode, decode, and translate operations. Tests cover frontend and core combinations, round trips, batched inputs, and gradient behavior.
Multimodal losses and validation
src/loss/multimodal_losses.jl, docs/src/reduced_order_modeling/losses.md, test/architectures/multimodal_symplectic_autoencoder.jl, test/runtests.jl
Adds CharbonnierRelativeLoss, IsometricRolloutLoss, and CrossModalCycleLoss, with tests for loss values, invalid inputs, and gradients.

Reduced-system reference shifts and pullbacks

Layer / File(s) Summary
Reference state and cache setup
src/reduced_system/reduced_system.jl, test/reduced_system/reference_shift_and_vjp.jl
Adds reference and pullback options to HRedSys constructors, validates reference dimensions and pullback modes, and stores reusable work buffers and typed caches.
Reduced-field pullback paths
src/reduced_system/reduced_system.jl, test/reduced_system/reference_shift_and_vjp.jl
Updates reduced-field builders to apply reference offsets and select Jacobian or VJP evaluation. Tests compare pullback results and check cache behavior.
Reference-aware encoding and integration
src/reduced_system/reduced_system.jl, test/reduced_system/reference_shift_and_vjp.jl
Adds reference-aware encode and decode methods and uses them in integration and error calculations. Tests cover shifted equilibria, Hamiltonians, and element-type conversion.
Change records and test registration
CHANGELOG.md, KNOWN_ISSUES.md, test/runtests.jl
Records the new multimodal and reduced-system APIs. The known-issue entry describes HRedSys cache-related fields and pullback_mode that source code does not read.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

Translation between modalities

sequenceDiagram
  participant SourceFrontend
  participant CoreEncoder
  participant CoreDecoder
  participant DestinationInverseFrontend
  SourceFrontend->>CoreEncoder: encode source modality
  CoreEncoder->>CoreDecoder: produce latent representation
  CoreDecoder->>DestinationInverseFrontend: decode destination modality
Loading

VJP reduced-field evaluation

sequenceDiagram
  participant HRedSys
  participant ReducedVFCache
  participant Decoder
  participant FullVectorFields
  participant Zygote
  HRedSys->>ReducedVFCache: retrieve typed work buffers
  HRedSys->>Decoder: decode reduced state
  Decoder->>FullVectorFields: evaluate at reference-shifted state
  FullVectorFields->>Zygote: provide vector-field cotangent
  Zygote->>HRedSys: return reduced-coordinate pullback
Loading

Possibly related PRs

Merge Risk: Low · up to 1dd22

Large batched loss evaluations may use avoidable memory, and the cache documentation needs correction. These are bounded follow-ups rather than merge blockers.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely summarizes the three main changes: the multimodal autoencoder, multimodal losses, and HRedSys reference shifting and VJP support.
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.
Description check Passed The pull request description directly and comprehensively describes the multimodal autoencoder, multimodal losses, and HRedSys changes listed in the changeset.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@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


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e5e65a81-75eb-4896-825d-014a5e9c8730
Commits

Reviewing files that changed from the base of the PR and between 9ef9680 and a436a12.

Files selected for processing: 10
  • CHANGELOG.md
  • docs/src/architectures/symplectic_autoencoder.md
  • docs/src/reduced_order_modeling/losses.md
  • src/GeometricMachineLearning.jl
  • src/architectures/multimodal_symplectic_autoencoder.jl
  • src/loss/multimodal_losses.jl
  • src/reduced_system/reduced_system.jl
  • test/architectures/multimodal_symplectic_autoencoder.jl
  • test/reduced_system/reference_shift_and_vjp.jl
  • test/runtests.jl

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread src/loss/multimodal_losses.jl Outdated
modality::Symbol, xs::AbstractVector)
K = length(xs)
_check_traj_len(K)
T = promote_type(_state_eltype(xs[1]), _leaf_eltype(ps.core))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor · Functional Correctness · Quick win

Remove the res::T assertion in IsometricRolloutLoss. It throws a TypeError when the integrator or H changes the element type.

T comes only from xs[1] and ps.core. The accumulators err_lat, err_rec and err_H also take the element type of loss.integrator(z_curr) and of loss.H(z).

Take a Float32 network with a user integrator z -> A * z, where A is a Float64 matrix. Then z_curr is Float64 and res is Float64. The assertion res::T expects Float32 and throws. The same happens when a custom H returns Float64.

CharbonnierRelativeLoss and CrossModalCycleLoss do not have this problem. Their T already includes the element types of the encoded latents.

Return res without the assertion. If you want a concrete accumulator type, derive it from z1, for example promote_type(T, eltype(z1)). The integrator and H can still widen the type.

Proposed fix
-    res::T
+    res

Also applies to: 208-212

sol_full_matrices = data_tensors_from_geometric_solution(sol_full)
sol_reduced_matrices = data_tensors_from_geometric_solution(sol_reduced)
_norm(_diff(rs.decoder(sol_reduced_matrices), sol_full_matrices)) /
_norm(_diff(decode(rs, sol_reduced_matrices), sol_full_matrices)) /

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor · Functional Correctness · Quick win

Supported by static analysis

Script executed:

#!/bin/bash
# Check the layout returned by data_tensors_from_geometric_solution and existing test coverage.
rg -nP -A25 'function\s+data_tensors_from_geometric_solution' src
rg -nP -C3 '\b(reduction_error|projection_error)\s*\(' test

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 1882


Script executed:

#!/bin/bash
set -o pipefail
printf '%s\n' '--- helper and callers ---'
rg -n -F -- 'data_tensors_from_geometric_solution' src test || test "$?" -eq 1
printf '%s\n' '--- error functions and nearby definitions ---'
rg -n -F -- 'function reduction_error' src test || test "$?" -eq 1
rg -n -F -- 'function projection_error' src test || test "$?" -eq 1
sed -n '360,475p' src/reduced_system/reduced_system.jl
printf '%s\n' '--- reference-aware methods ---'
rg -n -F -- 'q_ref' src/reduced_system/reduced_system.jl test/reduced_system || test "$?" -eq 1

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 13179


Script executed:

#!/bin/bash
set -o pipefail
printf '%s\n' '--- reduced-system imports and module context ---'
sed -n '1,115p' src/reduced_system/reduced_system.jl
sed -n '70,100p' src/GeometricMachineLearning.jl
printf '%s\n' '--- dependency declarations ---'
rg -n -C3 -F -- 'GeometricIntegrators' Project.toml Manifest.toml src test || test "$?" -eq 1
printf '%s\n' '--- local dependency/source candidates ---'
rg -n -F -- 'data_tensors_from_geometric_solution' . /tmp/coderabbit-repo-knowledge 2>/dev/null || test "$?" -eq 1

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 13115


Script executed:

#!/bin/bash
set -o pipefail
printf '%s\n' '--- project dependency compatibility ---'
rg -n -C3 -F -- 'ReducedComplexityModeling' Project.toml test/Project.toml
printf '%s\n' '--- local package source candidates ---'
find "${JULIA_DEPOT_PATH:-$HOME/.julia}" -type f -path '*ReducedComplexityModeling*' 2>/dev/null | head -40

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 1416


Web query:

ReducedComplexityModeling 0.4.1 data_tensors_from_geometric_solution

Result:

Sources consulted:
- https://raw.githubusercontent.com/JuliaRegistries/General/master/R/ReducedComplexityModeling/Versions.toml
- https://raw.githubusercontent.com/JuliaRegistries/General/master/R/ReducedComplexityModeling/Package.toml
- GitHub - SciML/ModelOrderReduction.jl: High-level model-order reduction to automate the acceleration of large-scale simulations · GitHub — https://github.com/SciML/ModelOrderReduction.jl
- SciMLDocs/docs/src/highlevels/equation_solvers.md at main · SciML/SciMLDocs · GitHub — https://github.com/SciML/SciMLDocs/blob/main/docs/src/highlevels/equation_solvers.md
- GitHub - MORFEproject/MORFE.jl: Reduced Order Modelling via the Parametrisation Method · GitHub — https://github.com/MORFEproject/MORFE.jl
- …and 41 more

Script executed:

#!/bin/bash
set -o pipefail
tree='bed0ac78af861e0b5ed0d9bf77a871aa4e2d2916'
api="https://api.github.com/repos/JuliaRCM/ReducedComplexityModeling.jl/git/trees/${tree}?recursive=1"
json=$(curl -fsSL "$api")
printf '%s\n' '--- matching paths ---'
printf '%s' "$json" | python3 -c '
import json, sys
data=json.load(sys.stdin)
for item in data.get("tree", []):
    if item.get("type") == "blob":
        print(item["path"])
' | grep -Ei 'loader|solution|data|src' | head -100
printf '%s\n' '--- matching source lines ---'
printf '%s' "$json" | python3 -c '
import json, sys
data=json.load(sys.stdin)
for item in data.get("tree", []):
    if item.get("type") != "blob" or not item["path"].endswith((".jl", ".md")):
        continue
    url="https://raw.githubusercontent.com/JuliaRCM/ReducedComplexityModeling.jl/bed0ac78af861e0b5ed0d9bf77a871aa4e2d2916/"+item["path"]
    import urllib.request
    try:
        text=urllib.request.urlopen(url).read().decode()
    except Exception:
        continue
    if "data_tensors_from_geometric_solution" in text:
        print("PATH", item["path"])
        for i,line in enumerate(text.splitlines(), 1):
            if "data_tensors_from_geometric_solution" in line or (i > 1 and "function data_tensors" in text.splitlines()[i-2]):
                lo=max(1,i-8); hi=min(len(text.splitlines()),i+35)
                for n in range(lo,hi+1):
                    print(f"{n}: {text.splitlines()[n-1]}")
'

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 1032


Script executed:

#!/bin/bash
set -o pipefail
base='https://raw.githubusercontent.com/JuliaRCM/ReducedComplexityModeling.jl/bed0ac78af861e0b5ed0d9bf77a871aa4e2d2916'
for path in src/TrainingData/GeometricData.jl src/TrainingData/TrainingData.jl src/ReducedComplexityModeling.jl src/data_loader/data_loader.jl; do
  printf '\n--- %s ---\n' "$path"
  curl -fsSL "$base/$path" | nl -ba | grep -E -C8 'geometric|solution|tensor|export|StateVariable|q|p' | head -240
done

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 537


Script executed:

#!/bin/bash
set -o pipefail
tree='bed0ac78af861e0b5ed0d9bf77a871aa4e2d2916'
api="https://api.github.com/repos/JuliaRCM/ReducedComplexityModeling.jl/git/trees/${tree}?recursive=1"
python3 - "$api" <<'PY'
import base64, json, subprocess, sys, urllib.request
tree = json.load(urllib.request.urlopen(sys.argv[1]))
base = "https://api.github.com/repos/JuliaRCM/ReducedComplexityModeling.jl/git/blobs/"
for item in tree.get("tree", []):
    path = item.get("path", "")
    if item.get("type") != "blob" or not path.endswith(".jl"):
        continue
    if not any(x in path.lower() for x in ("trainingdata", "data_loader", "reducedcomplexitymodeling")):
        continue
    try:
        blob = json.load(urllib.request.urlopen(base + item["sha"]))
        text = base64.b64decode(blob["content"]).decode()
    except Exception:
        continue
    if any(term in text for term in ("data_tensors_from_geometric_solution", "geometric_solution", "GeometricSolution", "StateVariable")):
        print(f"--- {path} ---")
        lines = text.splitlines()
        for i, line in enumerate(lines, 1):
            if any(term in line for term in ("data_tensors_from_geometric_solution", "geometric_solution", "GeometricSolution", "StateVariable")):
                for n in range(max(1, i - 10), min(len(lines), i + 45) + 1):
                    print(f"{n}: {lines[n-1]}")
                print()
PY

Repository: JuliaGNI/GeometricMachineLearning.jl

Length of output: 41545


Broadcast references over the leading data axis.

data_tensors_from_geometric_solution returns (system dimension, time steps, 1). A vector reference broadcasts against the trailing axis in Julia, so rs.q_ref and rs.p_ref create an unintended third dimension instead of shifting each system component. This makes both error metrics incorrect for non-zero references.

Reshape each reference vector to (N, 1, 1) for tensor inputs, and add a non-zero-reference test for both reduction_error and projection_error.

Suggested fix
 function encode(rs::HRedSys, qp::NamedTuple{(:q, :p)})
-    rs.encoder((q = qp.q .- rs.q_ref, p = qp.p .- rs.p_ref))
+    q_ref = reshape(rs.q_ref, (length(rs.q_ref), ntuple(_ -> 1, ndims(qp.q) - 1)...))
+    p_ref = reshape(rs.p_ref, (length(rs.p_ref), ntuple(_ -> 1, ndims(qp.p) - 1)...))
+    rs.encoder((q = qp.q .- q_ref, p = qp.p .- p_ref))
 end

 function decode(rs::HRedSys, qp̃::NamedTuple{(:q, :p)})
     dec = rs.decoder(qp̃)
-    (q = dec.q .+ rs.q_ref, p = dec.p .+ rs.p_ref)
+    q_ref = reshape(rs.q_ref, (length(rs.q_ref), ntuple(_ -> 1, ndims(dec.q) - 1)...))
+    p_ref = reshape(rs.p_ref, (length(rs.p_ref), ntuple(_ -> 1, ndims(dec.p) - 1)...))
+    (q = dec.q .+ q_ref, p = dec.p .+ p_ref)
 end

@michakraus michakraus left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

JuliaGNI/GeometricMachineLearning.jl PR #370 — Add MultiModalSymplecticAutoencoder, multimodal losses, and HRedSys reference shift and VJP

Verdict: request changes (posted as a comment review, because the PR author is the account that posts it)
Reviewed: a436a12fbf4bcf3f5d6fdb09754d6e555a486f3e
CI: red on every release job because of this diff. Julia 1 (macOS, ubuntu, windows) and Julia min (macOS, windows) each fail with one error in test/quality/aqua.jl:101:

every name reached in GeometricOptimizers is public: Error During Test at .../test/quality/aqua.jl:101
  Expression: check_all_qualified_accesses_are_public(GeometricMachineLearning; ignore = NON_PUBLIC_QUALIFIED) === nothing
  NonPublicQualifiedAccessException
  - `MutableDiffResult` is not public in `DiffResults` but it was imported from `DiffResults` at `.../src/reduced_system/reduced_system.jl:6:29`
Some tests did not pass: 16 passed, 0 failed, 1 errored, 0 broken.

Not from this diff: Julia pre (1.14.0-alpha2) and Julia nightly (1.15.0-DEV.258) fail to precompile GPUCompiler (UndefVarError: libLLVMExtra not defined in LLVM.API; The following 1 package failed to precompile: GPUCompiler). Downgrade fails at julia-downgrade-compat before any test runs (forcedeps check failed: Zygote resolved to 0.7.5 but lower bound is 0.7.0, and the same for ChainRulesCore, NNlib and KernelAbstractions). The same four lines fail the Downgrade job of main at 9ef9680 (run 40950534234). Both Metal jobs and Doctests pass. Julia min ubuntu, Documentation and Scripts were still running when this review was written.

Findings

# severity file:line claim evidence
1 blocker src/reduced_system/reduced_system.jl:6 The field type DiffResults.MutableDiffResult{1, Vector{T}, Tuple{Matrix{T}}} names a non-public type. The ExplicitImports check in test/quality/aqua.jl:101 errors on all five finished release jobs. Simplest fix: make the type a parameter, ReducedVFCache{T, JR} with jac_result::JR, as HRedSys already does with JR. Do not add :MutableDiffResult to NON_PUBLIC_QUALIFIED. The CI lines above. Locally: Base.ispublic(DiffResults, :MutableDiffResult) gives false.
2 bug src/loss/multimodal_losses.jl:9-15 CharbonnierRelativeLoss fails on a batched DLRA input (X, S, V) with 3-D factors. encode and decode accept this input (the test file checks it at lines 564-567). _frob_sq_norm calls transpose on the 3-D X and V. CharbonnierRelativeLoss(; ε = 1e-2, λ_lat = 5e-2)(nn, :dlra, (X = X_b, S = S_b, V = V_b)) with size(X_b) == (6, 2, 3) gives transpose not defined for Array{Float64, 3}. Consider using permutedims for higher-dimensional arrays.
3 bug src/architectures/multimodal_symplectic_autoencoder.jl:135 initializer is a named keyword, so kwargs... never holds it. The frontends get the caller's initializer and the core always gets its own default, without a warning. CodeRabbit's inline comment is right. With the parameter-free frontend CanonicalSortLayer(2, 2): NeuralNetwork(core, CPU(), Float64; initializer = ZeroInitializer()) throws OrthonormalizationFailure, but NeuralNetwork(MultiModalSymplecticAutoencoder((particles = fe,), core), CPU(), Float64; initializer = ZeroInitializer()) builds, and its 24 core leaves are not all zero.
4 quality PR body, sections "Critic" and "Checked and clean" The body describes code that is not at this head. (a) It says git grep "non_differentiable|ChainRules|rrule|frule" over the three source files "returns 0 matches" and that the spec bans custom ChainRules rules. The head defines four ChainRulesCore.rrule methods (multimodal_symplectic_autoencoder.jl:403,439,494,532) and two @non_differentiable (multimodal_symplectic_autoencoder.jl:25, multimodal_losses.jl:185). (b) It names _split_core_params(ps, ::Val{M}), Base.structdiff and _apply_frontend_chain. None of them exists in src/. (c) It cites a cold-subprocess allocation test at test/reduced_system/reference_shift_and_vjp.jl:194-216. Those lines are the end of the ForwardDiff.Dual cache test and the start of an equilibrium test, and the file has no @allocated. (d) It says ExplicitImports is clean, but finding 1 shows that it fails. Either the code breaks the spec that the body cites, or the body is stale. The body must state which one. git grep -n -E "structdiff|_split_core_params|non_differentiable|rrule" a436a12 -- src; read test/reduced_system/reference_shift_and_vjp.jl:176-235.
5 quality PR body; src/reduced_system/reduced_system.jl:1-28,237-253 The body claims "verified size-independent allocations across 2N = 12 and 2N = 40". The claim does not reproduce. The allocations of a warm v_reduced call grow with N, because the decoder pass allocates. Against main, the buffers save about 20-35 % of the bytes. --check-bounds=auto, warm, minimum of 5 calls, 2n = 4, one fresh process each, on a loaded machine. main default: 4736 / 8688 / 31520 B at 2N = 12 / 40 / 200. This head, :jacobian: 3728 / 6304 / 20624 B. This head, :vjp: 27968 / 29376 / 37248 B.
6 quality src/reduced_system/reduced_system.jl:299,314-317,353-356 The docstring offers :vjp as an alternative to :jacobian but does not give its cost. At every measured size, :vjp is one to two orders of magnitude slower per v_reduced call, and v_reduced and f_reduced each run their own decoder pullback. State the trade in the docstring, or show the system size at which :vjp gets ahead. Same script, one run on a loaded machine. :jacobian: 0.74 / 0.89 / 2.83 µs. :vjp: 95 / 101 / 104 µs at 2N = 12 / 40 / 200.
7 quality src/reduced_system/reduced_system.jl:102-103,122-127,170-178 HRedSys gets five buffer fields, the type parameter JR and the field pullback_mode. Nothing in src/ reads them. The cache lives in the v_reduced and f_reduced closures. Only hasfield assertions in the test read the buffer fields. Remove the fields, JR, and the hasfield tests (test/reduced_system/reference_shift_and_vjp.jl:177-182). git grep -e ξ_buf -e jac_result -e dual_cache -e pullback_mode a436a12 -- src test docs: no read access outside the constructor and the tests.
8 quality src/loss/multimodal_losses.jl:192,212 IsometricRolloutLoss asserts res::T with T taken only from xs[1] and ps.core. A Float32 network with an integrator or H that returns Float64 throws TypeError. CodeRabbit's inline comment is right. Promote T to include the integrator's and H's output types, or remove the assertion. Float32 network, step = z -> A64 * z with A64::Matrix{Float64}: TypeError: in typeassert, expected Float32, got a value of type Float64. With H = z -> 0.5 * sum(abs2, z) and an identity step, the same error.
9 quality test/runtests.jl:66,74 Both new files are in core, but test/architectures/multimodal_symplectic_autoencoder.jl takes more than the 60 s limit of that group, even warm in CI. The PR body lists this as "pre-existing, adjacent". These files are new in this PR, so the placement comes from this diff. Move the file to slow. The macOS Julia 1 log, in a warm process: MultiModalSymplecticAutoencoder and multimodal losses … 182 182 1m12.1s and HRedSys reference-state shifting and VJP pullback mode … 267 267 30.8s. The body itself gives 198.2 s and 133.7 s cold.
10 quality test/reduced_system/reference_shift_and_vjp.jl:185-194 The ForwardDiff.Dual test checks only size and all(isfinite, …), so a wrong Dual-path Jacobian passes. Compare it with central differences of v_reduced, or with the :vjp result applied column by column. Read lines 185-194.
11 correctness-risk src/reduced_system/reduced_system.jl:137-139,155-166,238-252 v_reduced and f_reduced of one HRedSys share one mutable ReducedVFCache (ξ_buf, jac_result, v_intermediate, f_intermediate) and return views into it. On main, each call allocated its own arrays. Two tasks that integrate the same HRedSys now race. At a minimum, state in the docstring that the object is not safe to share between threads. Read the lines. No concurrent run was done.
12 nit src/reduced_system/reduced_system.jl:305-307,344-346 The default cache of build_v_reduced and build_f_reduced is ReducedVFCache(Float64, …). A Float32 caller therefore always takes the IdDict path with a type assertion, never the direct buffer. HRedSys passes eltype(ics.q). The standalone builders could take the type from decoder's parameters. Read the lines. _get_vf_cache returns the base cache only when T === T0 (line 22).
13 nit src/reduced_system/reduced_system.jl:373-380 HRedSys always passes vectors (zeros by default), so the nothing branch of h_reduced never runs from HRedSys. The shifted branch allocates two N-vectors on each call, even for a zero reference. Read the lines and lines 134-135 and 168.
14 nit src/architectures/multimodal_symplectic_autoencoder.jl:580-583 (model::MultiModalSymplecticLayer)(x, ps), and therefore nn(x), silently round-trips through the first modality in keys(frontends). No docstring states this. Throw an ArgumentError that points to encode and decode, as Chain(::MultiModalSymplecticAutoencoder) does at lines 73-79, or document the behaviour. Read the lines.
15 nit test/architectures/multimodal_symplectic_autoencoder.jl:73,112,268,336,345,398; test/reduced_system/reference_shift_and_vjp.jl:15,99,128,199 Test labels and comments cite "Clause 1/2/3", "Mutant M1", "catches O3/O5", "catches M2/M3" and "Proposition 13.1". These names come from a plan document that is not in the repository, so a reader cannot follow them. Name the property that each test checks. Read the lines.
16 nit src/reduced_system/reduced_system.jl:384-402,433-459 CodeRabbit's inline comment about broadcast over the leading axis is wrong. Julia broadcasting extends trailing singleton dimensions, so qp.q .- rs.q_ref shifts each component of an (N, T, 1) tensor. However, no test calls reduction_error or projection_error with a non-zero reference. Add one. size(rand(3, 5, 1) .- [10.0, 20.0, 30.0]) == (3, 5, 1), and the shift acts on axis 1. With q_ref, p_ref given: projection_error = 0.0935, reduction_error = 0.0935. Without: 0.853, 0.853. Neither run raised an error.

Verified and fine

  • Sign and block layout of the :vjp path. z̄ = [-f; v] gives v_reduced = g[n+1:2n] and f_reduced = -g[1:n], which matches J_{2n} (∇Ψ)ᵀ J_{2N}ᵀ [v; f] and the :jacobian branch (lines 276-280, 317, 323, 356, 362).
  • The custom rrules for encode and decode give correct parameter gradients on the paths that the test only checks for finiteness: a Chain frontend (PairwiseSymplecticLayerQ and PairwiseSymplecticLayerP), a SymplecticAutoencoder core, and translate, CharbonnierRelativeLoss and CrossModalCycleLoss. Zygote against central differences (h = 1e-6) over every parameter leaf: the maximum absolute error is 4.9e-10 to 3.3e-9, with gradient magnitudes of 1.4 to 18.
  • The two new test files pass in CI: 182/182 and 267/267 on macOS Julia 1.
  • The Downgrade, pre and nightly failures do not come from this diff (see the CI section). The PR does not change Project.toml.
  • test-layout.jl --check on the head reports no violations.
  • The PR body holds no closing keyword: closingIssuesReferences is empty.

Not checked

  • Julia min ubuntu, Documentation and Scripts: they were still running.
  • Device arrays. The _narrow_* helpers (lines 194-224) assert Vector{T} and Matrix{T}, so a device array would raise a TypeError there. The probe could not reach these helpers, because NeuralNetwork(WeightTiedSymplecticAutoencoder(…), JLBackend(), Float32) already fails on main's code path (Illegal conversion of a JLArray to a Ptr in cholesky, psd_like_layer.jl:33). Is the multi-modal autoencoder meant to support device arrays?
  • Whether the twelve _narrow_* methods, which exist only to assert types, can be removed without loss of inference. No inference probe was run.
  • A full local Pkg.test().

- ReducedVFCache takes its Jacobian result type as a parameter instead of
  naming DiffResults' non-public MutableDiffResult, which failed the
  ExplicitImports check on every release job.
- CharbonnierRelativeLoss accepts batched DLRA input (3-D X, S, V factors).
- NeuralNetwork(::MultiModalSymplecticAutoencoder, ...) passes its
  initializer keyword to the core network as well as to the frontends.
- Tests for the batched loss and for the initializer reaching the core.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michakraus

Copy link
Copy Markdown
Member Author

Follow-up to the review above: what happened to each finding. The fixes are in 432509b.

# severity action detail
1 blocker fixed in 432509b ReducedVFCache{T, JR} holds jac_result::JR, so the source no longer names DiffResults.MutableDiffResult. check_all_qualified_accesses_are_public with the ignore list of test/quality/aqua.jl returns nothing, and test/quality/aqua.jl passes locally (17/17). On the Dual path the cache's JR is not inferred, so DiffResults.value and DiffResults.jacobian are asserted to Vector{T} and Matrix{T}; Base.return_types of evaluate_vf_and_compute_∇Ψ is concrete for both Float64 and Dual input. The Dual-path Jacobian of v_reduced agrees with central differences to 4.3e-11.
2 bug fixed in 432509b A _frob_sq_norm method for 3-D X, S, V sums the squared norms of the slices, with the package's tensor kernels. It equals the dense sum(abs2, X_b * S_b * V_b') summed over the batch; the batched loss and its Zygote gradient are finite. New tests in test/architectures/multimodal_symplectic_autoencoder.jl.
3 bug fixed in 432509b initializer is passed to the core NeuralNetwork. The default is unchanged: DefaultInitializer === GlorotUniform in the resolved AbstractNeuralNetworks, and the default call gives the same parameters as an explicit GlorotUniform(). A new test with a counting initializer checks that the core calls it.
4 quality not fixed The PR body is the author's text. Its "Critic" and "Checked and clean" sections do not match this head and should be rewritten or removed by the author.
5 quality not fixed Same: the claim of size-independent allocations in the body does not reproduce and should be removed from the body.
6 quality needs a decision Whether to document :vjp as the slower mode, or to compute one pullback for both v_reduced and f_reduced, is a design choice.
7 quality needs a decision The five buffer fields, JR and pullback_mode on HRedSys are never read in src/, but the tests assert that they exist (hasfield). Removing them changes what the tests specify.
8 quality needs a decision The res::T assertion turns a Float64 integrator or H with a Float32 network into a TypeError. Whether to convert, promote, or reject with an ArgumentError is an API choice.
9 quality needs a decision Moving the two new test files from core to slow changes the suite's grouping.
10 quality not fixed A stronger Dual-path test needs a chosen reference and tolerance. A central-difference comparison (agreement 4.3e-11 in Float64) is a candidate.
11 correctness-risk needs a decision The shared mutable cache makes v_reduced and f_reduced non-reentrant. A per-task cache or a documented restriction is a design choice.
12 nit not fixed Standalone builders default the cache to Float64; changing the default is part of the same API question as 8.
13 nit not fixed Left for the author: it does not change results, and removing the dead branch or the two allocations is a cleanup choice.
14 nit not fixed Documenting nn(x) is a docs choice for the author.
15 nit not fixed The plan labels in the new test files are left for the author to rename.
16 nit disputed (CodeRabbit's part) As the review said: the length-N reference broadcasts over axis 1 of the (N, T, 1) tensor, so reduction_error and projection_error are correct. The missing test with a non-zero reference remains open.

Not addressed by this push: the Downgrade, pre and nightly failures, which also fail on main and are not caused by this PR.

@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: 1


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9e513901-5b05-43b9-8ad5-c64d6116885b
Commits

Reviewing files that changed from the base of the PR and between a436a12 and 432509b.

Files selected for processing: 4
  • src/architectures/multimodal_symplectic_autoencoder.jl
  • src/loss/multimodal_losses.jl
  • src/reduced_system/reduced_system.jl
  • test/architectures/multimodal_symplectic_autoencoder.jl
Files skipped from review as they are similar to previous changes: 1
  • src/architectures/multimodal_symplectic_autoencoder.jl

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread src/loss/multimodal_losses.jl Resolved
@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.65546% with 54 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.37%. Comparing base (9ef9680) to head (c0030b4).

Files with missing lines Patch % Lines
src/loss/multimodal_losses.jl 80.25% 31 Missing ⚠️
...architectures/multimodal_symplectic_autoencoder.jl 88.61% 23 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #370      +/-   ##
==========================================
- Coverage   95.45%   94.37%   -1.08%     
==========================================
  Files          61       63       +2     
  Lines        2264     2719     +455     
==========================================
+ Hits         2161     2566     +405     
- Misses        103      153      +50     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

… fields

- IsometricRolloutLoss and CrossModalCycleLoss raise an ArgumentError that
  names both element types when the data, the integrator's output or H
  has another element type than the network's parameters.
- build_v_reduced and build_f_reduced default their cache to the
  decoder's parameter element type; a floating-point state of another
  element type than the cache's raises an ArgumentError. Dual states keep
  their own cache.
- evaluate_vf_and_compute_∇Ψ returns copies, so no caller holds memory
  of the cache.
- KNOWN_ISSUES.md K40: HRedSys fields that no code in src/ reads.
- Tests for each error and for results that do not alias the cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michakraus

Copy link
Copy Markdown
Member Author

Follow-up: the author decided the open findings, and 775e13f carries them.

# decision action
7 keep the fields kept; recorded as K40 in KNOWN_ISSUES.md; the hasfield tests stay
8 reject mixed precision with an ArgumentError that names the types IsometricRolloutLoss checks the data, the integrator's output and the value of H; CrossModalCycleLoss checks x_a and x_b; one test per check
12 same as 8, in the builders the default cache of build_v_reduced and build_f_reduced has the decoder's parameter element type; a floating-point state of another element type than the cache's raises an ArgumentError; ForwardDiff.Dual states keep their own cache; tested
11 never return a view into a cache evaluate_vf_and_compute_∇Ψ returns copies; a test mutates a result and checks the next call, and checks that a later call leaves an earlier result alone, for both helpers. A mutant that returns the cache's buffers is caught. Concurrent use of one HRedSys from two tasks still shares the cache buffers; this change does not make it reentrant.
9 move to slow only if over 60 s cold measured alone, cold: 56.5 s and 33.7 s (testset times), so both stay in core
4, 5 rewrite the "Checked and clean" and "Critic" sections done; the allocation figures were measured again, in two fresh processes, and grow with N

Findings 6, 10 and 13–16 are unchanged from the earlier comment.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (2)

Minor · Check each component’s element type. · multimodal_symplectic_autoencoder.jl:2

test/architectures/multimodal_symplectic_autoencoder.jl:2
Minor · Functional Correctness · Quick win

Check each component’s element type.

For a Float64 network, a particle state with Float64 q and Float32 p passes _check_eltype because _state_eltype promotes them to Float64. CanonicalSlotLayer then raises a MethodError instead of the documented ArgumentError. Check each component in _check_eltype and add a mixed-component test. (raw.githubusercontent.com)

Minor · Handle omitted references in standalone reduced-field builders. · reduced_system.jl:44-53

src/reduced_system/reduced_system.jl:44-53
Minor · Functional Correctness · Quick win

Handle omitted references in standalone reduced-field builders.

build_v_reduced and build_f_reduced document both references as optional. HRedSys also defaults each reference independently to a zero vector. When a standalone builder receives only q_ref or only p_ref, its evaluation path calls _add_ref! with one vector and one nothing, which raises MethodError.

Add one-sided _add_ref! methods that shift only the supplied component.

Suggested fix
 _add_ref!(z::AbstractVector, ::Nothing, ::Nothing, ::Int) = z
+
+function _add_ref!(
+        z::AbstractVector, q_ref::AbstractVector, ::Nothing, N2::Int)
+    @inbounds for i in 1:N2
+        z[i] += q_ref[i]
+    end
+    z
+end
+
+function _add_ref!(
+        z::AbstractVector, ::Nothing, p_ref::AbstractVector, N2::Int)
+    @inbounds for i in 1:N2
+        z[N2 + i] += p_ref[i]
+    end
+    z
+end

Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0e45db27-d315-4f68-a44a-3373d6a8ee7b
Commits

Reviewing files that changed from the base of the PR and between 432509b and 775e13f.

Files selected for processing: 6
  • CHANGELOG.md
  • KNOWN_ISSUES.md
  • src/loss/multimodal_losses.jl
  • src/reduced_system/reduced_system.jl
  • test/architectures/multimodal_symplectic_autoencoder.jl
  • test/reduced_system/reference_shift_and_vjp.jl

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread CHANGELOG.md Resolved
michakraus and others added 3 commits October 30, 2026 15:55
…acobian, drop dead branch

Document in build_v_reduced and build_f_reduced that pullback_mode = :vjp allocates
more and runs slower than :jacobian for small problems, with measured figures.
Compare the Dual-path Jacobian of the reduced field with central finite differences
under a non-zero reference shift, reject a transposed and a sign-flipped Jacobian,
and test reduction_error and projection_error against a loop-based value with a
non-zero reference shift. Remove the unreachable nothing branch of build_h_reduced.
Document that nn(x) of MultiModalSymplecticAutoencoder uses the first modality only.
Rename the plan labels in the two new test files to descriptive names.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…mponent, one-sided references

- _frob_sq_norm of a batch of DLRA states reuses a factor whose element type is already T.
- _check_eltype checks every component of a state, so a mixed-precision particle state raises the ArgumentError.
- _add_ref! shifts only the supplied component when one reference is given.
- CHANGELOG: state the default cache element type for HRedSys and for the standalone builders.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…t NamedTuple raises a MethodError

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@michakraus
michakraus merged commit 7c92ea8 into main Oct 30, 2026
12 of 17 checks passed
@michakraus
michakraus deleted the multimodal-symplectic-ae/part-f branch October 30, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant