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

Add rank spanning branchings routine for possible inclusion in library. #82

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from

Conversation

mbradle
Copy link

@mbradle mbradle commented Nov 6, 2016

Hello,

I am opening a new version of this pull request (previous version). I've squashed all the development commits into a single commit (but have included the development history in the commit message).

The documentation file (rank_spanning_branchings.html) describes the added code (rank_spanning_branchings.hpp). I've included two examples (rank-branchings1.cpp and rank-branchings2.cpp), the second of which reads an input file (branching_input.txt). I've also included a test routine (rank_branchings_test.cpp). I added the examples and the test to the corresponding Jam files. These have small conflicts with the development branch that I thought it might be better for the maintainers to resolve.

Thanks for your consideration, and best wishes.

Brad Meyer

@anadon
Copy link
Contributor

anadon commented Aug 31, 2018

I'm helping out with the PR backlog. Looks like you have feature additions, new documentation, no test, and new examples will be needed. Please add tests for your added features. This is to let you know and help me prioritize PR's.

@mbradle
Copy link
Author

mbradle commented Sep 2, 2018

Thanks for the update. There are two examples included in the pull request:

example/rank-branchings1.cpp

and

example/rank-branchings2.cpp

Once compiled, they are executed as:

./rank-branchings1

and (for example)

./rank-branchings2 branching_input.txt -10

I've included the compilation of these in the example/Jamfile.v2.

There is also a test:

test/rank_branchings_test.cpp

Once compiled, this can be executed as (for example)

./rank_branchings_test 4 10

I've included it in the test/Jamfile.v2 file.

I notice above that two Travis builds failed on my complex graph for clang on linux. I can't find anything wrong with my file and have succeeded compiling and running the test code with clang-4.0 on a linux computer, so I wonder if there is an issue with the compiler on the test machine. Nevertheless, I suppose this needs to be addressed.

Best wishes.

@anadon
Copy link
Contributor

anadon commented Sep 2, 2018

I'm in the process of dealing with some other build and test failures. When I'm done with those, I'll have you rebase your changes on upstream and that may fix your problems. Thank you for following up!

@anadon
Copy link
Contributor

anadon commented Oct 15, 2018

Can you rebase your PR?

@mbradle
Copy link
Author

mbradle commented Oct 18, 2018

I've squashed and reworded commits. I've rebased to boostorg:develop. I'm still seeing a couple of travis-ci failures that I can't reproduce on my end. Thanks, and best wishes.

@anadon
Copy link
Contributor

anadon commented Oct 18, 2018

You test around line 820 has a template faux pas, and is causing timeout errors. Better, but you still need to put in just a little more work. You're close!

@mbradle mbradle force-pushed the dev branch 3 times, most recently from ed7585b to 613a5f5 Compare October 23, 2018 21:05
@anadon
Copy link
Contributor

anadon commented Oct 30, 2018

I'll get to a proper review when I can. This week got really busy for me, sorry!

@anadon
Copy link
Contributor

anadon commented Nov 1, 2018

@mbradle It appears that you're still not rebased on boostorg/graph's devel branch. Please do so.

@anadon
Copy link
Contributor

anadon commented Nov 5, 2018

@mbradle Looking more closely now. It looks like you've done your job and everything does appear clear. I'll need to take more time to look through though. Please be patient while I catch up!

@anadon anadon mentioned this pull request Nov 6, 2018
@mbradle
Copy link
Author

mbradle commented Nov 8, 2018

Sorry, I rebased again before I saw your last message. I hope that's ok. Best wishes.


Edge e;

heap::fibonacci_heap<BranchingEntry<Edge, WeightMap, Compare> > Q;
Copy link
Contributor

Choose a reason for hiding this comment

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

In the same tradition of other Boost.Graph algorithms, I would recommend trying to allow the user to choose what type of property map and min heap to use, and provide these choices as defaults.
Some users will have special-case problems where different data structures are better, and in the future there might simply be a better property map, or min heap in general.

You'll have to experiment to find the best way to do it, but in general by making these data structures parameters to the algorithm so that users can pass them in by reference and an overload without those parameters that chooses the defaults. It will require some experimentation and might have to be all or nothing.

The other benefit of letting the client pass in data structures by reference is that the final result of computation is in them for the client to query afterwards if they like. (Think, for example, the open and closed sets in A*.)

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to sit back and see how someone more experienced reviews these.

So a default of a Fibonacci heap, but are there any extra concepts which must be true for a data structure to be viable that can be checked for?

Copy link
Author

@mbradle mbradle Nov 20, 2018

Choose a reason for hiding this comment

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

Thanks for this. I use two priority queues--one to keep track of branchings in the ranking routine and one to keep track of edge weights in the best and next routines. The former is just a regular priority queue (PriorityQueue concept), but the latter needs to be mergeable (MergablePriorityQueue concept). Neither one is "visible" to the user, and the former queue will have had all its entries popped off if all branchings have been found, but I do think it makes sense to allow the user to choose, with the Fibonacci heap as the default. I'll experiment with this (I think there are some examples in Boost Graph), and with the desirability of distinguishing between the two queues (as input--that is, pq1 for the branchings and pq2 for the graph edge weights).


vertex_idx_t n = num_vertices(g);

disjoint_sets<Rank, Pred> W( rank, pred1 ), S( rank, pred2 );
Copy link
Contributor

Choose a reason for hiding this comment

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

I understand the motivation for single-letter variable names like W, S, C, etc, but in my experience, it's better to use a descriptive name. Not everyone has the algorithm paper on hand to look up what the letters mean. And it makes the variables awfully hard to text search for in a file, such as in this review.
g for graph, u and v for vertices, etc I think is fine... there is no perfect rule about it.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, I agree with this suggestion. Going through and making the changes will probably only reinforce your point.


unordered_set<Edge> best_branching, empty_set;

shared_ptr< std::pair<Edge, weight_t> > p;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why shared_ptr? Is that really necessary?

Copy link
Contributor

Choose a reason for hiding this comment

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

Why avoid a shared pointer? What is bad about them?

Copy link
Contributor

Choose a reason for hiding this comment

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

Like any programming construct they are not bad intrinsically, but they are often misused when a simpler construct would suffice.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for this. I used pointers to check for uninitialized or not found objects, but I think maybe boost::optional is better. For example,

Suggested change
shared_ptr< std::pair<Edge, weight_t> > p;
boost::optional< std::pair<Edge, weight_t> > p;

The NEXT routine could then return the appropriate pair, if found. If not found, p will be null (I guess really boost::none), as in the current implementation. I have a branch that does that successfully. Are there any caveats to boost::optional?

else
{
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Some of the indentation here seems to have gone awry?

unordered_set<Edge>& include_edges,
unordered_set<Edge>& exclude_edges
)
{
Copy link
Contributor

Choose a reason for hiding this comment

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

This function, next_spanning_branching, is very long. I recommend you break it up along the lines of major sequences, loops and/or conditions.

@anadon
Copy link
Contributor

anadon commented May 28, 2019

I have a couple of big, no change PR's you might want to keep an eye on.

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