Skip to content

Implement Havel-Hakimi and Kleitman-Wang graph realization algorithms#202

Draft
InterdisciplinaryPhysicsTeam wants to merge 11 commits intoJuliaGraphs:masterfrom
InPhyT:havel_hakimi_kleitman_wang
Draft

Implement Havel-Hakimi and Kleitman-Wang graph realization algorithms#202
InterdisciplinaryPhysicsTeam wants to merge 11 commits intoJuliaGraphs:masterfrom
InPhyT:havel_hakimi_kleitman_wang

Conversation

@InterdisciplinaryPhysicsTeam
Copy link
Member

Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com>
Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
@codecov
Copy link

codecov bot commented Dec 16, 2022

Codecov Report

❌ Patch coverage is 97.40260% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.71%. Comparing base (c4360cf) to head (c2ca53e).
⚠️ Report is 145 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #202      +/-   ##
==========================================
+ Coverage   97.43%   97.71%   +0.27%     
==========================================
  Files         113      122       +9     
  Lines        6554     9454    +2900     
==========================================
+ Hits         6386     9238    +2852     
- Misses        168      216      +48     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@simonschoelly
Copy link
Member

Somehow github send me an email, that I am mentioned in this PR - but I can't find that comment anymore. It it important that this gets merged very soon? Then I can focus more on this PR than others.

@InterdisciplinaryPhysicsTeam
Copy link
Member Author

Hi @simonschoelly ,

We're sorry for the inconvenience. We have posted a this comment here by mistake: we intended to post it in #186 (where it is right now). So we'd need #186 to be merged so the master branch of our fork is free and we may move on to the next contribution.

Comment on lines +1035 to +1052
"""
lexicographical_order_ntuple(A::NTuple{N,T}, B::NTuple{M,T}) where {N,T}

The less than (lt) function that implements lexicographical order for `NTuple`s of equal length.

See [Wikipedia](https://en.wikipedia.org/wiki/Lexicographic_order).
"""
function lexicographical_order_ntuple(A::Tuple{Vararg{<:Real}}, B::Tuple{Vararg{<:Real}})
length(A) == length(B) ||
throw(ArgumentError("The length of A must match the length of B"))
for (a, b) in zip(A, B)
if a != b
return a < b
end
end

return false
end
Copy link
Member

Choose a reason for hiding this comment

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

Do we need this function? Julia already implements lexicographical orders for tuples (but it also does that for tuples of different lengths. E.g.

julia> (1, 2) < (3, 4)
true

julia> (1, 2) < (1, 2)
false

julia> (1, 2) < (1, 2, 1)
true

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, we didn't think this functionality was implemented out of the box. We then removed lexicographical_order_ntuple.

Comment on lines +1006 to +1007
all(degree_sequence .>= 0) ||
throw(ArgumentError("The degree sequence must contain non-negative integers only."))
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense, to just call isgraphical here? Or do you think that the overhead is too big then?

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe, in order to maximize performance and code simplicity, we should completely separate the functionalities of isgraphical and havel_hakimi_graph. So if the user knows that the sequence is graphical and just wants the graph, she/he may use havel_hakimi_graph, while if just/also a check for graphicality is needed, then a call to isgraphical must be made.

Then I'd suggest to either:

  1. Remove all checks from havel_hakimi_graph;
  2. Add a bool kwarg check_graphicality to havel_hakimi_graph, that performs the isgraphical check before executing the algorithm (in which case we may skip the subsequent check in the loop).

Similar reasoning would apply to isdigraphical and kleitman_wang_graph.

Comment on lines +1023 to +1024
all(collect(values(vertices_degrees_dict))[1:max_degree] .> 0) ||
throw(ErrorException("The degree sequence is not graphical."))
Copy link
Member

Choose a reason for hiding this comment

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

It would probably more efficient to do this check, when set vertices_degrees_dict[vertex] -= 1.

Copy link
Member Author

Choose a reason for hiding this comment

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

I inserted this check in the loop. But it may be temporary, depending on what comes out of this comment.

Comment on lines +1017 to +1019
vertices_degrees_dict = OrderedDict(
sort(collect(vertices_degrees_dict); by=last, rev=true)
)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
vertices_degrees_dict = OrderedDict(
sort(collect(vertices_degrees_dict); by=last, rev=true)
)
sort!(vertices_degrees_dict, byvalues=true, rev=true)

Copy link
Member Author

Choose a reason for hiding this comment

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

It throws an error https://github.com/JuliaGraphs/Graphs.jl/actions/runs/3919202599/jobs/6700055795.

So we reinstated the allocating line.

return prufer_decode(random_code)
end

"""
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if randgraphs.jl is the correct place for these functions, maybe staticgraphs.jl is a better place, as generators are not random.

Copy link
Member Author

Choose a reason for hiding this comment

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

We moved it to staticgraphs.jl. Thanks for the suggestion.

# Instantiate an empty simple graph
graph = SimpleGraph(length(degree_sequence))
# Create a (vertex, degree) ordered dictionary
vertices_degrees_dict = OrderedDict(
Copy link
Member

Choose a reason for hiding this comment

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

As long as it work correctly, we can keep it that way, but we probably could make this function much faster, by using a Vector of tuples instead. The sorting step should also be fairly easy to speed up, as after adding a vertex, the degree order is only slightly not sorted.

Copy link
Member Author

Choose a reason for hiding this comment

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

We unfortunately don't have much time for this, but it would surely help. Would even be better if the final instantiation of a graph object was optional or put in a wrapper method, so that also other packages in the ecosystem may benefit from the full performance of the method (e.g. MutlilayerGraphs.jl's configuration model-like constructors).

Co-authored-by: Simon Schölly <sischoel@gmail.com>
Co-authored-by: Simon Schölly <sischoel@gmail.com>
Co-authored-by: Simon Schölly <sischoel@gmail.com>
Co-authored-by: Simon Schölly <sischoel@gmail.com>
Co-authored-by: Simon Schölly <sischoel@gmail.com>
Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com>
Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com>
Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com>
Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
@Krastanov
Copy link
Member

closing and reopening to rerun the tests

@Krastanov Krastanov closed this Feb 21, 2026
@Krastanov Krastanov reopened this Feb 21, 2026
)
# Find a vertex with positive outdegree,and temporarily remove it from `vertices_degrees_dict`
i, (a_i, b_i) = 0, (0, 0)
for (_i, (_a_i, _b_i)) in collect(deepcopy(vertices_degrees_dict))
Copy link
Member

Choose a reason for hiding this comment

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

any reason this is a deepcopy and not just a normal copy?

@Krastanov
Copy link
Member

@InterdisciplinaryPhysicsTeam , @pitmonticone , @ClaudMor -- any reason to not merge this? It seems you have addressed most of the review comments (there is one more deepcopy that you probably should turn into a copy)

Could you rerun the formatter on this?

@Krastanov
Copy link
Member

Maintainer edits have been disabled on this PR, so I can not run the formatting myself. I will mark this is a draft to keep my review queue a bit more organized, but the only outstanding issue seems to be the formatting check. Please do not hesitate to convert it back to not a draft if you have the bandwidth to pass this last hurdle.

@Krastanov Krastanov marked this pull request as draft February 21, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants