diff --git a/src/messages.jl b/src/messages.jl index d5a8711..7f3603a 100755 --- a/src/messages.jl +++ b/src/messages.jl @@ -117,7 +117,6 @@ plotkin_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer = elias_bassalygo_bound(q::T, n::T, d::T) where T <: Integer = elias_bassalygo_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer = - function __johnson_bound_core(round_func::Function, q::T, n::T, d::T) where T <: Integer if isinteger((d - 1) / 2) # is odd t = T((d - 1) / 2) @@ -128,8 +127,6 @@ function __johnson_bound_core(round_func::Function, q::T, n::T, d::T) where T <: end end - - """ construct_ham_matrix(r::Int, q::Int) -> Matrix @@ -271,7 +268,7 @@ end Takes in an array and a word. As long as the word does not mean that the distance is smaller than d, we add w to the array. If we are successful in doing this, return true. Otherwise, return false. *This is a mutating function.* """ -function push_if_allowed!(C::AbstractArray{T}, w::T, d::Int) where T +function push_if_allowed!(C::AbstractArray{T}, w::T, d::Int) where T <: AbstractWord isempty(C) && (push!(C, w); return true) for c in C @@ -289,7 +286,7 @@ end Takes in two arrays, A and B. If w is allowed in C given distance d, push to C′. If we are successful in doing this, return true. Otherwise, return false. *This is a mutating function.* """ -function push_if_allowed!(C::AbstractArray{T}, C′::AbstractArray{T}, w::T, d::Int) where T +function push_if_allowed!(C::AbstractVector{T}, C′::AbstractVector{T}, w::T, d::Int) where T <: AbstractWord isempty(C) && (push!(C′, w); return true) for c in C @@ -307,7 +304,7 @@ end Takes in an array and a word. As long as the word does not mean that the distance is smaller than d, we replace a with b in the array. Replaces and returns true if allowed; otherwise returns false. *This is a mutating function.* """ -function replace_if_allowed!(C::AbstractArray, d::Int, ws::Pair) +function replace_if_allowed!(C::AbstractVector{T}, d::Int, ws::Pair) where T <: AbstractWord w, w′ = ws for c in C @@ -319,29 +316,30 @@ function replace_if_allowed!(C::AbstractArray, d::Int, ws::Pair) replace!(C, ws) return true end - -function replace_if_allowed!(C::AbstractArray, d::Int, w, w′) +function replace_if_allowed!(C::AbstractVector{T}, d::Int, w::T, w′::T) where T <: AbstractWord return replace_if_allowed!(C, d, Pair(w, w′)) end +_mutate_codeword(w::Word{N, T}, i::Int, a::T) where {T, N} = + setindex!(w, a, i) + """ - mutate_codeword(w::Tuple{T}, n::Int, i::Int, a::T) -> Tuple + mutate_codeword(w::NonStaticAbstractWord{N, T}, n::Int, i::Int, a::T) where {T, N} -> MVector{N, T} + mutate_codeword(w::Word{N, T}, n::Int, i::Int, a::T) where {T, N} -> MVector{N, T} -Mutates the word w, which is a `Tuple` of length n, changing its iᵗʰ index to a. +Mutates the word w, which is an `MVector` of length N, changing its iᵗʰ index to a. """ -function mutate_codeword(w::Union{Tuple{T}, NTuple{N, T}}, n::Int, i::Int, a::T) where {N, T} - w̲ = collect(w) - w̲[i] = a - - return ntuple(j -> w̲[j], n) -end +mutate_codeword(w::NonStaticAbstractWord{N, T}, i::Int, a::T) where {T, N} = + _mutate_codeword(Word{N, T}(w), i, a) +mutate_codeword(w::Word{N, T}, n::Int, i::Int, a::T) where {T, N} = + _mutate_codeword(w, i, a) """ - get_all_words(Σ::Alphabet, q::Int, n::Int) -> Array{Tuple{Symbol}, 1} - get_all_words(Σ::Alphabet, n::Int) -> Array{Tuple{Symbol}, 1} - get_all_words(Σ::AbstractArray, q::Int, n::Int) -> Array{Tuple{Symbol}, 1} - get_all_words(Σ::AbstractArray, n::Int) -> Array{Tuple{Symbol}, 1} - get_all_words(q::Int, n::Int) -> Array{Tuple{Symbol}, 1} + get_all_words(Σ::Alphabet{N}, q::Int, n::Int) -> Codewords{M} + get_all_words(Σ::Alphabet{N}, n::Int) -> Codewords{M} + get_all_words(Σ::AbstractArray, q::Int, n::Int) -> Codewords{M} + get_all_words(Σ::AbstractArray, n::Int) -> Codewords{M} + get_all_words(q::Int, n::Int) -> Codewords{M} Get the universe of all codewords of a given alphabet. The alphabet will be uniquely generated if none is given. @@ -353,31 +351,26 @@ Parameters: - 𝒰::AbstractArray: The universe of all codewords of q many letters of block length n. Returns: - - Array{Tuple{Symbol}, 1}: An array of codewords. Each codewords is a tuple, and each character in said word is a symbol. + - Codewords{M}: An array of codewords, each of length `M`. Each codewords is a tuple, and each character in said word is a symbol. """ - -function get_all_words(Σ::Alphabet, q::Int, n::Int) - return CodeUniverseIterator(UniverseParameters(Σ, q, n)) -end - -get_all_words(Σ::Alphabet, n::Int) = - get_all_words(Σ, length(unique(Σ)), n) # if alphabet is given, then q is the length of that alphabet -get_all_words(Σ::AbstractArray, q::Int, n::Int) = - get_all_words(Alphabet(Σ), q, Val(n)) +get_all_words(Σ::Alphabet{N}, q::Int, n::Int) where {N} = + collect(CodeUniverseIterator(UniverseParameters(Σ, q, n))) +get_all_words(Σ::Alphabet{N}, n::Int) where {N} = + get_all_words(Σ, length(Set(Σ)), n) # if alphabet is given, then q is the length of that alphabet get_all_words(Σ::AbstractArray, n::Int) = - get_all_words(Alphabet(Σ), length(unique(Σ)), n) # if alphabet is given, then q is the length of that alphabet + get_all_words(Alphabet(Σ), length(Set(Σ)), n) # if alphabet is given, then q is the length of that alphabet get_all_words(q::Int, n::Int) = - get_all_words(Alphabet(Symbol[gensym() for _ in 1:q]), q, n) # generate symbols if no alphabet is given + get_all_words(genalphabet(q), q, n) # generate symbols if no alphabet is given """ - get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(𝒰::UniverseParameters, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(Σ::Alphabet, q::Int, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(Σ::Alphabet, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(q::Int, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(Σ::AbstractArray, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Array{Tuple{Symbol}, 1} + get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Codewords{M} + get_codewords_greedy(𝒰::UniverseParameters, d::Int) -> Codewords{M} + get_codewords_greedy(Σ::Alphabet{N}, q::Int, n::Int, d::Int) -> Codewords{M} + get_codewords_greedy(Σ::Alphabet{N}, n::Int, d::Int) -> Codewords{M} + get_codewords_greedy(q::Int, n::Int, d::Int) -> Codewords{M} + get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int) -> Codewords{M} + get_codewords_greedy(Σ::AbstractArray, n::Int, d::Int) ->Codewords{M} + get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Codewords{M} Search through the universe of all codewords and find a code of block length n and distance d, using the alphabet Σ. The alphabet will be uniquely generated if none is given. @@ -389,10 +382,10 @@ Parameters: - d::Int: The minimum distance between words in the code. Returns: - - Array{Tuple{Symbol}, 1}: An array of codewords. Each codewords is a tuple, and each character in said word is a symbol. + - Codewords{M}: An array of codewords, each of length `M`. Each codewords is a tuple, and each character in said word is a symbol. """ function get_codewords_greedy(𝒰::UniverseParameters, d::Int) - C = Tuple[] + C = eltype(𝒰)[] for wᵢ in CodeUniverseIterator(𝒰) push_if_allowed!(C, wᵢ, d) @@ -400,10 +393,9 @@ function get_codewords_greedy(𝒰::UniverseParameters, d::Int) return C end - -get_codewords_greedy(Σ::Alphabet, q::Int, n::Int, d::Int) = +get_codewords_greedy(Σ::Alphabet{N}, q::Int, n::Int, d::Int) where {N} = get_codewords_greedy(UniverseParameters(Σ, q, n), d) -get_codewords_greedy(Σ::Alphabet, n::Int, d::Int) = +get_codewords_greedy(Σ::Alphabet{N}, n::Int, d::Int) where {N} = get_codewords_greedy(UniverseParameters(Σ, n), d) get_codewords_greedy(q::Int, n::Int, d::Int) = get_codewords_greedy(UniverseParameters(q, n), d) @@ -415,18 +407,18 @@ get_codewords_greedy(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractAr get_codewords_greedy(Alphabet(Σ), q, n, d, 𝒰) -argmaxminima(A::AbstractArray; dims::Int) = getindex(argmin(A, dims=dims), argmax(argmin(A, dims=dims))) -maxminima(A::AbstractArray; dims::Int) = getindex(minimum(A, dims=dims), maximum(minimum(A, dims=dims))) -argminmaxima(A::AbstractArray; dims::Int) = getindex(argmax(A, dims=dims), argmin(argmax(A, dims=dims))) -minmaxima(A::AbstractArray; dims::Int) = getindex(maximum(A, dims=dims), minimum(maximum(A, dims=dims))) +argmaxminima(A::AbstractArray; dims::Int) = getindex(argmin(A, dims = dims), argmax(argmin(A, dims = dims))) +maxminima(A::AbstractArray; dims::Int) = getindex(minimum(A, dims = dims), maximum(minimum(A, dims = dims))) +argminmaxima(A::AbstractArray; dims::Int) = getindex(argmax(A, dims = dims), argmin(argmax(A, dims = dims))) +minmaxima(A::AbstractArray; dims::Int) = getindex(maximum(A, dims = dims), minimum(maximum(A, dims = dims))) """ - get_codewords_random(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Array{Tuple{Symbol}, 1} - get_codewords_random(Σ::AbstractArray, n::Int, d::Int, 𝒰::AbstractArray) -> Array{Tuple{Symbol}, 1} - get_codewords_random(q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Array{Tuple{Symbol}, 1} - get_codewords_random(Σ::AbstractArray, q::Int, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_random(Σ::AbstractArray, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} - get_codewords_random(q::Int, n::Int, d::Int) -> Array{Tuple{Symbol}, 1} + get_codewords_random(Σ::Alphabet{N}, q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Codewords{M} + get_codewords_random(Σ::Alphabet{N}, n::Int, d::Int, 𝒰::AbstractArray) -> Codewords{M} + get_codewords_random(q::Int, n::Int, d::Int, 𝒰::AbstractArray) -> Codewords{M} + get_codewords_random(Σ::AbstractArray, q::Int, n::Int, d::Int) -> Codewords{M} + get_codewords_random(Σ::AbstractArray, n::Int, d::Int) -> Codewords{M} + get_codewords_random(q::Int, n::Int, d::Int) -> Codewords{M} Search through the universe of all codewords at random and find a code of block length n and distance d, using the alphabet Σ. The alphabet will be uniquely generated if none is given. @@ -438,22 +430,22 @@ Parameters: - 𝒰::AbstractArray: The universe of all codewords of q many letters of block length n. Returns: - - Array{Tuple{Symbol}, 1}: An array of codewords. Each codewords is a tuple, and each character in said word is a symbol. + - Codewords{M}: An array of codewords, each of length `M`. Each codewords is a tuple, and each character in said word is a symbol. """ -function get_codewords_random(𝒰::UniverseParameters, d::Int; m::Int=1000) - C = Tuple[] +function get_codewords_random(𝒰::UniverseParameters, d::Int; m::Int = 1000) + C = eltype(𝒰)[] starting_word = rand(𝒰) # get a random word in the code start push!(C, starting_word) for _ in 1:length(𝒰) - C′ = Tuple[] + C′ = eltype(𝒰)[] for _ in 1:m push_if_allowed!(C, C′, rand(𝒰), d) # if allowed in C, push to C′ end isempty(C′) && break # [push_if_allowed!(C, C′, w, d) for _ in 1:m] - distances = [hamming_distance(wᵢ, wⱼ) for wᵢ in C, wⱼ in C′] + distances = Int[hamming_distance(wᵢ, wⱼ) for wᵢ in C, wⱼ in C′] best_word = getindex(C′, getindex(argmaxminima(distances, dims = 1), 2)) push!(C, best_word) end @@ -461,9 +453,9 @@ function get_codewords_random(𝒰::UniverseParameters, d::Int; m::Int=1000) return C end -get_codewords_random(Σ::Alphabet, q::Int, n::Int, d::Int; m::Int=1000) = +get_codewords_random(Σ::Alphabet{N}, q::Int, n::Int, d::Int; m::Int=1000) where {N} = get_codewords_random(UniverseParameters(Σ, q, n), d, m=m) -get_codewords_random(Σ::Alphabet, n::Int, d::Int; m::Int=1000) = +get_codewords_random(Σ::Alphabet{N}, n::Int, d::Int; m::Int=1000) where {N} = get_codewords_random(UniverseParameters(Σ, n), d, m=m) get_codewords_random(q::Int, n::Int, d::Int; m::Int=1000) = get_codewords_random(UniverseParameters(q, n), d, m=m) @@ -475,43 +467,43 @@ get_codewords_random(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractAr get_codewords_random(Alphabet(Σ), q, n, d, 𝒰, m=m) -using Mmap -function get_codewords_random_mmap(mmappath::AbstractString, 𝒰::UniverseParameters, d::Int) - io = open(mmappath, "r+") # allow read and write - # write(s, size(A,2)) - # read(s, Int) - # close(s) - # B = Mmap.mmap(io, BitArray, (25,30000)) - # Mmap.sync!(B); - # close(io); - # rm("mmap.bin") - starting_word = rand(𝒰) # get a random word in the code start - push!(C, starting_word) - - for _ in 1:length(𝒰) - C′ = Tuple[] - for _ in 1:m - push_if_allowed!(C, C′, rand(𝒰), d) # if allowed in C, push to C′ - end - isempty(C′) && break - # [push_if_allowed!(C, C′, w, d) for _ in 1:m] - distances = [hamming_distance(wᵢ, wⱼ) for wᵢ in C, wⱼ in C′] - best_word = getindex(C′, getindex(argmaxminima(distances, dims = 1), 2)) - push!(C, best_word) - end - - return C -end +# using Mmap +# function get_codewords_random_mmap(mmappath::AbstractString, 𝒰::UniverseParameters, d::Int) +# io = open(mmappath, "r+") # allow read and write +# # write(s, size(A,2)) +# # read(s, Int) +# # close(s) +# # B = Mmap.mmap(io, BitArray, (25,30000)) +# # Mmap.sync!(B); +# # close(io); +# # rm("mmap.bin") +# starting_word = rand(𝒰) # get a random word in the code start +# push!(C, starting_word) +# +# for _ in 1:length(𝒰) +# C′ = Tuple[] +# for _ in 1:m +# push_if_allowed!(C, C′, rand(𝒰), d) # if allowed in C, push to C′ +# end +# isempty(C′) && break +# # [push_if_allowed!(C, C′, w, d) for _ in 1:m] +# distances = [hamming_distance(wᵢ, wⱼ) for wᵢ in C, wⱼ in C′] +# best_word = getindex(C′, getindex(argmaxminima(distances, dims = 1), 2)) +# push!(C, best_word) +# end +# +# return C +# end # get_codewords_random(𝒰::UniverseParameters, d::Int) = get_codewords_random(joinpath(tempdir(), "mmap.bin"), 𝒰, d) """ - get_codewords(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Array{Tuple{Symbol}, 1} - get_codewords(Σ::AbstractArray, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Array{Tuple{Symbol}, 1} - get_codewords(q::Int, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Array{Tuple{Symbol}, 1} - get_codewords(Σ::AbstractArray, q::Int, n::Int, d::Int; m::Int=10) -> Array{Tuple{Symbol}, 1} - get_codewords(Σ::AbstractArray, n::Int, d::Int; m::Int=10) -> Array{Tuple{Symbol}, 1} - get_codewords(q::Int, n::Int, d::Int; m::Int=10) -> Array{Tuple{Symbol}, 1} + get_codewords(Σ::Alphabet{N}, q::Int, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Codewords{M} + get_codewords(Σ::Alphabet{N}, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Codewords{M} + get_codewords(q::Int, n::Int, d::Int, 𝒰::AbstractArray; m::Int=10) -> Codewords{M} + get_codewords(Σ::AbstractArray, q::Int, n::Int, d::Int; m::Int=10) -> Codewords{M} + get_codewords(Σ::AbstractArray, n::Int, d::Int; m::Int=10) -> Codewords{M} + get_codewords(q::Int, n::Int, d::Int; m::Int=10) -> Codewords{M} Use function `get_codewords_random` m many times, and `get_codewords_greedy`. Return the code with the greatest number of words. The alphabet will be uniquely generated if none is given. You can omit Σ and 𝒰. You can omit q if Σ is given. @@ -524,11 +516,11 @@ Parameters: - m::Int (kwarg): Try a random code m many times. Returns: - - Array{Tuple{Symbol}, 1}: An array of codewords. Each codewords is a tuple, and each character in said word is a symbol. + - Codewords{M}: An array of codewords, each of length `M`. Each codewords is a tuple, and each character in said word is a symbol. """ function get_codewords(𝒰::UniverseParameters, d::Int; m::Int=10) code_size = 0 - C = Tuple[] + C = eltype(𝒰)[] for _ in 1:m @@ -550,9 +542,9 @@ function get_codewords(𝒰::UniverseParameters, d::Int; m::Int=10) return C end -get_codewords(Σ::Alphabet, q::Int, n::Int, d::Int; m::Int=10) = +get_codewords(Σ::Alphabet{N}, q::Int, n::Int, d::Int; m::Int=10) where {N} = get_codewords(UniverseParameters(Σ, q, n), d, m=m) -get_codewords(Σ::Alphabet, n::Int, d::Int; m::Int=10) = +get_codewords(Σ::Alphabet{N}, n::Int, d::Int; m::Int=10) where {N} = get_codewords(UniverseParameters(Σ, n), d, m=m) get_codewords(q::Int, n::Int, d::Int; m::Int=10) = get_codewords(UniverseParameters(q, n), d, m=m) @@ -564,7 +556,7 @@ get_codewords(Σ::AbstractArray, q::Int, n::Int, d::Int, 𝒰::AbstractArray; m: get_codewords(Alphabet(Σ), q, n, d, 𝒰, m=m) """ - get_codewords(G::AbstractArray, m::Int) -> Array{Tuple{Symbol}, 1} + get_codewords(G::AbstractArray, m::Int) -> Codewords{M} Get codewords of a code from the generating matrix under a finite field of modulo m. Precisely, computes all linear combinations of the rows of the generating matrix. @@ -573,7 +565,7 @@ Parameters: - m::Int: The bounds of the finite field (i.e., the molulus you wish to work in). Returns: - - Array{Tuple{Symbol}, 1}: An array of codewords. Each codewords is a tuple, and each character in said word is a symbol. + - Codewords{M}: An array of codewords, each of length `M`. Each codewords is a tuple, and each character in said word is a symbol. """ function get_codewords(G::AbstractArray, m::Int) codewords = Vector() @@ -583,7 +575,7 @@ function get_codewords(G::AbstractArray, m::Int) rows[i] = [G[i, j] for j in 1:size(G, 2)] end - for c in Base.Iterators.product([0:m-1 for i in 1:size(G, 1)]...) + for c in Base.Iterators.product([0:m-1 for _ in 1:size(G, 1)]...) word = Ref(c[1]) .* rows[1] for i in 2:size(G, 1) diff --git a/src/rref.jl b/src/rref.jl index abe4254..e354b86 100644 --- a/src/rref.jl +++ b/src/rref.jl @@ -8,30 +8,30 @@ Gauss-Jordan elimination over finite fields, modulo n =# -function swaprows!(A::Matrix, i::Integer, j::Integer) - for k in 1:size(A, 2) +function swaprows!(A::Matrix{T}, i::Int, j::Int) where T + for k in axes(A, 2) A[i, k], A[j, k] = A[j, k], A[i, k] end - return nothing + return A end -function swapcols!(A::Matrix, i::Integer, j::Integer) - for k in 1:size(A, 1) +function swapcols!(A::Matrix{T}, i::Int, j::Int) where T + for k in axes(A, 1) A[k, i], A[k, j] = A[k, j], A[k, i] end - return nothing + return A end """ - rref!(A::Matrix{Int}, n::Integer; colswap::Bool=false, verbose::Bool=false, vverbose::Bool=false) -> Matrix{Integer} + rref!(A::Matrix{Int}, n::Int; colswap::Bool=false, verbose::Bool=false, vverbose::Bool=false) -> Matrix{Int} Performs Gauss-Jordan Elimination on a matrix A. *This directly changes the matrix A. Use `rref` for a non-mutating version of this function.* Parameters: - - A::Matrix{Int}: A matrix of integers you wish to perform Gauss-Jordan elimiation on. - - n::Integer: The modulus of the finite field you are working under. + - A::Matrix{Int}: A matrix of Ints you wish to perform Gauss-Jordan elimiation on. + - n::Int: The modulus of the finite field you are working under. - colswap::Bool (kwarg): Whether or not you allow for column swapping. - verbose::Bool (kwarg): Print the row operations. - vverbose::Bool(kwarg): Print the intermediate matrices of the algorithm. @@ -40,15 +40,14 @@ Returns: - Matrix{Int}: a matrix in row echelon form. """ function rref!(A::Matrix{Int}, - n::Integer; - colswap::Bool=false, - verbose::Bool=false, - vverbose::Bool=false)::Matrix{Int} + n::Int; + colswap::Bool = false, + verbose::Bool = false, + vverbose::Bool = false) - nrows, ncols = size(A) i = j = 1 - while i ≤ nrows && j ≤ ncols + while i ≤ size(A, 1) && j ≤ size(A, 2) # Rule 1: Swap zero rows if out of order and ensure leading ones cascade down diagonally. s = findfirst(!iszero, A[i:end, :]) isnothing(s) && break @@ -77,7 +76,7 @@ function rref!(A::Matrix{Int}, # Rule 3: Subtract it from the others s = findfirst(!iszero, A[i,:]) isnothing(s) && break - for k in 1:nrows + for k in axes(A, 1) if i ≠ k β = A[k, s] A[k, :] .= mod.(A[k, :] .- β .* A[i, :], n) @@ -123,13 +122,13 @@ function rref!(A::Matrix{Int}, end """ - rref(A::Matrix{Int}, n::Integer; colswap::Bool=false, verbose::Bool=false, vverbose::Bool=false) -> Matrix{Integer} + rref(A::Matrix{Int}, n::Int; colswap::Bool=false, verbose::Bool=false, vverbose::Bool=false) -> Matrix{Int} Performs Gauss-Jordan Elimination on a matrix A. Parameters: - - A::Matrix{Int}: A matrix of integers you wish to perform Gauss-Jordan elimiation on. - - n::Integer: The modulus of the finite field you are working under. + - A::Matrix{Int}: A matrix of Ints you wish to perform Gauss-Jordan elimiation on. + - n::Int: The modulus of the finite field you are working under. - colswap::Bool (kwarg): Whether or not you allow for column swapping. - verbose::Bool (kwarg): Print the row operations. - vverbose::Bool(kwarg): Print the intermediate matrices of the algorithm. @@ -138,8 +137,8 @@ Returns: - Matrix{Int}: a matrix in row echelon form. """ rref(A::Matrix{Int}, - n::Integer; - colswap::Bool=false, - verbose::Bool=false, - vverbose::Bool=false - )::Matrix{Int} = rref!(copy(A), n::Integer; colswap=colswap, verbose=verbose, vverbose=vverbose) + n::Int; + colswap::Bool = false, + verbose::Bool = false, + vverbose::Bool = false + ) = rref!(copy(A), n::Int; colswap = colswap, verbose = verbose, vverbose = vverbose) diff --git a/src/utils.jl b/src/utils.jl index dc200b0..5077c72 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -13,55 +13,49 @@ function displaymatrix(M::AbstractArray) return show(IOContext(stdout, :limit => true, :compact => true, :short => true), "text/plain", M); print("\n") end +_Iterable{T} = Union{AbstractArray{T}, NTuple{N, T}} where N + """ - allequal_length(A::AbstractArray) -> Bool + allequal_length(A) -> Bool allequal_length(a, b...) -> Bool Check that all elements in a list are of equal length. """ -@inline function allequal_length(A::AbstractArray) +@inline function allequal_length(A::_Iterable{T}) where T length(A) < 2 && return true @inbounds for i in 2:length(A) - isequal(length(A[1]), length(A[i])) || return false + isequal(length(first(A)), length(A[i])) || return false end return true end - -@inline function allequal_length(a...)::Bool - A = [a...] - return allequal_length(A) -end +@inline allequal_length(a::T...) where {T} = allequal_length(a) """ - allequal(A::AbstractArray) -> Bool + allequal(A) -> Bool allequal(a, b...) -> Bool Check that all elements in a list are equal to each other. """ -@inline function allequal(A::AbstractArray) +@inline function allequal(A::_Iterable{T}) where T length(A) < 2 && return true @inbounds for i in 2:length(A) - A[1] ≠ A[i] && return false + first(A) ≠ A[i] && return false end return true end - -@inline function allequal(a...)::Bool - A = [a...] - return allequal(A) -end +@inline allequal(a::T...) where {T} = allequal(a) """ - aredistinct(A::AbstractArray) -> Bool + aredistinct(A) -> Bool aredistinct(a, b...) -> Bool Check that all elements in a list are distinct from every other element in the list. """ -@inline function aredistinct(A::AbstractArray) +@inline function aredistinct(A::_Iterable{T}) where T length(A) < 2 && return true while ! iszero(length(A)) @@ -71,30 +65,22 @@ Check that all elements in a list are distinct from every other element in the l return true end - -@inline function aredistinct(a...)::Bool - A = [a...] - return aredistinct(A) -end +@inline aredistinct(a::T...) where {T} = aredistinct(a) """ - arelessthan(x::Number, A::AbstractArray) -> Bool + arelessthan(x::Number, A) -> Bool arelessthan(x::Number, a, b...) -> Bool Check that all elements in a list are less than a given x. """ -@inline function arelessthan(x::Number, A::AbstractArray) +@inline function arelessthan(x::Number, A::_Iterable{T}) where T @inbounds for a in A a < x || return false end return true end - -@inline function arelessthan(x::Number, a::Number...)::Bool - A = [a...] - return arelessthan(x, A) -end +@inline arelessthan(x::Number, a::Number...) = arelessthan(x, a) """ areequalto(x::Number, A::AbstractArray) -> Bool @@ -102,23 +88,14 @@ end Check that all elements in a list are equal to a given x. """ -@inline function areequalto(x, A::AbstractArray) +@inline function areequalto(x, A::_Iterable{T}) where T @inbounds for a in A a != x || return false end return true end - -@inline function areequalto(x, a::Number...)::Bool - A = [a...] - return areequalto(x, A) -end - -@inline function areequalto(x, A::Tuple) - A = [A...] - return areequalto(x, A) -end +@inline areequalto(x, a::Number...) = areequalto(x, a) """ deepsym(a::AbstractArray) @@ -126,7 +103,7 @@ end Convert inner-most elements into symbols """ deepsym(a) = Symbol.(a) -deepsym(a::AbstractArray) = deepsym.(a) +deepsym(a::_Iterable{T}) where {T} = deepsym.(a) """ deepeltype(a::AbstractArray) -> Type @@ -134,7 +111,7 @@ deepsym(a::AbstractArray) = deepsym.(a) Returns the type of the inner-most element in a nested array structure. """ deepeltype(a) = deepeltype(typeof(a)) -deepeltype(::Type{T}) where {T <: AbstractArray} = deepeltype(eltype(T)) +deepeltype(::Type{T}) where {T <: _Iterable{R}} where {R} = deepeltype(eltype(T)) deepeltype(::Type{T}) where T = T """ @@ -176,14 +153,14 @@ Examples: julia> has_identity(B) false """ -has_identity(M::Matrix) = isequal(M[:, 1:size(M, 1)], I(size(M, 1))) ? true : false +has_identity(M::Matrix) = isequal(M[:, axes(M, 1)], I(size(M, 1))) ? true : false """ sizeof_perfect_code(q::Number, n::Number, d::Number) -> Number Calculates the number of gigabytes required to store a perfect code of parameters q, n, and d. """ -function sizeof_perfect_code(q::Integer, n::Integer, d::Integer) +function sizeof_perfect_code(q::Int, n::Int, d::Int) return (sizeof(ntuple(_ -> gensym(), n)) * hamming_bound(big.([q, n, d])...)) / (2^30) end sizeof_perfect_code(q::Number, n::Number, d::Number) = sizeof_perfect_code(round.(BigInt, [q, n, d])...) @@ -193,7 +170,7 @@ sizeof_perfect_code(q::Number, n::Number, d::Number) = sizeof_perfect_code(round Calculates the number of gigabytes required to store all unique words of length n from an alphabet of size q. """ -function sizeof_all_words(q::Integer, n::Integer) +function sizeof_all_words(q::Int, n::Int) return (sizeof(ntuple(_ -> gensym(), n)) * big(q)^n) / (2^30) end -sizeof_all_words(q::Number, n::Number) = sizeof_all_words(round.(BigInt, [q, n])...) +sizeof_all_words(q::Number, n::Number) = sizeof_all_words(round.(BigInt, (q, n))...)