@@ -267,6 +267,7 @@ function _parse_system(exprs::NTuple{N,Expr}) where {N}
267267 noise_var = nothing
268268 dimension = nothing
269269 initial_state = nothing # for initial-value problems
270+ parametric = false
270271
271272 # main loop to parse the subexpressions in exprs
272273 for ex in exprs
@@ -315,6 +316,10 @@ function _parse_system(exprs::NTuple{N,Expr}) where {N}
315316 end
316317 initial_state = X0
317318
319+ elseif @capture(ex, A ∈ Set_) # COV_EXCL_LINE
320+ parametric = true
321+ push!(constraints, ex) # parse a constraint
322+
318323 elseif @capture(ex, state_ ∈ Set_) # COV_EXCL_LINE
319324 push!(constraints, ex) # parse a constraint
320325
@@ -361,7 +366,7 @@ function _parse_system(exprs::NTuple{N,Expr}) where {N}
361366 end
362367
363368 return dynamic_equation, AT, constraints,
364- state_var, input_var, noise_var, dimension, initial_state
369+ state_var, input_var, noise_var, dimension, initial_state, parametric
365370end
366371
367372"""
676681# Take the vectors of tuples providing the variable and fields names for the
677682# lhs, the rhs and the sets, combine them, and return a vector of field names
678683# and a vector of variable names.
679- function constructor_input(lhs, rhs, set)
684+ function constructor_input(lhs, rhs, set, parametric )
680685 rhs_fields = [tuple[2 ] for tuple in rhs]
681686 lhs_fields = [tuple[2 ] for tuple in lhs]
682687 set_fields = [tuple[2 ] for tuple in set]
@@ -687,15 +692,40 @@ function constructor_input(lhs, rhs, set)
687692 set_var_names = [tuple[1 ] for tuple in set]
688693 field_names = (rhs_fields... , lhs_fields... , set_fields... )
689694 var_names = (rhs_var_names... , lhs_var_names... , set_var_names... )
695+ if parametric
696+ # strip off normal matrices from expressions (they are just variables)
697+ if length(field_names) == 2
698+ @assert field_names == (:A, :AS)
699+ field_names = (field_names[2 ],)
700+ @assert length(var_names) == 2
701+ @assert var_names == (:A, :AS)
702+ var_names = (var_names[2 ],)
703+ elseif length(field_names) == 4
704+ @assert field_names == (:A, :B, :AS, :BS)
705+ field_names = (field_names[3 ], field_names[4 ])
706+ @assert length(var_names) == 4
707+ @assert (var_names[3 ], var_names[4 ]) == (:AS, :BS)
708+ var_names = (var_names[3 ], var_names[4 ])
709+ else
710+ throw(ArgumentError(" the entry $(field_names) does not match a " *
711+ " parametric `MathematicalSystems.jl` structure" ))
712+ end
713+ end
690714 return field_names, var_names
691715end
692716
693717# extract the variable name and the field name for a set expression. The method
694718# checks whether the set belongs to the `state`, `input` or `noise` and returns a
695719# tuple of symbols where the field name is either `:X`, `:U` or `:W` and
696720# the variable name is the value parsed as Set_
697- function extract_set_parameter(expr, state, input, noise) # input => to check set definitions
698- if @capture(expr, x_ ∈ Set_)
721+ function extract_set_parameter(expr, state, input, noise, parametric) # input => to check set definitions
722+ if parametric
723+ if @capture(expr, A ∈ Set_)
724+ return Set, :AS
725+ elseif @capture(expr, B ∈ Set_)
726+ return Set, :BS
727+ end
728+ elseif @capture(expr, x_ ∈ Set_)
699729 if x == state
700730 return Set, :X
701731 elseif x == input
@@ -766,11 +796,13 @@ function _sort(parameters::Vector{<:Tuple{Any,Symbol}}, order::NTuple{N,Symbol})
766796 return order_parameters
767797end
768798
769- function _get_system_type(dyn_eq, AT, constr, state, input, noise, dim)
799+ function _get_system_type(dyn_eq, AT, constr, state, input, noise, dim, parametric )
770800 lhs, rhs = extract_dyn_equation_parameters(dyn_eq, state, input, noise, dim, AT)
771- ordered_rhs = _sort(rhs, (:A, :B, :c, :D, :f, :statedim, :inputdim, :noisedim))
772- ordered_set = _sort(extract_set_parameter.(constr, state, input, noise), (:X, :U, :W))
773- field_names, var_names = constructor_input(lhs, ordered_rhs, ordered_set)
801+ ordered_rhs = _sort(rhs, (:A, :B, :c, :D, :f, :statedim, :inputdim, :noisedim, :AS, :BS))
802+ extract_set_parameter.(constr, state, input, noise, parametric)
803+ ordered_set = _sort(extract_set_parameter.(constr, state, input, noise, parametric),
804+ (:X, :U, :W, :AS, :BS))
805+ field_names, var_names = constructor_input(lhs, ordered_rhs, ordered_set, parametric)
774806 sys_type = _corresponding_type(AT, field_names)
775807 return sys_type, var_names
776808end
@@ -891,8 +923,9 @@ ConstrainedBlackBoxControlDiscreteSystem{typeof(f), BallInf{Float64, Vector{Floa
891923"""
892924macro system(expr... )
893925 try
894- dyn_eq, AT, constr, state, input, noise, dim, x0 = _parse_system(expr)
895- sys_type, var_names = _get_system_type(dyn_eq, AT, constr, state, input, noise, dim)
926+ dyn_eq, AT, constr, state, input, noise, dim, x0, parametric = _parse_system(expr)
927+ sys_type, var_names = _get_system_type(dyn_eq, AT, constr, state, input, noise, dim,
928+ parametric)
896929 sys = Expr(:call, :($ sys_type), :($ (var_names... )))
897930 if isnothing(x0)
898931 return esc(sys)
@@ -961,8 +994,9 @@ macro ivp(expr...)
961994 ivp = Expr(:call, InitialValueProblem, :($ (expr[1 ])), :($ x0))
962995 return esc(ivp)
963996 else
964- dyn_eq, AT, constr, state, input, noise, dim, x0 = _parse_system(expr)
965- sys_type, var_names = _get_system_type(dyn_eq, AT, constr, state, input, noise, dim)
997+ dyn_eq, AT, constr, state, input, noise, dim, x0, parametric = _parse_system(expr)
998+ sys_type, var_names = _get_system_type(dyn_eq, AT, constr, state, input, noise, dim,
999+ parametric)
9661000 sys = Expr(:call, :($ sys_type), :($ (var_names... )))
9671001 if isnothing(x0)
9681002 return throw(ArgumentError(" an initial-value problem should define the " *
0 commit comments