-
Notifications
You must be signed in to change notification settings - Fork 125
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
[NDTensors] Fix bugs in SortedSets
and SmallVectors
#1211
Conversation
Codecov ReportAll modified lines are covered by tests ✅
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #1211 +/- ##
===========================================
- Coverage 85.40% 67.22% -18.18%
===========================================
Files 88 87 -1
Lines 8426 8388 -38
===========================================
- Hits 7196 5639 -1557
- Misses 1230 2749 +1519 ☔ View full report in Codecov by Sentry. |
Sure thing: here is one of the bugs (I think it's a bug – shouldn't the duplicate element get overwritten/ignored?) julia> s = SmallSet{5}([2,4,6,8])
4-element SmallSet{5, Int64, Base.Order.ForwardOrdering}
2
4
6
8
julia> union(s,[10])
5-element SmallSet{5, Int64, Base.Order.ForwardOrdering}
2
4
6
8
10
julia> union(s,[2])
ERROR: ArgumentError: New length 7 must be ≤ the maximum length 5.
Stacktrace:
[1] resize!
@ NDTensors.SmallVectors ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/msmallvector/msmallvector.jl:71 [inlined]
[2] unionsortedunique(itr1::NDTensors.SmallVectors.SmallVector{…}, itr2::Vector{…}, order::Base.Order.ForwardOrdering)
@ NDTensors.SmallVectors ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/BaseExt/sortedunique.jl:95
[3] union
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:258 [inlined]
[4] union(inds::SmallSet{5, Int64, Base.Order.ForwardOrdering}, items::Vector{Int64})
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:263
[5] top-level scope
@ REPL[4]:1
Some type information was truncated. Use `show(err)` to see complete types. |
Here is a different one: in this case the set is not at its full capacity yet, and if I union in an element that's already there, it hits an issue involving trying to call julia> s = SmallSet{5}([2,4,6])
3-element SmallSet{5, Int64, Base.Order.ForwardOrdering}
2
4
6
julia> union(s,[2])
ERROR: setindex!(::StaticArraysCore.SVector{5, Int64}, value, ::Int) is not defined.
Hint: Use `MArray` or `SizedArray` to create a mutable static array
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] setindex!(a::StaticArraysCore.SVector{5, Int64}, value::Int64, i::Int64)
@ StaticArrays ~/.julia/packages/StaticArrays/dTwvg/src/indexing.jl:3
[3] setindex!
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/subsmallvector/subsmallvector.jl:57 [inlined]
[4] reverse!
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl:98 [inlined]
[5] circshift!
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl:119 [inlined]
[6] deleteat!
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl:138 [inlined]
[7] uniquesorted(vec::NDTensors.SmallVectors.SmallVector{5, Int64}, order::Base.Order.ForwardOrdering)
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/BaseExt/sorted.jl:47
[8] NDTensors.SortedSets.SortedIndices{…}(a::Vector{…}, order::Base.Order.ForwardOrdering; issorted::typeof(issorted), allunique::Function)
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:26 [inlined]
[9] SortedIndices
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:19 [inlined]
[10] #_#6
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:42 [inlined]
[11] SortedIndices
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:39 [inlined]
[12] #SortedIndices#7
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:48 [inlined]
[13] SortedIndices
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:45 [inlined]
[14] union
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:259 [inlined]
[15] union(inds::SmallSet{5, Int64, Base.Order.ForwardOrdering}, items::Vector{Int64})
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:263
[16] top-level scope
@ REPL[8]:1
Some type information was truncated. Use `show(err)` to see complete types. |
Another one that might be related to the previous two. In this one I don't get an error, but and in a sense it works but the bug is that the length increases even though the number of elements does not: julia> s = SmallSet{4}([1,2,3])
3-element SmallSet{4, Int64, Base.Order.ForwardOrdering}
1
2
3
julia> union(s,[2])
4-element SmallSet{4, Int64, Base.Order.ForwardOrdering}
1
2
3
6101072064 |
One other question I have is, if the set has a non-trivial |
Ok thanks, I'll take a look at those Good question about julia> struct Composite
a::Symbol
b::Float64
end
julia> Base.isequal(x::Composite, y::Composite) = x.a == y.a
julia> Base.hash(x::Composite, h::UInt64) = hash(x.a, h)
julia> union(Set([Composite(:a, 2), Composite(:b, 3)]), [Composite(:a, 3)])
Set{Composite} with 2 elements:
Composite(:a, 3.0)
Composite(:b, 3.0) so it replaces the element. Maybe we should follow that behavior. |
Probably following what Julia does for sets is the best. Do you think it would make sense to provide a keyword argument that specifies what to do for collisions? The default could be replace, but for Qn's I can think of cases where other behaviors would nicely implement some code patterns I need. |
Good question, I was wondering about that. As we discussed, at least when fusing abelian QNs it is very closely related to Maybe best to make up a new name for that more general functionality, maybe it could be called julia> mapunion(+, [1, 2], [2, 3]; default=0)
3-element Vector{Int64}:
1
4
3
mapunion(+, QN(("N", 1), ("Sz", 2)), QN(("N", 2)); default=Sector()) == QN(("N", 3), ("Sz", 2)) |
@emstoudenmire I believe I've fixed the issues you brought up, could you try out this branch and see if they are fixed? |
….jl into NDTensors_smallset_bugs
Looks like all the cases I listed above are fixed for integers. Unfortunately I am running into an issue when I try to put The error I get seems to be related to some code paths that is perhaps ending up calling an overly generic constructor of SortedSet, based on the error message and looking at the code. Ultimately this leads to calling julia> a1 = Sector("A",1)
Sector("A",1,SU{2})
julia> a2 = Sector("A",2)
Sector("A",2,SU{2})
julia> b = Sector("B",3)
Sector("B",3,SU{2})
julia> s = SmallSet{4}([a1,b];by=ITensorFusion.name)
2-element SmallSet{4, Sector, Base.Order.By{typeof(ITensorFusion.name), Base.Order.ForwardOrdering}}
Sector("A",1,SU{2})
Sector("B",3,SU{2})
julia> union(s,a2)
ERROR: MethodError: no method matching iterate(::Sector)
Closest candidates are:
iterate(::ITensors.TruncEigen)
@ ITensors ~/.julia/dev/ITensors/src/tensor_operations/matrix_decomposition.jl:196
iterate(::ITensors.TruncEigen, ::Val{:V})
@ ITensors ~/.julia/dev/ITensors/src/tensor_operations/matrix_decomposition.jl:197
iterate(::ITensors.TruncEigen, ::Val{:spec})
@ ITensors ~/.julia/dev/ITensors/src/tensor_operations/matrix_decomposition.jl:198
...
Stacktrace:
[1] copyto!(dest::Vector{Any}, src::Sector)
@ Base ./abstractarray.jl:938
[2] _collect(cont::UnitRange{Int64}, itr::Sector, ::Base.HasEltype, isz::Base.HasLength)
@ Base ./array.jl:763
[3] collect(itr::Sector)
@ Base ./array.jl:757
[4] SortedSet{T, Data, Order}(a::Data, order::Order) where {T, Data<:(AbstractArray{T}), Order<:Base.Order.Ordering}
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:56 [inlined]
[5] union(set::SmallSet{4, Sector, Base.Order.By{typeof(ITensorFusion.name), Base.Order.ForwardOrdering}}, items::Sector)
@ NDTensors.SortedSets ~/.julia/dev/ITensors/NDTensors/src/SortedSets/src/sortedset.jl:277
[6] top-level scope
@ REPL[35]:1 |
Separately from that issue, I really like your idea of having a "map" variation of union, which would make it clearer that the user need to provide a function to handle collisions or reductions. (It's a lot better than my first idea, which could result in having an over-designed union function that takes too many keyword arguments.) |
That's not really a Two solutions are:
|
Additionally, something to consider to avoid having to pass You could define things like: Base.isless(s1::Sector, s2::Sector) = isless(name(s1), name(s2))
Base.:(==)(s1::Sector, s2::Sector) = name(s1) == name(s2)
Base.hash(s::Sector, h::UInt) = hash(name(s), hash(:Sector, h)) Then for all other purposes (using in a hash table like a |
Ah ok, that was just my mistake. I had known you had to call I'll just go with the solution of calling Next I'll see how far I get with the existing set tools (union, intersect, setdiff) and let you know if something like |
I just tried |
Fixes a bug in
SortedSets
when the inputs were not already sorted:I also plan to fix some other bugs related to
SmallVectors
.@emstoudenmire could you share the bug you came across in
union
?