Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Topologies using CollectionOfVectors #965

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions src/CollectionOfVectors.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
struct CollectionOfVectors{IT<:Union{AbstractArray{UnitRange{Int}}, AbstractDict{<:Any, UnitRange{Int}}}, DT}
indices::IT
data::Vector{DT}
end

Base.getindex(cv::CollectionOfVectors, index) = view(cv.data, cv.indices[index])
Base.keys(cv::CollectionOfVectors) = keys(cv.indcies)
Base.values(cv::CollectionOfVectors) = (view(cv.data, idx) for idx in values(cv.indices))
nonempty_values(cv::CollectionOfVectors) = (view(cv.data, idx) for idx in values(cv.indices) if !isempty(idx))

Check warning on line 9 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L7-L9

Added lines #L7 - L9 were not covered by tests

# Structure for building this efficiently
struct AdaptiveRange
start::Int
ncurrent::Int # These two could be UInt8 or similar in
nmax::Int # many applications, but probably not worth.
end

struct ConstructionBuffer{IT, DT}
indices::IT # eltype = AdaptiveRange
data::Vector{DT}
sizehint::Int
end

# Note: Workaround since ndims(Vector) or (Array{T, N} where T) doesn't work on julia 1.6
_ndims(::Type{<:Array{T, N} where T}) where N = N

function ConstructionBuffer(IT::Type{<:Array}, data::Vector; dims = nothing, sizehint)
dims === nothing && error("dims must be given when indexed by an $IT")
_ndims(IT) == length(dims) || error("The number of dims must match IT's number of dimensions")

indices = fill(AdaptiveRange(0, 0, 0), dims)
return ConstructionBuffer(indices, data, sizehint)
end
function ConstructionBuffer(::Type{<:OrderedDict{K}}, data::Vector; sizehint::Int) where K
return ConstructionBuffer(OrderedDict{K, AdaptiveRange}(), data, sizehint)

Check warning on line 35 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L34-L35

Added lines #L34 - L35 were not covered by tests
end

function add!(b::ConstructionBuffer{<:Array}, val, indices...)
r = getindex(b.indices, indices...)
n = length(b.data)
if r.start == 0 # Not previously added
resize!(b.data, n + b.sizehint)
b.data[n+1] = val
setindex!(b.indices, AdaptiveRange(n + 1, 1, b.sizehint), indices...)
elseif r.ncurrent == r.nmax # We have used up our space, move data to the end of the vector.
resize!(b.data, n + r.nmax + b.sizehint)
for i in 1:r.ncurrent
b.data[n + i] = b.data[r.start + i - 1]
end
b.data[n + r.ncurrent + 1] = val
setindex!(b.indices, AdaptiveRange(n + 1, r.ncurrent + 1, r.nmax + b.sizehint), indices...)
else # We have space in an already allocated section
b.data[r.start + r.ncurrent] = val
setindex!(b.indices, AdaptiveRange(r.start, r.ncurrent + 1, r.nmax), indices...)
end
return b
end

function add!(b::ConstructionBuffer{<:AbstractDict}, val, key)
n = length(b.data)
added_range = AdaptiveRange(n + 1, 1, b.sizehint)
r = get!(b.indices, key) do

Check warning on line 62 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L59-L62

Added lines #L59 - L62 were not covered by tests
# Enters only if key is not in b.indices
resize!(b.data, n + b.sizehint)
b.data[n + 1] = val
added_range

Check warning on line 66 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L64-L66

Added lines #L64 - L66 were not covered by tests
end
r === added_range && return b # We added `added_range` and can exit

Check warning on line 68 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L68

Added line #L68 was not covered by tests

# Otherwise, `added_range` already exists in `b.indices` and we
# need to add more elements to this index.

if r.ncurrent == r.nmax # Need to move to the end of the vector
b.indices[key] = AdaptiveRange(n + 1, r.ncurrent + 1, r.nmax + b.sizehint)
resize!(b.data, n + r.nmax + b.sizehint)
for i in 1:r.ncurrent
b.data[n + i] = b.data[r.start + i - 1]
end
b.data[n + r.ncurrent + 1] = val

Check warning on line 79 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L73-L79

Added lines #L73 - L79 were not covered by tests
else
b.indices[key] = AdaptiveRange(r.start, r.ncurrent + 1, r.nmax)
b.data[r.start + r.ncurrent] = val

Check warning on line 82 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L81-L82

Added lines #L81 - L82 were not covered by tests
end
return b

Check warning on line 84 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L84

Added line #L84 was not covered by tests
end

function compress_data!(data, indices, sorted_iterator, buffer_indices)
n = 0
for (index, r) in sorted_iterator
nstop = r.start + r.ncurrent - 1
for (iold, inew) in zip(r.start:nstop, (n + 1):(n + r.ncurrent))
@assert inew ≤ iold # To not overwrite
data[inew] = data[iold]
end
indices[index] = (n + 1):(n + r.ncurrent)
n += r.ncurrent
end
resize!(data, n)
sizehint!(data, n) # Free memory
if buffer_indices isa Union{Vector, AbstractDict} # Higher-dim Array's don't support empty!/resize!
empty!(buffer_indices)
sizehint!(buffer_indices, 0) # Free memory
end
return data, indices
end

function CollectionOfVectors(f!::F, IT::Type, DT::Type; sizehint = nothing, kwargs...) where {F <: Function}
sizehint === nothing && error("Providing sizehint is mandatory")
b = ConstructionBuffer(IT, DT[]; sizehint, kwargs...)
f!(b)
return CollectionOfVectors(b)
end

function CollectionOfVectors(b::ConstructionBuffer{<:Array})
I = sortperm(reshape(b.indices, :); by = x -> x.start)
sorted_iterator = ((idx, b.indices[idx]) for idx in I if b.indices[idx].start != 0)
indices = fill(1:0, size(b.indices))
compress_data!(b.data, indices, sorted_iterator, b.indices)
return CollectionOfVectors(indices, b.data)
end


# Efficient creation of a new OrderedDict with new types of values
function _withnewvalues(d::OrderedDict{K}, vals::Vector{V}) where {K, V}
if d.ndel > 0
OrderedCollections.rehash!(d)

Check warning on line 126 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L124-L126

Added lines #L124 - L126 were not covered by tests
end
@assert d.ndel == 0
length(d.vals) == length(vals) || error("Length of new vals must match old")
OrderedDict{K,V}(copy(d.slots), copy(d.keys), vals, 0, d.maxprobe, false)

Check warning on line 130 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L128-L130

Added lines #L128 - L130 were not covered by tests
end

function CollectionOfVectors(b::ConstructionBuffer{<:OrderedDict})
sort!(b.indices; byvalue=true, by = r -> r.start)
indices = _withnewvalues(b.indices, fill(1:0, length(b.indices)))
compress_data!(b.data, indices, b.indices, b.indices)
return CollectionOfVectors(indices, b.data)

Check warning on line 137 in src/CollectionOfVectors.jl

View check run for this annotation

Codecov / codecov/patch

src/CollectionOfVectors.jl#L133-L137

Added lines #L133 - L137 were not covered by tests
end
4 changes: 3 additions & 1 deletion src/Ferrite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ using LinearAlgebra:
using NearestNeighbors:
NearestNeighbors, KDTree, knn
using OrderedCollections:
OrderedSet
OrderedSet, OrderedDict
using SparseArrays:
SparseArrays, SparseMatrixCSC, nonzeros, nzrange, rowvals, sparse
using StaticArrays:
Expand Down Expand Up @@ -159,4 +159,6 @@ include("PointEvalHandler.jl")
include("deprecations.jl")
include("docs.jl")

include("Grid/topology2.jl")

end # module
1 change: 1 addition & 0 deletions src/Grid/grid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ get_coordinate_eltype(::Node{dim,T}) where {dim,T} = T
# abstract type AbstractCell{refshape <: AbstractRefShape} end

getrefshape(::AbstractCell{refshape}) where refshape = refshape
getrefshape(::Type{<:AbstractCell{refshape}}) where refshape = refshape

nvertices(c::AbstractCell) = length(vertices(c))
nedges( c::AbstractCell) = length(edges(c))
Expand Down
Loading