Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
LazySets = "b4f0291d-fe17-52bc-9479-3d1a343d9043"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
MathematicalSystems = "d14a8603-c872-5ed3-9ece-53e0e82e39da"
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
ReachabilityBase = "379f33d0-9447-4353-bd03-d664070e549f"
Expand All @@ -25,6 +26,7 @@ LaTeXStrings = "1"
LazySets = "2.14, 3, 4, 5"
Literate = "2"
MathematicalSystems = "0.14.1"
Optim = "0.15 - 0.22, 1"
OrdinaryDiffEq = "6"
Plots = "1"
ReachabilityBase = "0.2.3 - 0.3"
Expand Down
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Documenter, ReachabilityAnalysis, DocumenterCitations

# load optional packages for complete documentation
import ExponentialUtilities
import ExponentialUtilities, Optim

DocMeta.setdocmeta!(ReachabilityAnalysis, :DocTestSetup,
:(using ReachabilityAnalysis); recursive=true)
Expand Down
1 change: 1 addition & 0 deletions docs/src/tutorials/linear_methods/discrete_time.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ To gain some intuition, let's build the matrix and apply it to some points.
```@example discrete_propagation
using ReachabilityAnalysis, Plots
using ReachabilityAnalysis: center
import Optim

# initial set
X0 = BallInf(ones(2), 0.2)
Expand Down
184 changes: 34 additions & 150 deletions src/Flowpipes/recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ using LazySets: plot_recipe,
isapproxzero,
_plot_singleton_list

DEFAULT_COLOR_FLOWPIPE = :blue

# heuristics for projecting a reach-set either concretely or lazily to the space
# spanned by vars; the returned set is concrete when the exact projection can be done
# efficiently; in all other cases a lazy set is returned
Expand Down Expand Up @@ -65,7 +67,7 @@ end

function _project_reachset(::Type{<:LazySet}, R, vars)
πR = Projection(R, vars) # lazy projection
return X = set(πR)
return set(πR)
end

# ---------------------------------------
Expand Down Expand Up @@ -128,9 +130,6 @@ end
vars=nothing,
ε=N(PLOT_PRECISION)) where {N}
_check_vars(vars)
X = _project_reachset(R, vars)

dim(X) == 1 && return plot_recipe(X, ε)

label --> DEFAULT_LABEL
grid --> DEFAULT_GRID
Expand All @@ -140,121 +139,20 @@ end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR

# extract limits and extrema of already plotted sets
p = plotattributes[:plot_object]
lims = _extract_limits(p, plotattributes)
extr = _extract_extrema(p)

if !isbounded(X)
_set_auto_limits_to_extrema!(lims, extr)
X = intersection(X, _bounding_hyperrectangle(lims, eltype(X)))

elseif length(p) > 0
# if there is already a plotted set and the limits are fixed,
# automatically adjust the axis limits (e.g. after plotting a unbounded set)
_update_plot_limits!(lims, X)
end

xlims --> lims[:x]
ylims --> lims[:y]

x, y = plot_recipe(X, ε)
if !isempty(x)
m = length(x)
if m == 1
seriestype := :scatter
elseif m == 2 && isapproxzero((x[1] - x[2])^2 + (y[1] - y[2])^2)
seriestype := :scatter
else
seriestype := :shape
end
end
return (x, y)
end

# TODO use LazySets._plot_singleton_list_1D if the reach-sets are stored as a struct
# array. Otherwise, we could use pass the list through x -> set(x)
function _plot_singleton_list_1D(list::Union{Flowpipe{N},AbstractVector{<:AbstractReachSet{N}}}) where {N}
m = length(list)

x = Vector{N}(undef, m)
y = zeros(N, m)

@inbounds for (i, Xi) in enumerate(list)
p = element(set(Xi))
x[i] = p[1]
end
return x, y
end

function _plot_singleton_list_2D(list::Union{Flowpipe{N},AbstractVector{<:AbstractReachSet{N}}}) where {N}
m = length(list)
x = Vector{N}(undef, m)
y = Vector{N}(undef, m)

@inbounds for (i, Xi) in enumerate(list)
p = element(set(Xi))
x[i] = p[1]
y[i] = p[2]
end
return x, y
X = _project_reachset(R, vars)
return X
end

function _plot_reachset_list(list, N, vars, ε, Nφ)
first = true
x = Vector{N}()
y = Vector{N}()
for Ri in list
Xi = _project_reachset(Ri, vars)

if Xi isa Intersection
xcoords, ycoords = plot_recipe(Xi, ε, Nφ)

else
Pi = isoperation(Xi) ? overapproximate(Xi, ε) : Xi
vlist = convex_hull(vertices_list(Pi))
m = length(vlist)
if m == 0
@warn "overapproximation during plotting was empty"
continue
end
xcoords = Vector{N}(undef, m)
ycoords = Vector{N}(undef, m)
@inbounds for (i, v) in enumerate(vlist)
xcoords[i] = v[1]
ycoords[i] = v[2]
end
if m > 1
# add first vertex to "close" the polygon
push!(xcoords, xcoords[1])
push!(ycoords, ycoords[1])
end
end
isempty(xcoords) && continue

x_new = xcoords
y_new = ycoords

if first
first = false
else
push!(x, N(NaN))
push!(y, N(NaN))
end
append!(x, x_new)
append!(y, y_new)
end
return x, y
function _plot_reachset_list(list, vars)
return [_project_reachset(Ri, vars) for Ri in list]
end

# ========================
# Flowpipe plot recipes
# ========================

@recipe function plot_list(list::Union{Flowpipe{N},AbstractVector{<:AbstractReachSet{N}}};
vars=nothing,
ε=N(PLOT_PRECISION),
Nφ=PLOT_POLAR_DIRECTIONS) where {N}
vars=nothing) where {N}
_check_vars(vars)

label --> DEFAULT_LABEL
Expand All @@ -263,22 +161,20 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE

if !(0 ∈ vars) && (setrep(list) <: AbstractSingleton)
@series if !(0 ∈ vars) && (setrep(list) <: AbstractSingleton)
seriestype --> :scatter
_plot_singleton_list(list)
else
seriestype --> :shape
_plot_reachset_list(list, N, vars, ε, Nφ)
_plot_reachset_list(list, vars)
end
end

# composite flowpipes
@recipe function plot_list(fp::Union{<:HybridFlowpipe{N},<:MixedFlowpipe{N}};
vars=nothing,
ε=Float64(PLOT_PRECISION),
Nφ=PLOT_POLAR_DIRECTIONS) where {N}
vars=nothing) where {N}
_check_vars(vars)

label --> DEFAULT_LABEL
Expand All @@ -287,30 +183,24 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE
seriestype --> :shape

x = Vector{N}()
y = Vector{N}()

for F in fp
x_new, y_new = _plot_reachset_list(F, N, vars, ε, Nφ)
append!(x, x_new)
append!(y, y_new)
push!(x, N(NaN))
push!(y, N(NaN))
@series begin
Xs = LazySet{N}[]
for F in fp
append!(Xs, _plot_reachset_list(F, vars))
end
Xs
end
return x, y
end

# ========================
# Solution plot recipes
# ========================

@recipe function plot_list(sol::ReachSolution{<:Flowpipe{N}};
vars=nothing,
ε=Float64(PLOT_PRECISION),
Nφ=PLOT_POLAR_DIRECTIONS) where {N}
vars=nothing) where {N}
_check_vars(vars)

label --> DEFAULT_LABEL
Expand All @@ -319,24 +209,22 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE

fp = flowpipe(sol)
if !(0 ∈ vars) && (setrep(fp) <: AbstractSingleton)
@series if !(0 ∈ vars) && (setrep(fp) <: AbstractSingleton)
seriestype --> :scatter
_plot_singleton_list(fp)
else
seriestype --> :shape
_plot_reachset_list(fp, N, vars, ε, Nφ)
_plot_reachset_list(fp, vars)
end
end

# compound solution flowpipes
@recipe function plot_list(sol::Union{ReachSolution{<:MixedFlowpipe{N}},
ReachSolution{<:HybridFlowpipe{N}}};
vars=nothing,
ε=Float64(PLOT_PRECISION),
Nφ=PLOT_POLAR_DIRECTIONS) where {N}
vars=nothing) where {N}
_check_vars(vars)

label --> DEFAULT_LABEL
Expand All @@ -345,21 +233,17 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE
seriestype --> :shape

x = Vector{N}()
y = Vector{N}()

fp = flowpipe(sol)
for F in fp
x_new, y_new = _plot_reachset_list(F, N, vars, ε, Nφ)
append!(x, x_new)
append!(y, y_new)
push!(x, N(NaN))
push!(y, N(NaN))
@series begin
fp = flowpipe(sol)
Xs = LazySet{N}[]
for F in fp
append!(Xs, _plot_reachset_list(F, vars))
end
Xs
end
return x, y
end

# TODO new plot recipe to dispatch on ShiftedFlowpipe
Expand All @@ -379,7 +263,7 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE
seriestype --> :shape

first = true
Expand Down Expand Up @@ -450,7 +334,7 @@ end
aspect_ratio --> DEFAULT_ASPECT_RATIO
end
seriesalpha --> DEFAULT_ALPHA
seriescolor --> DEFAULT_COLOR
seriescolor --> DEFAULT_COLOR_FLOWPIPE
seriestype --> :scatter
markershape --> :circle

Expand Down
Loading