Skip to content

Commit 60445d8

Browse files
feat: consider non-unit coefficients as solvable in find_eq_solvables!
1 parent 479fdbb commit 60445d8

2 files changed

Lines changed: 51 additions & 19 deletions

File tree

lib/ModelingToolkitTearing/src/stateselection_interface.jl

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,25 @@ function StateSelection.find_eq_solvables!(state::TearingState, ieq, to_rm = Int
261261
# When the expression is linear with numeric `a`, then we can safely
262262
# only consider `b` for the following iterations.
263263
term = b
264-
a_is_one = SU._isone(a)
265-
if a_is_one || manual_dispatch_isabsone(unwrap_const(a))
266-
coeffs === nothing || push!(coeffs, a_is_one ? 1 : -1)
267-
else
264+
a = manual_dispatch_is_small_int(unwrap_const(a))::Int
265+
if a == typemin(Int)
268266
all_int_vars = false
269267
conservative && continue
268+
elseif conservative && abs(a) > 1
269+
continue
270+
else
271+
coeffs === nothing || push!(coeffs, a)
270272
end
271-
if !SU._iszero(a)
273+
274+
if !iszero(a)
272275
add_edge!(solvable_graph, ieq, j)
276+
continue
277+
end
278+
279+
if may_be_zero
280+
push!(to_rm, j)
273281
else
274-
if may_be_zero
275-
push!(to_rm, j)
276-
else
277-
@warn "Internal error: Variable $var was marked as being in $eq, but was actually zero"
278-
end
282+
@warn "Internal error: Variable $var was marked as being in $eq, but was actually zero"
279283
end
280284
end
281285
for j in to_rm
@@ -289,22 +293,36 @@ function StateSelection.find_eq_solvables!(state::TearingState, ieq, to_rm = Int
289293
all_int_vars, term
290294
end
291295

292-
function manual_dispatch_isabsone(@nospecialize(x))
296+
"""
297+
$TYPEDSIGNATURES
298+
299+
If `x` is a small integer (fits in `Int8`) return `Int(x)`. Otherwise, return
300+
`typemin(Int)`.
301+
"""
302+
function manual_dispatch_is_small_int(@nospecialize(x::Number))::Int
293303
if x isa Int
294-
return isone(abs(x))
304+
return typemin(Int8) <= x <= typemax(Int8) ? x : typemin(Int)
295305
elseif x isa BigInt
296-
return isone(abs(x))
306+
return typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
307+
elseif x isa Int32
308+
return typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
297309
elseif x isa Float64
298-
return isone(abs(x))
310+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
299311
elseif x isa Float32
300-
return isone(abs(x))
312+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
301313
elseif x isa BigFloat
302-
return isone(abs(x))
314+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
303315
elseif x isa Rational{Int}
304-
return isone(abs(x))
316+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
317+
elseif x isa Rational{Int32}
318+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
305319
elseif x isa Rational{BigInt}
306-
return isone(abs(x))
320+
return isinteger(x) && typemin(Int8) <= x <= typemax(Int8) ? Int(x) : typemin(Int)
307321
else
308-
return isone(abs(x))::Bool
322+
return if isinteger(x)::Bool && (typemin(Int8) <= x <= typemax(Int8))::Bool
323+
Int(x)::Int
324+
else
325+
typemin(Int)
326+
end
309327
end
310328
end

lib/ModelingToolkitTearing/test/runtests.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,17 @@ end
9696
MTKTearing.infer_clocks!(ci)
9797
@test all(isequal(Clock(1 // 10)), ci.var_domain)
9898
end
99+
100+
@testset "non-unit integer coefficients are considered solvable" begin
101+
# https://github.com/SciML/ModelingToolkit.jl/issues/4322
102+
@variables x(t) y(t)
103+
eqs = [
104+
0 ~ x - y
105+
0 ~ 2y - x
106+
]
107+
108+
@named sys = System(eqs, t)
109+
sys = mtkcompile(sys)
110+
@test isempty(unknowns(sys))
111+
@test length(observed(sys)) == 2
112+
end

0 commit comments

Comments
 (0)