Skip to content

Commit d7d82bf

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 9f4e7b8 commit d7d82bf

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/systems/model_parsing.jl

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,13 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
281281
varval = (@isdefined default_val) ? default_val :
282282
unit_handled_variable_value(meta, varname)
283283
if varclass == :parameters
284+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
284285
var = :($varname = $first(@parameters ($a[$(indices...)]::$type = $varval),
285286
$meta_val))
286287
else
288+
Meta.isexpr(a, :call) ||
289+
throw("$a is not a variable of the independent variable")
290+
assert_unique_independent_var(dict, a.args[end])
287291
var = :($varname = $first(@variables ($a[$(indices)]::$type = $varval),
288292
$meta_val))
289293
end
@@ -301,10 +305,15 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
301305
val, def_n_meta = (def_n_meta.args[1], def_n_meta.args[2:end])
302306
push!(kwargs, Expr(:kw, varname, nothing))
303307
if varclass == :parameters
308+
Meta.isexpr(a, :call) &&
309+
assert_unique_independent_var(dict, a.args[end])
304310
var = :($varname = $varname === nothing ? $val : $varname;
305311
$varname = $first(@parameters ($a[$(indices...)]::$type = $varval),
306312
$(def_n_meta...)))
307313
else
314+
Meta.isexpr(a, :call) ||
315+
throw("$a is not a variable of the independent variable")
316+
assert_unique_independent_var(dict, a.args[end])
308317
var = :($varname = $varname === nothing ? $val : $varname;
309318
$varname = $first(@variables $a[$(indices...)]::$type = (
310319
$varval),
@@ -313,9 +322,14 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
313322
else
314323
push!(kwargs, Expr(:kw, varname, nothing))
315324
if varclass == :parameters
325+
Meta.isexpr(a, :call) &&
326+
assert_unique_independent_var(dict, a.args[end])
316327
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
317328
$varname = $first(@parameters $a[$(indices...)]::$type = $varname))
318329
else
330+
Meta.isexpr(a, :call) ||
331+
throw("$a is not a variable of the independent variable")
332+
assert_unique_independent_var(dict, a.args[end])
319333
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
320334
$varname = $first(@variables $a[$(indices...)]::$type = $varname))
321335
end
@@ -331,8 +345,12 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
331345
varname = a isa Expr && a.head == :call ? a.args[1] : a
332346
push!(kwargs, Expr(:kw, varname, nothing))
333347
if varclass == :parameters
348+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
334349
var = :($varname = $first(@parameters $a[$(indices...)]::$type = $varname))
335350
elseif varclass == :variables
351+
Meta.isexpr(a, :call) ||
352+
throw("$a is not a variable of the independent variable")
353+
assert_unique_independent_var(dict, a.args[end])
336354
var = :($varname = $first(@variables $a[$(indices...)]::$type = $varname))
337355
else
338356
throw("Symbolic array with arbitrary length is not handled for $varclass.
@@ -411,14 +429,22 @@ function generate_var!(dict, a, varclass;
411429
generate_var(a, varclass; indices, type)
412430
end
413431

432+
function assert_unique_independent_var(dict, iv::Num)
433+
assert_unique_independent_var(dict, nameof(iv))
434+
end
435+
function assert_unique_independent_var(dict, iv)
436+
prev_iv = get!(dict, :independent_variable) do
437+
iv
438+
end
439+
prev_iv isa Num && (prev_iv = nameof(prev_iv))
440+
@assert isequal(iv, prev_iv) "Multiple independent variables are used in the model $(typeof(iv)) $(typeof(prev_iv))"
441+
end
442+
414443
function generate_var!(dict, a, b, varclass, mod;
415444
indices::Union{Vector{UnitRange{Int}}, Nothing} = nothing,
416445
type = Real)
417446
iv = b == :t ? get_t(mod, b) : generate_var(b, :independent_variables)
418-
prev_iv = get!(dict, :independent_variable) do
419-
iv
420-
end
421-
@assert isequal(iv, prev_iv) "Multiple independent variables are used in the model"
447+
assert_unique_independent_var(dict, iv)
422448
check_name_uniqueness(dict, a, varclass)
423449
vd = get!(dict, varclass) do
424450
Dict{Symbol, Dict{Symbol, Any}}()

0 commit comments

Comments
 (0)