From da41318c886ad69de8c9ce20520f16edb5c46eca Mon Sep 17 00:00:00 2001 From: schillic Date: Sat, 23 Mar 2019 10:51:23 +0100 Subject: [PATCH 1/3] function to remove zero columns from a matrix --- docs/src/lib/utils.md | 1 + src/helper_functions.jl | 34 ++++++++++++++++++++++++++++++++++ test/unit_util.jl | 8 ++++++++ 3 files changed, 43 insertions(+) diff --git a/docs/src/lib/utils.md b/docs/src/lib/utils.md index 9d305272dd..6fd4f669f4 100644 --- a/docs/src/lib/utils.md +++ b/docs/src/lib/utils.md @@ -15,6 +15,7 @@ end an_element_helper binary_search_constraints cross_product(::AbstractMatrix{N}) where {N<:Real} +delete_zero_columns dot_zero get_radius! isinvertible diff --git a/src/helper_functions.jl b/src/helper_functions.jl index 5d2f6f0a97..694b20d514 100644 --- a/src/helper_functions.jl +++ b/src/helper_functions.jl @@ -605,3 +605,37 @@ function subtypes(interface, concrete::Bool) end return sort(result, by=string) end + +""" + delete_zero_columns(A::AbstractMatrix) + +Remove all columns that only contain zeros from a given matrix. + +### Input + +- `A` -- matrix +- `copy_always` -- (optional, default: `false`) flag to copy the matrix even if + it does not contain any zero column + +### Output + +A matrix. + +If the input matrix `A` does not contain any zero column, we return `A` unless +the option `copy_always` is set. +If the input matrix contains zero columns, we always return a copy. +""" +function delete_zero_columns(A::AbstractMatrix, copy_always::Bool=false) + n = size(A, 2) + nonzero_columns = Vector{Int}() + sizehint!(nonzero_columns, n) + for i in 1:n + if !iszero(A[:, i]) + push!(nonzero_columns, i) + end + end + if !copy_always && length(nonzero_columns) == n + return A + end + return A[:, nonzero_columns] +end diff --git a/test/unit_util.jl b/test/unit_util.jl index e24035a272..9d5daf96f1 100644 --- a/test/unit_util.jl +++ b/test/unit_util.jl @@ -48,5 +48,13 @@ for _dummy_ in 1:1 # avoid global variable warnings # modified dot product @test isnan(dot(N[1, 0], N[Inf, -Inf])) @test LazySets.dot_zero(N[1, 0], N[Inf, -Inf]) == N(Inf) + + # remove zero columns + m = 3 + n = 10 + A = rand(N, m, n) + A[:, 1] = A[:, 5] = A[:, n] = zeros(N, m) + B = LazySets.delete_zero_columns(A) + @test size(B) == (m, n-3) end end From fd327b0a310b0f77a16d5dcf2feeb8eb840dc886 Mon Sep 17 00:00:00 2001 From: schillic Date: Sat, 23 Mar 2019 12:51:59 +0100 Subject: [PATCH 2/3] remove zero columns in zonotope constructor --- src/Zonotope.jl | 18 ++++++++++++++++-- test/unit_Zonotope.jl | 10 ++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Zonotope.jl b/src/Zonotope.jl index 3b8b5c27a4..3961c7d19b 100644 --- a/src/Zonotope.jl +++ b/src/Zonotope.jl @@ -42,6 +42,10 @@ ball in ``\\mathbb{R}^n`` by an affine transformation. generators_list::AbstractVector{VN} ) where {N<:Real, VN<:AbstractVector{N}}` +The optional argument `remove_zero_generators` controls whether we remove zero +columns from the `generators` matrix. +This option is active by default. + ### Examples A two-dimensional zonotope with given center and set of generators: @@ -87,12 +91,22 @@ julia> Z.generators struct Zonotope{N<:Real} <: AbstractCentrallySymmetricPolytope{N} center::AbstractVector{N} generators::AbstractMatrix{N} + + function Zonotope(center::AbstractVector{N}, generators::AbstractMatrix{N}; + remove_zero_generators::Bool=true) where {N<:Real} + if remove_zero_generators + generators = delete_zero_columns(generators) + end + new{N}(center, generators) + end end # constructor from center and list of generators -Zonotope(center::AbstractVector{N}, generators_list::AbstractVector{VN} +Zonotope(center::AbstractVector{N}, generators_list::AbstractVector{VN}; + remove_zero_generators::Bool=true ) where {N<:Real, VN<:AbstractVector{N}} = - Zonotope(center, hcat(generators_list...)) + Zonotope(center, hcat(generators_list...); + remove_zero_generators=remove_zero_generators) # --- AbstractCentrallySymmetric interface functions --- diff --git a/test/unit_Zonotope.jl b/test/unit_Zonotope.jl index 94a1b852a6..9709653da0 100644 --- a/test/unit_Zonotope.jl +++ b/test/unit_Zonotope.jl @@ -40,6 +40,13 @@ for N in [Float64, Rational{Int}, Float32] d = N[0, -1] @test σ(d, z) == N[2, 1] + # zero column in generators + g = zeros(N, 2, 5) + g[:, 3] = ones(N, 2) + g[1, 2] = N(2) + z = Zonotope(N[1, 2], g) + @test size(z.generators) == (2, 2) + # boundedness @test isbounded(z) @@ -100,6 +107,9 @@ for N in [Float64, Rational{Int}, Float32] Z = convert(Zonotope, Hyperrectangle(N[2, 3], N[4, 5])) @test Z.center == N[2, 3] && diag(Z.generators) == N[4, 5] convert(Zonotope, BallInf(N[5, 3], N(2))) + # flat hyperrectangle + Z = convert(Zonotope, Hyperrectangle(N[2, 3], N[0, 0])) + @test Z.center == N[2, 3] && isempty(Z.generators) # convert the cartesian product of two hyperrectangles to a zonotope h1 = Hyperrectangle(N[1/2], N[1/2]) From a2d58356c333920d6e64abf33f1e580d2a1d80b5 Mon Sep 17 00:00:00 2001 From: schillic Date: Sat, 23 Mar 2019 13:00:42 +0100 Subject: [PATCH 3/3] use view --- src/helper_functions.jl | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/helper_functions.jl b/src/helper_functions.jl index 694b20d514..72c18446ba 100644 --- a/src/helper_functions.jl +++ b/src/helper_functions.jl @@ -613,19 +613,19 @@ Remove all columns that only contain zeros from a given matrix. ### Input -- `A` -- matrix -- `copy_always` -- (optional, default: `false`) flag to copy the matrix even if - it does not contain any zero column +- `A` -- matrix +- `copy` -- (optional, default: `false`) flag to copy the matrix ### Output A matrix. If the input matrix `A` does not contain any zero column, we return `A` unless -the option `copy_always` is set. -If the input matrix contains zero columns, we always return a copy. +the option `copy` is set. +If the input matrix contains zero columns, we always return a copy if the option +`copy` is set and otherwise a `SubArray` via `@view`. """ -function delete_zero_columns(A::AbstractMatrix, copy_always::Bool=false) +function delete_zero_columns(A::AbstractMatrix, copy::Bool=false) n = size(A, 2) nonzero_columns = Vector{Int}() sizehint!(nonzero_columns, n) @@ -634,8 +634,17 @@ function delete_zero_columns(A::AbstractMatrix, copy_always::Bool=false) push!(nonzero_columns, i) end end - if !copy_always && length(nonzero_columns) == n - return A + if copy + if length(nonzero_columns) == n + return copy(A) + else + return A[:, nonzero_columns] + end + else + if length(nonzero_columns) == n + return A + else + return @view A[:, nonzero_columns] + end end - return A[:, nonzero_columns] end