From 18a1e0474b71669e4ec4fedada4e31264ad19449 Mon Sep 17 00:00:00 2001 From: mforets Date: Mon, 22 Apr 2019 15:38:02 -0300 Subject: [PATCH 01/19] use eps by default in plots --- src/plot_recipes.jl | 166 ++++++++++++++------------------------------ 1 file changed, 53 insertions(+), 113 deletions(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 767f8d322c..160dbc25dd 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -1,6 +1,8 @@ using RecipesBase import RecipesBase.apply_recipe +using LazySets.Approximations: overapproximate + function warn_empty_polytope() @warn "received a polytope with no vertices during plotting" end @@ -10,45 +12,66 @@ end # ==================================== """ - plot_lazyset(S::LazySet; ...) + plot_lazyset(X::LazySet, [ε]::Float64; ...) -Plot a convex set in two dimensions using an axis-aligned approximation. +Plot a convex set in two dimensions. ### Input -- `S` -- convex set +- `X` -- convex set +- `ε` -- (optional, default: `1e-3`) approximation error bound ### Examples -```jldoctest +```jldoctest test_plot_lazyset julia> using Plots, LazySets julia> B = BallInf(ones(2), 0.1); julia> plot(2.0 * B); +``` + +An iterative refinement method is applied to obtain an overapproximation of `X` +in constraint representation, which is then plotted. To change the default tolerance +for the iterative refinement, use the second argument: + +```jldoctest test_plot_lazyset +julia> B = Ball2(ones(2), 0.1); + +julia> plot(B, 1e-3); +julia> plot(B, 1e-2); # faster than the previous algorithm, but less accurate ``` ### Algorithm -For any 2D lazy set we compute its box overapproximation, followed by the list of -vertices. A post-processing `convex_hull` is applied to the vertices list; -this ensures that the shaded area inside the convex hull of the vertices is covered +In first stage, an overapproximation of the given set to a polygon in constraint +representation is computed. The second argument, `ε`, corresponds to the error +in Hausdorff distance between the overapproximating set and `X`. The default +value `1e-3` is chosen such that the unit ball in the 2-norm is plotted with +reasonable accuracy. On the other hand, if you only want to produce a fast +box-overapproximation of `X`, pass `ε=Inf`. + +In a second stage, the list of vertices of the overapproximation is computed +with the `vertices_list` function of the polygon. + +A post-processing `convex_hull` is applied to the vertices list to ensure +that the shaded area inside the convex hull of the vertices is covered correctly. ### Notes -This recipe detects if the axis-aligned approximation is such that the first two -vertices returned by `vertices_list` are the same. In that case, a scatter plot -is used (instead of a shape plot). This use case arises, for example, when -plotting singletons. +This recipe detects if overapproximation is such that the first two vertices +returned by `vertices_list` are the same. In that case, a scatter plot is used +(instead of a shape plot). This corner case arises, for example, when lazy linear +maps of singletons. """ -@recipe function plot_lazyset(S::LazySet; +@recipe function plot_lazyset(X::LazySet, ε::Float64=1e-3; color="blue", label="", grid=true, alpha=0.5) - @assert dim(S) == 2 "cannot plot a $(dim(S))-dimensional set" + @assert dim(X) == 2 "cannot plot a $(dim(S))-dimensional set" - P = Approximations.overapproximate(S) + P = overapproximate(X, ε) vlist = transpose(hcat(convex_hull(vertices_list(P))...)) if isempty(vlist) @@ -68,14 +91,14 @@ plotting singletons. end """ - plot_lazyset(Xk::Vector{S}) where {S<:LazySet} + plot_lazyset(Xk::Vector{LazySet}, [ε]::Float64; ...) -Plot an array of convex sets in two dimensions using an axis-aligned -approximation. +Plot an array of convex sets in two dimensions. ### Input - `Xk` -- array of convex sets +- `ε` -- (optional, default: `1e-3`) approximation error bound ### Examples @@ -87,101 +110,13 @@ julia> B1 = BallInf(zeros(2), 0.4); julia> B2 = BallInf(ones(2), 0.4); julia> plot([B1, B2]); - ``` -### Algorithm - -For each 2D lazy set in the array we compute its box overapproximation, followed -by the list of vertices. A post-processing `convex_hull` is applied to the vertices list; -this ensures that the shaded area inside the convex hull of the vertices is covered -correctly. -""" -@recipe function plot_lazyset(Xk::Vector{S}; - seriescolor="blue", label="", grid=true, - alpha=0.5) where {S<:LazySet} - - seriestype := :shape - - for X in Xk - if X isa EmptySet - continue - end - @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set" - Pi = Approximations.overapproximate(X) - vlist = transpose(hcat(convex_hull(vertices_list(Pi))...)) - - if isempty(vlist) - warn_empty_polytope() - continue - end - - x, y = vlist[:, 1], vlist[:, 2] - - # add first vertex to "close" the polygon - push!(x, vlist[1, 1]) - push!(y, vlist[1, 2]) - - @series (x, y) - end -end - -""" - plot_lazyset(S::LazySet, ε::Float64; ...) - -Plot a lazy set in two dimensions using iterative refinement. - -### Input - -- `S` -- convex set -- `ε` -- approximation error bound - -### Examples - -```jldoctest -julia> using Plots, LazySets; - -julia> B = BallInf(ones(2), 0.1); - -julia> plot(randn(2, 2) * B, 1e-3); - -``` -""" -@recipe function plot_lazyset(S::LazySet, ε::Float64; - color="blue", label="", grid=true, alpha=0.5) - - @assert dim(S) == 2 "cannot plot a $(dim(S))-dimensional set" - seriestype := :shape - - P = Approximations.overapproximate(S, ε) - vlist = transpose(hcat(vertices_list(P)...)) - - if isempty(vlist) - warn_empty_polytope() - return [] - end - - (x, y) = vlist[:, 1], vlist[:, 2] - - # add first vertex to "close" the polygon - push!(x, vlist[1, 1]) - push!(y, vlist[1, 2]) - - x, y -end - -""" - plot_lazyset(Xk::Vector{S}, ε::Float64; ...) where {S<:LazySet} - -Plot an array of lazy sets in two dimensions using iterative refinement. - -### Input - -- `Xk` -- array of convex sets -- `ε` -- approximation error bound - -### Examples +An iterative refinement method is applied to obtain an overapproximation of each +set in `Xk` in constraint representation, which is then plotted. To change the +default tolerance for the iterative refinement, use the second argument: +```julia ```jldoctest julia> using Plots, LazySets; @@ -189,11 +124,16 @@ julia> B1 = BallInf(zeros(2), 0.4); julia> B2 = Ball2(ones(2), 0.4); -julia> plot([B1, B2], 1e-4); +julia> plot([B1, B2], 1e-1); # faster but less accurate +julia> plot([B1, B2], 1e-4); # slower but more accurate ``` + +### Algorithm + +See the documentation of `plot_lazyset(S::LazySet, [ε]::Float64; ...)` for details. """ -@recipe function plot_lazyset(Xk::Vector{S}, ε::Float64; +@recipe function plot_lazyset(Xk::Vector{S}, ε::Float64=1e-3; seriescolor="blue", label="", grid=true, alpha=0.5) where {S<:LazySet} @@ -204,8 +144,8 @@ julia> plot([B1, B2], 1e-4); continue end @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set" - Pi = Approximations.overapproximate(X, ε) - vlist = transpose(hcat(vertices_list(Pi)...)) + Pi = overapproximate(X, ε) + vlist = transpose(hcat(convex_hull(vertices_list(Pi))...)) if isempty(vlist) warn_empty_polytope() From fa9f5181ee05df37a78ed2859d594a6afdff5558 Mon Sep 17 00:00:00 2001 From: mforets Date: Mon, 22 Apr 2019 18:18:46 -0300 Subject: [PATCH 02/19] remove plotting with rational --- src/plot_recipes.jl | 20 ++++++++++++++++++-- test/unit_plot.jl | 10 +++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 160dbc25dd..c236ed886f 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -69,7 +69,7 @@ maps of singletons. @recipe function plot_lazyset(X::LazySet, ε::Float64=1e-3; color="blue", label="", grid=true, alpha=0.5) - @assert dim(X) == 2 "cannot plot a $(dim(S))-dimensional set" + @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set using iterative refinement" P = overapproximate(X, ε) vlist = transpose(hcat(convex_hull(vertices_list(P))...)) @@ -143,7 +143,7 @@ See the documentation of `plot_lazyset(S::LazySet, [ε]::Float64; ...)` for deta if X isa EmptySet continue end - @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set" + @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set using iterative refinement" Pi = overapproximate(X, ε) vlist = transpose(hcat(convex_hull(vertices_list(Pi))...)) @@ -539,3 +539,19 @@ julia> plot(∅, 1e-2); legend=false) return [] end + +@recipe function plot_universe(::Universe, ε::Float64=0.0) + error("cannot plot the universal set") +end + +@recipe function plot_line(::Line, ε::Float64=0.0) + error("cannot plot an infinite line") +end + +@recipe function plot_halfspace(::HalfSpace, ε::Float64=0.0) + error("cannot plot a half-space") +end + +@recipe function plot_hyperplane(::Hyperplane, ε::Float64=0.0) + error("cannot plot a hyperplane") +end diff --git a/test/unit_plot.jl b/test/unit_plot.jl index 95ce33a328..0bd3a146bb 100644 --- a/test/unit_plot.jl +++ b/test/unit_plot.jl @@ -1,4 +1,4 @@ -for N in [Float64, Rational{Int}, Float32] +for N in [Float64, Float32] p0 = zero(N) p1 = one(N) v0 = zeros(N, 2) @@ -73,10 +73,10 @@ for N in [Float64, Rational{Int}, Float32] plot(vpg) plot(vpt) plot(es) - @test_throws Exception plot(hs) # TODO see #576 - @test_throws Exception plot(hp) # TODO see #576 + @test_throws ErrorException plot(hs) # TODO see #576 + @test_throws ErrorException plot(hp) # TODO see #576 @test_throws ErrorException plot(l) # TODO see #576 - @test_throws Exception plot(uni) # TODO see #576 + @test_throws ErrorException plot(uni) # TODO see #576 plot(ch) plot(cha) plot(sih) @@ -108,7 +108,7 @@ for N in [Float64, Rational{Int}, Float32] @test_throws ErrorException plot(hs, ε) # TODO see #576/#578 @test_throws ErrorException plot(hp, ε) # TODO see #576/#578 @test_throws ErrorException plot(l, ε) # TODO see #576/#578 - plot(uni, ε) + @test_throws ErrorException plot(uni, ε) # TODO see #576/#578 plot(ch, ε) plot(cha, ε) plot(sih, ε) From d60b185b74a06d2e08f0df3e7b3634928d5cefa5 Mon Sep 17 00:00:00 2001 From: mforets Date: Mon, 22 Apr 2019 20:33:02 -0300 Subject: [PATCH 03/19] fixes --- src/plot_recipes.jl | 31 ++++++++++++++++++++++++++++++- test/unit_plot.jl | 5 ++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index c236ed886f..305251314a 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -1,7 +1,7 @@ using RecipesBase import RecipesBase.apply_recipe -using LazySets.Approximations: overapproximate +using LazySets.Approximations: overapproximate, PolarDirections function warn_empty_polytope() @warn "received a polytope with no vertices during plotting" @@ -555,3 +555,32 @@ end @recipe function plot_hyperplane(::Hyperplane, ε::Float64=0.0) error("cannot plot a hyperplane") end + +@recipe function plot_intersection(X::Intersection; Nφ=10, + color="blue", label="", grid=true, alpha=0.5) + + @assert dim(X) == 2 "this recipe only plots two-dimensional sets" + + P = convert(HPolygon, overapproximate(X, PolarDirections(Nφ))) + vlist = transpose(hcat(convex_hull(vertices_list(P))...)) + + if isempty(vlist) + warn_empty_polytope() + return [] + end + + (x, y) = vlist[:, 1], vlist[:, 2] + + # add first vertex to "close" the polygon + push!(x, vlist[1, 1]) + push!(y, vlist[1, 2]) + + seriestype := norm(vlist[1, :] - vlist[2, :]) ≈ 0 ? :scatter : :shape + + x, y +end + +#@recipe function plot_intersection(::Intersection, ε::Float64=0.0) +# error("cannot plot a lazy intersection using iterative refinement " * +# "(the exact support vector of an intersection is not implemented)") +#end diff --git a/test/unit_plot.jl b/test/unit_plot.jl index 0bd3a146bb..1e1b5f3370 100644 --- a/test/unit_plot.jl +++ b/test/unit_plot.jl @@ -1,4 +1,4 @@ -for N in [Float64, Float32] +for N in [Float64] p0 = zero(N) p1 = one(N) v0 = zeros(N, 2) @@ -125,7 +125,7 @@ for N in [Float64, Float32] end # set types that do not work with Rational{Int} -for N in [Float64, Float32] +for N in [Float64] v0 = zeros(N, 2) p1 = one(N) @@ -190,6 +190,5 @@ for N in [Float64] # ε-close ε = N(1e-2) - plot(its) @test_throws ErrorException plot(itsa, ε) # TODO not implemented yet end From 6138084d86f8bf9fc687be4a5d95015b128613b2 Mon Sep 17 00:00:00 2001 From: mforets Date: Tue, 23 Apr 2019 12:08:50 -0300 Subject: [PATCH 04/19] fixes --- docs/src/lib/interfaces.md | 7 +++---- src/plot_recipes.jl | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/docs/src/lib/interfaces.md b/docs/src/lib/interfaces.md index 2dc667789c..6f0396807a 100644 --- a/docs/src/lib/interfaces.md +++ b/docs/src/lib/interfaces.md @@ -59,10 +59,9 @@ diameter(::LazySet, ::Real=Inf) isbounded(::LazySet) isbounded_unit_dimensions(::LazySet{N}) where {N<:Real} an_element(::LazySet{N}) where {N<:Real} -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:LazySet} -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet, ::Float64) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}, ::Float64) where {S<:LazySet} +RecipesBase.apply_recipe(∅::EmptySet{Float64}, ε::Float64=0.0) +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet{Float64}, ε::Float64=1e-3) +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{LazySet{Float64}}, ε::Float64=1e-3) tosimplehrep(::LazySet) isuniversal(::LazySet{N}, ::Bool=false) where {N<:Real} ``` diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 305251314a..988950b7d2 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -12,7 +12,7 @@ end # ==================================== """ - plot_lazyset(X::LazySet, [ε]::Float64; ...) + plot_lazyset(X::LazySet{N}, [ε]::N=N(1e-3); ...) where {N<:Real} Plot a convex set in two dimensions. @@ -66,8 +66,8 @@ returned by `vertices_list` are the same. In that case, a scatter plot is used (instead of a shape plot). This corner case arises, for example, when lazy linear maps of singletons. """ -@recipe function plot_lazyset(X::LazySet, ε::Float64=1e-3; - color="blue", label="", grid=true, alpha=0.5) +@recipe function plot_lazyset(X::LazySet{N}, ε::N=N(1e-3); + color="blue", label="", grid=true, alpha=0.5) where {N} @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set using iterative refinement" @@ -91,7 +91,7 @@ maps of singletons. end """ - plot_lazyset(Xk::Vector{LazySet}, [ε]::Float64; ...) + plot_lazyset(Xk::Vector{LazySet{N}}, ε::N=N(1e-3); ...) where {N<:Real} Plot an array of convex sets in two dimensions. @@ -133,9 +133,9 @@ julia> plot([B1, B2], 1e-4); # slower but more accurate See the documentation of `plot_lazyset(S::LazySet, [ε]::Float64; ...)` for details. """ -@recipe function plot_lazyset(Xk::Vector{S}, ε::Float64=1e-3; +@recipe function plot_lazyset(Xk::Vector{LazySet{N}}, ε::N=N(1e-3); seriescolor="blue", label="", grid=true, - alpha=0.5) where {S<:LazySet} + alpha=0.5) where {N<:Real} seriestype := :shape @@ -535,24 +535,24 @@ julia> plot(∅, 1e-2); ``` """ -@recipe function plot_emptyset(∅::EmptySet, ε::Float64=0.0; label="", grid=true, - legend=false) +@recipe function plot_emptyset(∅::EmptySet{N}, ε::N=N(0.0); label="", grid=true, + legend=false) where {N<:Real} return [] end -@recipe function plot_universe(::Universe, ε::Float64=0.0) +@recipe function plot_universe(::Universe{N}, ε::N=N(0.0)) where {N<:Real} error("cannot plot the universal set") end -@recipe function plot_line(::Line, ε::Float64=0.0) +@recipe function plot_line(::Line{N}, ε::N=N(0.0)) where {N<:Real} error("cannot plot an infinite line") end -@recipe function plot_halfspace(::HalfSpace, ε::Float64=0.0) +@recipe function plot_halfspace(::HalfSpace{N}, ε::N=N(0.0)) where {N<:Real} error("cannot plot a half-space") end -@recipe function plot_hyperplane(::Hyperplane, ε::Float64=0.0) +@recipe function plot_hyperplane(::Hyperplane{N}, ε::N=N(0.0)) where {N<:Real} error("cannot plot a hyperplane") end @@ -580,7 +580,7 @@ end x, y end -#@recipe function plot_intersection(::Intersection, ε::Float64=0.0) +#@recipe function plot_intersection(::Intersection{N}, ε::N=N(0.0)) where {N<:Real} # error("cannot plot a lazy intersection using iterative refinement " * # "(the exact support vector of an intersection is not implemented)") #end From 807f499d6dc44f9a29bdcc02d942c5028b5f7dff Mon Sep 17 00:00:00 2001 From: mforets Date: Wed, 24 Apr 2019 08:29:09 -0300 Subject: [PATCH 05/19] Fix intersectionc --- src/plot_recipes.jl | 61 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 988950b7d2..28396abe6e 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -515,14 +515,14 @@ end # ============================== """ - plot_emptyset(∅::EmptySet, [ε::Float64=0.0]; ...) + plot_emptyset(∅::EmptySet, [ε]; ...) Plot an empty set. ### Input - `∅` -- empty set -- `ε` -- (optional, default: `0.0`) approximation error bound +- `ε` -- (optional, default: `0`) approximation error bound ### Examples @@ -535,32 +535,70 @@ julia> plot(∅, 1e-2); ``` """ -@recipe function plot_emptyset(∅::EmptySet{N}, ε::N=N(0.0); label="", grid=true, +@recipe function plot_emptyset(∅::EmptySet{N}, ε::N=zero(N); label="", grid=true, legend=false) where {N<:Real} return [] end -@recipe function plot_universe(::Universe{N}, ε::N=N(0.0)) where {N<:Real} +@recipe function plot_universe(::Universe{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot the universal set") end -@recipe function plot_line(::Line{N}, ε::N=N(0.0)) where {N<:Real} +@recipe function plot_line(::Line{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot an infinite line") end -@recipe function plot_halfspace(::HalfSpace{N}, ε::N=N(0.0)) where {N<:Real} +@recipe function plot_halfspace(::HalfSpace{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot a half-space") end -@recipe function plot_hyperplane(::Hyperplane{N}, ε::N=N(0.0)) where {N<:Real} +@recipe function plot_hyperplane(::Hyperplane{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot a hyperplane") end -@recipe function plot_intersection(X::Intersection; Nφ=10, - color="blue", label="", grid=true, alpha=0.5) +""" + plot_intersection(X::Intersection{N}, ε::N=-one(N); Nφ=40, + color="blue", label="", grid=true, alpha=0.5) where {N} + +Plot a lazy intersection. + +### Input + +- `X` -- lazy intersection +- `ε` -- (optional, default -1) ignored, used only for dispatch +- `Nφ` -- (optional, default: `40`) number of template directions used in the + template overapproximation + +### Notes + +The vertices list of an `HPolygon` has known issues (see LazySets#1306). Consider +using the `Polyhedra` backend to compute the dual representation, as in: + +```julia +julia> using Polyhedra, LazySets.Approximations + +julia> X = rand(Ball2) ∩ rand(Ball2); # lazy intersection + +julia> Nφ = 40; # or a bigger number + +julia> P = convert(HPolytope, overapproximate(X, PolarDirections(Nφ)); + +julia> plot(P) +``` +""" +@recipe function plot_intersection(X::Intersection{N}, ε::N=-one(N); Nφ=40, + color="blue", label="", grid=true, alpha=0.5) where {N} @assert dim(X) == 2 "this recipe only plots two-dimensional sets" + if ε != -one(N) + error("cannot plot a lazy intersection using iterative refinement with " * + "error threshold `ε = $ε`, because the exact support vector of an " * + "intersection is not available; using instead a set of `Nφ` " * + "template directions. To control the number of directions, pass the " * + "variable Nφ as in `plot(X, Nφ=...)`") + end + P = convert(HPolygon, overapproximate(X, PolarDirections(Nφ))) vlist = transpose(hcat(convex_hull(vertices_list(P))...)) @@ -579,8 +617,3 @@ end x, y end - -#@recipe function plot_intersection(::Intersection{N}, ε::N=N(0.0)) where {N<:Real} -# error("cannot plot a lazy intersection using iterative refinement " * -# "(the exact support vector of an intersection is not implemented)") -#end From f565e1eddb391bb8dda119ba8cd16427a722830a Mon Sep 17 00:00:00 2001 From: mforets Date: Wed, 1 May 2019 12:35:39 +1000 Subject: [PATCH 06/19] add all docstrings and fix tests --- docs/src/lib/interfaces.md | 23 +- docs/src/lib/operations.md | 1 + docs/src/lib/representations.md | 14 +- docs/src/man/reach_zonotopes.md | 8 +- src/plot_recipes.jl | 385 ++++++++++++++++++-------------- test/unit_plot.jl | 154 +++++-------- 6 files changed, 307 insertions(+), 278 deletions(-) diff --git a/docs/src/lib/interfaces.md b/docs/src/lib/interfaces.md index 6f0396807a..58e7cd0626 100644 --- a/docs/src/lib/interfaces.md +++ b/docs/src/lib/interfaces.md @@ -59,13 +59,17 @@ diameter(::LazySet, ::Real=Inf) isbounded(::LazySet) isbounded_unit_dimensions(::LazySet{N}) where {N<:Real} an_element(::LazySet{N}) where {N<:Real} -RecipesBase.apply_recipe(∅::EmptySet{Float64}, ε::Float64=0.0) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet{Float64}, ε::Float64=1e-3) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{LazySet{Float64}}, ε::Float64=1e-3) tosimplehrep(::LazySet) isuniversal(::LazySet{N}, ::Bool=false) where {N<:Real} ``` +The following functions dispatch in a general `LazySet` and work provided that the overapproximation using iterative refinement in two dimensions is available: + +```@docs +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet{N}, ::N=N(1e-3)) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{XN}, ::N=N(1e-3)) where {N<:Real, XN<:LazySet{N}} +``` + ### Set functions that override Base functions ```@docs @@ -134,8 +138,13 @@ This interface defines the following functions: isbounded(::AbstractPolytope) singleton_list(::AbstractPolytope{N}) where {N<:Real} isempty(::AbstractPolytope) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::AbstractPolytope) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:AbstractPolytope} +``` + +Plotting abstract polytopes is available too: + +```@docs +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::AbstractPolytope{N}, ::N=zero(N)) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{PN}, ::N=zero(N)) where {N<:Real, PN<:AbstractPolytope{N}} ``` #### Polygon @@ -243,6 +252,6 @@ high(::AbstractSingleton{N}, ::Int) where {N<:Real} low(::AbstractSingleton{N}) where {N<:Real} low(::AbstractSingleton{N}, ::Int) where {N<:Real} linear_map(::AbstractMatrix{N}, ::AbstractSingleton{N}) where {N<:Real} -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::AbstractSingleton) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:AbstractSingleton} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::AbstractSingleton{N}, ::N=zero(N)) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{SN}, ::N=zero(N)) where {N<:Real, SN<:AbstractSingleton{N}} ``` diff --git a/docs/src/lib/operations.md b/docs/src/lib/operations.md index a3b66b4ef3..ca22a3afe8 100644 --- a/docs/src/lib/operations.md +++ b/docs/src/lib/operations.md @@ -127,6 +127,7 @@ use_precise_ρ _line_search _projection linear_map(::AbstractMatrix{N}, ::Intersection{N}) where {N} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Intersection{N}, ::N=-one(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): diff --git a/docs/src/lib/representations.md b/docs/src/lib/representations.md index be65d7807d..643d7f57b2 100644 --- a/docs/src/lib/representations.md +++ b/docs/src/lib/representations.md @@ -156,7 +156,7 @@ radius(::EmptySet, ::Real=Inf) diameter(::EmptySet, ::Real=Inf) linear_map(::AbstractMatrix{N}, ::EmptySet{N}) where {N} translate(::EmptySet{N}, ::AbstractVector{N}) where {N<:Real} -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::EmptySet, ::Float64=0.0) +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::EmptySet{N}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -185,6 +185,7 @@ halfspace_right(::AbstractVector{N}, ::AbstractVector{N}) where {N<:Real} tosimplehrep(::AbstractVector{HalfSpace{N}}) where {N<:Real} remove_redundant_constraints(::AbstractVector{LinearConstraint{N}}) where {N<:Real} remove_redundant_constraints!(::AbstractVector{LinearConstraint{N}}) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::HalfSpace{N}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -206,6 +207,7 @@ isempty(::Hyperplane) constrained_dimensions(::Hyperplane{N}) where {N<:Real} constraints_list(::Hyperplane{N}) where {N<:Real} translate(::Hyperplane{N}, ::AbstractVector{N}) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Hyperplane{N}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -265,8 +267,8 @@ radius_hyperrectangle(::Interval{N}, ::Int) where {N<:Real} -(::Interval{N}, ::Interval{N}) where {N<:Real} *(::Interval{N}, ::Interval{N}) where {N<:Real} rand(::Type{Interval}) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Interval) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:Interval} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Interval{N}, ::N=zero(N)) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{Interval{N}}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) @@ -296,6 +298,7 @@ isempty(::Line) constrained_dimensions(::Line{N}) where {N<:Real} constraints_list(::Line{N}) where {N<:Real} translate(::Line{N}, ::AbstractVector{N}) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Line{N}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -317,8 +320,8 @@ halfspace_right(::LineSegment) vertices_list(::LineSegment{N}) where {N<:Real} constraints_list(::LineSegment{N}) where {N<:Real} translate(::LineSegment{N}, ::AbstractVector{N}) where {N<:Real} -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LineSegment) -RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:LineSegment} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LineSegment{N}, ::N=zero(N)) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{LineSegment{N}}, ::N=zero(N)) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -584,6 +587,7 @@ diameter(::Universe, ::Real=Inf) constraints_list(::Universe{N}) where {N<:Real} constrained_dimensions(::Universe) translate(::Universe{N}, ::AbstractVector{N}) where {N<:Real} +RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Universe{N}, ::N=zero(N)) where {N<:Real} ``` ## Zero set diff --git a/docs/src/man/reach_zonotopes.md b/docs/src/man/reach_zonotopes.md index 3ffaf5758c..ce0815a604 100644 --- a/docs/src/man/reach_zonotopes.md +++ b/docs/src/man/reach_zonotopes.md @@ -47,8 +47,8 @@ function Algorithm1(A, X0, δ, μ, T) N = floor(Int, T / δ) # preallocate arrays - Q = Vector{LazySet}(undef, N) - R = Vector{LazySet}(undef, N) + Q = Vector{LazySet{Float64}}(undef, N) + R = Vector{LazySet{Float64}}(undef, N) # initial reach set in the time interval [0, δ] ϕp = (I+ϕ) / 2 @@ -93,7 +93,7 @@ R = Algorithm1(A, X0, δ, μ, 2 * δ); # warm-up R = Algorithm1(A, X0, δ, μ, T) -plot(R, 1e-2, fillalpha=0.1) +plot(R, fillalpha=0.1) ``` @@ -115,5 +115,5 @@ R = Algorithm1(A, X0, δ, μ, 2 * δ); # warm-up R = Algorithm1(A, X0, δ, μ, T) Rproj = project(R, [1, 3], 5) -plot(Rproj, 1e-2, fillalpha=0.1, xlabel="x1", ylabel="x3") +plot(Rproj, fillalpha=0.1, xlabel="x1", ylabel="x3") ``` diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 28396abe6e..55dd736fda 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -23,29 +23,27 @@ Plot a convex set in two dimensions. ### Examples -```jldoctest test_plot_lazyset -julia> using Plots, LazySets - +```julia julia> B = BallInf(ones(2), 0.1); -julia> plot(2.0 * B); +julia> plot(2.0 * B) ``` An iterative refinement method is applied to obtain an overapproximation of `X` -in constraint representation, which is then plotted. To change the default tolerance -for the iterative refinement, use the second argument: +in constraint representation, which is then plotted. To improve the accuracy +of the iterative refinement, use the second argument using a small value: -```jldoctest test_plot_lazyset +```julia julia> B = Ball2(ones(2), 0.1); julia> plot(B, 1e-3); -julia> plot(B, 1e-2); # faster than the previous algorithm, but less accurate +julia> plot(B, 1e-2); # faster than the previous try, but less accurate ``` ### Algorithm -In first stage, an overapproximation of the given set to a polygon in constraint +In a first stage, an overapproximation of the given set to a polygon in constraint representation is computed. The second argument, `ε`, corresponds to the error in Hausdorff distance between the overapproximating set and `X`. The default value `1e-3` is chosen such that the unit ball in the 2-norm is plotted with @@ -67,7 +65,7 @@ returned by `vertices_list` are the same. In that case, a scatter plot is used maps of singletons. """ @recipe function plot_lazyset(X::LazySet{N}, ε::N=N(1e-3); - color="blue", label="", grid=true, alpha=0.5) where {N} + color="blue", label="", grid=true, alpha=0.5) where {N<:Real} @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set using iterative refinement" @@ -91,60 +89,58 @@ maps of singletons. end """ - plot_lazyset(Xk::Vector{LazySet{N}}, ε::N=N(1e-3); ...) where {N<:Real} + plot_lazyset(X::Vector{XN}, ε::N=N(1e-3); ...) where {N<:Real, XN<:LazySet{N}} Plot an array of convex sets in two dimensions. ### Input -- `Xk` -- array of convex sets +- `X` -- array of convex sets - `ε` -- (optional, default: `1e-3`) approximation error bound ### Examples -```jldoctest -julia> using Plots, LazySets; - +```julia julia> B1 = BallInf(zeros(2), 0.4); julia> B2 = BallInf(ones(2), 0.4); -julia> plot([B1, B2]); +julia> plot([B1, B2]) ``` An iterative refinement method is applied to obtain an overapproximation of each -set in `Xk` in constraint representation, which is then plotted. To change the -default tolerance for the iterative refinement, use the second argument: +set in `X` in constraint representation, which is then plotted. To change the +default tolerance for the iterative refinement, use the second argument; it applies +all sets in the array. ```julia -```jldoctest -julia> using Plots, LazySets; - julia> B1 = BallInf(zeros(2), 0.4); julia> B2 = Ball2(ones(2), 0.4); -julia> plot([B1, B2], 1e-1); # faster but less accurate +julia> plot([B1, B2], 1e-1) # faster but less accurate -julia> plot([B1, B2], 1e-4); # slower but more accurate +julia> plot([B1, B2], 1e-4) # slower but more accurate ``` ### Algorithm -See the documentation of `plot_lazyset(S::LazySet, [ε]::Float64; ...)` for details. +Refer to the documentation of `plot_lazyset(S::LazySet, [ε]::Float64; ...)` for +further details. """ -@recipe function plot_lazyset(Xk::Vector{LazySet{N}}, ε::N=N(1e-3); - seriescolor="blue", label="", grid=true, - alpha=0.5) where {N<:Real} +@recipe function plot_lazysets(X::Vector{XN}, ε::N=N(1e-3); + seriescolor="blue", label="", grid=true, + alpha=0.5) where {N<:Real, XN<:LazySet{N}} seriestype := :shape - for X in Xk - if X isa EmptySet + for Xi in X + if Xi isa EmptySet continue end - @assert dim(X) == 2 "cannot plot a $(dim(X))-dimensional set using iterative refinement" - Pi = overapproximate(X, ε) + @assert dim(Xi) == 2 "cannot plot a $(dim(Xi))-dimensional set using " * + "iterative refinement" + Pi = overapproximate(Xi, ε) vlist = transpose(hcat(convex_hull(vertices_list(Pi))...)) if isempty(vlist) @@ -167,39 +163,43 @@ end # ============================== """ - plot_polygon(P::AbstractPolytope; ...) + plot_polytope(P::AbstractPolytope, [ε]::N=zero(N); ...) where {N<:Real} Plot a 2D polytope as the convex hull of its vertices. ### Input - `P` -- polygon or polytope +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest plotting_polytope -julia> using Plots, LazySets; - +```julia julia> P = HPolygon([LinearConstraint([1.0, 0.0], 0.6), LinearConstraint([0.0, 1.0], 0.6), LinearConstraint([-1.0, 0.0], -0.4), LinearConstraint([0.0, -1.0], -0.4)]); -julia> plot(P); - +julia> plot(P) ``` This recipe also applies if the polygon is given in vertex representation: -```jldoctest plotting_polytope +```julia julia> P = VPolygon([[0.6, 0.6], [0.4, 0.6], [0.4, 0.4], [0.6, 0.4]]); julia> plot(P); - ``` + +### Algorithm + +This function checks that the polytope received is two-dimensional, then +computes its vertices accessing its `vertices_list` function and takes their +convex hull. The set is plotted and shaded using the `:shape` series type from +`Plots`. """ -@recipe function plot_polytope(P::AbstractPolytope; - color="blue", label="", grid=true, alpha=0.5) +@recipe function plot_polytope(P::AbstractPolytope{N}, ε::N=zero(N); + color="blue", label="", grid=true, alpha=0.5) where {N<:Real} # for polytopes @assert dim(P) == 2 "cannot plot a $(dim(P))-dimensional polytope" @@ -223,54 +223,49 @@ julia> plot(P); end """ - plot_polytopes(Xk::Vector{S}; ...) + plot_polytopes(P::Vector{PN}, [ε]::N=zero(N); ...) where {N<:Real, PN<:AbstractPolytope{N}} -Plot an array of 2D polytopes. +Plot an array of 2D polytopes as the convex hull of their vertices. ### Input -- `Xk` -- array of polytopes +- `P` -- vector of polygons or polytopes +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest plotting_polytopes -julia> using Plots, LazySets; - -julia> P1 = HPolygon([LinearConstraint([1.0, 0.0], 0.6), - LinearConstraint([0.0, 1.0], 0.6), - LinearConstraint([-1.0, 0.0], -0.4), - LinearConstraint([0.0, -1.0], -0.4)]); - -julia> P2 = HPolygon([LinearConstraint([2.0, 0.0], 0.6), - LinearConstraint([0.0, 2.0], 0.6), - LinearConstraint([-2.0, 0.0], -0.4), - LinearConstraint([0.0, -2.0], -0.4)]); - -julia> plot([P1, P2]); +```julia +julia> P = HPolygon([LinearConstraint([1.0, 0.0], 0.6), + LinearConstraint([0.0, 1.0], 0.6), + LinearConstraint([-1.0, 0.0], -0.4), + LinearConstraint([0.0, -1.0], -0.4)]); +julia> plot(P) ``` -```jldoctest plotting_polytopes -julia> P1 = VPolygon([[0.6, 0.6], [0.4, 0.6], [0.4, 0.4], [0.6, 0.4]]); - -julia> P2 = VPolygon([[0.3, 0.3], [0.2, 0.3], [0.2, 0.2], [0.3, 0.2]]); - -julia> plot([P1, P2]); +This recipe also applies if the polygon is given in vertex representation: + +```julia +julia> P = VPolygon([[0.6, 0.6], [0.4, 0.6], [0.4, 0.4], [0.6, 0.4]]); +julia> plot(P) ``` -### Notes +### Algorithm -It is assumed that the given vector of polytopes is two-dimensional. +This function checks that the polytope received is two-dimensional, then +computes its vertices accessing its `vertices_list` function and takes their +convex hull. The set is plotted and shaded using the `:shape` series type from +`Plots`. """ -@recipe function plot_polytopes(Xk::Vector{S}; - seriescolor="blue", label="", grid=true, - alpha=0.5) where {S<:AbstractPolytope} +@recipe function plot_polytopes(P::Vector{PN}, ε::N=zero(N); + seriescolor="blue", label="", grid=true, + alpha=0.5) where {N<:Real, PN<:AbstractPolytope{N}} # it is assumed that the polytopes are two-dimensional seriestype := :shape - for Pi in Xk + for Pi in P @assert dim(Pi) == 2 "cannot plot a $(dim(Pi))-dimensional polytope" points = convex_hull(vertices_list(Pi)) vlist = transpose(hcat(points...)) @@ -295,108 +290,99 @@ end # ============================ """ - plot_singleton(X::AbstractSingleton; ...) + plot_singleton(S::AbstractSingleton{N}, [ε]::N=zero(N);; ...) where {N<:Real} Plot a singleton. ### Input -- `X` -- singleton, i.e., a one-element set +- `S` -- singleton wrapping a point, i.e., a one-element set +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - -julia> plot(Singleton([0.5, 1.0])); - +```julia +julia> plot(Singleton([0.5, 1.0])) ``` """ -@recipe function plot_singleton(point::AbstractSingleton; +@recipe function plot_singleton(S::AbstractSingleton{N}, ε::N=zero(N); color="blue", label="", grid=true, - legend=false) + legend=false) where {N<:Real} seriestype := :scatter - @assert dim(point) == 2 || - dim(point) == 3 "cannot plot a $(dim(point))-dimensional singleton" - [Tuple(element(point))] + @assert dim(S) == 2 || + dim(S) == 3 "cannot plot a $(dim(S))-dimensional singleton" + [Tuple(element(S))] end """ - plot_singleton(Xk::Vector{S}; ...) where {S<:AbstractSingleton} + plot_singletons(S::Vector{SN}, ε::N=zero(N); ...) where {N<:Real, SN<:AbstractSingleton{N}} Plot a list of singletons. ### Input -- `Xk` -- list of singletons, i.e., a vector of one-element sets +- `S` -- list of singletons, i.e., a vector of one-element sets +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - -julia> plot([Singleton([0.0, 0.0]), Singleton([1., 0]), Singleton([0.5, .5])]); - +```julia +julia> plot([Singleton([0.0, 0.0]), Singleton([1., 0]), Singleton([0.5, .5])]) ``` -Three-dimensional singletons can be plotted as well: - -```jldoctest -julia> using Plots, LazySets; +Three-dimensional singletons can be plotted as well, with this same recipe: -julia> a, b, c = zeros(3), [1.0, 0, 0], [0.0, 1., 0]; - -julia> plot([Singleton(a), Singleton(b), Singleton(c)]); +```julia +julia> a, b, c = [0.0, 0, 0], [1.0, 0, 0], [0.0, 1., 0]; +julia> plot([Singleton(a), Singleton(b), Singleton(c)]) ``` """ -@recipe function plot_singleton(Xk::Vector{S}; - color="blue", label="", grid=true, legend=false - ) where {S<:AbstractSingleton} +@recipe function plot_singletons(S::Vector{SN}, ε::N=zero(N); + color="blue", label="", + grid=true, legend=false) where {N<:Real, SN<:AbstractSingleton{N}} seriestype := :scatter - if dim(Xk[1]) == 2 - @assert all([dim(pi) == 2 for pi in Xk]) "all points in this vector " * + if dim(S[1]) == 2 + @assert all([dim(p) == 2 for p in S]) "all points in this vector " * "should have the same dimension" - elseif dim(Xk[1]) == 3 - @assert all([dim(pi) == 3 for pi in Xk]) "all points in this vector " * + elseif dim(S[1]) == 3 + @assert all([dim(p) == 3 for p in S]) "all points in this vector " * "should have the same dimension" else error("can only plot 2D or 3D vectors of singletons") end - [Tuple(element(point)) for point in Xk] + [Tuple(element(p)) for p in S] end -# ===================================== -# Plot recipes for lines and intervals -# ===================================== +# ============================================== +# Plot recipes for line segments and intervals +# ============================================== """ - plot_linesegment(L::LineSegment; ...) + plot_linesegment(L::LineSegment{N}, [ε]::N=zero(N); ...) where {N<:Real} Plot a line segment. ### Input - `L` -- line segment +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - +```julia julia> L = LineSegment([0., 0.], [1., 1.]); -julia> plot(L); - +julia> plot(L) ``` """ -@recipe function plot_linesegment(L::LineSegment; color="blue", label="", +@recipe function plot_linesegment(L::LineSegment{N}, ε::N=zero(N); color="blue", label="", grid=true, alpha=0.5, legend=false, - add_marker=true) + add_marker=true) where {N<:Real} seriestype := :path linecolor --> color @@ -407,64 +393,60 @@ julia> plot(L); end """ - plot_linesegments(Xk::Vector{S}; ...) where {S<:LineSegment} + plot_linesegments(L::Vector{LineSegment{N}}, [ε]::N=zero(N); ...) where {N<:Real} Plot an array of line segments. ### Input -- `Xk` -- linear array of line segments +- `L` -- vector of line segments +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - +```julia julia> L1 = LineSegment([0., 0.], [1., 1.]); julia> L2 = LineSegment([1., 0.], [0., 1.]); -julia> plot([L1, L2]); - +julia> plot([L1, L2]) ``` """ -@recipe function plot_linesegments(Xk::Vector{S}; color="blue", +@recipe function plot_linesegments(L::Vector{LineSegment{N}}, ε::N=zero(N); color="blue", label="", grid=true, alpha=0.5, legend=false, - add_marker=true) where {S<:LineSegment} + add_marker=true) where {N<:Real} seriestype := :path linecolor --> color markershape --> (add_marker ? :circle : :none) markercolor --> color - for Li in Xk + for Li in L @series [Tuple(Li.p); Tuple(Li.q)] end end """ - plot_interval(I::Interval; ...) + plot_interval(I::Interval{N}, [ε]::N=zero(N); ...) where {N<:Real} Plot an interval. ### Input - `I` -- interval +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - +```julia julia> I = Interval(0.0, 1.0); -julia> plot(I); - +julia> plot(I) ``` """ -@recipe function plot_interval(I::Interval; color=:auto, label="", grid=true, - alpha=0.5, legend=false, add_marker=true, - linewidth=2.) +@recipe function plot_interval(I::Interval{N}, ε::N=zero(N); color=:auto, label="", + grid=true, alpha=0.5, legend=false, add_marker=true, + linewidth=2.) where {N<:Real} seriestype := :path linecolor --> color @@ -475,37 +457,35 @@ julia> plot(I); end """ - plot_intervals(Xk::Vector{S}; ...) where {S<:Interval} + plot_intervals(I::Vector{Interval{N}}, [ε]::N=zero(N); ...); ...) where {N<:Real} Plot an array of intervals. ### Input -- `Xk` -- linear array of intervals +- `I` -- vector of intervals +- `ε` -- (optional, default: `0.0`) ignored, used for dispatch ### Examples -```jldoctest -julia> using Plots, LazySets; - +```julia julia> I1 = Interval([0., 1.]); julia> I2 = Interval([0.5, 2.]); -julia> plot([I1, I2]); - +julia> plot([I1, I2]) ``` """ -@recipe function plot_intervals(Xk::Vector{S}; color=:auto, label="", grid=true, +@recipe function plot_intervals(I::Vector{Interval{N}}, ε::N=zero(N); color=:auto, label="", grid=true, alpha=0.5, legend=false, add_marker=true, - linewidth=2.0) where {S<:Interval} + linewidth=2.0) where {N<:Real} seriestype := :path linecolor --> color markershape --> (add_marker ? :circle : :none) markercolor --> color - for Ii in Xk + for Ii in I @series [Tuple([min(Ii), 0.0]); Tuple([max(Ii), 0.0])] end end @@ -522,72 +502,149 @@ Plot an empty set. ### Input - `∅` -- empty set -- `ε` -- (optional, default: `0`) approximation error bound - -### Examples +- `ε` -- (optional, default: `0`) ignored, used for dispatch -```jldoctest -julia> using Plots, LazySets; +### Output -julia> plot(∅); - -julia> plot(∅, 1e-2); - -``` +An empty figure. """ @recipe function plot_emptyset(∅::EmptySet{N}, ε::N=zero(N); label="", grid=true, legend=false) where {N<:Real} return [] end +# =============================== +# Plot recipe for unbounded sets +# =============================== + +""" + plot_universe(U::Universe, [ε]; ...) + +Plot the universal set. + +### Input + +- `U` -- universal set +- `ε` -- (optional, default: `0`) ignored, used for dispatch + +### Output + +An error; plotting the universal set is not implemented. +""" @recipe function plot_universe(::Universe{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot the universal set") end +""" + plot_line(L::Line, [ε]; ...) + +Plot a line in 2D. + +### Input + +- `L` -- line +- `ε` -- (optional, default: `0`) ignored, used for dispatch + +### Output + +An error, since plotting a line is not implemented yet (see #576). +""" @recipe function plot_line(::Line{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot an infinite line") end +""" + plot_halfspace(H::HalfSpace, [ε]; ...) + +Plot a half-space in 2D. + +### Input + +- `H` -- half-space +- `ε` -- (optional, default: `0`) ignored, used for dispatch + +### Output + +An error, since plotting a half-space is not implemented yet (see #576). +""" @recipe function plot_halfspace(::HalfSpace{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot a half-space") end +""" + plot_hyperplane(H::Hyperplane, [ε]; ...) + +Plot a hyperplane in 2D. + +### Input + +- `H` -- hyperplane +- `ε` -- (optional, default: `0`) ignored, used for dispatch + +### Output + +An error, since plotting a hyperplane is not implemented yet (see #576). +""" @recipe function plot_hyperplane(::Hyperplane{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot a hyperplane") end +# =================================== +# Plot recipe for lazy intersections +# =================================== + """ - plot_intersection(X::Intersection{N}, ε::N=-one(N); Nφ=40, - color="blue", label="", grid=true, alpha=0.5) where {N} + plot_intersection(X::Intersection{N}, [ε]::N=-one(N); Nφ=40, + color="blue", label="", grid=true, alpha=0.5) where {N<:Real} Plot a lazy intersection. ### Input -- `X` -- lazy intersection -- `ε` -- (optional, default -1) ignored, used only for dispatch +- `X` -- lazy intersection +- `ε` -- (optional, default -1) ignored, used only for dispatch - `Nφ` -- (optional, default: `40`) number of template directions used in the template overapproximation +### Output + +A plot with the overapproximation of the given lazy intersection. + ### Notes -The vertices list of an `HPolygon` has known issues (see LazySets#1306). Consider -using the `Polyhedra` backend to compute the dual representation, as in: +This function is separated from the main one `LazySet` plot recipe because +the iterative refinement is not available for lazy intersections, since it uses +the support vector (but see #1187). + +Also note that if the set is a *nested* intersection eg. the lazy linear map +a nested intersection you may have to manually overapproximate this set before +plotting, see `LazySets.Approximations.overapproximate` for details. ```julia julia> using Polyhedra, LazySets.Approximations julia> X = rand(Ball2) ∩ rand(Ball2); # lazy intersection -julia> Nφ = 40; # or a bigger number +julia> plot(X) +``` + +The vertices list of an `HPolygon` has known issues (until #1306 is fixed). +Consider using the `Polyhedra` backend to compute the dual representation. +One can specify the accuaracy of the overapproximation of the lazy intersection +passing a higher value in `Nφ`, which stands for amount of polar directions chosen. + +```julia +julia> Nφ = 100; # or a bigger number + +julia> Po = overapproximate(X, PolarDirections(Nφ)); -julia> P = convert(HPolytope, overapproximate(X, PolarDirections(Nφ)); +julia> P = convert(HPolytope, Po) # see issue #1306 julia> plot(P) ``` """ @recipe function plot_intersection(X::Intersection{N}, ε::N=-one(N); Nφ=40, - color="blue", label="", grid=true, alpha=0.5) where {N} + color="blue", label="", grid=true, alpha=0.5) where {N<:Real} @assert dim(X) == 2 "this recipe only plots two-dimensional sets" @@ -599,7 +656,7 @@ julia> plot(P) "variable Nφ as in `plot(X, Nφ=...)`") end - P = convert(HPolygon, overapproximate(X, PolarDirections(Nφ))) + P = convert(HPolygon, overapproximate(X, PolarDirections{N}(Nφ))) vlist = transpose(hcat(convex_hull(vertices_list(P))...)) if isempty(vlist) diff --git a/test/unit_plot.jl b/test/unit_plot.jl index 1e1b5f3370..601226e04f 100644 --- a/test/unit_plot.jl +++ b/test/unit_plot.jl @@ -1,4 +1,9 @@ -for N in [Float64] +using Optim, SparseArrays + +# ------------------------- +# tests for floating points +# ------------------------- +for N in [Float64, Float32] p0 = zero(N) p1 = one(N) v0 = zeros(N, 2) @@ -18,6 +23,22 @@ for N in [Float64] zt = Zonotope(v0, Diagonal(N[1, 1])) zs = ZeroSet{N}(2) + # bounded basic set types which are not polytopes + b2 = Ball2(v0, p1) + bp = Ballp(N(1.5), v0, p1) + el = Ellipsoid(v0, Diagonal(N[1, 1])) + + # unary set operations + spI = SparseMatrixCSC{N}(2I, 2, 2) + sme = SparseMatrixExp(spI) + em = ExponentialMap(sme, b2) + psme = ProjectionSparseMatrixExp(spI, sme, spI) + epm = ExponentialProjectionMap(psme, b2) + + # binary set operations + its = Intersection(b1, bi) + itsa = IntersectionArray([b1, bi]) + # polygon/polytope types constraints = [LinearConstraint([p1, p0], p1), LinearConstraint([p0, p1], p1), @@ -54,22 +75,25 @@ for N in [Float64] cp = CartesianProduct(itv, itv) cpa = CartesianProductArray([itv, itv]) - # ----- - # plots - # ----- - - # direct + # ------------------------------------------- + # plots using the default epsilon-close value + # ------------------------------------------- plot(b1) plot(bi) plot(hr) plot(itv) + if N == Float64 # Float32 requires promotion see #1304 + plot(its) + end plot(ls) plot(st) plot(zt) plot(zs) plot(hpg) plot(hpgo) - plot(hpt) + if test_suite_polyhedra + plot(hpt) + end plot(vpg) plot(vpt) plot(es) @@ -88,107 +112,41 @@ for N in [Float64] plot(cp) plot(cpa) - # ε-close - ε = N(1e-2) - if N == Float64 # TODO see #578 - plot(b1, ε) - plot(bi, ε) - plot(hr, ε) - plot(ls, ε) - @test_throws AssertionError plot(itv, ε) # TODO see #575 - plot(st, ε) - plot(zt, ε) - plot(zs, ε) - plot(hpg, ε) - plot(hpgo, ε) - plot(hpt, ε) - plot(vpg, ε) - plot(vpt, ε) - plot(es, ε) - @test_throws ErrorException plot(hs, ε) # TODO see #576/#578 - @test_throws ErrorException plot(hp, ε) # TODO see #576/#578 - @test_throws ErrorException plot(l, ε) # TODO see #576/#578 - @test_throws ErrorException plot(uni, ε) # TODO see #576/#578 - plot(ch, ε) - plot(cha, ε) - plot(sih, ε) - plot(lm, ε) - plot(rm, ε) - plot(ms, ε) - plot(msa, ε) - plot(cms, ε) - plot(cp, ε) - plot(cpa, ε) - else - @test_throws ErrorException plot(b1, ε) # TODO see #578 - end + # ----- + # cases that are not implemented + # ----- + @test_throws ErrorException plot(itsa) # TODO not implemented yet end -# set types that do not work with Rational{Int} -for N in [Float64] - v0 = zeros(N, 2) +# ----------------------------------------------------------------- +# tests for rationals; iterative refinement is not available +# ----------------------------------------------------------------- +for N in [Rational{Int}] + p0 = zero(N) p1 = one(N) + v0 = zeros(N, 2) + v1 = ones(N, 2) # --------------- # set definitions # --------------- # bounded basic set types - b2 = Ball2(v0, p1) - bp = Ballp(N(1.5), v0, p1) - el = Ellipsoid(v0, Diagonal(N[1, 1])) - - # unary set operations - spI = SparseMatrixCSC{N}(2I, 2, 2) - sme = SparseMatrixExp(spI) - em = ExponentialMap(sme, b2) - psme = ProjectionSparseMatrixExp(spI, sme, spI) - epm = ExponentialProjectionMap(psme, b2) - - # ----- - # plots - # ----- - - # direct - plot(b2) - plot(bp) - plot(el) - plot(em) - plot(epm) - - # ε-close - ε = N(1e-2) - if N == Float64 # TODO see #578 - plot(b2, ε) - plot(bp, ε) - plot(el, ε) - plot(em, ε) - plot(epm, ε) - else - @test_throws ErrorException plot(b2, ε) # TODO see #578 - end -end - -# set types that only work with Float64 -for N in [Float64] - v0 = zeros(N, 2) - p1 = one(N) - b1 = Ball1(v0, p1) bi = BallInf(v0, p1) + hr = Hyperrectangle(v0, v1) + itv = Interval(p0, p1) + ls = LineSegment(v0, v1) + st = Singleton(v1) + zt = Zonotope(v0, Diagonal(N[1, 1])) + zs = ZeroSet{N}(2) - # binary set operations - its = Intersection(b1, bi) - itsa = IntersectionArray([b1, bi]) - - # ----- - # plots - # ----- - - plot(its) - @test_throws ErrorException plot(itsa) # TODO not implemented yet - - # ε-close - ε = N(1e-2) - @test_throws ErrorException plot(itsa, ε) # TODO not implemented yet + plot(b1) + plot(bi) + plot(hr) + plot(itv) + plot(ls) + plot(st) + plot(zt) + plot(zs) end From fd8962a54d983837169c8981761c585e819a92a8 Mon Sep 17 00:00:00 2001 From: mforets Date: Wed, 1 May 2019 15:09:37 +1000 Subject: [PATCH 07/19] fix for v0.6 (using SparseArrays) --- test/unit_plot.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit_plot.jl b/test/unit_plot.jl index 601226e04f..435a01216e 100644 --- a/test/unit_plot.jl +++ b/test/unit_plot.jl @@ -1,4 +1,6 @@ -using Optim, SparseArrays +@static if VERSION >= v"0.7-" + using SparseArrays +end # ------------------------- # tests for floating points From c1875a92495f3300f9dde1fb80c9dbd794b241ac Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:26:17 +1000 Subject: [PATCH 08/19] Update docs/src/lib/interfaces.md Co-Authored-By: mforets --- docs/src/lib/interfaces.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/lib/interfaces.md b/docs/src/lib/interfaces.md index 58e7cd0626..27525f3e7d 100644 --- a/docs/src/lib/interfaces.md +++ b/docs/src/lib/interfaces.md @@ -63,7 +63,7 @@ tosimplehrep(::LazySet) isuniversal(::LazySet{N}, ::Bool=false) where {N<:Real} ``` -The following functions dispatch in a general `LazySet` and work provided that the overapproximation using iterative refinement in two dimensions is available: +The following functions work with general two-dimensional `LazySet`s, provided that the overapproximation using iterative refinement is available: ```@docs RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LazySet{N}, ::N=N(1e-3)) where {N<:Real} From 83e61ef713e1d62daa8283b91672693d89b88cc1 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:30:20 +1000 Subject: [PATCH 09/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 55dd736fda..622bcf12ce 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -111,7 +111,7 @@ julia> plot([B1, B2]) An iterative refinement method is applied to obtain an overapproximation of each set in `X` in constraint representation, which is then plotted. To change the default tolerance for the iterative refinement, use the second argument; it applies -all sets in the array. +to all sets in the array. ```julia julia> B1 = BallInf(zeros(2), 0.4); From 428572f4dd5898daaea672be6a6a1225dd528c5f Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:30:31 +1000 Subject: [PATCH 10/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 622bcf12ce..4945bd5a2d 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -170,7 +170,7 @@ Plot a 2D polytope as the convex hull of its vertices. ### Input - `P` -- polygon or polytope -- `ε` -- (optional, default: `0.0`) ignored, used for dispatch +- `ε` -- (optional, default: `0`) ignored, used for dispatch ### Examples From 57822ff422beb059653ffa381afa867144702079 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:30:48 +1000 Subject: [PATCH 11/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 4945bd5a2d..2e24e279fc 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -529,7 +529,7 @@ Plot the universal set. ### Output -An error; plotting the universal set is not implemented. +An error, since plotting the universal set is not implemented yet (see #576). """ @recipe function plot_universe(::Universe{N}, ε::N=zero(N)) where {N<:Real} error("cannot plot the universal set") From 13151b29ab9eeae2c6c304f5cfb11f229c6b1cd7 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:31:03 +1000 Subject: [PATCH 12/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 2e24e279fc..8c69121c2a 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -612,7 +612,7 @@ A plot with the overapproximation of the given lazy intersection. ### Notes -This function is separated from the main one `LazySet` plot recipe because +This function is separated from the main `LazySet` plot recipe because the iterative refinement is not available for lazy intersections, since it uses the support vector (but see #1187). From 79ef383e49e31acf64d4c0e5fdfee52a5df8392c Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:31:18 +1000 Subject: [PATCH 13/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 8c69121c2a..78667a70c9 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -616,7 +616,7 @@ This function is separated from the main `LazySet` plot recipe because the iterative refinement is not available for lazy intersections, since it uses the support vector (but see #1187). -Also note that if the set is a *nested* intersection eg. the lazy linear map +Also note that if the set is a *nested* intersection, e.g., the lazy linear map, a nested intersection you may have to manually overapproximate this set before plotting, see `LazySets.Approximations.overapproximate` for details. From cff11655d6e208f7af73551964e68d26dafca571 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:31:33 +1000 Subject: [PATCH 14/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 78667a70c9..3dec789244 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -617,7 +617,7 @@ the iterative refinement is not available for lazy intersections, since it uses the support vector (but see #1187). Also note that if the set is a *nested* intersection, e.g., the lazy linear map, -a nested intersection you may have to manually overapproximate this set before +you may have to manually overapproximate this set before plotting, see `LazySets.Approximations.overapproximate` for details. ```julia From 9c9267a118ff204ba4a49836e14df70393ec4f60 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:31:47 +1000 Subject: [PATCH 15/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 3dec789244..b04393ce20 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -618,7 +618,7 @@ the support vector (but see #1187). Also note that if the set is a *nested* intersection, e.g., the lazy linear map, you may have to manually overapproximate this set before -plotting, see `LazySets.Approximations.overapproximate` for details. +plotting (see `LazySets.Approximations.overapproximate` for details). ```julia julia> using Polyhedra, LazySets.Approximations From 9fb0ee7327ee6ac3cc11453ebe62ab1532adf787 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:32:01 +1000 Subject: [PATCH 16/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index b04393ce20..afb231e099 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -631,7 +631,7 @@ julia> plot(X) The vertices list of an `HPolygon` has known issues (until #1306 is fixed). Consider using the `Polyhedra` backend to compute the dual representation. One can specify the accuaracy of the overapproximation of the lazy intersection -passing a higher value in `Nφ`, which stands for amount of polar directions chosen. +passing a higher value in `Nφ`, which stands for the number of polar directions chosen. ```julia julia> Nφ = 100; # or a bigger number From 76417364f1c1529321f67a308fcc989ee4b2bcf5 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:32:11 +1000 Subject: [PATCH 17/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index afb231e099..90bf288912 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -651,7 +651,7 @@ julia> plot(P) if ε != -one(N) error("cannot plot a lazy intersection using iterative refinement with " * "error threshold `ε = $ε`, because the exact support vector of an " * - "intersection is not available; using instead a set of `Nφ` " * + "intersection is currently not available; using instead a set of `Nφ` " * "template directions. To control the number of directions, pass the " * "variable Nφ as in `plot(X, Nφ=...)`") end From 484e878e5c8bca5f9aad753a8658f66a72325a61 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Wed, 1 May 2019 17:32:20 +1000 Subject: [PATCH 18/19] Update src/plot_recipes.jl Co-Authored-By: mforets --- src/plot_recipes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_recipes.jl b/src/plot_recipes.jl index 90bf288912..c007fc7922 100644 --- a/src/plot_recipes.jl +++ b/src/plot_recipes.jl @@ -630,7 +630,7 @@ julia> plot(X) The vertices list of an `HPolygon` has known issues (until #1306 is fixed). Consider using the `Polyhedra` backend to compute the dual representation. -One can specify the accuaracy of the overapproximation of the lazy intersection +One can specify the accuracy of the overapproximation of the lazy intersection passing a higher value in `Nφ`, which stands for the number of polar directions chosen. ```julia From e8f1f9b4803df6998d23a1addae65e2f4d6022b8 Mon Sep 17 00:00:00 2001 From: mforets Date: Wed, 1 May 2019 17:57:40 +1000 Subject: [PATCH 19/19] merge Rational tests with floating points --- test/unit_plot.jl | 69 +++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/test/unit_plot.jl b/test/unit_plot.jl index 435a01216e..202a89789e 100644 --- a/test/unit_plot.jl +++ b/test/unit_plot.jl @@ -2,10 +2,7 @@ using SparseArrays end -# ------------------------- -# tests for floating points -# ------------------------- -for N in [Float64, Float32] +for N in [Float64, Float32, Rational{Int}] p0 = zero(N) p1 = one(N) v0 = zeros(N, 2) @@ -25,6 +22,23 @@ for N in [Float64, Float32] zt = Zonotope(v0, Diagonal(N[1, 1])) zs = ZeroSet{N}(2) + # ------------------------------------------- + # plot polytopes + # ------------------------------------------- + plot(b1) + plot(bi) + plot(hr) + plot(itv) + plot(ls) + plot(st) + plot(zt) + plot(zs) + + if N == Rational{Int} + # rationals do not support epsilon-close approximation + continue + end + # bounded basic set types which are not polytopes b2 = Ball2(v0, p1) bp = Ballp(N(1.5), v0, p1) @@ -77,20 +91,12 @@ for N in [Float64, Float32] cp = CartesianProduct(itv, itv) cpa = CartesianProductArray([itv, itv]) - # ------------------------------------------- - # plots using the default epsilon-close value - # ------------------------------------------- - plot(b1) - plot(bi) - plot(hr) - plot(itv) + # ------------------------------------------------------------------ + # plot using epsilon-close approximation (default threshold ε value) + # ------------------------------------------------------------------ if N == Float64 # Float32 requires promotion see #1304 plot(its) end - plot(ls) - plot(st) - plot(zt) - plot(zs) plot(hpg) plot(hpgo) if test_suite_polyhedra @@ -119,36 +125,3 @@ for N in [Float64, Float32] # ----- @test_throws ErrorException plot(itsa) # TODO not implemented yet end - -# ----------------------------------------------------------------- -# tests for rationals; iterative refinement is not available -# ----------------------------------------------------------------- -for N in [Rational{Int}] - p0 = zero(N) - p1 = one(N) - v0 = zeros(N, 2) - v1 = ones(N, 2) - - # --------------- - # set definitions - # --------------- - - # bounded basic set types - b1 = Ball1(v0, p1) - bi = BallInf(v0, p1) - hr = Hyperrectangle(v0, v1) - itv = Interval(p0, p1) - ls = LineSegment(v0, v1) - st = Singleton(v1) - zt = Zonotope(v0, Diagonal(N[1, 1])) - zs = ZeroSet{N}(2) - - plot(b1) - plot(bi) - plot(hr) - plot(itv) - plot(ls) - plot(st) - plot(zt) - plot(zs) -end