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

Complement on multi-sets and sub-set iterators #1241

Merged
merged 7 commits into from
Oct 17, 2023

Conversation

StevellM
Copy link
Collaborator

Related to #1238

This is built on what was already implemented by @fieker :

  • Fix some non-working functions
  • Add more documentation and doctests
  • Create an html documentation
  • Test the different functions of the file
  • Add some constructors and functionalities

Not all possible functionalities are available, there are still many existing functions for Set and Dict which could be implemented for MSet; this would have to be done on-demand I guess.

I have changed the printing, to be closer to the printing of Set and Dict. The code could have been done nicer if julia offered the possibility to use their printing methods for Dict where one can choose the separator they want... Instead I wrote something which works similarly (if we see that we will get beyond the size of the screen, we cut and put some dots).

Nothing is perfect or fixed, those are my suggestions of improvements together with a template for the html documentation so that Hecke/Oscar users are aware of the existence of the functionalities for multi-sets.

@thofma
Copy link
Owner

thofma commented Oct 10, 2023

I have a small question: Could you add the "sum" while you are at it? (see https://en.wikipedia.org/wiki/Multiset#Basic_properties_and_operations).

I will talk to some people about the printing (whether we want to keep : or whether we really want to drop the multiplicity if it is one).

@StevellM
Copy link
Collaborator Author

Now I noticed that I had to change the sum(::MSet) which was falling back into sun(::AbstractSet). Should I add then a deprecation since now we have a proper method sum(::MSet, ::MSet) ? Or maybe define sum(::MSet) as it was working before ? The latter would imply two different behaviours depending on the number arguments though.

@codecov
Copy link

codecov bot commented Oct 10, 2023

Codecov Report

Attention: 3 lines in your changes are missing coverage. Please review.

Comparison is base (c4ffff3) 74.57% compared to head (af4893b) 74.68%.
Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1241      +/-   ##
==========================================
+ Coverage   74.57%   74.68%   +0.10%     
==========================================
  Files         346      346              
  Lines      110842   110995     +153     
==========================================
+ Hits        82661    82897     +236     
+ Misses      28181    28098      -83     
Files Coverage Δ
src/Misc/MSet.jl 96.23% <98.58%> (+46.49%) ⬆️

... and 38 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

src/Misc/MSet.jl Outdated
Base.isempty(s::MSet) = isempty(s.dict)
Base.length(s::MSet) = sum(values(s.dict))
Base.IteratorSize(::Type{MSet}) = Base.HasLength()
Base.IteratorEltype(::Type{MSet}) = Base.HasEltype()
Base.eltype(::Type{MSet{T}}) where {T} = T
Base.in(x, s::MSet) = haskey(s.dict, x)
Base.in(x, s::MSet) = any(y -> x == y, keys(s.dict))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this much slower than the old version? O(n) Vs O(1)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tried but the previous version is not practical. See for instance what could happen in a very basic example:

julia> d = Dict{QQFieldElem, Int}(2 => 2)
Dict{QQFieldElem, Int64} with 1 entry:
  2 => 2

julia> haskey(d, 2)
false

I have not thought about about a better work-around..

src/Misc/MSet.jl Outdated
@@ -119,48 +568,92 @@ function Base.filter(pred, s::MSet)
return t
end

function Base.filter!(pred, s::MSet)
un = unique(s)
for x in un
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This copies everything

src/Misc/MSet.jl Outdated
s = similar(s1, T)
d = s.dict
for x in val
y = un2[findfirst(y -> x == y, un2)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use isequal(x)?

src/Misc/MSet.jl Outdated
@doc raw"""
multiset(T::Type) -> MSet{T}

Create an unitialized multi-set `M` with elements of type `T`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's empty, not uninitialised

src/Misc/MSet.jl Outdated
if !(x in val)
delete!(s1, x)
else
y = un2[findfirst(y -> x == y, un2)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isequal

src/Misc/MSet.jl Outdated
y = x isa T ? x : T(x)
if haskey(s.dict, y)
return s.dict[y]
function multiplicity(s::MSet, x)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change from constant time to linear? Why?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as explain for the in function: if I have a MSet{QQFieldElem}, then for testing the multiplicity of 2, one needs to check for QQ(2). If we want to force this and then do not leave room for this kind of flexibility, I am ok with reverting this.

@@ -462,7 +462,7 @@ function _ds(fa)
@assert all(x->x == 1, values(fa.fac))
T = Int[degree(x) for x = keys(fa.fac)]
M = MSet(T)
return Set(sum(s) for s = subsets(M) if length(s) > 0)
return Set(sum(collect(s)) for s = subsets(M) if length(s) > 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why collect?

@fieker
Copy link
Collaborator

fieker commented Oct 11, 2023 via email

@StevellM
Copy link
Collaborator Author

The naming sum for MSet is taken from what I have seen on Wikipedia. I had a look to other CAS: python apparently uses "combine" and maple uses the "+" operator. The thing with sum(::MSet{T}) is that it would only work whenever T <: RingElem or at least the types for which sum is defined. We could change sum as I defined it with something of the form multiset_sum, disjoint_union or combine and keep maybe the + operator for simplicity ? In that case the sum(::MSet) will use directly sum(::AbstractSet) as it was doing before (provided that the user know what they are doing)

@fieker
Copy link
Collaborator

fieker commented Oct 11, 2023 via email

@fieker
Copy link
Collaborator

fieker commented Oct 11, 2023 via email

@StevellM
Copy link
Collaborator Author

Thanks for the explanation! I will revert what I have changed to keep it in linear time then. I have modified also some other parts to avoid to create unnecessary lists.

For the sum, I will just keep the + for now and if one day one comes up with an acceptable name, it will be easy to add.

@StevellM
Copy link
Collaborator Author

@fieker Do the last changes I have been seem good for you ?

@thofma thofma merged commit 4a830bc into thofma:master Oct 17, 2023
14 of 16 checks passed
@thofma
Copy link
Owner

thofma commented Oct 17, 2023

Merci Stevell

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants