From 6a46d1c35ad5d628608f8e8d20fae2298ebc1d7c Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 23 Sep 2026 09:58:21 -0400 Subject: [PATCH 1/3] Fix plot idxs dim check to use transform output arity Mirror the SciMLBase fix: assert plot-series consistency on each transform's output length, not idxs input arity, and throw ArgumentError when series genuinely mix 2-D and 3-D outputs. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent CLI 2026.09.18-9a7762b Agent-Model: auto Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/jobs/fix-SciMLBase-DE360/log.txt on amdci2.julia.csail.mit.edu --- src/vector_of_array.jl | 30 +++++++++++++++++++++++---- test/Core/public_api_test.jl | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/vector_of_array.jl b/src/vector_of_array.jl index 4b637d9c..25f259ff 100644 --- a/src/vector_of_array.jl +++ b/src/vector_of_array.jl @@ -1240,6 +1240,31 @@ function is supplied. This is a developer interface for plot recipe implementati DEFAULT_PLOT_FUNC(x, y) = (x, y) DEFAULT_PLOT_FUNC(x, y, z) = (x, y, z) +# Plot dimensionality is the number of coordinates returned by a series +# transform `f`, not `length(var) - 1` (input arity). A bare index `3` and +# `(f, 0, 3, 4)` with `f(t,a,b)=(t,a+b)` both produce 2-D series. +function plot_series_output_dims(var) + f = var[1] + return length(f(ntuple(Returns(1), length(var) - 1)...)) +end + +function check_plot_series_output_dims(vars) + dims = plot_series_output_dims(vars[1]) + for var in vars + d = plot_series_output_dims(var) + if d != dims + throw( + ArgumentError( + "Plot idxs series must all have the same output dimension, but got $dims and $d. " * + "Output dimension is the number of coordinates returned by each series transform " * + "(e.g. `(t, u)` is 2-D), not the number of input indices in the idxs tuple." + ) + ) + end + end + return dims +end + """ plottable_indices(x) @@ -1408,10 +1433,7 @@ function diffeq_to_arrays( plott = A.t[start_idx:end_idx] end - dims = length(vars[1]) - 1 - for var in vars - @assert length(var) - 1 == dims - end + dims = check_plot_series_output_dims(vars) return solplot_vecs_and_labels(dims, vars, plott, A) end diff --git a/test/Core/public_api_test.jl b/test/Core/public_api_test.jl index b41f610d..3dc5d4c8 100644 --- a/test/Core/public_api_test.jl +++ b/test/Core/public_api_test.jl @@ -51,3 +51,43 @@ end @test plot_vecs == [[0.0 0.0; 1.0 1.0], [1.0 2.0; 3.0 4.0]] @test plot_labels == ["u[1]", "u[2]"] end + +# Regression for DifferentialEquations.jl#360: input-arity of idxs specs is not +# plot dimensionality. Mixing a bare index / (0,i) with (f,0,i,j) when f returns +# a 2-tuple must succeed; mixing a 2-D series with a 3-D series must throw. +@testset "plot idxs with mixed input arity but matching output dims (#360)" begin + t = [0.0, 0.25, 0.5, 0.75, 1.0] + u = [[1.0, 2.0, 10.0 + tt, 20.0 + 2tt] for tt in t] + A = DiffEqArray(u, t) + + adder(tt, a, b) = (tt, a + b) + adder3(tt, a, b) = (tt, a, b) + + function plot_sparse(idxs) + vars = interpret_vars(idxs, A) + return diffeq_to_arrays(A, false, 100, nothing, vars, :identity, nothing) + end + + u3 = [uu[3] for uu in u] + u3pu4 = [uu[3] + uu[4] for uu in u] + + for idxs in ([3, (adder, 0, 3, 4)], [(0, 3), (adder, 0, 3, 4)]) + plot_vecs, labels = plot_sparse(idxs) + @test length(plot_vecs) == 2 + @test size(plot_vecs[1], 2) == 2 + @test plot_vecs[1][:, 1] ≈ t + @test plot_vecs[2][:, 1] ≈ u3 + @test plot_vecs[1][:, 2] ≈ t + @test plot_vecs[2][:, 2] ≈ u3pu4 + @test length(labels) == 2 + end + + err = try + plot_sparse([3, (adder3, 0, 3, 4)]) + nothing + catch e + e + end + @test err isa ArgumentError + @test occursin("output dimension", sprint(showerror, err)) +end From 3990f88b39f6bf097cc23cbb782794bd81bca33c Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 23 Sep 2026 11:46:46 -0400 Subject: [PATCH 2/3] Fix plot label regression and stop probing transforms Mirror SciMLBase: require DEFAULT_PLOT_FUNC for short labels, and take series dims from evaluated map(f, ...) output instead of probing with integer 1s that break typed/domain-restricted transforms. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent CLI 2026.09.18-9a7762b Agent-Model: auto Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/jobs/fix-SciMLBase-DE360/log.txt on amdci2.julia.csail.mit.edu --- src/vector_of_array.jl | 46 +++++++++++++++--------------------- test/Core/public_api_test.jl | 19 ++++++++++++++- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/vector_of_array.jl b/src/vector_of_array.jl index 25f259ff..93fad7a1 100644 --- a/src/vector_of_array.jl +++ b/src/vector_of_array.jl @@ -1242,28 +1242,8 @@ DEFAULT_PLOT_FUNC(x, y, z) = (x, y, z) # Plot dimensionality is the number of coordinates returned by a series # transform `f`, not `length(var) - 1` (input arity). A bare index `3` and -# `(f, 0, 3, 4)` with `f(t,a,b)=(t,a+b)` both produce 2-D series. -function plot_series_output_dims(var) - f = var[1] - return length(f(ntuple(Returns(1), length(var) - 1)...)) -end - -function check_plot_series_output_dims(vars) - dims = plot_series_output_dims(vars[1]) - for var in vars - d = plot_series_output_dims(var) - if d != dims - throw( - ArgumentError( - "Plot idxs series must all have the same output dimension, but got $dims and $d. " * - "Output dimension is the number of coordinates returned by each series transform " * - "(e.g. `(t, u)` is 2-D), not the number of input indices in the idxs tuple." - ) - ) - end - end - return dims -end +# `(f, 0, 3, 4)` with `f(t,a,b)=(t,a+b)` both produce 2-D series. Dims are +# taken from evaluated series output in `solplot_vecs_and_labels` (no probe). """ plottable_indices(x) @@ -1387,7 +1367,7 @@ This is a developer interface for plot recipe implementations. """ function add_labels!(labels, x, dims, A, strs) if ((x[2] isa Integer && x[2] == 0) || isequal(x[2], getindepsym_defaultt(A))) && - dims == 2 + dims == 2 && x[1] === DEFAULT_PLOT_FUNC push!(labels, strs[end]) elseif x[1] !== DEFAULT_PLOT_FUNC push!(labels, "f($(join(strs, ',')))") @@ -1433,21 +1413,21 @@ function diffeq_to_arrays( plott = A.t[start_idx:end_idx] end - dims = check_plot_series_output_dims(vars) - return solplot_vecs_and_labels(dims, vars, plott, A) + return solplot_vecs_and_labels(vars, plott, A) end """ - solplot_vecs_and_labels(dims, vars, plott, A) + solplot_vecs_and_labels(vars, plott, A) Build plot vectors and labels for interpreted plotting variables over the sample points `plott`. This is a developer interface for plot recipe implementations. """ -function solplot_vecs_and_labels(dims, vars, plott, A) +function solplot_vecs_and_labels(vars, plott, A) plot_vecs = [] labels = String[] + dims = 0 batch_symbolic_vars = [] for x in vars for j in 2:length(x) @@ -1496,6 +1476,18 @@ function solplot_vecs_and_labels(dims, vars, plott, A) f = x[1] tmp = map(f, tmp...) + series_dims = length(tmp[1]) + if isempty(plot_vecs) + dims = series_dims + elseif series_dims != dims + throw( + ArgumentError( + "Plot idxs series must all have the same output dimension, but got $dims and $series_dims. " * + "Output dimension is the number of coordinates returned by each series transform " * + "(e.g. `(t, u)` is 2-D), not the number of input indices in the idxs tuple." + ) + ) + end tmp = tuple((getindex.(tmp, i) for i in eachindex(tmp[1]))...) for i in eachindex(tmp) if length(plot_vecs) < i diff --git a/test/Core/public_api_test.jl b/test/Core/public_api_test.jl index 3dc5d4c8..568c6c92 100644 --- a/test/Core/public_api_test.jl +++ b/test/Core/public_api_test.jl @@ -55,6 +55,8 @@ end # Regression for DifferentialEquations.jl#360: input-arity of idxs specs is not # plot dimensionality. Mixing a bare index / (0,i) with (f,0,i,j) when f returns # a 2-tuple must succeed; mixing a 2-D series with a 3-D series must throw. +# Labels for custom transforms must stay `f(...)` (not the bare last index), +# and dims must come from evaluated output (no probe with integer 1s). @testset "plot idxs with mixed input arity but matching output dims (#360)" begin t = [0.0, 0.25, 0.5, 0.75, 1.0] u = [[1.0, 2.0, 10.0 + tt, 20.0 + 2tt] for tt in t] @@ -62,6 +64,8 @@ end adder(tt, a, b) = (tt, a + b) adder3(tt, a, b) = (tt, a, b) + g(tt::Float64, x::Float64) = (tt, x) + dom(tt, x) = (tt, sqrt(x - 2)) function plot_sparse(idxs) vars = interpret_vars(idxs, A) @@ -79,9 +83,22 @@ end @test plot_vecs[2][:, 1] ≈ u3 @test plot_vecs[1][:, 2] ≈ t @test plot_vecs[2][:, 2] ≈ u3pu4 - @test length(labels) == 2 + @test labels == ["u[3]", "f(t,u[3],u[4])"] end + _, labels01 = plot_sparse((0, 1)) + @test labels01 == ["u[1]"] + + plot_vecs_g, labels_g = plot_sparse([(g, 0, 3)]) + @test plot_vecs_g[1][:, 1] ≈ t + @test plot_vecs_g[2][:, 1] ≈ u3 + @test labels_g == ["f(t,u[3])"] + + plot_vecs_dom, labels_dom = plot_sparse([(dom, 0, 3)]) + @test plot_vecs_dom[1][:, 1] ≈ t + @test plot_vecs_dom[2][:, 1] ≈ sqrt.(u3 .- 2) + @test labels_dom == ["f(t,u[3])"] + err = try plot_sparse([3, (adder3, 0, 3, 4)]) nothing From 4df95475520176dbf58042631b863d13e3d014b9 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 23 Sep 2026 13:21:45 -0400 Subject: [PATCH 3/3] Restore solplot_vecs_and_labels 4-arg API; drop orphan comment The exported helper previously took (dims, vars, plott, A). Keep accepting dims for compatibility and ignore it; plotted dims come from evaluated series output. Add a regression call of the 4-argument form. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent CLI 2026.09.18-9a7762b Agent-Model: auto Agent-Session: local session, transcript at /home/crackauc/sandbox/goals/issue-backlog/jobs/fix-SciMLBase-DE360/log.txt on amdci2.julia.csail.mit.edu --- src/vector_of_array.jl | 15 +++++++-------- test/Core/public_api_test.jl | 14 +++++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/vector_of_array.jl b/src/vector_of_array.jl index 93fad7a1..af4da6e9 100644 --- a/src/vector_of_array.jl +++ b/src/vector_of_array.jl @@ -1240,11 +1240,6 @@ function is supplied. This is a developer interface for plot recipe implementati DEFAULT_PLOT_FUNC(x, y) = (x, y) DEFAULT_PLOT_FUNC(x, y, z) = (x, y, z) -# Plot dimensionality is the number of coordinates returned by a series -# transform `f`, not `length(var) - 1` (input arity). A bare index `3` and -# `(f, 0, 3, 4)` with `f(t,a,b)=(t,a+b)` both produce 2-D series. Dims are -# taken from evaluated series output in `solplot_vecs_and_labels` (no probe). - """ plottable_indices(x) @@ -1413,20 +1408,24 @@ function diffeq_to_arrays( plott = A.t[start_idx:end_idx] end - return solplot_vecs_and_labels(vars, plott, A) + return solplot_vecs_and_labels(length(vars[1]) - 1, vars, plott, A) end """ - solplot_vecs_and_labels(vars, plott, A) + solplot_vecs_and_labels(dims, vars, plott, A) Build plot vectors and labels for interpreted plotting variables over the sample points `plott`. +The `dims` argument is accepted for API compatibility and ignored; the plotted +dimension is taken from each series transform's evaluated output. + This is a developer interface for plot recipe implementations. """ -function solplot_vecs_and_labels(vars, plott, A) +function solplot_vecs_and_labels(dims, vars, plott, A) plot_vecs = [] labels = String[] + # Ignore caller-supplied `dims`; recompute from evaluated series output. dims = 0 batch_symbolic_vars = [] for x in vars diff --git a/test/Core/public_api_test.jl b/test/Core/public_api_test.jl index 568c6c92..23694bda 100644 --- a/test/Core/public_api_test.jl +++ b/test/Core/public_api_test.jl @@ -52,11 +52,7 @@ end @test plot_labels == ["u[1]", "u[2]"] end -# Regression for DifferentialEquations.jl#360: input-arity of idxs specs is not -# plot dimensionality. Mixing a bare index / (0,i) with (f,0,i,j) when f returns -# a 2-tuple must succeed; mixing a 2-D series with a 3-D series must throw. -# Labels for custom transforms must stay `f(...)` (not the bare last index), -# and dims must come from evaluated output (no probe with integer 1s). +# #360: check plot dims from transform output, not idxs input arity. @testset "plot idxs with mixed input arity but matching output dims (#360)" begin t = [0.0, 0.25, 0.5, 0.75, 1.0] u = [[1.0, 2.0, 10.0 + tt, 20.0 + 2tt] for tt in t] @@ -99,6 +95,14 @@ end @test plot_vecs_dom[2][:, 1] ≈ sqrt.(u3 .- 2) @test labels_dom == ["f(t,u[3])"] + # Exported 4-arg form: `dims` is accepted and ignored. + vars4 = interpret_vars([3, (adder, 0, 3, 4)], A) + plot_vecs4, labels4 = solplot_vecs_and_labels(99, vars4, t, A) + @test length(plot_vecs4) == 2 + @test plot_vecs4[2][:, 1] ≈ u3 + @test plot_vecs4[2][:, 2] ≈ u3pu4 + @test labels4 == ["u[3]", "f(t,u[3],u[4])"] + err = try plot_sparse([3, (adder3, 0, 3, 4)]) nothing