-
Notifications
You must be signed in to change notification settings - Fork 54
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
Added algorithms for finding strong components and cycles. #65
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add some tests for these functions.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
Module : Data.Graph.Inductive.Query.Cycles | ||
Description : Algorithms for finding all cycles. | ||
Copyright : (c) Gabriel Hjort Blindell 2017 | ||
License : 2-Clause BSD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FGL is licensed under 3-Clause BSD; in interests of using the same license for all, would you mind changing this?
(And some code from here is from Graphalyze, which isn't under your Copyright.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed as part of the reply to your comment below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to include a header, with the BSD3 license and copyright held by both me and you (due to copied functions from Graphalize package).
Data/Graph/Inductive/Query/Cycles.hs
Outdated
Description : Algorithms for finding all cycles. | ||
Copyright : (c) Gabriel Hjort Blindell 2017 | ||
License : 2-Clause BSD | ||
Maintainer : [email protected] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you be maintaining this module?
(Actually, if you look at all the current FGL modules they tend not to bother with the header block at all, so you could just remove the entire thing.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I didn't read the header carefully. =)
I've removed the header entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added header, but removed maintainer information.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
|
||
import Data.Graph.Inductive.Graph | ||
|
||
import Data.List |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put import blocks on the same line, e.g.
import Data.List ((\\), delete, tails)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
-- index, and its low link). | ||
, sccGraph :: g a b | ||
-- ^ The input graph. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no instances? At least Eq, Show and Read plaese.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Show, Read, and Eq added.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
= SCCState | ||
{ sccComponents :: [g a b] | ||
-- ^ The components found so far. | ||
, sccCurrentIndex :: Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (and others) should probably be banged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've not used bangs before, so I'm not sure of whether they apply here or not. I'll try looking into it.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
, sccNodeInfo = M.insert n (True, i, i) (sccNodeInfo st0) | ||
} | ||
g = sccGraph st1 | ||
st2 = foldr ( \m st -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is large enough that I think a new function - even if it's in a where block - is warranted for documentation, etc.
That way, you can also use guards rather than nested if/else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
} | ||
g = sccGraph st1 | ||
st2 = foldr ( \m st -> | ||
let st_ni = sccNodeInfo st |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for snake_case here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some refactoring, and the only use of snake_case here is to distinguish the low link of the n node from the low link of the m node.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
-- ^ The current index. | ||
, sccStack :: [Node] | ||
-- ^ The node stack. | ||
, sccNodeInfo :: M.Map Node (Bool, Int, Int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a specific data structure with record labels would work better than a triple here; it would not only provide documentation as to what each field means, but you can then use them as selectors rather than pattern matching on the entire triple to get values out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
( fromJust ) | ||
import Control.Monad | ||
( ap ) | ||
import qualified Data.Map as M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not an IntMap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, wasn't aware of that module. =)
Fixed.
-- ^ The components of the input graph. | ||
, cisGraph :: g a b | ||
-- ^ The input graph. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instances please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Show, Read, and Eq added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs bangs: ![[Node]]
, !(M.IntMap Bool)
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bang patterns added.
…yclesIn' to 'cycles'.
… duplicate nodes (hence the node indicating the start and end of a cycle appears only once).
I've addressed all requests now, except for the one regarding bang patterns. |
Hi! I would like to detect cycles. Is this held up for lack of tests? I could write some ... |
Don't know. I thought the tests as part of the change request were sufficient, but maybe it's due to the fact that the bang patterns are missing, but I don't know how to fix that. @ivan-m Is there anything else I need to do in order to make the pull request go through? |
Data/Graph/Inductive/Query/Cycles.hs
Outdated
c = fromJust $ cisCurrentComp st1 | ||
n_suc = suc c n | ||
(st2, f) = | ||
foldr ( \m (st, f') -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is big enough that it should be split into a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now broken into several, smaller functions.
test_strongComponentsOf :: (Graph gr) => Proxy (gr a b) -> gr a b -> Bool | ||
test_strongComponentsOf _ g = | ||
sort (concatMap nodes (strongComponentsOf g)) == sort (nodes g) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you able to add a property as to the behaviour of the results of strongComponentsOf (e.g. disjoint)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test case has been expanded with additional property checks.
Data/Graph/Inductive/Query/Cycles.hs
Outdated
cycles :: (Graph g) => g a b -> [[LNode a]] | ||
cycles g = map (addLabels g) (cycles' g) | ||
|
||
-- | Same as 'cycles' but for unlabeled graphs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for unlabelled graphs, just doesn't return the labels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
…between any two nodes belonging to separate components.
@ivan-m Requested changes have now been addressed. |
then let (st1, f1) = cCircuits n st0 | ||
in (st1, f0 || f1) | ||
else (st0, f0) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could have been in a where
clause rather than top level.
Maybe consider guards rather than nested if/then/else?
The fromJust
can also potentially throw an error. Using PatternGuards
can make that neater.
cCircuitsVisit n (st0, f0)
| maybe False (n==) (cisS st0) = ...
| fromMaybe False (M.lookup n (cisBlocked st0)) = ...
| otherwise = ...
(Or else use case (cisS st0, M.lookup n (cisBlocked st0)) of (Just n', _) | n == n' -> ...; (_, Just True) ...
).
Same goes with the other functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now using guards and removed need for fromJust
.
…function parameter instead (this removes the need for using Maybe, which could fail).
… value as function parameter instead (this removes the need for using Maybe, which could fail).
Data/Graph/Inductive/Query/Cycles.hs
Outdated
@@ -100,45 +96,41 @@ cyclesFor n st0 = | |||
filter (\c -> n `gelem` c) $ | |||
cisComponents st0 | |||
in if noNodes n_comp > 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that noNodes
is O(|V|)
for PatriciaTree (but O(1)
for Tree
); it would probably be better to do something like not . null . drop 1 . nodes $ n_comp
which should be O(1)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, didn't know that. Fixed.
…ead of potentially O(n).
Any reason this never got merged? I could really do with it. (I came here trying to work out whether the outputs of |
No description provided.