diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 985f592f3..74b6a0e2c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -21,7 +21,7 @@ jobs: run: | using Pkg Pkg.add([ - PackageSpec(url="https://github.com/blegat/IntervalLinearAlgebra.jl", rev="radius"), + PackageSpec(url="https://github.com/jump-dev/JuMP.jl", rev="master"), PackageSpec(path=pwd()), ]) Pkg.instantiate() diff --git a/docs/src/examples/Getting Started.jl b/docs/src/examples/Getting Started.jl index b7758cbd5..1136a101d 100644 --- a/docs/src/examples/Getting Started.jl +++ b/docs/src/examples/Getting Started.jl @@ -80,7 +80,7 @@ measnoise = SVector(0.0, 0.0); sysnoise = SVector(0.0, 0.0); # And now the instantiation of the ControlSystem -contsys = ST.NewControlSystemGrowthRK4( +contsys = ST.discretize_system_with_growth_bound( tstep, F_sys, L_growthbound, diff --git a/docs/src/examples/solvers/Unicycle robot.jl b/docs/src/examples/solvers/Unicycle robot.jl new file mode 100644 index 000000000..e54cb914d --- /dev/null +++ b/docs/src/examples/solvers/Unicycle robot.jl @@ -0,0 +1,220 @@ +using Test #src +# # Example: Unicycle Robot solved by [Uniform grid abstraction](https://github.com/dionysos-dev/Dionysos.jl/blob/master/docs/src/manual/manual.md#solvers). +# +# This example was adapted from the numerical experiments in [1, Sec. 5] from Symbolically guided Model Predictive Control (SgMPC) [paper](https://doi.org/10.1016/j.ifacol.2022.09.039).. +# This is a **control problem** for a **discrete-time nonlinear system**. +# +# Let us consider the 3-dimensional state space control system of the form +# ```math +# x_{t+1} = f(x_t, u_t) +# ``` +# with $f: \mathbb{R}^3 × \mathbb{R}^2 \to \mathbb{R}^3$ given by +# ```math +# f(x, (u_1, u_2)) = \begin{bmatrix} x_1 + u_1 \cos(x_3) \\ x_2 + u_1 \sin(x_3) \\ x_3 + u_2 \ (\text{mod} \ 2\pi) \end{bmatrix} +# ``` +# and with state and control constraints given by: +# ```math +# X = \left\{ (x_1, x_2)^T \in \mathbb{R}^2 \ | \ x_1^2 - x_2^2 \leq 4, \ 4x_2^2 - x_1^2 \leq 16 \right\} +# ``` +# ```math +# U = [0.2, 2] \times [-1, 1] +# ``` +# Here, $(x_1, x_2)$ represents the 2D Cartesian coordinates and $x_3$ is the angular orientation of a mobile cart. +# The control inputs $u_1$ and $u_2$ are the linear and angular velocities. +# The control objective is to drive the mobile cart to a desired reference position $x_r$. +# +# Considering this as a reachability problem, we will use it to showcase the capabilities of the Uniform grid abstraction solving discrete-time problem in Dionysos. +# The nonlinear constraints are handled as obstacles in the state-space. + +# First, let us import [StaticArrays](https://github.com/JuliaArrays/StaticArrays.jl) and [Plots](https://github.com/JuliaPlots/Plots.jl). +using StaticArrays, Plots + +# At this point, we import Dionysos and JuMP. +using Dionysos, JuMP + +# Define the problem using JuMP +# We first create a JuMP model: +model = Model(Dionysos.Optimizer) + +# Define the discretization step +hx = 0.1 + +# Define the state variables: x1(t), x2(t), x3(t) without specifying the start value since here it's a set. We will specify the start later using constraints. +x_low = [-3.5, -2.6, -pi] +x_upp = -x_low +@variable(model, x_low[i] <= x[i = 1:3] <= x_upp[i]) + +# Define the control variables: u1(t), u2(t) +@variable(model, -1 <= u[1:2] <= 1) + +# Define the dynamics, we do not include the remainder modulo `2π` for `Δ(x[3])`. There are options to set periodic variables in Dionysos but that's not needed for this example. +@constraint(model, Δ(x[1]) == x[1] + u[1] * cos(x[3])) +@constraint(model, Δ(x[2]) == x[2] + u[1] * sin(x[3])) +@constraint(model, Δ(x[3]) == x[3] + u[2]) + +# Define the initial and target sets +x_initial = [1.0, -1.7, 0.0] +x_target = [sqrt(32) / 3, sqrt(20) / 3, -pi] + +@constraint(model, start(x[1]) in MOI.Interval(x_initial[1] - hx, x_initial[1] + hx)) +@constraint(model, start(x[2]) in MOI.Interval(x_initial[2] - hx, x_initial[2] + hx)) +@constraint(model, start(x[3]) in MOI.Interval(x_initial[3] - hx, x_initial[3] + hx)) + +@constraint(model, final(x[1]) in MOI.Interval(x_target[1] - hx, x_target[1] + hx)) +@constraint(model, final(x[2]) in MOI.Interval(x_target[2] - hx, x_target[2] + hx)) +@constraint(model, final(x[3]) in MOI.Interval{Float64}(-pi, pi)) + +# Obstacle boundaries computed using the function `get_obstacles` below +function extract_rectangles(matrix) + if isempty(matrix) + return [] + end + + n, m = size(matrix) + tlx, tly, brx, bry = Int[], Int[], Int[], Int[] + + ## Build histogram heights + for i in 1:n + j = 1 + while j <= m + if matrix[i, j] == 1 + j += 1 + continue + end + push!(tlx, j) + push!(tly, i) + while j <= m && matrix[i, j] == 0 + j += 1 + end + push!(brx, j - 1) + push!(bry, i) + end + end + + return zip(tlx, tly, brx, bry) +end + +function get_obstacles(lb, ub, h) + ## lb_x1 = -3.5, ub_x1 = 3.5, lb_x2 = -2.6, ub_x2 = 2.6, h = 0.1 + lb_x1, lb_x2, lb_x3 = lb + ub_x1, ub_x2, ub_x3 = ub + + ## Define the obstacles + x1 = range(lb_x1; stop = ub_x1, step = h) + x2 = range(lb_x2; stop = ub_x2, step = h) + steps1, steps2 = length(x1), length(x2) + + X1 = x1' .* ones(steps2) + X2 = ones(steps1)' .* x2 + + Z1 = (X1 .^ 2 .- X2 .^ 2) .<= 4 + Z2 = (4 .* X2 .^ 2 .- X1 .^ 2) .<= 16 + + ## Find the upper and lower bounds of X1 and X2 for the obstacle + grid = Z1 .& Z2 + + return [ + MOI.HyperRectangle([x1[x1lb], x2[x2lb]], [x1[x1ub], x2[x2ub]]) for + (x1lb, x2lb, x1ub, x2ub) in extract_rectangles(grid) + ] +end + +obstacles = get_obstacles(x_low, x_upp, hx) + +# Function to add rectangular obstacle avoidance constraints + +for obstacle in obstacles + @constraint(model, x[1:2] ∉ obstacle) +end + +# ### Definition of the abstraction + +# We define the growth bound function of $f$: +function growth_bound(r, u, _) + β = u[1] * r[3] + return StaticArrays.SVector{3}(β, β, 0.0) +end +set_attribute(model, "growthbound_map", growth_bound) + +# We define the invariant system map: +function sys_inv(x, u, _) + return StaticArrays.SVector{3}( + x[1] - u[1] * cos((x[3] - u[2]) % (2 * π)), + x[2] - u[1] * sin((x[3] - u[2]) % (2 * π)), + (x[3] - u[2]) % (2 * π), + ) +end +set_attribute(model, "sys_inv_map", sys_inv) + +# Definition of the grid of the state-space on which the abstraction is based (origin `x0` and state-space discretization `h`): +x0 = SVector(0.0, 0.0, 0.0); +h = SVector(hx, hx, 0.2); +set_attribute(model, "state_grid", Dionysos.Domain.GridFree(x0, h)) + +# Definition of the grid of the input-space on which the abstraction is based (origin `u0` and input-space discretization `h`): +u0 = SVector(1.1, 0.0); +h = SVector(0.3, 0.3); +set_attribute(model, "input_grid", Dionysos.Domain.GridFree(u0, h)) + +optimize!(model) + +# Get the results +abstract_system = get_attribute(model, "abstract_system"); +abstract_problem = get_attribute(model, "abstract_problem"); +abstract_controller = get_attribute(model, "abstract_controller"); +concrete_controller = get_attribute(model, "concrete_controller") +concrete_problem = get_attribute(model, "concrete_problem"); +concrete_system = concrete_problem.system + +# ### Trajectory display +# We choose a stopping criterion `reached` and the maximal number of steps `nsteps` for the sampled system, i.e. the total elapsed time: `nstep`*`tstep` +# as well as the true initial state `x0` which is contained in the initial state-space `_I_` defined previously. +nstep = 100 +function reached(x) + if x ∈ concrete_problem.target_set + return true + else + return false + end +end + +control_trajectory = Dionysos.System.get_closed_loop_trajectory( + get_attribute(model, "discretized_system"), + concrete_controller, + x_initial, + nstep; + stopping = reached, +) + +using Plots + +# Here we display the coordinate projection on the two first components of the state space along the trajectory. +fig = plot(; aspect_ratio = :equal); +# We display the concrete domain +plot!(concrete_system.X; color = :yellow, opacity = 0.5); + +# We display the abstract domain +plot!(abstract_system.Xdom; color = :blue, opacity = 0.5); + +# We display the concrete specifications +plot!(concrete_problem.initial_set; color = :green, opacity = 0.2); +plot!(concrete_problem.target_set; dims = [1, 2], color = :red, opacity = 0.2); + +# We display the abstract specifications +plot!( + Dionysos.Symbolic.get_domain_from_symbols( + abstract_system, + abstract_problem.initial_set, + ); + color = :green, +); +plot!( + Dionysos.Symbolic.get_domain_from_symbols(abstract_system, abstract_problem.target_set); + color = :red, +); + +# We display the concrete trajectory +plot!(control_trajectory; ms = 0.5) + +# ### References +# 1. Z. Azaki, A. Girard and S. Olaru, "Predictive and Symbolic Control: Performance and Safety for Non-linear Systems," in IFAC-PapersOnLine, 2022, vol. 55, no 16, pp. 290-295.. diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 2cc49ee65..29fb7bfb1 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -7,17 +7,20 @@ import Symbolics @enum(VariableType, INPUT, STATE, MODE) +@enum(TimeType, UNKNOWN, CONTINUOUS, DISCRETE) + mutable struct Optimizer <: MOI.AbstractOptimizer inner::Any nlp_model::Any evaluator::Union{Nothing, MOI.Nonlinear.Evaluator} + time_type::TimeType variable_values::Vector{Float64} derivative_values::Vector{Float64} variable_types::Vector{VariableType} variable_index::Vector{Int} # MOI.VariableIndex -> state/input/mode index lower::Vector{Float64} upper::Vector{Float64} - start::Vector{Float64} + start::Vector{MOI.Interval{Float64}} target::Vector{MOI.Interval{Float64}} dynamic::Vector{Union{Nothing, MOI.ScalarNonlinearFunction}} obstacles::Vector{Tuple{Vector{MOI.VariableIndex}, MOI.HyperRectangle}} @@ -29,13 +32,14 @@ mutable struct Optimizer <: MOI.AbstractOptimizer MOI.instantiate(Dionysos.Optim.Abstraction.UniformGridAbstraction.Optimizer), nothing, nothing, + UNKNOWN, Float64[], Float64[], VariableType[], Int[], Float64[], Float64[], - Float64[], + MOI.Interval{Float64}[], MOI.Interval{Float64}[], Union{Nothing, MOI.ScalarNonlinearFunction}[], Tuple{Vector{MOI.VariableIndex}, MOI.HyperRectangle}[], @@ -49,6 +53,7 @@ end MOI.is_empty(model::Optimizer) = isempty(model.variable_types) function MOI.empty!(model::Optimizer) + model.time_type = UNKNOWN empty!(model.variable_values) empty!(model.derivative_values) empty!(model.variable_types) @@ -71,7 +76,7 @@ function MOI.add_variable(model::Optimizer) push!(model.variable_index, 0) push!(model.lower, -Inf) push!(model.upper, Inf) - push!(model.start, NaN) + push!(model.start, MOI.Interval(-Inf, Inf)) push!(model.target, MOI.Interval(-Inf, Inf)) push!(model.dynamic, nothing) return MOI.VariableIndex(length(model.upper)) @@ -139,6 +144,12 @@ function MOI.add_constraint( model.nonlinear_index += 1 return MOI.ConstraintIndex{typeof(func), typeof(set)}(model.nonlinear_index) end + + if var isa MOI.VariableIndex && func.head == :start + model.start[var.value] = set + model.nonlinear_index += 1 + return MOI.ConstraintIndex{typeof(func), typeof(set)}(model.nonlinear_index) + end end dump(func) return error("Unsupported") @@ -162,7 +173,25 @@ function MOI.add_constraint( if lhs isa MOI.ScalarNonlinearFunction && length(lhs.args) == 1 var = lhs.args[] if var isa MOI.VariableIndex - if lhs.head == :diff + if lhs.head == :∂ + if model.time_type == DISCRETE + error( + "Cannot add constraint with `∂` since you already added a constraint with `Δ`.", + ) + end + model.time_type = CONTINUOUS + model.dynamic[var.value] = rhs + model.nonlinear_index += 1 + return MOI.ConstraintIndex{typeof(func), typeof(set)}( + model.nonlinear_index, + ) + elseif lhs.head == :Δ + if model.time_type == CONTINUOUS + error( + "Cannot add constraint with `Δ` since you already added a constraint with `∂`.", + ) + end + model.time_type = DISCRETE model.dynamic[var.value] = rhs model.nonlinear_index += 1 return MOI.ConstraintIndex{typeof(func), typeof(set)}( @@ -191,6 +220,11 @@ function MOI.supports(::Optimizer, ::MOI.VariablePrimalStart, ::Type{MOI.Variabl end function MOI.set(model::Optimizer, ::MOI.VariablePrimalStart, vi::MOI.VariableIndex, value) + # create a MOI.Interval from the value if value is a scalar + if !isa(value, MOI.Interval) + value = MOI.Interval(value, value) + end + return model.start[vi.value] = value end @@ -292,20 +326,39 @@ function system( ) _U_ = Dionysos.Utils.HyperRectangle(_svec(model.lower, u_idx), _svec(model.upper, u_idx)) - return MathematicalSystems.ConstrainedBlackBoxControlContinuousSystem( - dynamic(model, x_idx, u_idx), - Dionysos.Utils.get_dims(_X_), - Dionysos.Utils.get_dims(_U_), - _X_, - _U_, - ) + if model.time_type == CONTINUOUS + return MathematicalSystems.ConstrainedBlackBoxControlContinuousSystem( + dynamic(model, x_idx, u_idx), + Dionysos.Utils.get_dims(_X_), + Dionysos.Utils.get_dims(_U_), + _X_, + _U_, + ) + else + # `dynamic(model, x_idx, u_idx)` is a function `(x_k, u) -> x_{k+1}` + # However, `UniformGridAbstraction` will call it with `(x, u, t)` so with + # an additional time argument. I would expect it to error because there is + # too many arguments but it seems that `RuntimeGeneratedFunction` just + # ignores any trailing arguments. To be safe, we still ignore the time + # like so: + dyn = dynamic(model, x_idx, u_idx) + return MathematicalSystems.ConstrainedBlackBoxControlDiscreteSystem( + (x, u, _) -> dyn(x, u), + Dionysos.Utils.get_dims(_X_), + Dionysos.Utils.get_dims(_U_), + _X_, + _U_, + ) + end end function problem(model::Optimizer) x_idx = state_indices(model) u_idx = input_indices(model) - _I_ = - Dionysos.Utils.HyperRectangle(_svec(model.start, x_idx), _svec(model.start, x_idx)) + _I_ = Dionysos.Utils.HyperRectangle( + _svec([s.lower for s in model.start], x_idx), + _svec([s.upper for s in model.start], x_idx), + ) _T_ = Dionysos.Utils.HyperRectangle( _svec([s.lower for s in model.target], x_idx), _svec([s.upper for s in model.target], x_idx), @@ -387,14 +440,23 @@ function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value) return MOI.set(model.inner, attr, value) end -export ∂, final +export ∂, Δ, final, start function _diff end -∂ = JuMP.NonlinearOperator(_diff, :diff) +∂ = JuMP.NonlinearOperator(_diff, :∂) + +function _delta end +Δ = JuMP.NonlinearOperator(_delta, :Δ) function _final end final = JuMP.NonlinearOperator(_final, :final) +function _start end +start = JuMP.NonlinearOperator(_start, :start) + +function rem end +rem_op = JuMP.NonlinearOperator(rem, :rem) + # Type piracy function JuMP.parse_constraint_call( error_fn::Function, @@ -413,3 +475,7 @@ function JuMP.parse_constraint_call( build_call = :(build_constraint($error_fn, $f, $(OuterSet)($set))) return parse_code, build_call end + +function Base.rem(x::JuMP.AbstractJuMPScalar, d) + return rem_op(x, d) +end diff --git a/src/optim/abstraction/uniform_grid_abstraction.jl b/src/optim/abstraction/uniform_grid_abstraction.jl index b4b246113..4ed0d7e70 100644 --- a/src/optim/abstraction/uniform_grid_abstraction.jl +++ b/src/optim/abstraction/uniform_grid_abstraction.jl @@ -4,6 +4,8 @@ module UniformGridAbstraction import StaticArrays +import MathematicalSystems + import Dionysos const DI = Dionysos const UT = DI.Utils @@ -37,6 +39,12 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer δGAS::Union{Nothing, Bool} solve_time_sec::T approx_mode::ApproxMode + + ## for the discrete time (no need for the jacobian_bound) + # but for the `growthbound_map` and `sys_inv_map` + growthbound_map::Union{Nothing, Function} + sys_inv_map::Union{Nothing, Function} + function Optimizer{T}() where {T} return new{T}( nothing, @@ -54,6 +62,8 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer false, 0.0, GROWTH, + nothing, + nothing, ) end end @@ -71,27 +81,41 @@ function MOI.get(model::Optimizer, param::MOI.RawOptimizerAttribute) return getproperty(model, Symbol(param.name)) end -function build_abstraction(concrete_system, model) - Xfull = DO.DomainList(model.state_grid) - DO.add_set!(Xfull, concrete_system.X, DO.INNER) - Ufull = DO.DomainList(model.input_grid) - DO.add_set!(Ufull, concrete_system.U, DO.CENTER) - abstract_system = SY.NewSymbolicModelListList(Xfull, Ufull) - - # TODO add noise to the description of the system so in a MathematicalSystems - # this is a workaround - nstates = Dionysos.Utils.get_dims(concrete_system.X) - noise = StaticArrays.SVector(ntuple(_ -> 0.0, Val(nstates))) +function discretized_system( + concrete_system::MathematicalSystems.ConstrainedBlackBoxControlDiscreteSystem, + model, + noise, +) + if isnothing(model.growthbound_map) + error("Please set the `growthbound_map`.") + end + if isnothing(model.sys_inv_map) + error("Please set the `sys_inv_map`.") + end + return Dionysos.System.ControlSystemGrowth( + 1.0, # `time_step` should be ignored by `concrete_system.f`, `model.growthbound_map` and `model.sys_inv_map` anyway + noise, + noise, + concrete_system.f, + model.growthbound_map, + model.sys_inv_map, + ) +end +function discretized_system( + concrete_system::MathematicalSystems.ConstrainedBlackBoxControlContinuousSystem, + model, + noise, +) if isnan(model.time_step) error("Please set the `time_step`.") end - model.discretized_system = if model.approx_mode == GROWTH + if model.approx_mode == GROWTH if isnothing(model.jacobian_bound) error("Please set the `jacobian_bound`.") end - Dionysos.System.NewControlSystemGrowthRK4( + return Dionysos.System.discretize_system_with_growth_bound( model.time_step, concrete_system.f, model.jacobian_bound, @@ -101,7 +125,7 @@ function build_abstraction(concrete_system, model) model.num_sub_steps_growth_bound, ) elseif model.approx_mode == LINEARIZED - Dionysos.System.NewControlSystemLinearizedRK4( + return Dionysos.System.discretize_system_with_linearization( model.time_step, concrete_system.f, model.jacobian, @@ -112,13 +136,28 @@ function build_abstraction(concrete_system, model) ) else @assert model.approx_mode == DELTA_GAS - Dionysos.System.NewSimpleSystem( + return Dionysos.System.NewSimpleSystem( model.time_step, concrete_system.f, noise, model.num_sub_steps_system_map, ) end +end + +function build_abstraction(concrete_system, model) + Xfull = DO.DomainList(model.state_grid) + DO.add_set!(Xfull, concrete_system.X, DO.INNER) + Ufull = DO.DomainList(model.input_grid) + DO.add_set!(Ufull, concrete_system.U, DO.CENTER) + abstract_system = SY.NewSymbolicModelListList(Xfull, Ufull) + + # TODO add noise to the description of the system so in a MathematicalSystems + # this is a workaround + nstates = Dionysos.Utils.get_dims(concrete_system.X) + noise = StaticArrays.SVector(ntuple(_ -> 0.0, Val(nstates))) + + model.discretized_system = discretized_system(concrete_system, model, noise) if model.δGAS @time SY.compute_deterministic_symmodel_from_controlsystem!( diff --git a/src/system/controlsystem.jl b/src/system/controlsystem.jl index cd5acca73..453444a5e 100644 --- a/src/system/controlsystem.jl +++ b/src/system/controlsystem.jl @@ -41,7 +41,7 @@ struct ControlSystemGrowth{N, T, F1 <: Function, F2 <: Function, F3 <: Function} sys_inv_map::F3 end -function NewControlSystemGrowthRK4( +function discretize_system_with_growth_bound( tstep, F_sys, L_growthbound, @@ -128,7 +128,7 @@ function BoundSecondOrder(a, b, tstep) end end -function NewControlSystemLinearizedRK4( +function discretize_system_with_linearization( tstep, F_sys, DF_sys, @@ -276,7 +276,7 @@ end ############################################ ############################################ -struct SymbolicSystem{} +struct SymbolicSystem fsymbolicT::Any fsymbolic::Any Ts::Any diff --git a/test/optim/unit_tests_UniformGridAbstraction/test_controllerreach.jl b/test/optim/unit_tests_UniformGridAbstraction/test_controllerreach.jl index b45c12c1c..b159e4dbc 100644 --- a/test/optim/unit_tests_UniformGridAbstraction/test_controllerreach.jl +++ b/test/optim/unit_tests_UniformGridAbstraction/test_controllerreach.jl @@ -45,7 +45,7 @@ println("Started test") measnoise = SVector(1.0, 1.0) * 0.001 L_growthbound(u) = SMatrix{2, 2}(0.0, 0.0, 0.0, 0.0) - contsys = ST.NewControlSystemGrowthRK4( + contsys = ST.discretize_system_with_growth_bound( tstep, F_sys, L_growthbound, diff --git a/test/optim/unit_tests_UniformGridAbstraction/test_controllersafe.jl b/test/optim/unit_tests_UniformGridAbstraction/test_controllersafe.jl index 196093b72..85d228170 100644 --- a/test/optim/unit_tests_UniformGridAbstraction/test_controllersafe.jl +++ b/test/optim/unit_tests_UniformGridAbstraction/test_controllersafe.jl @@ -39,7 +39,7 @@ println("Started test") measnoise = SVector(1.0, 1.0) * 0.001 L_growthbound(u) = SMatrix{2, 2}(0.0, 0.0, 0.0, -1.0) - contsys = ST.NewControlSystemGrowthRK4( + contsys = ST.discretize_system_with_growth_bound( tstep, F_sys, L_growthbound, diff --git a/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemgrowth.jl b/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemgrowth.jl index d9f54cf6f..bdd4635a8 100644 --- a/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemgrowth.jl +++ b/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemgrowth.jl @@ -39,7 +39,7 @@ println("Started test") sysnoise = SVector(1.0, 1.0) * 0.1 measnoise = SVector(1.0, 1.0) * 0.0 - contsys = ST.NewControlSystemGrowthRK4( + contsys = ST.discretize_system_with_growth_bound( tstep, F_sys, L_growthbound, diff --git a/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemlinearized.jl b/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemlinearized.jl index 4ca132952..978cc1548 100644 --- a/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemlinearized.jl +++ b/test/optim/unit_tests_UniformGridAbstraction/test_fromcontrolsystemlinearized.jl @@ -41,7 +41,7 @@ println("Started test") bound_DDF(u) = 1.0 measnoise = SVector(1.0, 1.0) * 0.0 - contsys = ST.NewControlSystemLinearizedRK4( + contsys = ST.discretize_system_with_linearization( tstep, F_sys, DF_sys,