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

Bug in maximum bipartite matching? #48

Closed
kmicinski opened this issue Jul 20, 2019 · 12 comments
Closed

Bug in maximum bipartite matching? #48

kmicinski opened this issue Jul 20, 2019 · 12 comments

Comments

@kmicinski
Copy link

kmicinski commented Jul 20, 2019

Test case:

#lang racket
(require graph)

;; Each vertex is a pair via a struct
(struct vtx (tag contents) #:transparent)

;; List of edges in an undirected graph
(define edges
  (list
   (list (vtx 0 (set 3)) (vtx 1 (set 3 2)))
   (list (vtx 0 (set 0)) (vtx 1 (set 3 0)))
   (list (vtx 0 (set 1)) (vtx 1 (set 1 2)))
   (list (vtx 0 (set 1)) (vtx 1 (set 1 3)))
   (list (vtx 0 (set 3 2)) (vtx 1 (set 3 0 2)))
   (list (vtx 0 (set 0)) (vtx 1 (set 0 2)))
   (list (vtx 0 (set 3)) (vtx 1 (set 1 3)))
   (list (vtx 0 (set 3)) (vtx 1 (set 3 0)))
   (list (vtx 0 (set 1)) (vtx 1 (set 1 3 0)))
   (list (vtx 0 (set 2)) (vtx 1 (set 3 0 2)))
   (list (vtx 0 (set 3 0)) (vtx 1 (set 3 0 2)))
   (list (vtx 0 (set 2)) (vtx 1 (set 0 2)))
   (list (vtx 0 (set 3)) (vtx 1 (set 1 3 0)))
   (list (vtx 0 (set 0)) (vtx 1 (set 3 0 2)))
   (list (vtx 0 (set 1 3)) (vtx 1 (set 1 3 0)))
   (list (vtx 0 (set 2)) (vtx 1 (set 3 2)))
   (list (vtx 0 (set 3)) (vtx 1 (set 3 0 2)))
   (list (vtx 0 (set 2)) (vtx 1 (set 1 2)))
   (list (vtx 0 (set 3 0)) (vtx 1 (set 1 3 0)))
   (list (vtx 0 (set 0)) (vtx 1 (set 1 3 0)))
   (list (vtx 0 (set 0 2)) (vtx 1 (set 3 0 2)))))

;; Perform maximum bipartite matching.
(pretty-print (maximum-bipartite-matching (undirected-graph edges)))

Results in:

(list
 (list (vtx 1 (set 1 3 0)) (vtx 0 (set 1 3)))
 (list (vtx 1 (set 1 3)) (vtx 0 (set 1)))
 (list (vtx 1 (set 0 2)) (vtx 0 (set 0)))
 (list (vtx 0 (set 1)) (vtx 1 (set 1 3 0)))
 (list (vtx 1 (set 3 2)) (vtx 0 (set 2)))
 (list (vtx 1 (set 3 0)) (vtx 0 (set 3)))
 (list (vtx 1 (set 1 2)) (vtx 0 (set 1)))
 (list (vtx 1 (set 3 0 2)) (vtx 0 (set 3 2)))
 (list (vtx 1 (set 1 3 0)) (vtx 0 (set 3 0))))

I believe this is wrong, since I see (vtx 0 (set 1)) included in two edges here. Given that this is a maximal bipartite graph matching, this should not occur, as long as vertices are compared using equal?. I did a quick test to ensure that (equal? (vtx 0 (set 1)) (vtx 0 set 1)) is true. Next, I dug into the source of the implementation, and it does seem that the implementation respects equal?. So I don't see an obvious reason why this should happen.

Thoughts?

@stchang
Copy link
Owner

stchang commented Jul 23, 2019

Thanks for the report.

A first wild guess would be that the algorithm depends on some unreliable behavior, e.g., hash table ordering.

I assume you're using a recent version of Racket?

It's been a while since I've checked the tests against the latest Racket so I'm going to do that first. Then I will revisit this bug.

@kmicinski
Copy link
Author

Thanks for the response! Yes, that's right: v7.2. Your suspicions here sound like good intuition to me, for sure.

@stchang
Copy link
Owner

stchang commented Jul 25, 2019

I think I see the problem. The maximum-bipartite-matching function uses a max flow algorithm for directed graphs. So giving it an undirected graph counts the edges twice.

Looking into possible fixes.

@kmicinski
Copy link
Author

kmicinski commented Jul 25, 2019 via email

@stchang
Copy link
Owner

stchang commented Jul 25, 2019

Actually, you are right. Looking at the code more closely, it looks like the duplicate edges are removed before calling the max flow algorithm, so it should work out. Back to testing.

@kmicinski
Copy link
Author

kmicinski commented Jul 25, 2019 via email

@kmicinski
Copy link
Author

Wow! Thanks for handling this so quickly!

@stchang
Copy link
Owner

stchang commented Jul 25, 2019

I think I fixed it.

Problem was that edge-weight was returning inf for non-existent edges, but that is the wrong default for maxflow.

Let me know if anything still seems off.

@stchang
Copy link
Owner

stchang commented Jul 25, 2019

Thanks again for the report!

@kmicinski
Copy link
Author

kmicinski commented Jul 25, 2019 via email

@stchang
Copy link
Owner

stchang commented Jul 25, 2019

since I installed this as a Racket package, is there a good way to get the fixed version in a way that is harmonious?

Normally, yes. But the commits before this fix were somewhat drastic. Specifically, they modernized the package by splitting docs/tests/core into different packages, to accommodate min-racket installs and minimize dependencies (see #37). And I've had mixed experiences with updating this kind of change. But worst case, an uninstall-reinstall should do the trick.

@kmicinski
Copy link
Author

kmicinski commented Jul 26, 2019 via email

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

No branches or pull requests

2 participants