# JuliaLang/julia

### Subversion checkout URL

You can clone with
or
.
Fetching contributors…

Cannot retrieve contributors at this time

1913 lines (1644 sloc) 49.6 KB
 # prelimnary definitions: constants, macros # and functions used throughout the code const _msk64 = ~uint64(0) macro _mskr(l) quote _msk64 >>> (64-\$(esc(l))) end end macro _div64(l) quote \$(esc(l)) >>> 6 end end macro _mod64(l) quote \$(esc(l)) & 63 end end macro _msk_end(l) quote @_mskr @_mod64 \$(esc(l)) end end _jl_num_bit_chunks(n::Int) = @_div64 (n+63) function _jl_check_is_valid_bit{T}(x::T) if !(isequal(x, zero(T)) || isequal(x, one(T))) error("invalid BitArray value") end end ## BitArray # notes: bits are stored in contiguous chunks # unused bits must always be set to 0 type BitArray{T<:Integer, N} <: AbstractArray{T, N} chunks::Vector{Uint64} dims::Vector{Int} function BitArray(dims::Int...) if length(dims) == 0 dims = 0 end n = prod(dims) nc = _jl_num_bit_chunks(n) chunks = Array(Uint64, nc) if nc > 0 chunks[end] = uint64(0) end new(chunks, [i::Int for i in dims]) end end BitArray{T}(::Type{T}) = BitArray{T, 1}(0) BitArray() = BitArray(Bool, 0) BitArray{T}(::Type{T}, dims::Dims) = BitArray{T, max(length(dims), 1)}(dims...) BitArray(dims::Dims) = BitArray(Bool, dims) BitArray{T}(::Type{T}, dims::Int...) = BitArray{T, max(length(dims), 1)}(dims...) BitArray(dims::Int...) = BitArray(Bool, dims...) typealias BitVector{T} BitArray{T,1} typealias BitMatrix{T} BitArray{T,2} # non-standard compact representation function _jl_print_bit_chunk(io::IO, c::Uint64, l::Integer) for s = 0 : l - 1 d = (c >>> s) & 1 print(io, "01"[d + 1]) if (s + 1) & 7 == 0 print(io, " ") end end end _jl_print_bit_chunk(io::IO, c::Uint64) = _jl_print_bit_chunk(io, c, 64) _jl_print_bit_chunk(c::Uint64, l::Integer) = _jl_print_bit_chunk(stdout_stream, c, l) _jl_print_bit_chunk(c::Uint64) = _jl_print_bit_chunk(stdout_stream, c) function bitshow(io::IO, B::BitArray) if length(B) == 0 return end for i = 1 : length(B.chunks) - 1 _jl_print_bit_chunk(io, B.chunks[i]) print(io, ": ") end l = (@_mod64 (length(B)-1)) + 1 _jl_print_bit_chunk(io, B.chunks[end], l) end bitshow(B::BitArray) = bitshow(stdout_stream, B) bitstring(B::BitArray) = sprint(bitshow, B) ## utility functions ## length(B::BitArray) = prod(B.dims) eltype{T}(B::BitArray{T}) = T ndims{T,N}(B::BitArray{T,N}) = N numel(B::BitArray) = prod(B.dims) size(B::BitArray) = tuple(B.dims...) ## Aux functions ## function _jl_get_chunks_id(i::Integer) j = int(i-1) return (@_div64 j)+1, @_mod64 j end function _jl_glue_src_bitchunks(src::Vector{Uint64}, k::Int, ks1::Int, msk_s0::Uint64, ls0::Int) chunk = ((src[k] & msk_s0) >>> ls0) if ks1 > k && ls0 > 0 chunk_n = (src[k + 1] & ~msk_s0) chunk |= (chunk_n << (64 - ls0)) end return chunk end function _jl_copy_chunks(dest::Vector{Uint64}, pos_d::Integer, src::Vector{Uint64}, pos_s::Integer, numbits::Integer) if numbits == 0 return end kd0, ld0 = _jl_get_chunks_id(pos_d) kd1, ld1 = _jl_get_chunks_id(pos_d + numbits - 1) ks0, ls0 = _jl_get_chunks_id(pos_s) ks1, ls1 = _jl_get_chunks_id(pos_s + numbits - 1) delta_kd = kd1 - kd0 delta_ks = ks1 - ks0 u = _msk64 if delta_kd == 0 msk_d0 = ~(u << ld0) | (u << ld1 << 1) else msk_d0 = ~(u << ld0) msk_d1 = (u << ld1 << 1) end if delta_ks == 0 msk_s0 = (u << ls0) & ~(u << ls1 << 1) else msk_s0 = (u << ls0) end chunk_s0 = _jl_glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0) dest[kd0] = (dest[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0) if delta_kd == 0 return end for i = 1 : kd1 - kd0 - 1 chunk_s1 = _jl_glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0) chunk_s = (chunk_s0 >>> (63 - ld0) >>> 1) | (chunk_s1 << ld0) dest[kd0 + i] = chunk_s chunk_s0 = chunk_s1 end if ks1 >= ks0 + delta_kd chunk_s1 = _jl_glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0) else chunk_s1 = uint64(0) end chunk_s = (chunk_s0 >>> (63 - ld0) >>> 1) | (chunk_s1 << ld0) dest[kd1] = (dest[kd1] & msk_d1) | (chunk_s & ~msk_d1) return end ## similar, fill, copy_to etc ## similar{T}(B::BitArray{T}) = BitArray(T, B.dims...) similar{T}(B::BitArray{T}, dims::Int...) = BitArray(T, dims) similar{T}(B::BitArray{T}, dims::Dims) = BitArray(T, dims...) similar{S<:Integer}(B::BitArray, T::Type{S}, dims::Dims) = BitArray(T, dims) # changing type to a non-Integer returns an Array # (this triggers conversions like float(bitvector) etc.) similar(B::BitArray, T::Type, dims::Dims) = Array(T, dims) function fill!{T<:Integer}(B::BitArray{T}, x::Number) y = convert(T, x) if isequal(y, zero(T)) for i = 1 : length(B.chunks) B.chunks[i] = uint64(0) end elseif isequal(y, one(T)) if length(B) == 0 return B end for i = 1 : length(B.chunks) - 1 B.chunks[i] = _msk64 end B.chunks[end] = @_msk_end length(B) else error("invalid BitArray value") end return B end fill!(B::BitArray, x) = fill!(B, int(x)) bitzeros{T}(::Type{T}, args...) = fill!(BitArray(T, args...), 0) bitzeros(args...) = fill!(BitArray(Int, args...), 0) bitones{T}(::Type{T}, args...) = fill!(BitArray(T, args...), 1) bitones(args...) = fill!(BitArray(Int, args...), 1) # XXX: temporary!? bitfalses(args...) = bitzeros(Bool, args...) bittrues(args...) = bitones(Bool, args...) biteye{T}(::Type{T}, n::Integer) = biteye(T, n, n) function biteye{T}(::Type{T}, m::Integer, n::Integer) a = bitzeros(T, m, n) for i = 1:min(m,n) a[i,i] = one(T) end return a end biteye(n::Integer) = biteye(Int, n) biteye(m::Integer, n::Integer) = biteye(Int, m, n) function one{T}(x::BitMatrix{T}) m, n = size(x) a = bitzeros(T,size(x)) for i = 1 : min(m,n) a[i,i] = one(T) end return a end function copy_to(dest::BitArray, src::BitArray) nc_d = length(dest.chunks) nc_s = length(src.chunks) nc = min(nc_s, nc_d) if nc == 0 return dest end for i = 1 : nc - 1 dest.chunks[i] = src.chunks[i] end if length(src) >= length(dest) dest.chunks[nc] = src.chunks[nc] else msk_s = @_msk_end length(src) msk_d = ~msk_s dest.chunks[nc] = (msk_d & dest.chunks[nc]) | (msk_s & src.chunks[nc]) end return dest end function copy_to(dest::BitArray, pos_d::Integer, src::BitArray, pos_s::Integer, numbits::Integer) if pos_s+numbits-1 > numel(src) || pos_d+numbits-1 > numel(dest) || pos_d < 1 || pos_s < 1 throw(BoundsError()) end _jl_copy_chunks(dest.chunks, pos_d, src.chunks, pos_s, numbits) return dest end function reshape{T,N}(B::BitArray{T}, dims::NTuple{N,Int}) if prod(dims) != numel(B) error("reshape: invalid dimensions") end Br = BitArray{T,N}() Br.chunks = B.chunks Br.dims = [i::Int for i in dims] return Br end ## Conversions ## convert{T,S,n}(::Type{Array{T}}, B::BitArray{S,n}) = convert(Array{T,n},B) function convert{T,S,n}(::Type{Array{T,n}}, B::BitArray{S,n}) A = Array(T, size(B)) for i = 1:length(A) A[i] = B[i] end return A end convert{T,S,n}(::Type{BitArray{S}}, A::AbstractArray{T,n}) = convert(BitArray{S,n},A) function convert{T,S,n}(::Type{BitArray{S,n}}, A::AbstractArray{T,n}) B = BitArray(S, size(A)) for i = 1:length(B) B[i] = A[i] end return B end convert{T<:Integer,n}(::Type{BitArray{T,n}}, B::BitArray{T,n}) = B convert{T<:Integer,S<:Integer,n}(::Type{BitArray{T,n}}, B::BitArray{S,n}) = copy_to(similar(B, T), B) # this version keeps dimensionality # (it's an extension of Array's behavior, which only does this for Vectors) function reinterpret{T<:Integer,S<:Integer,N}(::Type{T}, B::BitArray{S,N}) A = BitArray{T,N}() A.dims = copy(B.dims) A.chunks = B.chunks return A end function reinterpret{T<:Integer,S<:Integer,N}(::Type{T}, B::BitArray{S}, dims::NTuple{N,Int}) if prod(dims) != numel(B) error("reinterpret: invalid dimensions") end A = BitArray{T,N}() A.dims = [i::Int for i in dims] A.chunks = B.chunks return A end # shorthand forms BitArray <-> Array bitunpack{T,n}(B::BitArray{T,n}) = convert(Array{T,n}, B) bitpack{T,n}(A::Array{T,n}) = convert(BitArray{T,n}, A) ## Random ## function bitrand!(B::BitArray) if length(B) == 0 return B end for i = 1 : length(B.chunks) - 1 B.chunks[i] = randi(Uint64) end msk = @_msk_end length(B) B.chunks[end] = msk & randi(Uint64) return B end bitrand{T}(::Type{T}, dims::Dims) = bitrand!(BitArray(T, dims)) bitrand{T}(::Type{T}, dims::Int...) = bitrand(T, dims) bitrand(dims::Dims) = bitrand!(BitArray(dims)) bitrand(dims::Int...) = bitrand(dims) ## Bounds checking ## # @carlo: fixme function check_bounds(A::Array, B::BitArray) return nothing end ## Indexing: ref ## function ref{T<:Integer}(B::BitArray{T}, i::Integer) if i < 1 || i > length(B) throw(BoundsError()) end i1, i2 = _jl_get_chunks_id(i) return (B.chunks[i1] >>> i2) & one(Uint64) == one(Uint64) ? one(T) : zero(T) end # 0d bitarray ref{T<:Integer}(B::BitArray{T,0}) = B[1] ref(B::BitArray, i0::Integer, i1::Integer) = B[i0 + size(B,1)*(i1-1)] ref(B::BitArray, i0::Integer, i1::Integer, i2::Integer) = B[i0 + size(B,1)*((i1-1) + size(B,2)*(i2-1))] ref(B::BitArray, i0::Integer, i1::Integer, i2::Integer, i3::Integer) = B[i0 + size(B,1)*((i1-1) + size(B,2)*((i2-1) + size(B,3)*(i3-1)))] # note: although unused, the T here is necessary, otherwhise # ref(::BitArray, ::Integer) is shadowed (?) function ref{T<:Integer}(B::BitArray{T}, I::Integer...) ndims = length(I) index = I[1] stride = 1 for k=2:ndims stride *= size(B, k - 1) index += (I[k] - 1) * stride end return B[index] end # note: we can gain some performance if the first dimension is a range; # TODO: extend to I:Indices... (i.e. not necessarily contiguous) let ref_cache = nothing global ref function ref(B::BitArray, I0::Range1{Int}, I::Union(Integer, Range1{Int})...) # the < should become a != once # the stricter indexing behaviour is enforced if ndims(B) < 1 + length(I) error("wrong number of dimensions in ref") end X = similar(B, ref_shape(I0, I...)) nI = ndims(X) I = map(x->(isa(x,Integer) ? (x:x) : x), I[1:nI-1]) f0 = first(I0) l0 = length(I0) if nI == 1 _jl_copy_chunks(X.chunks, 1, B.chunks, f0, l0) return X end if is(ref_cache,nothing) ref_cache = Dict() end gap_lst = [last(r)-first(r)+1 for r in I] stride_lst = Array(Int, nI) stride = 1 ind = f0 for k = 1 : nI - 1 stride *= size(B, k) stride_lst[k] = stride ind += stride * (first(I[k]) - 1) gap_lst[k] *= stride end # we only need nI-1 elements, the last one # is dummy (used in bodies[k,2] below) stride_lst[nI] = 0 gen_cartesian_map(ref_cache, ivars->begin bodies = cell(nI, 2) bodies[1] = quote _jl_copy_chunks(X.chunks, storeind, B.chunks, ind, l0) storeind += l0 ind += stride_lst[loop_ind] end for k = 2 : nI bodies[k, 1] = quote loop_ind -= 1 end bodies[k, 2] = quote ind -= gap_lst[loop_ind] loop_ind += 1 ind += stride_lst[loop_ind] end end return bodies end, I, (:B, :X, :storeind, :ind, :l0, :stride_lst, :gap_lst, :loop_ind), B, X, 1, ind, l0, stride_lst, gap_lst, nI) return X end end # note: the Range1{Int} case is still handled by the version above # (which is fine) function ref{T<:Integer}(B::BitArray, I::AbstractVector{T}) X = similar(B, length(I)) ind = 1 for i in I X[ind] = B[i] ind += 1 end return X end let ref_cache = nothing global ref function ref(B::BitArray, I::Indices...) I = indices(I) X = similar(B, ref_shape(I...)) if is(ref_cache,nothing) ref_cache = Dict() end gen_cartesian_map(ref_cache, ivars -> quote X[storeind] = B[\$(ivars...)] storeind += 1 end, I, (:B, :X, :storeind), B, X, 1) return X end end # logical indexing function _jl_ref_bool_1d(B::BitArray, I::AbstractArray{Bool}) n = sum(I) out = similar(B, n) c = 1 for i = 1:numel(I) if I[i] out[c] = B[i] c += 1 end end out end # note : type specifiers needed to gain precedence over ref(::BitArray, ::Indices...) ref{T<:Integer}(B::BitVector{T}, I::AbstractVector{Bool}) = _jl_ref_bool_1d(B, I) ref{T<:Integer}(B::BitVector{T}, I::AbstractArray{Bool}) = _jl_ref_bool_1d(B, I) ref{T<:Integer}(B::BitArray{T}, I::AbstractVector{Bool}) = _jl_ref_bool_1d(B, I) ref{T<:Integer}(B::BitArray{T}, I::AbstractArray{Bool}) = _jl_ref_bool_1d(B, I) ref{T<:Integer}(B::BitMatrix{T}, I::Integer, J::AbstractVector{Bool}) = B[I, find(J)] ref{T<:Integer}(B::BitMatrix{T}, I::AbstractVector{Bool}, J::Integer) = B[find(I), J] ref{T<:Integer}(B::BitMatrix{T}, I::AbstractVector{Bool}, J::AbstractVector{Bool}) = B[find(I), find(J)] ref{T<:Integer,S<:Integer}(B::BitMatrix{T}, I::AbstractVector{S}, J::AbstractVector{Bool}) = B[I, find(J)] ref{T<:Integer,S<:Integer}(B::BitMatrix{T}, I::AbstractVector{Bool}, J::AbstractVector{S}) = B[find(I), J] ## Indexing: assign ## function assign{T<:Integer}(B::BitArray{T}, x::Number, i::Integer) if i < 1 || i > length(B) throw(BoundsError()) end i1, i2 = _jl_get_chunks_id(i) u = uint64(1) y = convert(T, x) if isequal(y, zero(T)) B.chunks[i1] &= ~(u << i2) elseif isequal(y, one(T)) B.chunks[i1] |= (u << i2) else error("invalid BitArray value") end return B end assign(B::BitArray, x::Number, i0::Integer, i1::Integer) = B[i0 + size(B,1)*(i1-1)] = x assign(B::BitArray, x::Number, i0::Integer, i1::Integer, i2::Integer) = B[i0 + size(B,1)*((i1-1) + size(B,2)*(i2-1))] = x assign(B::BitArray, x::Number, i0::Integer, i1::Integer, i2::Integer, i3::Integer) = B[i0 + size(B,1)*((i1-1) + size(B,2)*((i2-1) + size(B,3)*(i3-1)))] = x function assign(B::BitArray, x::Number, I0::Integer, I::Integer...) index = I0 stride = 1 for k = 1:length(I) stride = stride * size(B, k) index += (I[k] - 1) * stride end B[index] = x return B end let assign_cache = nothing global _jl_assign_array2bitarray_ranges function _jl_assign_array2bitarray_ranges(B::BitArray, X::BitArray, I0::Range1{Int}, I::Range1{Int}...) nI = 1 + length(I) if ndims(B) != nI error("wrong number of dimensions in assigment") end lI = length(I0) for r in I lI *= length(r) end if numel(X) != lI error("array assignment dimensions mismatch") end if lI == 0 return B end f0 = first(I0) l0 = length(I0) if nI == 1 _jl_copy_chunks(B.chunks, f0, X.chunks, 1, l0) return B end if is(assign_cache,nothing) assign_cache = Dict() end gap_lst = [last(r)-first(r)+1 for r in I] stride_lst = Array(Int, nI) stride = 1 ind = f0 for k = 1 : nI - 1 stride *= size(B, k) stride_lst[k] = stride ind += stride * (first(I[k]) - 1) gap_lst[k] *= stride end # we only need nI-1 elements, the last one # is dummy (used in bodies[k,2] below) stride_lst[nI] = 0 gen_cartesian_map(assign_cache, ivars->begin bodies = cell(nI, 2) bodies[1] = quote _jl_copy_chunks(B.chunks, ind, X.chunks, refind, l0) refind += l0 ind += stride_lst[loop_ind] end for k = 2 : nI bodies[k, 1] = quote loop_ind -= 1 end bodies[k, 2] = quote ind -= gap_lst[loop_ind] loop_ind += 1 ind += stride_lst[loop_ind] end end return bodies end, I, (:B, :X, :refind, :ind, :l0, :stride_lst, :gap_lst, :loop_ind), B, X, 1, ind, l0, stride_lst, gap_lst, nI) return B end end # note: we can gain some performance if the first dimension is a range; # currently this is mainly indended for the general cat case # TODO: extend to I:Indices... (i.e. not necessarily contiguous) function assign(B::BitArray, X::BitArray, I0::Range1{Int}, I::Union(Integer, Range1{Int})...) I = map(x->(isa(x,Integer) ? (x:x) : x), I) _jl_assign_array2bitarray_ranges(B, X, I0, I...) end function assign{T<:Integer}(B::BitArray, x::Number, I::AbstractVector{T}) for i in I B[i] = x end return B end function assign{T<:Number,S<:Integer}(B::BitArray, X::AbstractArray{T}, I::AbstractVector{S}) if length(X) != length(I); error("argument dimensions must match"); end for i = 1:length(I) B[I[i]] = X[i] end return B end let assign_cache = nothing global assign function assign(B::BitArray, x::Number, I0::Indices, I::Indices...) I0 = indices(I0) I = indices(I) if is(assign_cache,nothing) assign_cache = Dict() end gen_cartesian_map(assign_cache, ivars->:(B[\$(ivars...)] = x), tuple(I0, I...), (:B, :x), B, x) return B end end # note: use of T<:Integer in the following is to disambiguate assign{T<:Integer,S<:Number}(B::BitArray{T}, X::AbstractArray{S}, I0::Integer) = (B[I0] = X[1]) let assign_cache = nothing global assign function assign{T<:Integer,S<:Number}(B::BitArray{T}, X::AbstractArray{S}, I0::Indices, I::Indices...) I0 = indices(I0) I = indices(I) nel = length(I0) for idx in I nel *= length(idx) end if length(X) != nel error("argument dimensions must match") end if ndims(X) > 1 if size(X,1) != length(I0) error("argument dimensions must match") end for i = 1:length(I) if size(X,i+1) != length(I[i]) error("argument dimensions must match") end end end if is(assign_cache,nothing) assign_cache = Dict() end gen_cartesian_map(assign_cache, ivars->:(B[\$(ivars...)] = X[refind]; refind += 1), tuple(I0, I...), (:B, :X, :refind), B, X, 1) return B end end # logical indexing function _jl_assign_bool_scalar_1d(A::BitArray, x::Number, I::AbstractArray{Bool}) n = sum(I) for i = 1:numel(I) if I[i] A[i] = x end end A end function _jl_assign_bool_vector_1d{T<:Number}(A::BitArray, X::AbstractArray{T}, I::AbstractArray{Bool}) n = sum(I) c = 1 for i = 1:numel(I) if I[i] A[i] = X[c] c += 1 end end A end assign{T<:Number}(A::BitArray, X::AbstractArray{T}, I::AbstractVector{Bool}) = _jl_assign_bool_vector_1d(A, X, I) assign{T<:Number}(A::BitArray, X::AbstractArray{T}, I::AbstractArray{Bool}) = _jl_assign_bool_vector_1d(A, X, I) assign(A::BitArray, x::Number, I::AbstractVector{Bool}) = _jl_assign_bool_scalar_1d(A, x, I) assign(A::BitArray, x::Number, I::AbstractArray{Bool}) = _jl_assign_bool_scalar_1d(A, x, I) # note: use of T<:Integer in the following is to disambiguate assign{T<:Integer,S<:Number}(A::BitMatrix{T}, x::AbstractArray{S}, I::Integer, J::AbstractVector{Bool}) = (A[I,find(J)] = x) assign{T<:Integer}(A::BitMatrix{T}, x::Number, I::Integer, J::AbstractVector{Bool}) = (A[I,find(J)] = x) assign{T<:Integer,S<:Number}(A::BitMatrix{T}, x::AbstractArray{S}, I::AbstractVector{Bool}, J::Integer) = (A[find(I),J] = x) assign{T<:Integer}(A::BitMatrix{T}, x::Number, I::AbstractVector{Bool}, J::Integer) = (A[find(I),J] = x) assign{T<:Integer,S<:Number}(A::BitMatrix{T}, x::AbstractArray{S}, I::AbstractVector{Bool}, J::AbstractVector{Bool}) = (A[find(I),find(J)] = x) assign{T<:Integer}(A::BitMatrix{T}, x::Number, I::AbstractVector{Bool}, J::AbstractVector{Bool}) = (A[find(I),find(J)] = x) assign{T<:Integer,S<:Number,R<:Integer}(A::BitMatrix{T}, x::AbstractArray{S}, I::AbstractVector{R}, J::AbstractVector{Bool}) = (A[I,find(J)] = x) assign{T<:Integer,R<:Integer}(A::BitMatrix{T}, x::Number, I::AbstractVector{R}, J::AbstractVector{Bool}) = (A[I,find(J)] = x) assign{T<:Integer,S<:Number,R<:Integer}(A::BitMatrix{T}, x::AbstractArray{S}, I::AbstractVector{Bool}, J::AbstractVector{R}) = (A[find(I),J] = x) assign{T<:Integer,R<:Integer}(A::BitMatrix{T}, x::Number, I::AbstractVector{Bool}, J::AbstractVector{R}) = (A[find(I),J] = x) ## Dequeue functionality ## function push{T<:Integer}(B::BitVector{T}, item) # convert first so we don't grow the bitarray if the assignment won't work item = convert(T, item) _jl_check_is_valid_bit(item) l = @_mod64 length(B) if l == 0 ccall(:jl_array_grow_end, Void, (Any, Uint), B.chunks, 1) B.chunks[end] = uint64(0) end B.dims[1] += 1 B[end] = item return B end function append!{T<:Integer}(B::BitVector{T}, items::BitVector{T}) n0 = length(B) n1 = length(items) if n1 == 0 return B end k0 = length(B.chunks) k1 = _jl_num_bit_chunks(n0 + n1) if k1 > k0 ccall(:jl_array_grow_end, Void, (Any, Uint), B.chunks, k1 - k0) B.chunks[end] = uint64(0) end B.dims[1] += n1 _jl_copy_chunks(B.chunks, n0+1, items.chunks, 1, n1) return B end append!{T<:Integer}(B::BitVector{T}, items::BitVector) = append!(B, reinterpret(T, items)) append!{T<:Integer}(B::BitVector{T}, items::AbstractVector{T}) = append!(B, bitpack(items)) append!{T<:Integer}(A::Vector{T}, items::BitVector{T}) = append!(A, bitunpack(items)) function grow(B::BitVector, n::Integer) n0 = length(B) if n < -n0 throw(BoundsError()) end if n < 0 return del(B, n0+n+1:n0) end k0 = length(B.chunks) k1 = _jl_num_bit_chunks(n0 + int(n)) if k1 > k0 ccall(:jl_array_grow_end, Void, (Any, Uint), B.chunks, k1 - k0) B.chunks[end] = uint64(0) end B.dims[1] += n return B end function pop(B::BitVector) if isempty(B) error("pop: BitArray is empty") end item = B[end] B[end] = 0 l = @_mod64 length(B) if l == 1 ccall(:jl_array_del_end, Void, (Any, Uint), B.chunks, 1) end B.dims[1] -= 1 return item end function enqueue{T<:Integer}(B::BitVector{T}, item) item = convert(T, item) _jl_check_is_valid_bit(item) l = @_mod64 length(B) if l == 0 ccall(:jl_array_grow_end, Void, (Any, Uint), B.chunks, 1) B.chunks[end] = uint64(0) end B.dims[1] += 1 if B.dims[1] == 1 B.chunks[1] = item return B end for i = length(B.chunks) : -1 : 2 B.chunks[i] = (B.chunks[i] << 1) | (B.chunks[i-1] >>> 63) end B.chunks[1] = uint64(item) | (B.chunks[1] << 1) return B end function shift(B::BitVector) if isempty(B) error("shift: BitArray is empty") end item = B[1] for i = 1 : length(B.chunks) - 1 B.chunks[i] = (B.chunks[i] >>> 1) | (B.chunks[i+1] << 63) end l = @_mod64 length(B) if l == 1 ccall(:jl_array_del_end, Void, (Any, Uint), B.chunks, 1) else B.chunks[end] >>>= 1 end B.dims[1] -= 1 return item end function insert{T<:Integer}(B::BitVector{T}, i::Integer, item) if i < 1 throw(BoundsError()) end item = convert(T, item) _jl_check_is_valid_bit(item) n = length(B) if i > n x = bitzeros(T, i - n) append!(B, x) else k, j = _jl_get_chunks_id(i) l = @_mod64 length(B) if l == 0 ccall(:jl_array_grow_end, Void, (Any, Uint), B.chunks, 1) B.chunks[end] = uint64(0) end B.dims[1] += 1 for t = length(B.chunks) : -1 : k + 1 B.chunks[t] = (B.chunks[t] << 1) | (B.chunks[t - 1] >>> 63) end msk_aft = (_msk64 << j) msk_bef = ~msk_aft B.chunks[k] = (msk_bef & B.chunks[k]) | ((msk_aft & B.chunks[k]) << 1) end B[i] = item end function del(B::BitVector, i::Integer) n = length(B) if !(1 <= i <= n) throw(BoundsError()) end k, j = _jl_get_chunks_id(i) msk_bef = _msk64 >>> (63 - j) msk_aft = ~msk_bef msk_bef >>>= 1 B.chunks[k] = (msk_bef & B.chunks[k]) | ((msk_aft & B.chunks[k]) >> 1) if length(B.chunks) > k B.chunks[k] |= (B.chunks[k + 1] << 63) end for t = k + 1 : length(B.chunks) - 1 B.chunks[t] = (B.chunks[t] >>> 1) | (B.chunks[t + 1] << 63) end l = @_mod64 length(B) if l == 1 ccall(:jl_array_del_end, Void, (Any, Uint), B.chunks, 1) elseif length(B.chunks) > k B.chunks[end] >>>= 1 end B.dims[1] -= 1 return B end function del(B::BitVector, r::Range1{Int}) n = length(B) i_f = first(r) i_l = last(r) if !(1 <= i_f && i_l <= n) throw(BoundsError()) end if i_l < i_f return B end _jl_copy_chunks(B.chunks, i_f, B.chunks, i_l+1, n-i_l) delta_l = i_l - i_f + 1 new_l = length(B) - delta_l delta_k = length(B.chunks) - _jl_num_bit_chunks(new_l) if delta_k > 0 ccall(:jl_array_del_end, Void, (Any, Uint), B.chunks, delta_k) end if new_l > 0 B.chunks[end] &= @_msk_end new_l end B.dims[1] = new_l return B end function del_all(B::BitVector) ccall(:jl_array_del_end, Void, (Any, Uint), B.chunks, length(B.chunks)) B.dims[1] = 0 return B end ## Misc functions for f in (:iround, :itrunc, :ifloor, :iceil, :abs) @eval (\$f)(B::BitArray) = copy(B) end ## Unary operators ## (~)(B::BitArray) = ~bitunpack(B) (-)(B::BitArray) = -bitunpack(B) sign(B::BitArray) = copy(B) real(B::BitArray) = copy(B) imag{T}(B::BitArray{T}) = bitzeros(T, size(B)) conj!(B::BitArray) = B conj(B::BitArray) = copy(B) function flipbits(B::BitArray) C = similar(B) for i = 1:length(B.chunks) - 1 C.chunks[i] = ~B.chunks[i] end msk = @_msk_end length(B) C.chunks[end] = msk & (~B.chunks[end]) return C end # Bools have special treatment (~)(B::BitArray{Bool}) = flipbits(B) !(B::BitArray{Bool}) = flipbits(B) (-)(B::BitArray{Bool}) = copy(B) sign(B::BitArray{Bool}) = convert(BitArray{Int}, B) ## Binary arithmetic operators ## for f in (:+, :-, :div, :mod, :./, :.^, :/, :\) @eval begin (\$f)(A::BitArray, B::BitArray) = (\$f)(bitunpack(A), bitunpack(B)) (\$f)(B::BitArray, x::Number) = (\$f)(bitunpack(B), x) (\$f)(x::Number, B::BitArray) = (\$f)(x, bitunpack(B)) end end for f in (:&, :|, :\$) @eval begin function (\$f){T<:Integer}(A::BitArray{T}, B::BitArray{T}) F = BitArray(T, promote_shape(size(A),size(B))...) for i = 1:length(F.chunks) - 1 F.chunks[i] = (\$f)(A.chunks[i], B.chunks[i]) end msk = @_msk_end length(F) F.chunks[end] = msk & (\$f)(A.chunks[end], B.chunks[end]) return F end (\$f)(x::Number, B::BitArray) = (\$f)(x, bitunpack(B)) (\$f)(A::BitArray, x::Number) = (\$f)(x, A) end end (.*){T<:Integer}(A::BitArray{T}, B::BitArray{T}) = A & B (.*)(x::Number, B::BitArray) = x .* bitunpack(B) (.*)(A::BitArray, x::Number) = x .* A for f in (:+, :-, :div, :mod, :./, :.^, :.*, :&, :|, :\$) @eval begin (\$f)(A::BitArray, B::AbstractArray) = (\$f)(bitunpack(A), B) (\$f)(A::AbstractArray, B::BitArray) = (\$f)(A, bitunpack(B)) end end # specialized Bool versions function (&)(x::Number, B::BitArray{Bool}) if bool(x) return copy(B) else return bitzeros(Bool, size(B)) end end function (|)(x::Number, B::BitArray{Bool}) if bool(x) return bitones(Bool, size(B)) else return copy(B) end end function (\$)(x::Number, B::BitArray{Bool}) if bool(x) return ~B else return copy(B) end end (.*)(x::Number, B::BitArray{Bool}) = x & B ## promotion to complex ## # TODO? ## Binary comparison operators ## # note: these return BitArray{Bool} for (f,scalarf,t) in ((:(.==),:(==),:Number), (:.<, :<,:Real), (:.!=,:!=,:Number), (:.<=,:<=,:Real)) @eval begin function (\$f)(A::BitArray, B::BitArray) F = BitArray(Bool, promote_shape(size(A),size(B))) for i = 1:numel(B) F[i] = (\$scalarf)(A[i], B[i]) end return F end function (\$f)(x::(\$t), B::BitArray) F = similar(B, Bool) for i = 1:numel(F) F[i] = (\$scalarf)(x, B[i]) end return F end function (\$f)(A::BitArray, x::(\$t)) F = similar(A, Bool) for i = 1:numel(F) F[i] = (\$scalarf)(A[i], x) end return F end end end for f in (:(==), :(.==), :!=, :.!=, :<, :.<, :<=, :.<=) @eval begin (\$f)(A::BitArray, B::Array) = (\$f)(bitunpack(A), B) (\$f)(A::Array, B::BitArray) = (\$f)(A, bitunpack(B)) end end function (==)(A::BitArray, B::BitArray) if size(A) != size(B) return false end for i = 1:length(A.chunks) if A.chunks[i] != B.chunks[i] return false end end return true end function (!=)(A::BitArray, B::BitArray) if size(A) != size(B) return true end for i = 1:length(A.chunks) if A.chunks[i] != B.chunks[i] return true end end return false end ## Data movement ## # TODO some of this could be optimized function slicedim(A::BitArray, d::Integer, i::Integer) d_in = size(A) leading = d_in[1:(d-1)] d_out = tuple(leading..., 1, d_in[(d+1):end]...) M = prod(leading) N = numel(A) stride = M * d_in[d] B = similar(A, d_out) index_offset = 1 + (i-1)*M l = 1 if M==1 for j=0:stride:(N-stride) B[l] = A[j + index_offset] l += 1 end else for j=0:stride:(N-stride) offs = j + index_offset for k=0:(M-1) B[l] = A[offs + k] l += 1 end end end return B end function flipdim(A::BitArray, d::Integer) nd = ndims(A) sd = d > nd ? 1 : size(A, d) if sd == 1 return copy(A) end B = similar(A) nnd = 0 for i = 1:nd nnd += int(size(A,i)==1 || i==d) end if nnd==nd # flip along the only non-singleton dimension for i = 1:sd B[i] = A[sd+1-i] end return B end d_in = size(A) leading = d_in[1:(d-1)] M = prod(leading) N = numel(A) stride = M * sd if M==1 for j = 0:stride:(N-stride) for i = 1:sd ri = sd+1-i B[j + ri] = A[j + i] end end else for i = 1:sd ri = sd+1-i for j=0:stride:(N-stride) offs = j + 1 + (i-1)*M boffs = j + 1 + (ri-1)*M _jl_copy_chunks(B.chunks, boffs, A.chunks, offs, M) end end end return B end function rotl90(A::BitMatrix) m,n = size(A) B = similar(A,(n,m)) for i=1:m, j=1:n B[n-j+1,i] = A[i,j] end return B end function rotr90(A::BitMatrix) m,n = size(A) B = similar(A,(n,m)) for i=1:m, j=1:n B[j,m-i+1] = A[i,j] end return B end function rot180(A::BitMatrix) m,n = size(A) B = similar(A) for i=1:m, j=1:n B[m-i+1,n-j+1] = A[i,j] end return B end # implemented as a macro to improve performance macro _jl_reverse_bits(dest, src) quote z = \$(esc(src)) z = ((z >>> 1) & 0x5555555555555555) | ((z << 1) & 0xaaaaaaaaaaaaaaaa) z = ((z >>> 2) & 0x3333333333333333) | ((z << 2) & 0xcccccccccccccccc) z = ((z >>> 4) & 0x0f0f0f0f0f0f0f0f) | ((z << 4) & 0xf0f0f0f0f0f0f0f0) z = ((z >>> 8) & 0x00ff00ff00ff00ff) | ((z << 8) & 0xff00ff00ff00ff00) z = ((z >>> 16) & 0x0000ffff0000ffff) | ((z << 16) & 0xffff0000ffff0000) \$(esc(dest)) = ((z >>> 32) & 0x00000000ffffffff) | ((z << 32) & 0xffffffff00000000) end end function reverse!(B::BitVector) n = length(B) if n == 0 return B end pnc = length(B.chunks) & 1 hnc = (length(B.chunks) >>> 1) aux_chunks = Array(Uint64, 1) for i = 1 : hnc j = ((i - 1) << 6) @_jl_reverse_bits aux_chunks[1] B.chunks[i] _jl_copy_chunks(B.chunks, j+1, B.chunks, n-63-j, 64) @_jl_reverse_bits B.chunks[i] B.chunks[i] _jl_copy_chunks(B.chunks, n-63-j, aux_chunks, 1, 64) end if pnc == 0 return B end i = hnc + 1 j = hnc << 6 l = (@_mod64 (n+63)) + 1 msk = @_mskr l @_jl_reverse_bits aux_chunks[1] (B.chunks[i] & msk) aux_chunks[1] >>>= (64 - l) _jl_copy_chunks(B.chunks, j+1, aux_chunks, 1, l) return B end reverse(v::BitVector) = reverse!(copy(v)) function (<<){T}(B::BitVector{T}, i::Int64) n = length(B) i %= n if i == 0; return copy(B); end A = bitzeros(T, n); _jl_copy_chunks(A.chunks, 1, B.chunks, i+1, n-i) return A end (<<){T}(B::BitVector{T}, i::Int32) = B << int64(i) (<<){T}(B::BitVector{T}, i::Integer) = B << int64(i) function (>>>){T}(B::BitVector{T}, i::Int64) n = length(B) i %= n if i == 0; return copy(B); end A = bitzeros(T, n); _jl_copy_chunks(A.chunks, i+1, B.chunks, 1, n-i) return A end (>>>){T}(B::BitVector{T}, i::Int32) = B >>> int64(i) (>>>){T}(B::BitVector{T}, i::Integer) = B >>> int64(i) (>>)(B::BitVector, i::Int32) = B >>> i (>>)(B::BitVector, i::Integer) = B >>> i function rotl{T}(B::BitVector{T}, i::Integer) n = length(B) i %= n if i == 0; return copy(B); end A = BitArray(T, n); _jl_copy_chunks(A.chunks, 1, B.chunks, i+1, n-i) _jl_copy_chunks(A.chunks, n-i+1, B.chunks, 1, i) return A end function rotr{T}(B::BitVector{T}, i::Integer) n = length(B) i %= n if i == 0; return copy(B); end A = BitArray(T, n); _jl_copy_chunks(A.chunks, i+1, B.chunks, 1, n-i) _jl_copy_chunks(A.chunks, 1, B.chunks, n-i+1, i) return A end ## nnz & find ## function nnz(B::BitArray) n = 0 for i = 1:length(B.chunks) n += count_ones(B.chunks[i]) end return n end function find{T<:Integer}(B::BitArray{T}) nnzB = nnz(B) I = Array(Int, nnzB) z = zero(T) count = 1 for i = 1:length(B) if B[i] != z I[count] = i count += 1 end end return I end findn(B::BitVector) = find(B) function findn{T<:Integer}(B::BitMatrix{T}) nnzB = nnz(B) I = Array(Int, nnzB) J = Array(Int, nnzB) z = zero(T) count = 1 for j=1:size(B,2), i=1:size(B,1) if !isequal(B[i,j], z) I[count] = i J[count] = j count += 1 end end return (I, J) end let findn_cache = nothing function findn_one(ivars) s = { quote I[\$i][count] = \$(ivars[i]) end for i = 1:length(ivars)} quote Bind = B[\$(ivars...)] if Bind != z \$(s...) count +=1 end end end global findn function findn{T}(B::BitArray{T}) ndimsB = ndims(B) nnzB = nnz(B) I = ntuple(ndimsB, x->Array(Int, nnzB)) if nnzB > 0 ranges = ntuple(ndims(B), d->(1:size(B,d))) if is(findn_cache,nothing) findn_cache = Dict() end gen_cartesian_map(findn_cache, findn_one, ranges, (:B, :I, :count, :z), B, I, 1, zero(T)) end return I end end function findn_nzs{T<:Integer}(B::BitMatrix{T}) I, J = findn(B) return (I, J, bitones(T, length(I))) end nonzeros{T<:Integer}(B::BitArray{T}) = bitones(T, nnz(B)) ## Reductions ## areduce(f::Function, B::BitArray, region::Dimspec, v0, RType::Type) = areduce(f, bitunpack(B), region, v0, RType) let bitareduce_cache = nothing # generate the body of the N-d loop to compute a reduction function gen_bitareduce_func(n, f) ivars = { gensym() for i=1:n } # limits and vars for reduction loop lo = { gensym() for i=1:n } hi = { gensym() for i=1:n } rvars = { gensym() for i=1:n } setlims = { quote # each dim of reduction is either 1:sizeA or ivar:ivar if contains(region,\$i) \$(lo[i]) = 1 \$(hi[i]) = size(A,\$i) else \$(lo[i]) = \$(hi[i]) = \$(ivars[i]) end end for i=1:n } rranges = { :( \$(lo[i]):\$(hi[i]) ) for i=1:n } # lo:hi for all dims body = quote _tot = v0 \$(setlims...) \$(make_loop_nest(rvars, rranges, :(_tot = (\$f)(_tot, A[\$(rvars...)])))) R[_ind] = _tot _ind += 1 end quote local _F_ function _F_(f, A, region, R, v0) _ind = 1 \$(make_loop_nest(ivars, { :(1:size(R,\$i)) for i=1:n }, body)) end _F_ end end global bitareduce function bitareduce{T<:Integer}(f::Function, A::BitArray{T}, region::Dimspec, v0) dimsA = size(A) ndimsA = ndims(A) dimsR = ntuple(ndimsA, i->(contains(region, i) ? 1 : dimsA[i])) R = BitArray(T, dimsR) if is(bitareduce_cache,nothing) bitareduce_cache = Dict() end key = ndimsA fname = :f if (is(f,*) && (fname=:*;true)) || (is(f,max) && (fname=:max;true)) || (is(f,min) && (fname=:min;true)) key = (fname, ndimsA) end if !has(bitareduce_cache,key) fexpr = gen_bitareduce_func(ndimsA, fname) func = eval(fexpr) bitareduce_cache[key] = func else func = bitareduce_cache[key] end func(f, A, region, R, v0) return R end end max{T}(A::BitArray{T}, b::(), region::Dimspec) = bitareduce(max,A,region,typemin(T)) min{T}(A::BitArray{T}, b::(), region::Dimspec) = bitareduce(min,A,region,typemax(T)) sum{T}(A::BitArray{T}, region::Dimspec) = areduce(+,A,region,0,Int) prod{T}(A::BitArray{T}, region::Dimspec) = bitareduce(*,A,region,one(T)) sum(B::BitArray) = nnz(B) prod{T}(B::BitArray{T}) = (nnz(B) == length(B) ? one(T) : zero(T)) min{T}(B::BitArray{T}) = length(B) > 0 ? prod(B) : typemax(T) max{T}(B::BitArray{T}) = length(B) > 0 ? (nnz(B) > 0 ? one(T) : zero(T)) : typemin(T) ## map over bitarrays ## function map_to(f, dest::BitArray, A::Union(StridedArray,BitArray)) for i=1:numel(A) dest[i] = f(A[i]) end return dest end function map_to(f, dest::BitArray, A::Union(StridedArray,BitArray), B::Union(StridedArray,BitArray)) for i=1:numel(A) dest[i] = f(A[i], B[i]) end return dest end function map_to(f, dest::BitArray, A::Union(StridedArray,BitArray), B::Number) for i=1:numel(A) dest[i] = f(A[i], B) end return dest end function map_to(f, dest::BitArray, A::Number, B::Union(StridedArray,BitArray)) for i=1:numel(B) dest[i] = f(A, B[i]) end return dest end function map_to(f, dest::BitArray, As::Union(StridedArray,BitArray)...) n = numel(As[1]) i = 1 ith = a->a[i] for i=1:n dest[i] = f(map(ith, As)...) end return dest end ## Filter ## function filter(f::Function, Bs::BitArray) boolmap::Array{Bool} = map(f, Bs) Bs[boolmap] end ## Transpose ## transpose(B::BitVector) = reshape(copy(B), 1, length(B)) # fast 8x8 bit transpose from Henry S. Warrens's "Hacker's Delight" # http://www.hackersdelight.org/HDcode/transpose8.c.txt # implemented as a macro to improve performance macro _jl_transpose8x8(x) quote y = \$(esc(x)) t = (y \$ (y >>> 7)) & 0x00aa00aa00aa00aa; y = y \$ t \$ (t << 7) t = (y \$ (y >>> 14)) & 0x0000cccc0000cccc y = y \$ t \$ (t << 14) t = (y \$ (y >>> 28)) & 0x00000000f0f0f0f0 \$(esc(x)) = y \$ t \$ (t << 28) end end function _jl_form_8x8_chunk(B::BitMatrix, i1::Int, i2::Int, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::Uint64) x = uint64(0) k, l = _jl_get_chunks_id(i1 + (i2 - 1) * m) r = 0 for j = 1 : 8 if k > nc break end x |= ((B.chunks[k] >>> l) & msk8) << r if l + 8 >= 64 && nc > k r0 = 8 - (@_mod64 (l + 8)) x |= (B.chunks[k + 1] & (msk8 >>> r0)) << (r + r0) end k += cgap + (l + cinc >= 64 ? 1 : 0) l = @_mod64 (l + cinc) r += 8 end return x end # note: assumes B is filled with 0's function _jl_put_8x8_chunk(B::BitMatrix, i1::Int, i2::Int, x::Uint64, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::Uint64) k, l = _jl_get_chunks_id(i1 + (i2 - 1) * m) r = 0 for j = 1 : 8 if k > nc break end B.chunks[k] |= ((x >>> r) & msk8) << l if l + 8 >= 64 && nc > k r0 = 8 - (@_mod64 (l + 8)) B.chunks[k + 1] |= ((x >>> (r + r0)) & (msk8 >>> r0)) end k += cgap + (l + cinc >= 64 ? 1 : 0) l = @_mod64 (l + cinc) r += 8 end return end function transpose{T<:Integer}(B::BitMatrix{T}) l1 = size(B, 1) l2 = size(B, 2) Bt = bitzeros(T, l2, l1) cgap1 = @_div64 l1 cinc1 = @_mod64 l1 cgap2 = @_div64 l2 cinc2 = @_mod64 l2 nc = length(B.chunks) for i = 1 : 8 : l1 msk8_1 = uint64(0xff) if (l1 < i + 7) msk8_1 >>>= i + 7 - l1 end for j = 1 : 8 : l2 x = _jl_form_8x8_chunk(B, i, j, l1, cgap1, cinc1, nc, msk8_1) @_jl_transpose8x8 x msk8_2 = uint64(0xff) if (l2 < j + 7) msk8_2 >>>= j + 7 - l2 end _jl_put_8x8_chunk(Bt, j, i, x, l2, cgap2, cinc2, nc, msk8_2) end end return Bt end ctranspose(B::BitArray) = transpose(B) ## Permute ## let permute_cache = nothing, stridenames::Array{Any,1} = {} global permute function permute(B::BitArray, perm) dimsB = size(B) ndimsB = length(dimsB) dimsP = ntuple(ndimsB, i->dimsB[perm[i]]) P = similar(B, dimsP) ranges = ntuple(ndimsB, i->(colon(1,dimsP[i]))) while length(stridenames) < ndimsB push(stridenames, gensym()) end #calculates all the strides strides = [ prod(dimsB[1:(perm[dim]-1)])::Int for dim = 1:length(perm) ] #Creates offset, because indexing starts at 1 offset = 0 for i in strides offset+=i end offset = 1-offset function permute_one(ivars) len = length(ivars) counts = { gensym() for i=1:len} toReturn = cell(len+1,2) for i = 1:numel(toReturn) toReturn[i] = nothing end tmp = counts[end] toReturn[len+1] = quote ind = 1 \$tmp = \$(stridenames[len]) end #inner most loop toReturn[1] = quote P[ind] = B[+(\$(counts...))+offset] ind+=1 \$(counts[1]) += \$(stridenames[1]) end for i = 1:len-1 tmp = counts[i] val = i toReturn[(i+1)] = quote \$tmp = \$(stridenames[val]) end tmp2 = counts[i+1] val = i+1 toReturn[(i+1)+(len+1)] = quote \$tmp2 += \$(stridenames[val]) end end toReturn end if is(permute_cache,nothing) permute_cache = Dict() end gen_cartesian_map(permute_cache, permute_one, ranges, tuple(:B, :P, :perm, :offset, stridenames[1:ndimsB]...), B, P, perm, offset, strides...) return P end end # let ## Concatenation ## function hcat{T}(B::BitVector{T}...) height = length(B[1]) for j = 2:length(B) if length(B[j]) != height; error("hcat: mismatched dimensions"); end end M = BitArray(T, height, length(B)) for j = 1:length(B) _jl_copy_chunks(M.chunks, (height*(j-1))+1, B[j].chunks, 1, height) end return M end function vcat{T}(V::BitVector{T}...) n = 0 for Vk in V n += length(Vk) end B = BitArray(T, n) j = 1 for Vk in V _jl_copy_chunks(B.chunks, j, Vk.chunks, 1, length(Vk)) j += length(Vk) end return B end function hcat{T}(A::Union(BitMatrix{T},BitVector{T})...) nargs = length(A) nrows = size(A[1], 1) ncols = 0 dense = true for j = 1:nargs Aj = A[j] nd = ndims(Aj) ncols += (nd==2 ? size(Aj,2) : 1) if size(Aj, 1) != nrows; error("hcat: mismatched dimensions"); end end B = BitArray(T, nrows, ncols) pos = 1 for k=1:nargs Ak = A[k] n = numel(Ak) _jl_copy_chunks(B.chunks, pos, Ak.chunks, 1, n) pos += n end return B end function vcat{T}(A::BitMatrix{T}...) nargs = length(A) nrows = sum(a->size(a, 1), A)::Int ncols = size(A[1], 2) for j = 2:nargs if size(A[j], 2) != ncols; error("vcat: mismatched dimensions"); end end B = BitArray(T, nrows, ncols) nrowsA = [size(a, 1) for a in A] pos_d = 1 pos_s = ones(Int, nargs) for j = 1:ncols for k=1:nargs _jl_copy_chunks(B.chunks, pos_d, A[k].chunks, pos_s[k], nrowsA[k]) pos_s[k] += nrowsA[k] pos_d += nrowsA[k] end end return B end # general case, specialized for BitArrays and Integers function cat{T}(catdim::Integer, X::Union(BitArray{T}, Integer)...) nargs = length(X) # using integers results in conversion to Array{Int} # (except in the all-Bool case) has_bitarray = false has_integer = false for a in X if isa(a, BitArray) has_bitarray = true else has_integer = true end end # just integers and no BitArrays -> general case if !has_bitarray return invoke(cat, (Integer, Any...), catdim, X...) end dimsX = map((a->isa(a,BitArray) ? size(a) : (1,)), X) ndimsX = map((a->isa(a,BitArray) ? ndims(a) : 1), X) d_max = max(ndimsX) if catdim > d_max + 1 for i=1:nargs if dimsX[1] != dimsX[i] error("cat: all inputs must have same dimensions when concatenating along a higher dimension"); end end elseif nargs >= 2 for d=1:d_max if d == catdim; continue; end len = d <= ndimsX[1] ? dimsX[1][d] : 1 for i = 2:nargs if len != (d <= ndimsX[i] ? dimsX[i][d] : 1) error("cat: dimension mismatch on dimension ", d) end end end end cat_ranges = ntuple(nargs, i->(catdim <= ndimsX[i] ? dimsX[i][catdim] : 1)) function compute_dims(d) if d == catdim if catdim <= d_max return sum(cat_ranges) else return nargs end else if d <= ndimsX[1] return dimsX[1][d] else return 1 end end end ndimsC = max(catdim, d_max) dimsC = ntuple(ndimsC, compute_dims)::(Int...) typeC = promote_type(map(x->isa(x,BitArray) ? eltype(x) : typeof(x), X)...) if !has_integer || typeC == Bool C = BitArray(typeC, dimsC) else C = Array(typeC, dimsC) end range = 1 for k=1:nargs nextrange = range+cat_ranges[k] cat_one = ntuple(ndimsC, i->(i != catdim ? (1:dimsC[i]) : (range:nextrange-1) )) # note: when C and X are BitArrays, this calls # the special assign with ranges C[cat_one...] = X[k] range = nextrange end return C end # hvcat -> use fallbacks in abstractarray.jl ## Reductions and scans ## isequal(A::BitArray, B::BitArray) = (A == B) function cumsum{T}(v::BitVector{T}) n = length(v) c = Array(T, n) if n == 0; return c; end c[1] = v[1] for i=2:n c[i] = v[i] + c[i-1] end return c end function cumsum(v::BitVector{Bool}) n = length(v) c = bitones(Bool, n) for i=1:n if !v[i] c[i] = false else break end end return c end function cumprod{T}(v::BitVector{T}) n = length(v) c = bitzeros(T, n) for i=1:n if v[i] == one(T) c[i] = one(T) else break end end return c end write(s, B::BitArray) = write(s, B.chunks) read(s, B::BitArray) = read(s, B.chunks) function mmap_bitarray{T<:Integer,N}(::Type{T}, dims::NTuple{N,Int}, s::IOStream, offset::FileOffset) prot, flags, iswrite = mmap_stream_settings(s) if length(dims) == 0 dims = 0 end n = prod(dims) nc = _jl_num_bit_chunks(n) B = BitArray{T,N}() chunks = mmap_array(Uint64, (nc,), s, offset) if iswrite chunks[end] &= @_msk_end n else if chunks[end] != chunks[end] & @_msk_end n error("The given file does not contain a valid BitArray of size \$(join(dims, 'x')) (open with r+ to override)") end end dims = [i::Int for i in dims] B.chunks = chunks B.dims = dims return B end mmap_bitarray{T<:Integer,N}(::Type{T}, dims::NTuple{N,Int}, s::IOStream) = mmap_bitarray(T, dims, s, position(s)) msync{T}(B::BitArray{T}, flags::Integer) = msync(pointer(B.chunks), flags) msync{T}(B::BitArray{T}) = msync(B.chunks,MS_SYNC)
Something went wrong with that request. Please try again.