@@ -12,7 +12,6 @@ as SML/NJ to get nice trees.
1212-}
1313
1414import Control.Arrow (second)
15−import Data.Function (on)
1615import qualified Data.List as List
1716import qualified Data.Map as Map
1817import qualified Data.Set as Set
@@ -74,6 +73,7 @@ data DecisionTree a
7473 , _edges :: [(Test, DecisionTree a)]
7574 , _default :: Maybe (DecisionTree a)
7675 }
76+ deriving (Eq)
7777
7878
7979data Jump = Jump
@@ -144,37 +144,23 @@ toDecisionTree variantDict rawBranches =
144144 Nothing ->
145145 let
146146 path =
147− smallDefaults branches
148−
149− relevantTests =
150− testsAtPath path branches
151−
152− allRawEdges =
153− map (edgesFor path branches) relevantTests
154−
155− (rawEdges, unexplored) =
156− if isComplete variantDict relevantTests then
157− ( init allRawEdges
158− , snd (last allRawEdges)
159− )
147+ pickPath variantDict branches
160148
161− else
162− ( allRawEdges
163− , filter (isIrrelevantTo path) branches
164− )
149+ (edges, fallback) =
150+ gatherEdges variantDict branches path
165151
166− edges =
167− map (second (toDecisionTree variantDict)) rawEdges
152+ decisionEdges =
153+ map (second (toDecisionTree variantDict)) edges
168154 in
169− case (edges, unexplored) of
155+ case (decisionEdges, fallback) of
170156 ([(_tag, decisionTree)], []) ->
171157 decisionTree
172158
173159 (_, []) ->
174− Decision path edges Nothing
160+ Decision path decisionEdges Nothing
175161
176162 (_, _) ->
177− Decision path edges (Just (toDecisionTree variantDict unexplored))
163+ Decision path decisionEdges (Just (toDecisionTree variantDict fallback))
178164
179165
180166isComplete :: VariantDict -> [Test] -> Bool
@@ -283,6 +269,28 @@ getSubstitution (path, A.A _ pattern) =
283269 Nothing
284270
285271
272+-- GATHER OUTGOING EDGES
273+
274+gatherEdges :: VariantDict -> [Branch] -> Path -> ([(Test, [Branch])], [Branch])
275+gatherEdges variantDict branches path =
276+ let
277+ relevantTests =
278+ testsAtPath path branches
279+
280+ allRawEdges =
281+ map (edgesFor path branches) relevantTests
282+ in
283+ if isComplete variantDict relevantTests then
284+ ( init allRawEdges
285+ , snd (last allRawEdges)
286+ )
287+
288+ else
289+ ( allRawEdges
290+ , filter (isIrrelevantTo path) branches
291+ )
292+
293+
286294-- FIND RELEVANT TESTS
287295
288296testsAtPath :: Path -> [Branch] -> [Test]
@@ -420,18 +428,20 @@ needsTests (A.A _ pattern) =
420428 True
421429
422430
423−-- PATH PICKING HEURISTICS
431+-- PICK A PATH
424432
425−smallDefaults :: [Branch] -> Path
426−smallDefaults branches =
433+pickPath :: VariantDict -> [Branch] -> Path
434+pickPath variantDict branches =
427435 let
428436 allPaths =
429437 Maybe.mapMaybe isChoicePath (concatMap _patterns branches)
430−
431− weightedPaths =
432− map (\path -> (path, length (filter (isIrrelevantTo path) branches))) allPaths
433438 in
434− fst (List.minimumBy (compare `on` snd) weightedPaths)
439+ case bests (addWeights (smallDefaults branches) allPaths) of
440+ [path] ->
441+ path
442+
443+ tiedPaths ->
444+ head (bests (addWeights (smallBranchingFactor variantDict branches) tiedPaths))
435445
436446
437447isChoicePath :: (Path, CPattern) -> Maybe Path
@@ -442,4 +452,38 @@ isChoicePath (path, pattern) =
442452 Nothing
443453
444454
445−-- smallBranchingFactor :: [Branch] -> Path
455+addWeights :: (Path -> Int) -> [Path] -> [(Path, Int)]
456+addWeights toWeight paths =
457+ map (\path -> (path, toWeight path)) paths
458+
459+
460+bests :: [(Path, Int)] -> [Path]
461+bests ((path,weight):weightedPaths) =
462+ let
463+ gatherMinimum acc@(minWeight, paths) (path, weight) =
464+ if weight == minWeight then
465+ (minWeight, path : paths)
466+
467+ else if weight < minWeight then
468+ (weight, [path])
469+
470+ else
471+ acc
472+ in
473+ snd (List.foldl' gatherMinimum (weight, [path]) weightedPaths)
474+
475+
476+-- PATH PICKING HEURISTICS
477+
478+smallDefaults :: [Branch] -> Path -> Int
479+smallDefaults branches path =
480+ length (filter (isIrrelevantTo path) branches)
481+
482+
483+smallBranchingFactor :: VariantDict -> [Branch] -> Path -> Int
484+smallBranchingFactor variantDict branches path =
485+ let
486+ (edges, fallback) =
487+ gatherEdges variantDict branches path
488+ in
489+ length edges + (if null fallback then 0 else 1)