Commit 2d26af4b authored by Mikhail Glushenkov's avatar Mikhail Glushenkov Committed by GitHub
Browse files

Merge pull request #4131 from grayjay/goal-order

Solver: Avoid removing goal choices from the tree when applying heuristics.
parents 7613f78b 4b318f57
......@@ -4,11 +4,12 @@ module Distribution.Solver.Modular.PSQ
, casePSQ
, cons
, degree
, delete
, dminimumBy
, length
, lookup
, filter
, filterIfAny
, filterIfAnyByKeys
, filterKeys
, firstOnly
, fromList
......@@ -17,13 +18,11 @@ module Distribution.Solver.Modular.PSQ
, map
, mapKeys
, mapWithKey
, mapWithKeyState
, maximumBy
, minimumBy
, null
, prefer
, preferByKeys
, preferOrElse
, snoc
, sortBy
, sortByKeys
......@@ -68,15 +67,6 @@ mapKeys f (PSQ xs) = PSQ (fmap (first f) xs)
mapWithKey :: (k -> a -> b) -> PSQ k a -> PSQ k b
mapWithKey f (PSQ xs) = PSQ (fmap (\ (k, v) -> (k, f k v)) xs)
mapWithKeyState :: (s -> k -> a -> (b, s)) -> PSQ k a -> s -> PSQ k b
mapWithKeyState p (PSQ xs) s0 =
PSQ (F.foldr (\ (k, v) r s -> case p s k v of
(w, n) -> (k, w) : (r n))
(const []) xs s0)
delete :: Eq k => k -> PSQ k a -> PSQ k a
delete k (PSQ xs) = PSQ (snd (S.partition ((== k) . fst) xs))
fromList :: [(k, a)] -> PSQ k a
fromList = PSQ
......@@ -134,32 +124,31 @@ minimumBy :: (a -> Int) -> PSQ k a -> PSQ k a
minimumBy sel (PSQ xs) =
PSQ [snd (S.minimumBy (comparing fst) (S.map (\ x -> (sel (snd x), x)) xs))]
-- | Sort the list so that values satisfying the predicate are first.
prefer :: (a -> Bool) -> PSQ k a -> PSQ k a
prefer p = sortBy $ flip (comparing p)
-- | Sort the list so that keys satisfying the predicate are first.
preferByKeys :: (k -> Bool) -> PSQ k a -> PSQ k a
preferByKeys p = sortByKeys $ flip (comparing p)
-- | Will partition the list according to the predicate. If
-- there is any element that satisfies the precidate, then only
-- the elements satisfying the predicate are returned.
-- Otherwise, the rest is returned.
--
prefer :: (a -> Bool) -> PSQ k a -> PSQ k a
prefer p (PSQ xs) =
filterIfAny :: (a -> Bool) -> PSQ k a -> PSQ k a
filterIfAny p (PSQ xs) =
let
(pro, con) = S.partition (p . snd) xs
in
if S.null pro then PSQ con else PSQ pro
-- | Variant of 'prefer' that takes a continuation for the case
-- that there are none of the desired elements.
preferOrElse :: (a -> Bool) -> (PSQ k a -> PSQ k a) -> PSQ k a -> PSQ k a
preferOrElse p k (PSQ xs) =
let
(pro, con) = S.partition (p . snd) xs
in
if S.null pro then k (PSQ con) else PSQ pro
-- | Variant of 'prefer' that takes a predicate on the keys
-- | Variant of 'filterIfAny' that takes a predicate on the keys
-- rather than on the values.
--
preferByKeys :: (k -> Bool) -> PSQ k a -> PSQ k a
preferByKeys p (PSQ xs) =
filterIfAnyByKeys :: (k -> Bool) -> PSQ k a -> PSQ k a
filterIfAnyByKeys p (PSQ xs) =
let
(pro, con) = S.partition (p . fst) xs
in
......
......@@ -323,12 +323,13 @@ firstGoal = trav go
-- Note that we keep empty choice nodes, because they mean success.
-- | Transformation that tries to make a decision on base as early as
-- possible. In nearly all cases, there's a single choice for the base
-- package. Also, fixing base early should lead to better error messages.
-- possible by pruning all other goals when base is available. In nearly
-- all cases, there's a single choice for the base package. Also, fixing
-- base early should lead to better error messages.
preferBaseGoalChoice :: Tree d c -> Tree d c
preferBaseGoalChoice = trav go
where
go (GoalChoiceF xs) = GoalChoiceF (P.preferByKeys isBase xs)
go (GoalChoiceF xs) = GoalChoiceF (P.filterIfAnyByKeys isBase xs)
go x = x
isBase :: Goal QPN -> Bool
......@@ -353,7 +354,7 @@ deferSetupChoices = trav go
deferWeakFlagChoices :: Tree d c -> Tree d c
deferWeakFlagChoices = trav go
where
go (GoalChoiceF xs) = GoalChoiceF (P.prefer noWeakStanza (P.prefer noWeakFlag xs))
go (GoalChoiceF xs) = GoalChoiceF (P.prefer noWeakFlag (P.prefer noWeakStanza xs))
go x = x
noWeakStanza :: Tree d c -> Bool
......@@ -398,7 +399,7 @@ preferEasyGoalChoices = trav go
preferReallyEasyGoalChoices :: Tree d c -> Tree d c
preferReallyEasyGoalChoices = trav go
where
go (GoalChoiceF xs) = GoalChoiceF (P.prefer zeroOrOneChoices xs)
go (GoalChoiceF xs) = GoalChoiceF (P.filterIfAny zeroOrOneChoices xs)
go x = x
-- | Monad used internally in enforceSingleInstanceRestriction
......
......@@ -115,8 +115,8 @@ solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =
in case goalOrder sc of
Nothing -> goalChoiceHeuristics .
heuristicsTree .
P.deferWeakFlagChoices .
P.deferSetupChoices .
P.deferWeakFlagChoices .
P.preferBaseGoalChoice
Just order -> P.firstGoal .
heuristicsTree .
......@@ -140,19 +140,8 @@ solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =
$ addLinking
$ buildTree idx (independentGoals sc) (S.toList userGoals)
-- Counting conflicts and reordering goals interferes, as both are strategies to
-- change the order of goals.
--
-- We therefore change the strategy based on whether --count-conflicts is set or
-- not:
--
-- - when --count-conflicts is set, we use preferReallyEasyGoalChoices, which
-- prefers (keeps) goals only if the have 0 or 1 enabled choice.
--
-- - when --count-conflicts is not set, we use preferEasyGoalChoices, which
-- (next to preferring goals with 0 or 1 enabled choice)
-- also prefers goals that have 2 enabled choices over goals with more than
-- two enabled choices.
-- When --reorder-goals is set, we use preferReallyEasyGoalChoices, which
-- prefers (keeps) goals only if the have 0 or 1 enabled choice.
--
-- In the past, we furthermore used P.firstGoal to trim down the goal choice nodes
-- to just a single option. This was a way to work around a space leak that was
......@@ -164,9 +153,8 @@ solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =
-- Otherwise, we simply choose the first remaining goal.
--
goalChoiceHeuristics
| asBool (reorderGoals sc) && asBool (countConflicts sc) = P.preferReallyEasyGoalChoices
| asBool (reorderGoals sc) = P.preferEasyGoalChoices
| otherwise = id {- P.firstGoal -}
| asBool (reorderGoals sc) = P.preferReallyEasyGoalChoices
| otherwise = id {- P.firstGoal -}
-- | Dump solver tree to a file (in debugging mode)
--
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment