Skip to content

Commit f848d7b

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 1fcec41 commit f848d7b

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
@@ -275,9 +275,13 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
275275
varval = (@isdefined default_val) ? default_val :
276276
unit_handled_variable_value(meta, varname)
277277
if varclass == :parameters
278+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
278279
var = :($varname = $first(@parameters ($a[$(indices...)]::$type = $varval),
279280
$meta_val))
280281
else
282+
Meta.isexpr(a, :call) ||
283+
throw("$a is not a variable of the independent variable")
284+
assert_unique_independent_var(dict, a.args[end])
281285
var = :($varname = $first(@variables ($a[$(indices)]::$type = $varval),
282286
$meta_val))
283287
end
@@ -295,10 +299,15 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
295299
val, def_n_meta = (def_n_meta.args[1], def_n_meta.args[2:end])
296300
push!(kwargs, Expr(:kw, varname, nothing))
297301
if varclass == :parameters
302+
Meta.isexpr(a, :call) &&
303+
assert_unique_independent_var(dict, a.args[end])
298304
var = :($varname = $varname === nothing ? $val : $varname;
299305
$varname = $first(@parameters ($a[$(indices...)]::$type = $varval),
300306
$(def_n_meta...)))
301307
else
308+
Meta.isexpr(a, :call) ||
309+
throw("$a is not a variable of the independent variable")
310+
assert_unique_independent_var(dict, a.args[end])
302311
var = :($varname = $varname === nothing ? $val : $varname;
303312
$varname = $first(@variables $a[$(indices...)]::$type = (
304313
$varval),
@@ -307,9 +316,14 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
307316
else
308317
push!(kwargs, Expr(:kw, varname, nothing))
309318
if varclass == :parameters
319+
Meta.isexpr(a, :call) &&
320+
assert_unique_independent_var(dict, a.args[end])
310321
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
311322
$varname = $first(@parameters $a[$(indices...)]::$type = $varname))
312323
else
324+
Meta.isexpr(a, :call) ||
325+
throw("$a is not a variable of the independent variable")
326+
assert_unique_independent_var(dict, a.args[end])
313327
var = :($varname = $varname === nothing ? $def_n_meta : $varname;
314328
$varname = $first(@variables $a[$(indices...)]::$type = $varname))
315329
end
@@ -325,8 +339,12 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
325339
varname = a isa Expr && a.head == :call ? a.args[1] : a
326340
push!(kwargs, Expr(:kw, varname, nothing))
327341
if varclass == :parameters
342+
Meta.isexpr(a, :call) && assert_unique_independent_var(dict, a.args[end])
328343
var = :($varname = $first(@parameters $a[$(indices...)]::$type = $varname))
329344
elseif varclass == :variables
345+
Meta.isexpr(a, :call) ||
346+
throw("$a is not a variable of the independent variable")
347+
assert_unique_independent_var(dict, a.args[end])
330348
var = :($varname = $first(@variables $a[$(indices...)]::$type = $varname))
331349
else
332350
throw("Symbolic array with arbitrary length is not handled for $varclass.
@@ -410,14 +428,22 @@ function generate_var!(dict, a, varclass;
410428
generate_var(a, varclass; indices, type)
411429
end
412430

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

0 commit comments

Comments
 (0)