Skip to content

Conversation

@LoveLow-Global
Copy link
Contributor

Implement iFUB algorithm for diameter calculation of unweighted graphs, SimpleGraph and SimpleDiGraph

Below is a comparison with the original diameter calculation logic, ran on my desktop.

using Graphs

g = erdos_renyi(10000, 0.005) # 10k nodes, sparse

# New implentation
@time d = diameter(g) # 0.910222 seconds (372.05 k allocations: 6.602 MiB)

# Original Method
original_diameter(g) = maximum(eccentricity(g)) 
@time original_diameter(g) # 41.471079 seconds (650.01 k allocations: 13.515 GiB, 3.59% gc time)

@codecov
Copy link

codecov bot commented Dec 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.19%. Comparing base (e7e2e43) to head (48667e7).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #482      +/-   ##
==========================================
+ Coverage   97.16%   97.19%   +0.02%     
==========================================
  Files         121      121              
  Lines        7020     7092      +72     
==========================================
+ Hits         6821     6893      +72     
  Misses        199      199              

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Krastanov
Copy link
Member

Thank you! On first look this looks great, but it will take a bit to get a proper review.

In the meantime, we should probably have some more rigorous tests for it added. (1) Tests comparing against large graphs with known diameters (e.g. by construction); and (2) tests comparing against the old slow implementation for random graphs. Could you add such tests, maybe something that adds an additional 60 seconds to the tests, but with a "number of random samples" parameter that I can change locally and run for a few hours on my machine?

@LoveLow-Global
Copy link
Contributor Author

LoveLow-Global commented Dec 21, 2025

Hello Krastanov, thanks for the comment. I have added (1) comparison against graphs with known diameters and the (2) comparison with old slow implementation for random graphs, under test/distance.jl. You can change NUM_SAMPLES there. Also, please note that it is my first time contributing to an existing Julia package, so please tell me if there is any changes to be done.

@Krastanov
Copy link
Member

Thanks, this looks great! I will try to review this in the next few days.

One other thing that I need to check lately -- if you used an LLM-like tool, could you disclose that, which tool, and what the prompt was? I do not see anything in your PR that makes me think that was the case, and it is not like LLM tools are bad (they help a lot), but they do require approaching the review differently and having this extra info helps.

@LoveLow-Global
Copy link
Contributor Author

Thanks for the feedback! I have used Gemini 3.0 for code generation. This optimization method was originally used in one of my researches, but I needed to change the style of the code to be similar to Graphs.jl. Therefore, I used Gemini to first change the code into a "Graphs.jl" format. Then I manually edited the codes again.

@Krastanov
Copy link
Member

Do you happen to have a reference of where this algorithm was introduced first / who named it iFUB, etc? Or a textbook about it?

@Krastanov
Copy link
Member

Pardon the formatter error -- it seems it is due to an incorrect security configuration on our end, not due to your code.

@LoveLow-Global
Copy link
Contributor Author

Hello, sorry for the late response. The iFUB algorithm was first introduced in the following research papers.

[Undirected Graphs]
Crescenzi, P., Grossi, R., Habib, M., Lanzi, L., Marino, A.: On Computing the Diameter of Real-World Undirected Graphs. Presented at Workshop on Graph Algorithms and Applications (Zurich–July 3, 2011) and selected for submission to the special issue of Theoretical Computer Science in honor of Giorgio Ausiello in the occasion of his 70th birthday (2011)

[Directed Graphs]
Crescenzi, P., Grossi, R., Lanzi, L., Marino, A. (2012). On Computing the Diameter of Real-World Directed (Weighted) Graphs. In: Klasing, R. (eds) Experimental Algorithms. SEA 2012. Lecture Notes in Computer Science, vol 7276. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-642-30850-5_10

Thank you. Please let me know if there is anything more needed.

Copy link
Member

@Krastanov Krastanov left a comment

Choose a reason for hiding this comment

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

Here is the review. Thanks again for submitting this, it is a great improvement.

I have a couple of minor documentation comments and a bigger comment about breaking changes in the current behavior in an edge case. After they are addressed this should be pretty straightforward to merge.

Comment on lines +82 to +96
ccs = connected_components(g)
largest_component = ccs[argmax(length.(ccs))]
g_lscc, _ = induced_subgraph(g, largest_component)
Copy link
Member

Choose a reason for hiding this comment

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

While we should keep these tests of largest connected components, we should also have a set of tests that do not strip to just the largest connected subgraph, because this hides an inconsistency with the current master's behavior. One can argue that your current implementation has a more natural behavior, but even if that is true, it is a breaking change.

On master we have:

julia> diameter(Graph(2)) # a disconnected graph
┌ Warning: Infinite path length detected for vertex 1
└ @ Graphs ~/.julia/packages/Graphs/lNprZ/src/distance.jl:78
┌ Warning: Infinite path length detected for vertex 2
└ @ Graphs ~/.julia/packages/Graphs/lNprZ/src/distance.jl:78
9223372036854775807 # this is typemax(indextype)

If you do not like this behavior on current master and you have an argument for why it needs to be changed, we can discuss it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have edited the test/distance.jl file.
Please let me know if I have misunderstood something here, I believe I may have misunderstood something.

Copy link
Member

Choose a reason for hiding this comment

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

looks good

Copy link
Member

Choose a reason for hiding this comment

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

This might be an old dev script you added? Just make sure to remove it before merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, this was my mistake. I have removed it.

src/distance.jl Outdated
Comment on lines 120 to 122
if nv(g) <= 1
return 0
end
Copy link
Member

Choose a reason for hiding this comment

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

To keep things consistent with the current diameter (see the other comment for more details), we should change this to connectivity check and in absence of connectivity we should return typemax(eltype(g)).

If you consider the connectivity check too expensive, we can consider a keyword argument to skip it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I have noticed that it should have been typemax(). I have edited that, thanks for pointing this out.

src/distance.jl Outdated
eccentricities, return the maximum eccentricity of the graph.
For unweighted `SimpleGraph` and `SimpleDiGraph`, an optimized BFS algorithm
(iFUB) is used to avoid computing eccentricities for all vertices.
Copy link
Member

Choose a reason for hiding this comment

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

Could you add nicely formatted references (the two papers you shared) to the docstring?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I added the references.

test/distance.jl Outdated
end
end

@testset "$(typeof(g))" for g in test_generic_graphs(a3)
Copy link
Member

Choose a reason for hiding this comment

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

The name of this testset is a bit cryptic to me. Could you elaborate it so that it is more immediately understandable if a test failure is reported?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I have edited the test name. Let me know if there is another issue that comes into your mind.

@Krastanov
Copy link
Member

And one last thing: let's make sure diameters(Graph()) works (i.e. it works on empty graphs), which currently fails.

Copy link
Member

@Krastanov Krastanov left a comment

Choose a reason for hiding this comment

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

Thanks!

I think there are only two minor things left:

  • making sure this works on any graph, not just on specific graph types (after all other graph types might support the same API)
  • making sure the doc links are to archival pages that probably will exist for multiple decades

src/distance.jl Outdated
Given a graph and optional distance matrix, or a vector of precomputed
eccentricities, return the maximum eccentricity of the graph.
An optimizied BFS algorithm (iFUB) is used for unweighted graphs, both [undirected](https://semeval.inria.fr/2012/printemps/theme1/teams/gang/62.pdf)
Copy link
Member

Choose a reason for hiding this comment

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

This links seems to be someone's personal page or some informal repository. Could you switch the link to a more official resources, something that has better chances of still existing in 20 years?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have changed the link to a one on ScienceDirect. I hope this link will have a better change of existing after decades.

src/distance.jl Outdated
"""
diameter(eccentricities)
diameter(g, distmx=weights(g))
diameter(g::Union{SimpleGraph, SimpleDiGraph})
Copy link
Member

Choose a reason for hiding this comment

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

If I am reading this correctly, your algorithm supports any graph that implements the Graphs.jl API. E.g. LEMONGraph/IGraph/NautyGraph/VNGraph are all supported, because they have the outneighbors/inneighbors/vertices functions.

We should not artificially exclude them (that is not really in the spirit of Multiple Dispatch languages like Julia).

For an unweighted graph we automatically have weights(g) === DefaultDistance(g).

So the new methods should probably be:

  • diameter(g, ::DefaultDistance) your implementation
  • diameter(g) = diameter(g, weights(g))
  • diamgter(g, distmx) the already existing method but with the default =weights(g) removed so that the dispatch tree works

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have edited the codes, I hope it is alright now. Thanks for pointing this out, I missed this point.

Comment on lines +82 to +96
ccs = connected_components(g)
largest_component = ccs[argmax(length.(ccs))]
g_lscc, _ = induced_subgraph(g, largest_component)
Copy link
Member

Choose a reason for hiding this comment

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

looks good

Implement iFUB algorithm for unweighted diameter.
Added some more rigorous tests
Edited reference, edited diameters() for multiple dispatch.
Fixed code that it will pass tests.
@LoveLow-Global
Copy link
Contributor Author

Let me know if there's anything else needed from my side to get this merged. Thank you.

@Krastanov
Copy link
Member

Looks good! I pushed a couple of minor changes:

  • bumping the version so we can make a release immediately after merging
  • a minor typo in the docstring, and attaching the docstring to the function as a whole instead of attaching it to a specific method
  • removing the hardcoded seed (just to make sure tests explore more each time they run) -- for reproducibility, the test framework reports the RNG state in case of a failure

This should be merged and released shortly. Thank you for this contribution, it is very valuable!

@Krastanov Krastanov merged commit 1d94b7a into JuliaGraphs:master Dec 31, 2025
11 of 14 checks passed
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.

2 participants