-
Notifications
You must be signed in to change notification settings - Fork 710
Solver: Add individual flags to conflict sets. #4391
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
Comments
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 12, 2017
This just moves some functions and types into Validate.hs in preparation for haskell#4391.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 12, 2017
This commit changes the way that the solver tracks the variables that introduce dependencies, in order to fix some bugs that prevented the solver from tracking individual flags. I refactored Dep, the type that represents a build-depends or build-tool-depends dependency, so that it stores the package, flag, and stanza choices that introduced the dependency. That information is stored in a field of type DependencyReason. The DependencyReason is available to any solver phase that needs to create conflict sets, such as "build" or "validation". Whenever there is a conflict involving a dependency, the solver creates a conflict set and a log message using the dependency's DependencyReason. This means that the solver only needs to calculate the dependency reasons once, in IndexConversion.hs, rather than every time they are used, i.e., in Builder.hs (for goal reasons), Validate.hs, and Linking.hs. Another difference between this commit and master is the dependencies between solver variables. On master, each dependency or variable is introduced by exactly one other variable. For example, if package x has a flag y, which controls a dependency on package z, then the three variables depend on each other in a chain, x -> y -> z. If z can't be satisfied, the solver backjumps to its cause, y, and if flipping y doesn't help, it continues backjumping to y's cause, which is x. In contrast, this commit allows each dependency to be introduced by a package and any number of flags and stanzas. So z's DependencyReason would contain both x and y. Storing all flags that introduced a dependency allows the solver to correctly calculate conflict sets when there are nested conditionals. We no longer need to combine each package's flags into a single conflict set variable. This commit removes the 'simplifyVar' function and adds flag variables directly to conflict sets. See issue haskell#4391. This commit makes another minor change. In this commit and master, if a dependency appears in the if and else blocks of a conditional, the solver lifts it out of the conditional. Previously, the solver behaved as if the flag did not introduce the dependency. This commit adds the flag variable to the conflict set or error message if the dependency is involved in a conflict. This change doesn't affect correctness, but I think it improves the error messages, since it gives the whole reason that each dependency was introduced.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 12, 2017
This just moves some functions and types into Validate.hs in preparation for haskell#4391.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 12, 2017
This commit changes the way that the solver tracks the variables that introduce dependencies, in order to fix some bugs that prevented the solver from tracking individual flags. I refactored Dep, the type that represents a build-depends or build-tool-depends dependency, so that it stores the package, flag, and stanza choices that introduced the dependency. That information is stored in a field of type DependencyReason. The DependencyReason is available to any solver phase that needs to create conflict sets, such as "build" or "validation". Whenever there is a conflict involving a dependency, the solver creates a conflict set and a log message using the dependency's DependencyReason. This means that the solver only needs to calculate the dependency reasons once, in IndexConversion.hs, rather than every time they are used, i.e., in Builder.hs (for goal reasons), Validate.hs, and Linking.hs. Another difference between this commit and master is the dependencies between solver variables. On master, each dependency or variable is introduced by exactly one other variable. For example, if package x has a flag y, which controls a dependency on package z, then the three variables depend on each other in a chain, x -> y -> z. If z can't be satisfied, the solver backjumps to its cause, y, and if flipping y doesn't help, it continues backjumping to y's cause, which is x. In contrast, this commit allows each dependency to be introduced by a package and any number of flags and stanzas. So z's DependencyReason would contain both x and y. Storing all flags that introduced a dependency allows the solver to correctly calculate conflict sets when there are nested conditionals. We no longer need to combine each package's flags into a single conflict set variable. This commit removes the 'simplifyVar' function and adds flag variables directly to conflict sets. See issue haskell#4391. This commit makes another minor change. In this commit and master, if a dependency appears in the if and else blocks of a conditional, the solver lifts it out of the conditional. Previously, the solver behaved as if the flag did not introduce the dependency. This commit adds the flag variable to the conflict set or error message if the dependency is involved in a conflict. This change doesn't affect correctness, but I think it improves the error messages, since it gives the whole reason that each dependency was introduced.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 12, 2017
This commit changes the way that the solver tracks the variables that introduce dependencies, in order to fix some bugs that prevented the solver from tracking individual flags. I refactored Dep, the type that represents a build-depends or build-tool-depends dependency, so that it stores the package, flag, and stanza choices that introduced the dependency. That information is stored in a field of type DependencyReason. The DependencyReason is available to any solver phase that needs to create conflict sets, such as "build" or "validation". Whenever there is a conflict involving a dependency, the solver creates a conflict set and a log message using the dependency's DependencyReason. This means that the solver only needs to calculate the dependency reasons once, in IndexConversion.hs, rather than every time they are used, i.e., in Builder.hs (for goal reasons), Validate.hs, and Linking.hs. Another difference between this commit and master is the dependencies between solver variables. On master, each dependency or variable is introduced by exactly one other variable. For example, if package x has a flag y, which controls a dependency on package z, then the three variables depend on each other in a chain, x -> y -> z. If z can't be satisfied, the solver backjumps to its cause, y, and if flipping y doesn't help, it continues backjumping to y's cause, which is x. In contrast, this commit allows each dependency to be introduced by a package and any number of flags and stanzas. So z's DependencyReason would contain both x and y. Storing all flags that introduced a dependency allows the solver to correctly calculate conflict sets when there are nested conditionals. We no longer need to combine each package's flags into a single conflict set variable. This commit removes the 'simplifyVar' function and adds flag variables directly to conflict sets. See issue haskell#4391. This commit makes another minor change. In this commit and master, if a dependency appears in the if and else blocks of a conditional, the solver lifts it out of the conditional. Previously, the solver behaved as if the flag did not introduce the dependency. This commit adds the flag variable to the conflict set or error message if the dependency is involved in a conflict. This change doesn't affect correctness, but I think it improves the error messages, since it gives the whole reason that each dependency was introduced.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 14, 2017
This just moves some functions and types into Validate.hs in preparation for haskell#4391.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 14, 2017
This just moves some functions and types into Validate.hs in preparation for haskell#4391.
grayjay
added a commit
to grayjay/cabal
that referenced
this issue
Jun 17, 2017
This commit changes the way that the solver tracks the variables that introduce dependencies, in order to fix some bugs that prevented the solver from tracking individual flags. I refactored Dep, the type that represents a build-depends or build-tool-depends dependency, so that it stores the package, flag, and stanza choices that introduced the dependency. That information is stored in a field of type DependencyReason. The DependencyReason is available to any solver phase that needs to create conflict sets, such as "build" or "validation". Whenever there is a conflict involving a dependency, the solver creates a conflict set and a log message using the dependency's DependencyReason. This means that the solver only needs to calculate the dependency reasons once, in IndexConversion.hs, rather than every time they are used, i.e., in Builder.hs (for goal reasons), Validate.hs, and Linking.hs. Another difference between this commit and master is the dependencies between solver variables. On master, each dependency or variable is introduced by exactly one other variable. For example, if package x has a flag y, which controls a dependency on package z, then the three variables depend on each other in a chain, x -> y -> z. If z can't be satisfied, the solver backjumps to its cause, y, and if flipping y doesn't help, it continues backjumping to y's cause, which is x. In contrast, this commit allows each dependency to be introduced by a package and any number of flags and stanzas. So z's DependencyReason would contain both x and y. Storing all flags that introduced a dependency allows the solver to correctly calculate conflict sets when there are nested conditionals. We no longer need to combine each package's flags into a single conflict set variable. This commit removes the 'simplifyVar' function and adds flag variables directly to conflict sets. See issue haskell#4391. This commit makes another minor change. In this commit and master, if a dependency appears in the if and else blocks of a conditional, the solver lifts it out of the conditional. Previously, the solver behaved as if the flag did not introduce the dependency. This commit adds the flag variable to the conflict set or error message if the dependency is involved in a conflict. This change doesn't affect correctness, but I think it improves the error messages, since it gives the whole reason that each dependency was introduced.
This was implemented in #4562. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently, the solver uses one conflict set variable to represent all flags in a single package. Say package
pkg-1.0
has two flags,flagA
andflagB
. If eitherflagA
orflagB
introduces an unsatisfiable dependency, then the solver adds the variablepkg-1.0:flag
to the conflict set. Sincepkg-1.0:flag
represents all ofpkg
's flags, the solver must backtrack and try flipping bothflagA
andflagB
, even though only one of them introduced the dependency.I think it would be nice to keep track of the flags that introduce each dependency and then put individual flags in conflict sets. It would reduce the search space for the solver. (This is related to #1890.)
Another benefit of tracking individual flags is that it would allow us to change the order of flag goals without having a large impact on performance. Right now, the solver chooses flags relatively efficiently by solving for them in the order that they appear in the trees of conditionals. For example, the solver chooses A and D first for this package, since they are in top level conditionals:
The flag order allows it to discover the dependencies on
unknown
,unknown2
, andunknown3
as soon as possible and determine that there is no solution. If the solver instead chose flags in the order B, C, E, F, A, it wouldn't find the first unknown dependency until it had made five flag choices. At that point, it would need to backtrack and try all combinations for B, C, E, and F. So, we need to be careful when changing the order of flag goals. Some goal orders can cause the solver to get stuck trying too many combinations. However, if we added individual flags to conflict sets, the order B, C, E, F, A would work just as well as the current order. When the solver tried to choose a value for A and discovered the dependencies onunknown
andunknown2
, it would only addA
to the conflict set. It could immediately backtrack past B, C, E, and F, since they didn't contribute to the conflict.Making the solver perform well even after bad goal choices might increase the effectiveness of some goal order heuristics, such as randomization.
A third benefit of tracking individual flags is that we could treat stanza choices similarly to flags and fix issues like #3930 and #4390.
The text was updated successfully, but these errors were encountered: