
I'm using the Data.Graph.Inductive.Query.Dominators library (http://haskell.org/ghc/docs/latest/html/libraries/fgl/Data-Graph-Inductive-Q...) with GHC 6.8.2. The library is a bit spare on comments, so I may or may not be using it correctly. My goal is to compute the set of nodes that dominate two different nodes of a DAG, with respect to one initial node. My approach is: import qualified Data.Graph.Inductive.Graph as Graph import qualified Data.Graph.Inductive.Query.Dominators as Dom uips = intersect domConfl domAssigned :: [Graph.Node] -- my goal domConfl = fromJust $ lookup conflNode domFromLastd -- dominators of first node domAssigned = fromJust $ lookup (negate conflNode) domFromLastd -- dominators of second node domFromLastd = Dom.dom conflGraph lastd -- source node I compute the dominators individually and my answer is their intersection. When I call the dom function, my assumption is that I need to pass it the source node, and it tells me, for any node x to which there is a path from the source, the list of nodes for which *any path* from source to x must touch, i.e., the list of dominators of x. The DAG in question is attached as a postscript file, which is generated by `dot -Tps` using the output of the Graphviz module directly from the graph object. The nodes for which I'm computing dominators are labeled -2 and 2 (that is, conflNode = 2). The problem is that I think the answer is wrong. In particular I think the set of dominators for -2 is {20, -2}, and the set for 2 is {20, 2}. Their intersection is {20}, which is what I expect. But what I am getting is: --> uips = [-9,20] --> domConfl = [2,-9,20] --> domAssigned = [-2,-9,-12,20] --> lastd = 20 But -9 is not a dominator for 2, since 20,-7,8,6,2 is a path from 20 to 2 that does not touch 9. -9 is also not a dominator for -2, since 20,-7,8,6,-2 is a path from 20 to -2 not touching 9. Am I missing something? I've simplified the code above slightly from the original code in order to ignore some irrelevancies. The original code is for computing a learned clause in a SAT solver. The code in the state that will reproduce the error above is available via a git clone: git clone http://fid.stygian.net/dpllsat Build via cabal, configuring with --disable-optimization in order to enable assertions, then run: ./dist/build/dsat/dsat ./tests/problems/uf20/uf20-0226.cnf The graph should be saved in conflict.dot and with `dot -Tps -o conflict.ps conflict.dot` you should be able to turn it into the ps file attached. The problematic code referenced above starts on line 759. -- Denis

Denis Bueno wrote:
I'm using the Data.Graph.Inductive.Query.Dominators library (http://haskell.org/ghc/docs/latest/html/libraries/fgl/Data-Graph-Inductive-Q...) with GHC 6.8.2. The library is a bit spare on comments, so I may or may not be using it correctly.
[snip]
But what I am getting is: --> uips = [-9,20] --> domConfl = [2,-9,20] --> domAssigned = [-2,-9,-12,20] --> lastd = 20
But -9 is not a dominator for 2, since 20,-7,8,6,2 is a path from 20 to 2 that does not touch 9. -9 is also not a dominator for -2, since 20,-7,8,6,-2 is a path from 20 to -2 not touching 9.
Am I missing something?
No. Data.Graph.Inductive.Query.Dominators is just buggy. 1) domr is meant to find a fixed point of builddoms by iteratively applying builddoms, but in fact it calls builddoms at most twice. 2) the code doesn't handle nodes with no predecessors correctly. Here's a quick fix: diff -rN -u old-fgl/Data/Graph/Inductive/Query/Dominators.hs new-fgl/Data/Graph/Inductive/Query/Dominators.hs --- old-fgl/Data/Graph/Inductive/Query/Dominators.hs 2008-04-16 20:13:35.000000000 +0200 +++ new-fgl/Data/Graph/Inductive/Query/Dominators.hs 2008-04-16 20:13:35.000000000 +0200 @@ -18,13 +18,13 @@ builddoms :: DomSets -> [Node] -> DomSets builddoms ds [] = ds builddoms ds (v:vs) = builddoms ((fs++[(n,p,sort(n:idv))])++(tail rs)) vs - where idv = intersection (getdomv p ds) - (n,p,_) = head rs + where idv = intersection ((q \\ [n]):getdomv p ds) + (n,p,q) = head rs (fs,rs) = span (\(x,_,_)->x/=v) ds domr :: DomSets -> [Node] -> DomSets domr ds vs|xs == ds = ds - |otherwise = builddoms xs vs + |otherwise = domr xs vs where xs = (builddoms ds vs) {-| Bertram

On Wed, Apr 16, 2008 at 2:33 PM, Bertram Felgenhauer
No. Data.Graph.Inductive.Query.Dominators is just buggy. [...] Here's a quick fix:
Thanks! This fixes my problem. Have you submitted a bug and your patch to the appropriate tracker? If not, would someone point me to the appropriate one? Would in be the GHC trac, or is there a libraries-specific one? I'll be happy to submit your patch and credit you for it, if someone will point me in the right direction. -- Denis

On Thu, Apr 17, 2008 at 11:32 AM, Denis Bueno
On Wed, Apr 16, 2008 at 2:33 PM, Bertram Felgenhauer
wrote: No. Data.Graph.Inductive.Query.Dominators is just buggy.
I have one more problem. For the attached graph, the dominators of the -20 node are computed correctly (namely, [-20,-1,11,12]). But the list of dominators for 20 is present, when in fact 20 isn't reachable from 12. I think 20 should be absent from the return value of `dom graph 12'. (And hence a call to `lookup 20 (dom graph 12)' should return Nothing.) Instead it returns [-20,-1,-3,11,12,-14,17]. Is my reasoning correct? I'd try to fix the code, but, I don't understand how it works. -- Denis

Your reasoning differs from the usual understanding of a null product (1 or True), as compared to a null sum (0 or False):
the list of nodes for which *any path* from source to x must touch, i.e., the list of dominators of x.
Here, "any path" means all paths, a logical conjunction: and [True, True] = True and [True ] = True and [ ] = True The empty case of all sources touching is True, so 12 is a valid dominator for 20 if there is no path from 12 to 20. Dan Denis Bueno wrote:
On Thu, Apr 17, 2008 at 11:32 AM, Denis Bueno
wrote: On Wed, Apr 16, 2008 at 2:33 PM, Bertram Felgenhauer
wrote: No. Data.Graph.Inductive.Query.Dominators is just buggy.
I have one more problem. For the attached graph, the dominators of the -20 node are computed correctly (namely, [-20,-1,11,12]). But the list of dominators for 20 is present, when in fact 20 isn't reachable from 12. I think 20 should be absent from the return value of `dom graph 12'. (And hence a call to `lookup 20 (dom graph 12)' should return Nothing.) Instead it returns [-20,-1,-3,11,12,-14,17].
Is my reasoning correct? I'd try to fix the code, but, I don't understand how it works.
------------------------------------------------------------------------
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Apr 17, 2008 at 5:52 PM, Dan Weston
Your reasoning differs from the usual understanding of a null product (1 or True), as compared to a null sum (0 or False):
the list of nodes for which *any path* from source to x must touch, i.e., the list of dominators of x.
Here, "any path" means all paths, a logical conjunction:
I'm not sure I agree this is the common definition of dominators, but supposing it is: the upshot is that to get what I expect, I should only ask for the dominators of nodes which I know are reachable from the source node, right? -- Denis

I'm not sure I agree this is the common definition of dominators
Is one undefeated if one has never fought?
I should only ask for the dominators of nodes which I know are reachable from the source node, right?
Yes. Denis Bueno wrote:
On Thu, Apr 17, 2008 at 5:52 PM, Dan Weston
wrote: Your reasoning differs from the usual understanding of a null product (1 or True), as compared to a null sum (0 or False):
the list of nodes for which *any path* from source to x must touch, i.e., the list of dominators of x.
Here, "any path" means all paths, a logical conjunction:
I'm not sure I agree this is the common definition of dominators, but supposing it is: the upshot is that to get what I expect, I should only ask for the dominators of nodes which I know are reachable from the source node, right?

Dan Weston wrote:
Here, "any path" means all paths, a logical conjunction:
and [True, True] = True and [True ] = True and [ ] = True
Hate to nitpick, but what appears to be some kind of a limit in the opposite direction is a curious way of arguing that: and [] = True. Surely one can also write and [False, False] = False and [False ] = False and [ ] = False ??? -- Kim-Ee -- View this message in context: http://www.nabble.com/Wrong-Answer-Computing-Graph-Dominators-tp16714477p167... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Dan Weston wrote:
Here, "any path" means all paths, a logical conjunction:
and [True, True] = True and [True ] = True and [ ] = True
Kim-Ee Yeoh wrote:
Hate to nitpick, but what appears to be some kind of a limit in the opposite direction is a curious way of arguing that: and [] = True.
Surely one can also write
and [False, False] = False and [False ] = False and [ ] = False ???
No. I think what Dan meant was that for all non-null xs :: [Bool], it is clearly true that: and (True:xs) == and xs -- (1) It therefore makes sense to define (1) to hold also for empty lists, and since it is also true that: and (True:[]) == True We obtain: and [] == True Since we can't make any similar claim about the conjuctions of lists beginning with False, there is no reasonable argument to the contrary.

More algebraically, including 'or' for symmtry: and xs = foldr (&&) True xs or xs = foldr (||) False xs The True and False are the (monoid) identities with respect to && and || : True && x == x x && True == x False || x == x x || False == x And so an empty list, if defined at all, should be the identity: and [] = True or [] = False In english: "and returns false" when "is any element of the list false?" is yes "or returns true" when "is any element of the list true?" is yes Matthew Brecknell wrote:
Dan Weston wrote:
Here, "any path" means all paths, a logical conjunction:
and [True, True] = True and [True ] = True and [ ] = True
Kim-Ee Yeoh wrote:
Hate to nitpick, but what appears to be some kind of a limit in the opposite direction is a curious way of arguing that: and [] = True.
Surely one can also write
and [False, False] = False and [False ] = False and [ ] = False ???
No. I think what Dan meant was that for all non-null xs :: [Bool], it is clearly true that:
and (True:xs) == and xs -- (1)
It therefore makes sense to define (1) to hold also for empty lists, and since it is also true that:
and (True:[]) == True
We obtain:
and [] == True
Since we can't make any similar claim about the conjuctions of lists beginning with False, there is no reasonable argument to the contrary.

Matthew Brecknell wrote:
Dan Weston wrote:
Here, "any path" means all paths, a logical conjunction:
and [True, True] = True and [True ] = True and [ ] = True
Kim-Ee Yeoh wrote:
Hate to nitpick, but what appears to be some kind of a limit in the opposite direction is a curious way of arguing that: and [] = True.
Surely one can also write
and [False, False] = False and [False ] = False and [ ] = False ???
No. I think what Dan meant was that for all non-null xs :: [Bool], it is clearly true that:
and (True:xs) == and xs -- (1)
It therefore makes sense to define (1) to hold also for empty lists, and since it is also true that:
and (True:[]) == True
We obtain:
and [] == True
Since we can't make any similar claim about the conjuctions of lists beginning with False, there is no reasonable argument to the contrary.
Also, (and I know none of this is original, but it's worth repeating...) It is not just the definition of "and" at stake here. Logical propositions that extend painlessly to [] if (and [] == True) become inconsistent for [] if (and [] == False) and would have to be checked in program calculation. For instance, in propositional logic, you can prove (using Composition, Distribution[2], Material Implication) that for nonnull ys = [y0,y1,..,yn], implying everthing implies each thing: x -> (y0 && y1 && ... yn) <--> (x -> y0) && (x -> y1) && ... && (x -> yn) Writing this in Haskell and using the fact that x -> y means (not x || y), this says that not x || and ys == and (map (not x ||) ys) or in pointfree notation: f . and == and . map f where f = (not x ||) This should look familiar to origamists everywhere. "and" can be defined in terms of foldr iff (and [] == True) [Try it!]. Why is this important? If and is defined with foldr, then the above can be proven for all well-typed f, and for f = (not x ||) in particular, even if ys is null. The law is painlessly extended to cover the null case automatically (and is therefore consistent): LHS: not x || (and []) == not x || True == True RHS: and (map (not x ||) []) == and [] == True Therefore True |- True, an instance of x |- x If (and [] == False), then the law becomes inconsistent: LHS: not x || (and []) == not x || False == not x RHS: and (map (not x ||) []) == and [] == False Since not x == False, then x == True Therefore, True |- x ==> -| x (everything is derivable) so we would have to exclude the null case for this law (and many others). Uck! Better stick with (and [] == True) Naturally, similar reasoning justifies (or [] == False).

Dan Weston wrote:
f . and == and . map f where f = (not x ||)
If and is defined with foldr, then the above can be proven for all well-typed f, and for f = (not x ||) in particular, even if ys is null. The law is painlessly extended to cover the null case automatically (and is therefore consistent):
LHS: not x || (and []) == not x || True == True RHS: and (map (not x ||) []) == and [] == True Therefore True |- True, an instance of x |- x
If (and [] == False), then the law becomes inconsistent:
-- snipped -- Yes, the natural way of defining and [] is, well, natural in more than one sense of the word. I initially had a hard time grasping what you meant with the 3 equations that started this discussion. I was sure you meant something other than what I thought, but I couldn't work it out. I'm glad Matt Brecknell came to the rescue. Before I would've merely relied on a monoidal identity argument like the one Chris had presented. Appealing to uniformity (a la parametric polymorphism) definitely looks sexier. All the cool kids seem to be doing it. -- View this message in context: http://www.nabble.com/Wrong-Answer-Computing-Graph-Dominators-tp16714477p167... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Denis Bueno wrote:
On Wed, Apr 16, 2008 at 2:33 PM, Bertram Felgenhauer
wrote: No. Data.Graph.Inductive.Query.Dominators is just buggy. [...] Here's a quick fix:
Thanks! This fixes my problem.
Have you submitted a bug and your patch to the appropriate tracker? If not, would someone point me to the appropriate one? Would in be the GHC trac, or is there a libraries-specific one?
The library is shipped with ghc, and the darcs repository lists libraries@haskell.org as the maintainer, so GHC's trac seems to be the right place. I've created a ticket for this now, See http://hackage.haskell.org/trac/ghc/ticket/2227 Note that I opted for reimplementing the whole module instead of just fixing the bug. regards, Bertram

On Mon, Apr 21, 2008 at 5:21 PM, Bertram Felgenhauer
Denis Bueno wrote:
On Wed, Apr 16, 2008 at 2:33 PM, Bertram Felgenhauer
wrote: No. Data.Graph.Inductive.Query.Dominators is just buggy. [...] Here's a quick fix:
Thanks! This fixes my problem.
Have you submitted a bug and your patch to the appropriate tracker? If not, would someone point me to the appropriate one? Would in be the GHC trac, or is there a libraries-specific one?
The library is shipped with ghc, and the darcs repository lists libraries@haskell.org as the maintainer, so GHC's trac seems to be the right place.
I've created a ticket for this now, See http://hackage.haskell.org/trac/ghc/ticket/2227
Note that I opted for reimplementing the whole module instead of just fixing the bug.
/me grovels before int-e. My code went from 310s to 28s (as measured by the profiler, which represents a much longer wall time) after merely switching to your dominators implementation. Thank you for taking the time to reimplement the module. In particular, in the original dominators code the `intersection' function was the time-hog, followed by `builddoms': COST CENTRE MODULE %time %alloc intersection DPLLSat 73.6 18.5 builddoms DPLLSat 11.1 46.4 With your new module I now have the bottleneck I expected from my code, and the dominators code nowhere approaches that bottleneck. -- Denis
participants (6)
-
Bertram Felgenhauer
-
ChrisK
-
Dan Weston
-
Denis Bueno
-
Kim-Ee Yeoh
-
Matthew Brecknell