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

Enhancement: Catch negative edge weights in dijkstra #67

Merged
merged 2 commits into from
Aug 13, 2023

Conversation

joweich
Copy link
Collaborator

@joweich joweich commented Aug 12, 2023

Dijkstra's algorithm can't deal with negative edge weighs. Until now, we don't check this, which could lead to unexpected or misleading results. This PR fixes this by throwing an error on negative weights during the traversal.

The additional tests introduce some boilerplate code since we need to add a new type set that is purely signed. I'm open for feedback regarding more elegant ways to solve this!

@joweich joweich requested a review from bobluppes August 12, 2023 20:32
@codecov
Copy link

codecov bot commented Aug 12, 2023

Codecov Report

Patch coverage: 100.00% and no project coverage change.

Comparison is base (0844d8b) 99.73% compared to head (b3a596f) 99.73%.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #67   +/-   ##
=======================================
  Coverage   99.73%   99.73%           
=======================================
  Files          23       23           
  Lines        1140     1149    +9     
=======================================
+ Hits         1137     1146    +9     
  Misses          3        3           
Files Changed Coverage Δ
include/graaflib/algorithm/shortest_path.tpp 100.00% <100.00%> (ø)
test/graaflib/algorithm/shortest_path_test.cpp 100.00% <100.00%> (ø)

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

Copy link
Owner

@bobluppes bobluppes left a comment

Choose a reason for hiding this comment

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

Very nice 🚀
Should we do something similar for the dijkstra_shortest_paths (plural) function?

Comment on lines +102 to +106
if (edge_weight < 0) {
throw std::invalid_argument{fmt::format(
"Negative edge weight [{}] between vertices [{}] -> [{}].",
edge_weight, current.id, neighbor)};
}
Copy link
Owner

Choose a reason for hiding this comment

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

[sidenote]: I know it is sub-optimal, but I would like to restrict the usage of fmt to just the test and example source code. That way we can keep the library independent of other libraries, such that clients can install it header-only.

Last time I checked GCC and Clang still had some issues with the std::format implementation, so until then we will have to resort to manual string concatenation 😅

Suggested change
if (edge_weight < 0) {
throw std::invalid_argument{fmt::format(
"Negative edge weight [{}] between vertices [{}] -> [{}].",
edge_weight, current.id, neighbor)};
}
if (edge_weight < 0) {
throw std::invalid_argument{
"Negative edge weight [" + edge_weight + "] between vertices [" + current.id + "] -> [" + neighbor + "]."};
}

There might be some other places left in the codebase, so I can also go over this in a follow up.

Comment on lines +414 to +420
template <typename T>
struct DijkstraShortestPathSignedTypesTest : public testing::Test {
using graph_t = typename T::first_type;
using edge_t = typename T::second_type;
};

using weighted_graph_signed_types = testing::Types<
Copy link
Owner

Choose a reason for hiding this comment

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

I don't see a much better solution than this 👍🏻

In a follow-up I plan to rethink our testing code and see if I can extract some common patterns. For instance I think it would be sufficient to have 2 or 3 such test fixture definitions which we can reuse through the entire testing code.

Furthermore it might be nice to have some common pre-defined test structures we ca re-use for testing the various algorithms.

If you have any more ideas/pain points I would be happy to hear them!

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

Successfully merging this pull request may close these issues.

2 participants