I've run into a few situations where I would expect Snakemake would complain about ambiguous rules, but doesn't, so I'm trying to figure out exactly what the expected behavior is supposed to be.
For example, with this as rules1.smk:
rule rule1:
output: "something.txt"
rule rule2:
output: "{thing}.txt"
rule rule3:
output: "{thing}.{ext}"
If I request file.txt it complains as expected:
$ snakemake -n --debug-dag -s rules1.smk file.txt
Building DAG of jobs...
candidate job rule2
wildcards: thing=file
candidate job rule3
wildcards: thing=file, ext=txt
AmbiguousRuleException:
Rules rule2 and rule3 are ambiguous for the file file.txt.
...
But if I request something.txt, it goes straight to rule1 and stops at that:
$ snakemake -n --debug-dag -s rules1.smk something.txt
Building DAG of jobs...
candidate job rule1
wildcards:
selected job rule1
...
My question is, why does it do that? Shouldn't it complain that all three of these rules are ambiguous for that output?
My first thought was that rules that yield an output match with no wildcards might implicitly get a higher ruleorder defined than rules that use any number of wildcards, but I can't see anything like that in the documentation for ambiguous rules.
A slightly more complex example shows a little more about the behavior:
if not config.get("noruleorder"):
ruleorder: rule1 > rule1alt
rule rule1:
output: "something.txt"
rule rule1alt:
output: "something.txt"
rule rule2:
output: "{thing}.txt"
rule rule3:
output: "{thing}.{ext}"
That works by default, allowing that ruleorder directive:
$ snakemake -n --debug-dag -s rules2.smk something.txt
Building DAG of jobs...
candidate job rule1
wildcards:
selected job rule1
...
And obviously without ruleorder it can't work, since rule1 and rule1alt are as ambiguous as can be:
$ snakemake --config noruleorder=yep -n --debug-dag -s rules2.smk something.txt
Building DAG of jobs...
candidate job rule1alt
wildcards:
candidate job rule1
wildcards:
candidate job rule2
wildcards: thing=something
candidate job rule3
wildcards: thing=something, ext=txt
AmbiguousRuleException:
Rules rule1alt and rule1 are ambiguous for the file something.txt.
...
...but it's interesting that it then considers all the rules I would have thought would be candidates in the first place. I'm just not sure what that says about the candidate job logic. All this seems related to snakemake: Ambiguous rule not detected? but not quite identical.
This is with Snakemake 7.16.0.
Rules without wildcards are implicitly given a higher ruleorder than those with wildcards. This is noted way back in an old changelog for 3.2.2 as "rules without wildcards now beat other rules in case of ambiguity." There's actually a unit test for this that looks almost exactly like what I set up here. I just couldn't find any of this in the docs.
How I found this:
DAG.update
loops over each job and breaks from the loop if it finds a job that is >
than all other candidate jobs. Job.__gt__
just calls Rule.__gt__
which calls Ruleorder.compare
which does this:
# if no ruleorder given, prefer rule without wildcards
wildcard_cmp = rule2.has_wildcards() - rule1.has_wildcards()
if wildcard_cmp != 0:
return wildcard_cmp
If I comment that out, I get the behavior I originally expected:
$ snakemake -n --debug-dag -s rules1.smk something.txt
Building DAG of jobs...
candidate job rule1
wildcards:
candidate job rule2
wildcards: thing=something
candidate job rule3
wildcards: thing=something, ext=txt
AmbiguousRuleException:
Rules rule1 and rule2 are ambiguous for the file something.txt.
The behavior and test were added in this commit. Unless it's already there and I'm just missing it this should probably get documented in the section about ambiguous rules.