Repository: dionysos-dev/Dionysos.jl
Pull request #407: Jc/remove mosek
Author: login: JulienCalbert
Created: 2025-03-01T22:49:42Z | Merged: 2025-03-03T11:46:35Z



Diff:
diff --git a/docs/Project.toml b/docs/Project.toml
index afc538ba2..4c12e0023 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -18,8 +18,6 @@ Libtiff_jll = "89763e89-9b03-5906-acba-b20f662cd828"
 LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
 Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
 MathematicalSystems = "d14a8603-c872-5ed3-9ece-53e0e82e39da"
-Mosek = "6405355b-0ac2-5fba-af84-adbd65488c0e"
-MosekTools = "1ec41992-ff65-5c91-ac43-2df89e9693a4"
 OSQP = "ab2f91bb-94b4-55e3-9ba0-7f65df51de79"
 Pavito = "cd433a01-47d1-575d-afb7-6db927ee8d8f"
 Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
diff --git a/docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl b/docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl
index 8bac89d59..ea3719f59 100644
--- a/docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl
+++ b/docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl
@@ -3,7 +3,7 @@
 
 using StaticArrays, LinearAlgebra, Random, IntervalArithmetic
 using MathematicalSystems, HybridSystems
-using JuMP, Mosek, MosekTools
+using JuMP, Clarabel
 using Plots, Colors
 using Test
 Random.seed!(0)
@@ -26,9 +26,7 @@ concrete_problem = NonLinear.problem()
 concrete_system = concrete_problem.system
 
 # Optimizer's parameters
-const FALLBACK_URL = "mosek://solve.mosek.com:30080"
-sdp_opt = optimizer_with_attributes(Mosek.Optimizer, MOI.Silent() => true)
-MOI.set(sdp_opt, MOI.RawOptimizerAttribute("fallback"), FALLBACK_URL)
+sdp_opt = optimizer_with_attributes(Clarabel.Optimizer, MOI.Silent() => true)
 
 maxδx = 100
 maxδu = 10 * 2
@@ -82,7 +80,7 @@ cost_control_trajectory = ST.get_closed_loop_trajectory(
     noise = true,
 )
 cost_bound = concrete_lyap_fun(x0)
-cost_true = sum(cost_control_trajectory.costs.seq);
+cost_true = ST.get_cost(cost_control_trajectory);
 println("Goal set reached")
 println("Guaranteed cost:\t $(cost_bound)")
 println("True cost:\t\t $(cost_true)")
diff --git a/src/optim/abstraction/UniformGridAbstraction/empty_problem.jl b/src/optim/abstraction/UniformGridAbstraction/empty_problem.jl
index 01ba0cc5a..d675aa20e 100644
--- a/src/optim/abstraction/UniformGridAbstraction/empty_problem.jl
+++ b/src/optim/abstraction/UniformGridAbstraction/empty_problem.jl
@@ -45,6 +45,8 @@ mutable struct OptimizerEmptyProblem{T} <: MOI.AbstractOptimizer
     approx_mode::ApproxMode
     efficient::Bool
 
+    print_level::Int
+
     function OptimizerEmptyProblem{T}() where {T}
         optimizer = new{T}(
             nothing,
@@ -67,6 +69,7 @@ mutable struct OptimizerEmptyProblem{T} <: MOI.AbstractOptimizer
             5,  # Continuous-Time System
             GROWTH,
             true, # Approximation Settings
+            1,
         )
         return optimizer
     end
@@ -211,24 +214,41 @@ function MOI.optimize!(optimizer::OptimizerEmptyProblem)
         _get_domain_list(concrete_system.U, optimizer.input_grid, Dionysos.Domain.CENTER),
     )
 
+    if optimizer.print_level >= 2
+        @info("Number of states: $(SY.get_n_state(abstract_system))")
+        @info("Number of inputs: $(SY.get_n_input(abstract_system))")
+        @info(
+            "Number of forward images: $(SY.get_n_input(abstract_system)*SY.get_n_state(abstract_system))"
+        )
+    end
+
     # TODO: Consider adding noise handling
     @warn("Noise is not yet accounted for in system abstraction.")
     noise = _vector_of_tuple(Dionysos.Utils.get_dims(concrete_system.X))
 
+    optimizer.print_level >= 1 && println(
+        "compute_abstract_system_from_concrete_system!: started with $(typeof(optimizer.discrete_time_system_approximation))",
+    )
     if !optimizer.efficient &&
        ST.is_over_approximation(optimizer.discrete_time_system_approximation)
         Dionysos.Symbolic.compute_abstract_system_from_concrete_system!(
             abstract_system,
             ST.get_DiscreteTimeOverApproximationMap(
                 optimizer.discrete_time_system_approximation,
-            ),
+            );
+            verbose = optimizer.print_level >= 2,
         )
     else
         Dionysos.Symbolic.compute_abstract_system_from_concrete_system!(
             abstract_system,
-            optimizer.discrete_time_system_approximation,
+            optimizer.discrete_time_system_approximation;
+            verbose = optimizer.print_level >= 2,
         )
     end
+    optimizer.print_level >= 1 && println(
+        "compute_abstract_system_from_concrete_system! terminated with success: ",
+        "$(HybridSystems.ntransitions(abstract_system.autom)) transitions created",
+    )
 
     optimizer.abstract_system = abstract_system
     optimizer.abstraction_construction_time_sec = time() - t_ref
diff --git a/src/optim/abstraction/UniformGridAbstraction/optimal_control_problem.jl b/src/optim/abstraction/UniformGridAbstraction/optimal_control_problem.jl
index c06763731..4c1b3808a 100644
--- a/src/optim/abstraction/UniformGridAbstraction/optimal_control_problem.jl
+++ b/src/optim/abstraction/UniformGridAbstraction/optimal_control_problem.jl
@@ -13,8 +13,22 @@ mutable struct OptimizerOptimalControlProblem{T} <: MOI.AbstractOptimizer
     controllable_set::Union{Nothing, Dionysos.Domain.DomainList}
     uncontrollable_set::Union{Nothing, Dionysos.Domain.DomainList}
 
+    success::Bool
+    print_level::Int
+
     function OptimizerOptimalControlProblem{T}() where {T}
-        return new{T}(nothing, nothing, nothing, nothing, 0.0, true, nothing)
+        return new{T}(
+            nothing,
+            nothing,
+            nothing,
+            nothing,
+            0.0,
+            true,
+            nothing,
+            nothing,
+            false,
+            1,
+        )
     end
 end
 
@@ -56,6 +70,7 @@ function MOI.optimize!(optimizer::OptimizerOptimalControlProblem)
         optimizer.early_stop ? optimizer.abstract_problem.initial_set :
         Dionysos.Symbolic.enum_states(optimizer.abstract_problem.system)
 
+    optimizer.print_level >= 1 && println("compute_controller_reachability! started")
     abstract_controller, controllable_set_symbols, uncontrollable_set_symbols =
         compute_largest_controllable_set(
             optimizer.abstract_problem.system,
@@ -78,12 +93,10 @@ function MOI.optimize!(optimizer::OptimizerOptimalControlProblem)
 
     # Display results
     if ⊆(optimizer.abstract_problem.initial_set, controllable_set_symbols)
-        println("\n Reachability: terminated with success")
-    else
-        println("\n Reachability: terminated without covering initial set")
+        optimizer.success = true
     end
-
-    # Correctly track solve time
+    optimizer.print_level >= 1 &&
+        println("\n Reachability: terminated with $(optimizer.success)")
     optimizer.abstract_problem_time_sec = time() - t_ref
     return
 end
diff --git a/src/optim/abstraction/UniformGridAbstraction/safety_problem.jl b/src/optim/abstraction/UniformGridAbstraction/safety_problem.jl
index 6b4fd5ee8..87189f9db 100644
--- a/src/optim/abstraction/UniformGridAbstraction/safety_problem.jl
+++ b/src/optim/abstraction/UniformGridAbstraction/safety_problem.jl
@@ -12,8 +12,10 @@ mutable struct OptimizerSafetyProblem{T} <: MOI.AbstractOptimizer
     invariant_set::Union{Nothing, Dionysos.Domain.DomainList}
     uninvariant_set::Union{Nothing, Dionysos.Domain.DomainList}
 
+    success::Bool
+    print_level::Int
     function OptimizerSafetyProblem{T}() where {T}
-        return new{T}(nothing, nothing, nothing, nothing, 0.0, nothing, nothing)
+        return new{T}(nothing, nothing, nothing, nothing, 0.0, nothing, nothing, false, 1)
     end
 end
 
@@ -45,6 +47,7 @@ function MOI.optimize!(optimizer::OptimizerSafetyProblem)
     optimizer.abstract_problem =
         build_abstract_problem(optimizer.concrete_problem, optimizer.abstract_system)
 
+    optimizer.print_level >= 1 && println("compute_controller_safe! started")
     # Compute the largest invariant set
     abstract_controller, invariant_set_symbols, uninvariant_set_symbols =
         compute_largest_invariant_set(
@@ -67,12 +70,10 @@ function MOI.optimize!(optimizer::OptimizerSafetyProblem)
 
     # Display results
     if ⊆(optimizer.abstract_problem.initial_set, invariant_set_symbols)
-        println("\n Safety: terminated with success")
-    else
-        println("\n Safety: terminated without covering initial set")
+        optimizer.success = true
     end
 
-    # Correctly track solve time
+    optimizer.print_level >= 1 && println("\n Safety: terminated with $(optimizer.success)")
     optimizer.abstract_problem_time_sec = time() - t_ref
     return
 end
@@ -106,7 +107,6 @@ function compute_largest_invariant_set(
     abstract_system::Dionysos.Symbolic.SymbolicModelList,
     safelist,
 )
-    println("compute_controller_safe! started")
     autom = abstract_system.autom
     contr = NewControllerList()
     nstates = autom.nstates
diff --git a/src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl b/src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
index dbefcb1ce..2268f0271 100644
--- a/src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
+++ b/src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
@@ -4,9 +4,11 @@ module UniformGridAbstraction
 
 import Dionysos
 ST = Dionysos.System
+SY = Dionysos.Symbolic
 
 import StaticArrays: SVector, SMatrix
 import MathematicalSystems
+import HybridSystems
 using JuMP
 
 include("empty_problem.jl")
@@ -25,15 +27,20 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer
     control_solver::Union{Nothing, MOI.AbstractOptimizer}
     concrete_controller::Any
     solve_time_sec::T
+    print_level::Int
 
     function Optimizer{T}() where {T}
-        return new{T}(nothing, nothing, nothing, 0.0)
+        return new{T}(nothing, nothing, nothing, 0.0, 1)
     end
 end
 Optimizer() = Optimizer{Float64}()
 
 MOI.is_empty(optimizer::Optimizer) = optimizer.abstraction_solver === nothing
 
+function MOI.set(model::Optimizer, ::MOI.Silent, value::Bool)
+    return model.print_level = value ? 0 : 1
+end
+
 function MOI.set(model::Optimizer, param::MOI.RawOptimizerAttribute, value)
     param_symbol = Symbol(param.name)
 
@@ -176,11 +183,21 @@ function MOI.optimize!(optimizer::Optimizer)
 
     # Compute abstraction if not already done
     if !is_abstraction_computed(optimizer)
+        MOI.set(
+            optimizer.abstraction_solver,
+            MOI.RawOptimizerAttribute("print_level"),
+            optimizer.print_level,
+        )
         MOI.optimize!(optimizer.abstraction_solver)
     end
 
     # If there's a control solver, optimize it
     if optimizer.control_solver !== nothing
+        MOI.set(
+            optimizer.control_solver,
+            MOI.RawOptimizerAttribute("print_level"),
+            optimizer.print_level,
+        )
         abstract_system = MOI.get(
             optimizer.abstraction_solver,
             MOI.RawOptimizerAttribute("abstract_system"),
diff --git a/src/optim/abstraction/lazy_ellipsoids_abstraction.jl b/src/optim/abstraction/lazy_ellipsoids_abstraction.jl
index 607a44fae..b9d633f21 100644
--- a/src/optim/abstraction/lazy_ellipsoids_abstraction.jl
+++ b/src/optim/abstraction/lazy_ellipsoids_abstraction.jl
@@ -189,6 +189,7 @@ function build_concrete_controller(abstract_system)
     function concrete_controller(x)
         nodes = UT.get_nodes(abstract_system, x, compare)
         sorted_nodes = sort(nodes; by = UT.compare)
+        isempty(sorted_nodes) && return nothing
         cont = UT.get_action(sorted_nodes[1])
         c_eval = ST.get_c_eval(cont)
         return c_eval(x)
@@ -204,6 +205,7 @@ function build_concrete_lyap_fun(abstract_system, abstract_lyap_fun)
     function concrete_lyap_fun(x)
         nodes = UT.get_nodes(abstract_system, x, compare)
         sorted_nodes = sort(nodes; by = UT.compare)
+        isempty(sorted_nodes) && return Inf
         return abstract_lyap_fun(sorted_nodes[1])
     end
     return concrete_lyap_fun
diff --git a/src/symbolic/automaton.jl b/src/symbolic/automaton.jl
index 5a5e12e4e..823a38eff 100644
--- a/src/symbolic/automaton.jl
+++ b/src/symbolic/automaton.jl
@@ -17,8 +17,6 @@ function HybridSystems.ntransitions(autom::AutomatonList)
     return length(autom.transitions)
 end
 
-# In add_trans and add_translist:
-# Do not check that source, symbol, target are "inbounds"
 # Assumes not add twice same transition...
 function HybridSystems.add_transition!(autom::AutomatonList, source, target, symbol)
     return UT.push_new!(autom.transitions, (target, source, symbol))
@@ -42,6 +40,19 @@ function HybridSystems.add_state!(autom::AutomatonList)
     return autom.nstates += 1
 end
 
+function is_deterministic(autom::AutomatonList)
+    seen = Dict{Tuple{Int, Int}, Int}()  # Stores (source, symbol) → number of targets
+
+    for (target, source, symbol) in UT.get_data(autom.transitions)
+        key = (source, symbol)
+        seen[key] = get(seen, key, 0) + 1
+        if seen[key] > 1  # If we find more than one target for (source, symbol), it's non-deterministic
+            return false
+        end
+    end
+    return true
+end
+
 # function add_inputs_images_by_xref!(uref_coll, yref_coll, autom::AutomatonList, x_ref)
 #     ensure_sorted!(autom)
 #     ensure_unique!(autom)
diff --git a/src/symbolic/grid_based_symbolic_model/grid_based_symbolic_model.jl b/src/symbolic/grid_based_symbolic_model/grid_based_symbolic_model.jl
index 4e474a309..8b8e40d3e 100644
--- a/src/symbolic/grid_based_symbolic_model/grid_based_symbolic_model.jl
+++ b/src/symbolic/grid_based_symbolic_model/grid_based_symbolic_model.jl
@@ -125,17 +125,24 @@ function compute_abstract_transitions_from_points!(
         target = get_state_by_xpos(symmodel, ypos)
         push!(translist, (target, abstract_state, abstract_input))
     end
+    unique!(translist)
     return allin
 end
 
 function compute_abstract_system_from_concrete_system!(
     abstract_system::GridBasedSymbolicModel,
-    concrete_system_approx::ST.DiscreteTimeSystemOverApproximation,
+    concrete_system_approx::ST.DiscreteTimeSystemOverApproximation;
+    verbose = false,
+    update_interval = Int(1e5),
 )
-    println("compute_abstract_system_from_concrete_system!")
-    ntrans = 0
     translist = Tuple{Int, Int, Int}[]
     compute_reachable_set = ST.get_over_approximation_map(concrete_system_approx)
+    total_iterations = max(
+        div(get_n_input(abstract_system) * get_n_state(abstract_system), update_interval),
+        1,
+    )
+    progress = verbose ? ProgressMeter.Progress(total_iterations) : nothing
+    count = 0
     for abstract_input in enum_inputs(abstract_system)
         concrete_input = get_concrete_input(abstract_system, abstract_input)
         for abstract_state in enum_states(abstract_system)
@@ -149,29 +156,31 @@ function compute_abstract_system_from_concrete_system!(
                 abstract_input,
                 translist,
             )
-            if allin
-                add_transitions!(abstract_system, translist)
-                ntrans += length(translist)
-            end
+            allin && add_transitions!(abstract_system, translist)
+            count += 1
+            verbose && count % update_interval == 0 && ProgressMeter.next!(progress)
         end
     end
-    return println(
-        "compute_abstract_system_from_concrete_system! terminated with success: ",
-        "$(ntrans) transitions created",
-    )
+    verbose && ProgressMeter.finish!(progress)
+    return
 end
 
 function compute_abstract_system_from_concrete_system!(
     abstract_system::GridBasedSymbolicModel,
-    concrete_system_approx::ST.DiscreteTimeGrowthBound,
+    concrete_system_approx::ST.DiscreteTimeGrowthBound;
+    verbose = false,
+    update_interval = Int(1e5),
 )
-    println("compute_abstract_system_from_concrete_system!")
-    ntrans = 0
     translist = Tuple{Int, Int, Int}[]
-
     growthbound_map = concrete_system_approx.growthbound_map
     system_map = ST.get_system_map(concrete_system_approx)
     r = DO.get_h(DO.get_grid(get_state_domain(abstract_system))) / 2.0
+    total_iterations = max(
+        div(get_n_input(abstract_system) * get_n_state(abstract_system), update_interval),
+        1,
+    )
+    progress = verbose ? ProgressMeter.Progress(total_iterations) : nothing
+    count = 0
     for abstract_input in enum_inputs(abstract_system)
         concrete_input = get_concrete_input(abstract_system, abstract_input)
         Fr = growthbound_map(r, concrete_input)
@@ -187,33 +196,36 @@ function compute_abstract_system_from_concrete_system!(
                 abstract_input,
                 translist,
             )
-            if allin
-                add_transitions!(abstract_system, translist)
-                ntrans += length(translist)
-            end
+            allin && add_transitions!(abstract_system, translist)
+            count += 1
+            verbose && count % update_interval == 0 && ProgressMeter.next!(progress)
         end
     end
-    return println(
-        "compute_abstract_system_from_concrete_system! terminated with success: ",
-        "$(ntrans) transitions created",
-    )
+    verbose && ProgressMeter.finish!(progress)
+    return
 end
 
 function compute_abstract_system_from_concrete_system!(
     abstract_system::GridBasedSymbolicModel,
-    concrete_system_approx::ST.DiscreteTimeLinearized,
+    concrete_system_approx::ST.DiscreteTimeLinearized;
+    verbose = false,
+    update_interval = Int(1e5),
 )
-    println("compute_abstract_system_from_concrete_system! started")
     Xdom = get_state_domain(abstract_system)
     N = DO.get_dim(Xdom)
     r = DO.get_h(DO.get_grid(Xdom)) / 2.0
     _H_ = SMatrix{N, N}(I) .* r
     _ONE_ = ones(SVector{N})
     e = norm(r, Inf)
-    ntrans = 0
     translist = Tuple{Int, Int, Int}[]
     error_map = concrete_system_approx.error_map
     linsys_map = concrete_system_approx.linsys_map
+    total_iterations = max(
+        div(get_n_input(abstract_system) * get_n_state(abstract_system), update_interval),
+        1,
+    )
+    progress = verbose ? ProgressMeter.Progress(total_iterations) : nothing
+    count = 0
     for abstract_input in enum_inputs(abstract_system)
         concrete_input = get_concrete_input(abstract_system, abstract_input)
         Fe = error_map(e, concrete_input)
@@ -250,27 +262,29 @@ function compute_abstract_system_from_concrete_system!(
             #     target = get_state_by_xpos(abstract_system, ypos)
             #     push!(translist, (target, concrete_state, abstract_input))
             # end
-            if allin
-                add_transitions!(abstract_system.autom, translist)
-                ntrans += length(translist)
-            end
+            allin && add_transitions!(abstract_system, translist)
+            count += 1
+            verbose && count % update_interval == 0 && ProgressMeter.next!(progress)
         end
     end
-    return println(
-        "compute_abstract_system_from_concrete_system! terminated with success: ",
-        "$(ntrans) transitions created",
-    )
+    verbose && ProgressMeter.finish!(progress)
+    return
 end
 
 function compute_abstract_system_from_concrete_system!(
     abstract_system::GridBasedSymbolicModel,
-    concrete_system_approx::ST.DiscreteTimeSystemUnderApproximation,
+    concrete_system_approx::ST.DiscreteTimeSystemUnderApproximation;
+    verbose = false,
+    update_interval = Int(1e5),
 )
-    println("compute_abstract_system_from_concrete_system!")
-    ntrans = 0
     translist = Tuple{Int, Int, Int}[]
-
     under_approximation_map = ST.get_under_approximation_map(concrete_system_approx)
+    total_iterations = max(
+        div(get_n_input(abstract_system) * get_n_state(abstract_system), update_interval),
+        1,
+    )
+    progress = verbose ? ProgressMeter.Progress(total_iterations) : nothing
+    count = 0
     for abstract_input in enum_inputs(abstract_system)
         concrete_input = get_concrete_input(abstract_system, abstract_input)
         for abstract_state in enum_states(abstract_system)
@@ -284,27 +298,29 @@ function compute_abstract_system_from_concrete_system!(
                 abstract_input,
                 translist,
             )
-            if allin
-                add_transitions!(abstract_system, translist)
-                ntrans += length(translist)
-            end
+            allin && add_transitions!(abstract_system, translist)
+            count += 1
+            verbose && count % update_interval == 0 && ProgressMeter.next!(progress)
         end
     end
-    return println(
-        "compute_abstract_system_from_concrete_system! terminated with success: ",
-        "$(ntrans) transitions created",
-    )
+    verbose && ProgressMeter.finish!(progress)
+    return
 end
 
 function compute_abstract_system_from_concrete_system!(
     abstract_system::GridBasedSymbolicModel,
-    concrete_system_approx::ST.DiscreteTimeCenteredSimulation,
+    concrete_system_approx::ST.DiscreteTimeCenteredSimulation;
+    verbose = false,
+    update_interval = Int(1e5),
 )
-    println("compute_abstract_system_from_concrete_system!")
-    ntrans = 0
     translist = Tuple{Int, Int, Int}[]
-
     system_map = ST.get_system_map(concrete_system_approx)
+    total_iterations = max(
+        div(get_n_input(abstract_system) * get_n_state(abstract_system), update_interval),
+        1,
+    )
+    progress = verbose ? ProgressMeter.Progress(total_iterations) : nothing
+    count = 0
     for abstract_input in enum_inputs(abstract_system)
         concrete_input = get_concrete_input(abstract_system, abstract_input)
         for abstract_state in enum_states(abstract_system)
@@ -318,14 +334,11 @@ function compute_abstract_system_from_concrete_system!(
                 abstract_input,
                 translist,
             )
-            if allin
-                add_transitions!(abstract_system, translist)
-                ntrans += length(translist)
-            end
+            allin && add_transitions!(abstract_system, translist)
+            count += 1
+            verbose && count % update_interval == 0 && ProgressMeter.next!(progress)
         end
     end
-    return println(
-        "compute_abstract_system_from_concrete_system! terminated with success: ",
-        "$(ntrans) transitions created",
-    )
+    verbose && ProgressMeter.finish!(progress)
+    return
 end
diff --git a/src/symbolic/grid_based_symbolic_model/symbolic_model_list.jl b/src/symbolic/grid_based_symbolic_model/symbolic_model_list.jl
index a40937085..cbb487743 100644
--- a/src/symbolic/grid_based_symbolic_model/symbolic_model_list.jl
+++ b/src/symbolic/grid_based_symbolic_model/symbolic_model_list.jl
@@ -75,6 +75,38 @@ get_abstract_input(symmodel::SymbolicModelList, u) = symmodel.ucoord2int[u]
 add_transitions!(symmodel::SymbolicModelList, translist) =
     add_transitions!(symmodel.autom, translist)
 
+is_deterministic(symmodel::SymbolicModelList) = is_deterministic(symmodel.autom)
+
+function determinize_symbolic_model(symmodel::SymbolicModelList)
+    autom = symmodel.autom
+    new_uint2coord = Dict{Int, Tuple{Any, Int}}()  # New input mapping
+    new_ucoord2int = Dict{Tuple{Any, Int}, Int}()  # Reverse mapping
+
+    next_input_id = 1  # Track new input indices
+
+    # Go through all transitions and modify the input encoding
+    for (target, source, symbol) in UT.get_data(autom.transitions)
+        new_input = (symbol, target)  # Couple input with target
+
+        if !haskey(new_ucoord2int, new_input)
+            new_ucoord2int[new_input] = next_input_id
+            new_uint2coord[next_input_id] = new_input
+            next_input_id += 1
+        end
+    end
+
+    # Return a new symbolic model with updated inputs
+    return SymbolicModelList(
+        symmodel.Xdom,
+        symmodel.Udom,
+        autom,  # Automaton remains unchanged
+        symmodel.xpos2int,
+        symmodel.xint2pos,
+        new_ucoord2int,  # Updated input mappings
+        new_uint2coord,  # Updated input mappings
+    )
+end
+
 @recipe function f(symmodel::SymbolicModel; arrowsB = false, cost = false, lyap_fun = [])
     # Display the cells
     state_grid = symmodel.Xdom.grid
diff --git a/src/symbolic/symbolic.jl b/src/symbolic/symbolic.jl
index c007e55fa..4d5480677 100644
--- a/src/symbolic/symbolic.jl
+++ b/src/symbolic/symbolic.jl
@@ -2,6 +2,7 @@ module Symbolic
 
 import StaticArrays: SVector, SMatrix
 import RecipesBase: @recipe, @series
+import ProgressMeter
 
 using LinearAlgebra, Colors
 using HybridSystems
diff --git a/src/system/trajectory.jl b/src/system/trajectory.jl
index c1a7bb2a4..dd5f6aee5 100644
--- a/src/system/trajectory.jl
+++ b/src/system/trajectory.jl
@@ -102,6 +102,11 @@ get_cost(traj::Cost_control_trajectory, n::Int) = get_elem(traj.costs, n)
 get_elem(traj::Cost_control_trajectory, n::Int) =
     (get_state(traj, n), get_input(traj, n), get_cost(traj, n))
 
+function get_cost(traj::Cost_control_trajectory)
+    isempty(traj.costs.seq) && return 0.0
+    return sum(traj.costs.seq)
+end
+
 @recipe function f(traj::Cost_control_trajectory)
     return traj.control_trajectory
 end
diff --git a/src/utils/data_structures/sorted_vector_set.jl b/src/utils/data_structures/sorted_vector_set.jl
index f6b5df916..e98a9630e 100644
--- a/src/utils/data_structures/sorted_vector_set.jl
+++ b/src/utils/data_structures/sorted_vector_set.jl
@@ -6,6 +6,8 @@ mutable struct SortedTupleSet{N, T} <: AbstractSet{T}
     end
 end
 
+get_data(set::SortedTupleSet) = set.data
+
 function push_new!(set::SortedTupleSet, x::Tuple)
     push!(set.data, x)
     set.is_sorted = false
diff --git a/test/Project.toml b/test/Project.toml
index 2842e2742..e2cccfb3b 100644
--- a/test/Project.toml
+++ b/test/Project.toml
@@ -11,8 +11,6 @@ Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
 JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
 LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
 MathematicalSystems = "d14a8603-c872-5ed3-9ece-53e0e82e39da"
-Mosek = "6405355b-0ac2-5fba-af84-adbd65488c0e"
-MosekTools = "1ec41992-ff65-5c91-ac43-2df89e9693a4"
 OSQP = "ab2f91bb-94b4-55e3-9ba0-7f65df51de79"
 Pavito = "cd433a01-47d1-575d-afb7-6db927ee8d8f"
 Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
diff --git a/test/optim/unit_tests_UniformGridAbstraction/test_multidispatch.jl b/test/optim/unit_tests_UniformGridAbstraction/test_multidispatch.jl
index 38f64ba65..2f253dae3 100644
--- a/test/optim/unit_tests_UniformGridAbstraction/test_multidispatch.jl
+++ b/test/optim/unit_tests_UniformGridAbstraction/test_multidispatch.jl
@@ -24,6 +24,7 @@ u0 = SVector(1)
 hu = SVector(1)
 input_grid = DO.GridFree(u0, hu)
 using JuMP
+
 optimizer = MOI.instantiate(AB.UniformGridAbstraction.Optimizer)
 
 MOI.set(optimizer, MOI.RawOptimizerAttribute("concrete_problem"), empty_problem)
@@ -38,6 +39,8 @@ MOI.set(
 )
 MOI.set(optimizer, MOI.RawOptimizerAttribute("efficient"), true)
 MOI.set(optimizer, MOI.RawOptimizerAttribute("n_samples"), 1)
+MOI.set(optimizer, MOI.Silent(), true)
+MOI.set(optimizer, MOI.RawOptimizerAttribute("print_level"), 2)
 
 # USER_DEFINED GROWTH LINEARIZED CENTER_SIMULATION RANDOM_SIMULATION
 
@@ -134,63 +137,3 @@ plot!(controllable_set; color = :yellow, linecolor = :yellow, label = "Controlla
 plot!(uncontrollable_set; color = :black, linecolor = :black, label = "Uncontrollable set")
 plot!(control_trajectory)
 display(fig)
-
-# # # Example: DC-DC converter solved by [Uniform grid abstraction] (https://github.com/dionysos-dev/Dionysos.jl/blob/master/docs/src/manual/manual.md#solvers) by exploiting the incremental stability of the system.
-# # ### Definition of the system
-# # we can import the module containing the DCDC problem like this 
-
-# ### Construction of the abstraction
-
-# origin = SVector(0.0, 0.0)
-# η = (2 / 4.0) * 10^(-3)
-
-# # Note: In the following, `P` and `ϵ` are computed by hand, but their computation is not crucial since they only affect the visualization of the abstraction. See https://github.com/dionysos-dev/Dionysos.jl/issues/345
-# ϵ = 0.1 * 0.01
-# P = SMatrix{2, 2}(1.0224, 0.0084, 0.0084, 1.0031)
-# state_grid = DO.GridEllipsoidalRectangular(origin, SVector(η, η), P / ϵ, concrete_system.X)
-
-# u0 = SVector(1)
-# hu = SVector(1)
-# input_grid = DO.GridFree(u0, hu)
-
-# optimizer = MOI.instantiate(AB.UniformGridAbstraction.Optimizer)
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("concrete_problem"), concrete_problem_safety)
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("state_grid"), state_grid)
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("input_grid"), input_grid)
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("jacobian_bound"), DCDC.jacobian_bound())
-# MOI.set(
-#     optimizer,
-#     MOI.RawOptimizerAttribute("approx_mode"),
-#     Dionysos.Optim.Abstraction.UniformGridAbstraction.DELTA_GAS,
-# )
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("δGAS"), true)
-# MOI.set(optimizer, MOI.RawOptimizerAttribute("time_step"), 0.5)
-# MOI.optimize!(optimizer)
-
-# abstract_controller = MOI.get(optimizer, MOI.RawOptimizerAttribute("abstract_controller"))
-# concrete_controller = MOI.get(optimizer, MOI.RawOptimizerAttribute("concrete_controller"))
-
-# # ### Trajectory display
-# # We choose the 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 defined previously.
-# nstep = 300
-# x0 = SVector(1.2, 5.6)
-# control_trajectory = ST.get_closed_loop_trajectory(
-#     MOI.get(optimizer, MOI.RawOptimizerAttribute("discrete_time_system")),
-#     concrete_controller,
-#     x0,
-#     nstep,
-# )
-
-# fig = plot(; aspect_ratio = :equal);
-# plot!(concrete_problem_safety; opacity = 1.0);
-# plot!(invariant_set, color = :blue, linecolor = :blue)
-# plot!(uninvariant_set; color = :red, linecolor = :red)
-# plot!(concrete_problem_safety.initial_set; color = :green, opacity = 1.0, label = "");
-# plot!(control_trajectory)
-
-# ### References
-# 1. A. Girard, G. Pola and P. Tabuada, "Approximately Bisimilar Symbolic Models for Incrementally Stable Switched Systems," in IEEE Transactions on Automatic Control, vol. 55, no. 1, pp. 116-126, Jan. 2010.
-# 2. S. Mouelhi, A. Girard, and G. Gössler. “CoSyMA: a tool for controller synthesis using multi-scale abstractions”. In: HSCC. ACM. 2013, pp. 83–88.
-# 3. A. Girard. “Controller synthesis for safety and reachability via approximate bisimulation”. In: Automatica 48.5 (2012), pp. 947–953.
-# 4. G. Reissig, A. Weber and M. Rungger, "Feedback Refinement Relations for the Synthesis of Symbolic Controllers," in IEEE Transactions on Automatic Control, vol. 62, no. 4, pp. 1781-1796.
diff --git a/test/optim/units_tests_LazyEllispoidAbstraction/example_lazy_ellipsoid.jl b/test/optim/units_tests_LazyEllispoidAbstraction/example_lazy_ellipsoid.jl
index a6a6e3a95..21b10bdfe 100644
--- a/test/optim/units_tests_LazyEllispoidAbstraction/example_lazy_ellipsoid.jl
+++ b/test/optim/units_tests_LazyEllispoidAbstraction/example_lazy_ellipsoid.jl
@@ -1,6 +1,6 @@
 using StaticArrays, LinearAlgebra, Random, IntervalArithmetic
 using MathematicalSystems, HybridSystems
-using JuMP, Mosek, MosekTools
+using JuMP, Clarabel
 using Plots, Colors
 using Test
 Random.seed!(0)
@@ -20,10 +20,7 @@ include("../../../problems/non_linear.jl")
 concrete_problem = NonLinear.problem()
 concrete_system = concrete_problem.system
 
-# Optimizer's parameters, see https://github.com/MOSEK/Mosek.jl/issues/206
-const FALLBACK_URL = "mosek://solve.mosek.com:30080"
-sdp_opt = optimizer_with_attributes(Mosek.Optimizer, MOI.Silent() => true)
-MOI.set(sdp_opt, MOI.RawOptimizerAttribute("fallback"), FALLBACK_URL)
+sdp_opt = optimizer_with_attributes(Clarabel.Optimizer, MOI.Silent() => true)
 
 maxδx = 100
 maxδu = 10 * 2
@@ -77,7 +74,7 @@ cost_control_trajectory = ST.get_closed_loop_trajectory(
     noise = true,
 )
 cost_bound = concrete_lyap_fun(x0)
-cost_true = sum(cost_control_trajectory.costs.seq);
+cost_true = ST.get_cost(cost_control_trajectory)
 println("Goal set reached")
 println("Guaranteed cost:\t $(cost_bound)")
 println("True cost:\t\t $(cost_true)")
diff --git a/test/symbolic/test_automaton.jl b/test/symbolic/test_automaton.jl
index eb175bbd6..e8b9797c4 100644
--- a/test/symbolic/test_automaton.jl
+++ b/test/symbolic/test_automaton.jl
@@ -17,7 +17,9 @@ println("Started test")
     autom = SY.NewAutomatonList(nstates, nsymbols)
 
     SY.add_transition!(autom, 5, 9, 6)
+    @test SY.is_deterministic(autom) == true
     SY.add_transition!(autom, 5, 8, 6)
+    @test SY.is_deterministic(autom) == false
     SY.add_transition!(autom, 5, 3, 7)
     SY.add_transition!(autom, 8, 3, 6)
     SY.add_transition!(autom, 5, 5, 6)
@@ -42,6 +44,8 @@ println("Started test")
     soursymblist = SY.pre(autom, 8)
     @test length(soursymblist) == 1
     @test collect(soursymblist)[1] == (5, 6)
+
+    @test SY.is_deterministic(autom) == false
 end
 
 println("End test")
diff --git a/test/system/test_controller.jl b/test/system/test_controller.jl
index 1b67c7211..97333be34 100644
--- a/test/system/test_controller.jl
+++ b/test/system/test_controller.jl
@@ -2,7 +2,8 @@ module TestMain
 using Test
 
 using StaticArrays, LinearAlgebra, IntervalArithmetic, Random
-using JuMP, Mosek, MosekTools
+using JuMP
+using Clarabel
 using Plots
 
 using Dionysos
@@ -46,10 +47,7 @@ function trial(E2, c, μ, U, W, λ)
 
     # Solve the control problem
     S = UT.get_full_psd_matrix(problem.transition_cost)
-    # Optimizer's parameters, see https://github.com/MOSEK/Mosek.jl/issues/206
-    FALLBACK_URL = "mosek://solve.mosek.com:30080"
-    sdp_opt = optimizer_with_attributes(Mosek.Optimizer, MOI.Silent() => true)
-    MOI.set(sdp_opt, MOI.RawOptimizerAttribute("fallback"), FALLBACK_URL)
+    sdp_opt = optimizer_with_attributes(Clarabel.Optimizer, MOI.Silent() => true)
 
     maxδx = 100.0
     maxδu = 100.0


Reviews:
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T08:15:28Z
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T08:15:50Z
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T08:16:28Z
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T08:16:38Z
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T08:16:48Z
user: login: blegat
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T11:43:10Z
user: login: blegat
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-03T11:43:13Z

Review comments:
diff_hunk: @@ -26,9 +26,7 @@ concrete_problem = NonLinear.problem()
 concrete_system = concrete_problem.system
 
 # Optimizer's parameters
-const FALLBACK_URL = "mosek://solve.mosek.com:30080"
-sdp_opt = optimizer_with_attributes(Mosek.Optimizer, MOI.Silent() => true)
-MOI.set(sdp_opt, MOI.RawOptimizerAttribute("fallback"), FALLBACK_URL)
+sdp_opt = optimizer_with_attributes(COSMO.Optimizer, "verbose" => false)
path: docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl
user: login: blegat
body: ```suggestion
sdp_opt = optimizer_with_attributes(COSMO.Optimizer, MOI.Silent() => true)
```
created_at: 2025-03-03T08:15:28Z
author_association: COLLABORATOR
diff_hunk: @@ -26,9 +26,7 @@ concrete_problem = NonLinear.problem()
 concrete_system = concrete_problem.system
 
 # Optimizer's parameters
-const FALLBACK_URL = "mosek://solve.mosek.com:30080"
-sdp_opt = optimizer_with_attributes(Mosek.Optimizer, MOI.Silent() => true)
-MOI.set(sdp_opt, MOI.RawOptimizerAttribute("fallback"), FALLBACK_URL)
+sdp_opt = optimizer_with_attributes(COSMO.Optimizer, "verbose" => false)
path: docs/src/examples/solvers/Lazy-Ellipsoids-Abstraction.jl
user: login: blegat
body: this should work for any solver. It's better as then you don't need to remember the name of the option for each solver
created_at: 2025-03-03T08:15:50Z
author_association: COLLABORATOR
diff_hunk: @@ -25,12 +26,13 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer
     control_solver::Union{Nothing, MOI.AbstractOptimizer}
     concrete_controller::Any
     solve_time_sec::T
+    verbose::Bool
 
-    function Optimizer{T}() where {T}
-        return new{T}(nothing, nothing, nothing, 0.0)
+    function Optimizer{T}(verbose::Bool = true) where {T}
path: src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
user: login: blegat
body: ```suggestion
    function Optimizer{T}(; verbose::Bool = true) where {T}
```
created_at: 2025-03-03T08:16:28Z
author_association: COLLABORATOR
diff_hunk: @@ -25,12 +26,13 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer
     control_solver::Union{Nothing, MOI.AbstractOptimizer}
     concrete_controller::Any
     solve_time_sec::T
+    verbose::Bool
 
-    function Optimizer{T}() where {T}
-        return new{T}(nothing, nothing, nothing, 0.0)
+    function Optimizer{T}(verbose::Bool = true) where {T}
+        return new{T}(nothing, nothing, nothing, 0.0, verbose)
     end
 end
-Optimizer() = Optimizer{Float64}()
+Optimizer() = Optimizer{Float64}(true)
path: src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
user: login: blegat
body: ```suggestion
Optimizer() = Optimizer{Float64}(verbose = true)
```
created_at: 2025-03-03T08:16:38Z
author_association: COLLABORATOR
diff_hunk: @@ -25,12 +26,13 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer
     control_solver::Union{Nothing, MOI.AbstractOptimizer}
     concrete_controller::Any
     solve_time_sec::T
+    verbose::Bool
 
-    function Optimizer{T}() where {T}
-        return new{T}(nothing, nothing, nothing, 0.0)
+    function Optimizer{T}(verbose::Bool = true) where {T}
+        return new{T}(nothing, nothing, nothing, 0.0, verbose)
     end
 end
-Optimizer() = Optimizer{Float64}()
+Optimizer() = Optimizer{Float64}(true)
path: src/optim/abstraction/UniformGridAbstraction/uniform_grid_abstraction.jl
user: login: blegat
body: Otherwise, it's not clear chat this Bool is
created_at: 2025-03-03T08:16:48Z
author_association: COLLABORATOR
diff_hunk: @@ -211,24 +214,41 @@ function MOI.optimize!(optimizer::OptimizerEmptyProblem)
         _get_domain_list(concrete_system.U, optimizer.input_grid, Dionysos.Domain.CENTER),
     )
 
+    if optimizer.print_level >= 2
path: src/optim/abstraction/UniformGridAbstraction/empty_problem.jl
user: login: blegat
body: Nice use of multi-level printing :)
created_at: 2025-03-03T11:43:10Z
author_association: COLLABORATOR

PR comments:
user: login: JulienCalbert
created_at: 2025-03-02T21:51:24Z
body: @blegat I replaced mosek by COSMO (I need to manage -log(det) objective function). It works in local but it fails on github test. Any idea ? 
author_association: COLLABORATOR
user: login: JulienCalbert
created_at: 2025-03-03T07:54:59Z
body: On github the **number of steps** and **optimal value** are: 3250	-1.3894e+00
while on my computer                                                              : 1550    -1.5947e+00 
(the goal is to minimize)
But the status is "solved" even on github...
author_association: COLLABORATOR
user: login: blegat
created_at: 2025-03-03T08:18:45Z
body: COSMO is first order and less accurate, I would recommend Clarabel
author_association: COLLABORATOR
user: login: blegat
created_at: 2025-03-03T08:19:30Z
body: > I need to manage -log(det) objective function

What do you mean ? Mosek also does not support `-log(det)`
author_association: COLLABORATOR
user: login: blegat
created_at: 2025-03-03T08:22:16Z
body: This PR mixes two changes : Adding verbose flag everywhere and switching from Mosek to COSMO. It's maybe easier to make it two PRs because the verbose flag might create some bikeshedding.

For the verbose flag, I prefer `verbosity::Int` or `print_level::Int` over `verbose::Bool` as that allows some granuarity. `print_level = 0` is complete silence, `print_level = 1` is the default, just a bit of output to see the solver is doing some work (should print every few seconds some update like most solvers do). `print_level = 2` gives additional debug, etc...
author_association: COLLABORATOR
user: login: JulienCalbert
created_at: 2025-03-03T10:30:47Z
body: It works well with Clarabel.
Ok I agree, but in the end few changes were necessary to remove Mozek. I implemented your reviews.
author_association: COLLABORATOR