Skip to content

Commit 61dbb19

Browse files
committed
feat: check independent-var usage in symbolic vars
- Ensure `@variables` are variables of an independent var. - In both `@variables` and `@parameters` case, ensure a single indpendent var is used
1 parent 3b404eb commit 61dbb19

File tree

1 file changed

+22
-4
lines changed

1 file changed

+22
-4
lines changed

src/systems/model_parsing.jl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,11 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
274274
meta = parse_metadata(mod, meta_val)
275275
varval = (@isdefined default_val) ? default_val : unit_handled_variable_value(meta, varname)
276276
if varclass == :parameters
277+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
277278
var = :($varname = $first(@parameters ($a[$(indices...)]::$type = $varval), $meta_val))
278279
else
280+
Meta.isexpr(a, :call) || throw("$a is not a variable of the independent variable")
281+
assert_unique_independent_var(dict, a.args[end])
279282
var = :($varname = $first(@variables ($a[$(indices)]::$type = $varval), $meta_val))
280283
end
281284
push_array_kwargs_and_metadata!(dict, indices, meta, type, varclass, varname, varval)
@@ -291,20 +294,26 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
291294
val, def_n_meta = (def_n_meta.args[1], def_n_meta.args[2:end])
292295
push!(kwargs, Expr(:kw, varname, nothing))
293296
if varclass == :parameters
297+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
294298
var = :($varname = $varname === nothing ? $val : $varname;
295299
$varname = $first(@parameters ($a[$(indices...)]::$type =
296300
$varval), $(def_n_meta...)))
297301
else
302+
Meta.isexpr(a, :call) || throw("$a is not a variable of the independent variable")
303+
assert_unique_independent_var(dict, a.args[end])
298304
var = :($varname = $varname === nothing ? $val : $varname;
299305
$varname = $first(@variables $a[$(indices...)]::$type = (
300306
$varval), $(def_n_meta...)))
301307
end
302308
else
303309
push!(kwargs, Expr(:kw, varname, nothing))
304310
if varclass == :parameters
311+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
305312
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
306313
$varname = $first(@parameters $a[$(indices...)]::$type = $varname))
307314
else
315+
Meta.isexpr(a, :call) || throw("$a is not a variable of the independent variable")
316+
assert_unique_independent_var(dict, a.args[end])
308317
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
309318
$varname = $first(@variables $a[$(indices...)]::$type = $varname))
310319
end
@@ -319,8 +328,11 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
319328
varname = a isa Expr && a.head == :call ? a.args[1] : a
320329
push!(kwargs, Expr(:kw, varname, nothing))
321330
if varclass == :parameters
331+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
322332
var = :($varname = $first(@parameters $a[$(indices...)]::$type = $varname))
323333
elseif varclass == :variables
334+
Meta.isexpr(a, :call) || throw("$a is not a variable of the independent variable")
335+
assert_unique_independent_var(dict, a.args[end])
324336
var = :($varname = $first(@variables $a[$(indices...)]::$type = $varname))
325337
else
326338
throw("Symbolic array with arbitrary length is not handled for $varclass.
@@ -401,14 +413,20 @@ function generate_var!(dict, a, varclass;
401413
generate_var(a, varclass; indices, type)
402414
end
403415

416+
assert_unique_independent_var(dict, iv::Num) = assert_unique_independent_var(dict, nameof(iv))
417+
function assert_unique_independent_var(dict, iv)
418+
prev_iv = get!(dict, :independent_variable) do
419+
iv
420+
end
421+
prev_iv isa Num && (prev_iv = nameof(prev_iv))
422+
@assert isequal(iv, prev_iv) "Multiple independent variables are used in the model $(typeof(iv)) $(typeof(prev_iv))"
423+
end
424+
404425
function generate_var!(dict, a, b, varclass, mod;
405426
indices::Union{Vector{UnitRange{Int}}, Nothing} = nothing,
406427
type = Real)
407428
iv = b == :t ? get_t(mod, b) : generate_var(b, :independent_variables)
408-
prev_iv = get!(dict, :independent_variable) do
409-
iv
410-
end
411-
@assert isequal(iv, prev_iv) "Multiple independent variables are used in the model"
429+
assert_unique_independent_var(dict, iv)
412430
check_name_uniqueness(dict, a, varclass)
413431
vd = get!(dict, varclass) do
414432
Dict{Symbol, Dict{Symbol, Any}}()

0 commit comments

Comments
 (0)