@@ -194,11 +194,15 @@ prettyPlan (simplifySpec -> spec)
194194
195195-- ---------------------- Building a plan -----------------------------------
196196
197- substStage :: Env -> SolverStage -> SolverStage
198- substStage env (SolverStage y ps spec) = normalizeSolverStage $ SolverStage y (substPred env <$> ps) spec
197+ substStage :: HasSpec a => Set Name -> Var a -> a -> SolverStage -> SolverStage
198+ substStage rel' x val (SolverStage y ps spec relevant) =
199+ normalizeSolverStage $ SolverStage y (substPred env <$> ps) spec relevant'
200+ where env = Env. singleton x val
201+ relevant' | Name x `appearsIn` ps = rel' <> relevant
202+ | otherwise = relevant
199203
200204normalizeSolverStage :: SolverStage -> SolverStage
201- normalizeSolverStage (SolverStage x ps spec) = SolverStage x ps'' (spec <> spec')
205+ normalizeSolverStage (SolverStage x ps spec relevant ) = SolverStage x ps'' (spec <> spec') relevant
202206 where
203207 (ps', ps'') = partition ((1 == ) . Set. size . freeVarSet) ps
204208 spec' = fromGESpec $ computeSpec x (And ps')
@@ -228,7 +232,7 @@ prepareLinearization p = do
228232 ]
229233 )
230234 $ linearize preds graph
231- pure $ backPropagation $ SolverPlan plan
235+ pure $ backPropagation mempty $ SolverPlan plan
232236
233237-- | Flatten nested `Let`, `Exists`, and `And` in a `Pred fn`. `Let` and
234238-- `Exists` bound variables become free in the result.
@@ -300,7 +304,7 @@ linearize preds graph = do
300304 ]
301305 go (n@ (Name x) : ns) ps = do
302306 let (nps, ops) = partition (isLastVariable n . fst ) ps
303- (normalizeSolverStage (SolverStage x (map snd nps) mempty ) : ) <$> go ns ops
307+ (normalizeSolverStage (SolverStage x (map snd nps) mempty mempty ) : ) <$> go ns ops
304308
305309 isLastVariable n set = n `Set.member` set && solvableFrom n (Set. delete n set) graph
306310
@@ -823,7 +827,7 @@ totalWeight = fmap getSum . foldMapList (fmap Semigroup.Sum . weight)
823827
824828-- | Does nothing if the variable is not in the plan already.
825829mergeSolverStage :: SolverStage -> [SolverStage ] -> [SolverStage ]
826- mergeSolverStage (SolverStage x ps spec) plan =
830+ mergeSolverStage (SolverStage x ps spec relevant ) plan =
827831 [ case eqVar x y of
828832 Just Refl ->
829833 SolverStage
@@ -840,51 +844,63 @@ mergeSolverStage (SolverStage x ps spec) plan =
840844 )
841845 (spec <> spec')
842846 )
847+ (relevant <> relevant')
843848 Nothing -> stage
844- | stage@ (SolverStage y ps' spec') <- plan
849+ | stage@ (SolverStage y ps' spec' relevant' ) <- plan
845850 ]
846851
847852isEmptyPlan :: SolverPlan -> Bool
848853isEmptyPlan (SolverPlan plan) = null plan
849854
850- stepPlan :: MonadGenError m => Env -> SolverPlan -> GenT m (Env , SolverPlan )
851- stepPlan env plan@ (SolverPlan [] ) = pure (env, plan)
852- stepPlan env (SolverPlan (SolverStage (x :: Var a ) ps spec : pl)) = do
853- (spec', specs) <- runGE
854- $ explain
855- ( show
856- ( " Computing specs for variable "
857- <> pretty x
858- /> vsep' (map pretty ps)
859- )
860- )
861- $ do
862- ispecs <- mapM (computeSpec x) ps
863- pure $ (fold ispecs, ispecs)
864- val <-
865- genFromSpecT
866- ( addToErrorSpec
867- ( NE. fromList
868- ( ( " \n StepPlan for variable: "
869- ++ show x
870- ++ " ::"
871- ++ showType @ a
872- ++ " fails to produce Specification, probably overconstrained."
873- ++ " PS = "
874- ++ unlines (map show ps)
855+ stepPlan :: MonadGenError m => SolverPlan -> Env -> SolverPlan -> GenT m (Env , SolverPlan )
856+ stepPlan _ env plan@ (SolverPlan [] ) = pure (env, plan)
857+ stepPlan (SolverPlan origStages) env (SolverPlan (stage@ (SolverStage (x :: Var a ) ps spec relevant) : pl)) = do
858+ let errorMessage = " Failed to step the plan" />
859+ vsep [ " Relevant parts of original plan: " /> pretty narrowedOrigPlan
860+ , " Relevant parts of the env: " /> pretty narrowedEnv
861+ , " Current stage: " /> pretty stage
862+ ]
863+ -- TODO: tests for this, including tests for transitive behaviour
864+ narrowedOrigPlan = SolverPlan $ [ st | st@ (SolverStage v _ _ _) <- origStages, Name v `Set.member` relevant ]
865+ narrowedEnv = Env. filterKeys env (\ v -> nameOf v `Set.member` (Set. map (\ (Name n) -> nameOf n) relevant))
866+ explain (show errorMessage) $ do
867+ (spec', specs) <- runGE
868+ $ explain
869+ ( show
870+ ( " Computing specs for variable "
871+ <> pretty x
872+ /> vsep' (map pretty ps)
873+ )
874+ )
875+ $ do
876+ ispecs <- mapM (computeSpec x) ps
877+ pure $ (fold ispecs, ispecs)
878+ val <-
879+ genFromSpecT
880+ ( addToErrorSpec
881+ ( NE. fromList
882+ ( ( " \n StepPlan for variable: "
883+ ++ show x
884+ ++ " ::"
885+ ++ showType @ a
886+ ++ " fails to produce Specification, probably overconstrained."
887+ ++ " PS = "
888+ ++ unlines (map show ps)
889+ )
890+ : (" Relevant variables " ++ show relevant)
891+ : (" Original spec " ++ show spec)
892+ : " Predicates"
893+ : zipWith
894+ (\ pred specx -> " pred " ++ show pred ++ " -> " ++ show specx)
895+ ps
896+ specs
875897 )
876- : (" Original spec " ++ show spec)
877- : " Predicates"
878- : zipWith
879- (\ pred specx -> " pred " ++ show pred ++ " -> " ++ show specx)
880- ps
881- specs
882- )
883- )
884- (spec <> spec')
885- )
886- let env1 = Env. extend x val env
887- pure (env1, backPropagation $ SolverPlan (substStage env1 <$> pl) )
898+ )
899+ (spec <> spec')
900+ )
901+ let env1 = Env. extend x val env
902+ let relevant' = Set. insert (Name x) relevant
903+ pure (env1, backPropagation relevant' $ SolverPlan (substStage relevant' x val <$> pl) )
888904
889905-- | Generate a satisfying `Env` for a `p : Pred fn`. The `Env` contains values for
890906-- all the free variables in `flattenPred p`.
@@ -894,25 +910,22 @@ genFromPreds env0 (optimisePred . optimisePred -> preds) = do
894910 -- NOTE: this is just lazy enough that the work of flattening,
895911 -- computing dependencies, and linearizing is memoized in
896912 -- properties that use `genFromPreds`.
897- plan <- runGE $ prepareLinearization preds
898- go env0 plan
913+ origPlan <- runGE $ prepareLinearization preds
914+ let go :: Env -> SolverPlan -> GenT m Env
915+ go env plan | isEmptyPlan plan = pure env
916+ go env plan = do
917+ (env', plan') <- stepPlan origPlan env plan
918+ go env' plan'
919+ go env0 origPlan
899920 where
900- go :: Env -> SolverPlan -> GenT m Env
901- go env plan | isEmptyPlan plan = pure env
902- go env plan = do
903- (mess :: String ) <- (unlines . map NE. head ) <$> getMessages
904- (env', plan') <-
905- explain (show (fromString (mess ++ " Stepping the plan:" ) /> vsep [pretty plan, pretty env])) $
906- stepPlan env plan
907- go env' plan'
908921
909922-- | Push as much information we can backwards through the plan.
910- backPropagation :: SolverPlan -> SolverPlan
911- backPropagation (SolverPlan initplan) = SolverPlan (go [] (reverse initplan))
923+ backPropagation :: Set Name -> SolverPlan -> SolverPlan
924+ backPropagation relevant (SolverPlan initplan) = SolverPlan (go [] (reverse initplan))
912925 where
913926 go :: [SolverStage ] -> [SolverStage ] -> [SolverStage ]
914927 go acc [] = acc
915- go acc (s@ (SolverStage (x :: Var a ) ps spec) : plan) = go (s : acc) plan'
928+ go acc (s@ (SolverStage (x :: Var a ) ps spec _ ) : plan) = go (s : acc) plan'
916929 where
917930 newStages = concatMap (newStage spec) ps
918931 plan' = foldr mergeSolverStage plan newStages
@@ -926,12 +939,12 @@ backPropagation (SolverPlan initplan) = SolverPlan (go [] (reverse initplan))
926939 termVarEqCases :: HasSpec b => Specification a -> Var b -> Term b -> [SolverStage ]
927940 termVarEqCases (MemberSpec vs) x' t
928941 | Set. singleton (Name x) == freeVarSet t =
929- [SolverStage x' [] $ MemberSpec (NE. nub (fmap (\ v -> errorGE $ runTerm (Env. singleton x v) t) vs))]
942+ [SolverStage x' [] ( MemberSpec (NE. nub (fmap (\ v -> errorGE $ runTerm (Env. singleton x v) t) vs))) relevant ]
930943 termVarEqCases specx x' t
931944 | Just Refl <- eqVar x x'
932945 , [Name y] <- Set. toList $ freeVarSet t
933946 , Result ctx <- toCtx y t =
934- [SolverStage y [] (propagateSpec specx ctx)]
947+ [SolverStage y [] (propagateSpec specx ctx) relevant ]
935948 termVarEqCases _ _ _ = []
936949
937950-- | Function symbols for `(==.)`
@@ -1025,10 +1038,11 @@ pinnedBy _ _ = Nothing
10251038-- assert $ just_ x ==. lookup_ y (lit $ Map.fromList [(z, z) | z <- [100 .. 102]])
10261039
10271040-- Without this code the example wouldn't work because `y` is completely unconstrained during
1028- -- generation. With this code we essentially rewrite occurences of `just_ A == B` to
1029- -- `[cJust A == B, case B of Nothing -> False; Just _ -> True]` to add extra information
1041+ -- generation. With this code we _essentially_ rewrite occurences of `just_ A == B` to
1042+ -- `[just_ A == B, case B of Nothing -> False; Just _ -> True]` to add extra information
10301043-- about the variables in `B`. Consequently, `y` in the example above is
1031- -- constrained to `MemberSpec [100 .. 102]` in the plan.
1044+ -- constrained to `MemberSpec [100 .. 102]` in the plan. This is implemented using the `saturate`
1045+ -- function in the logic type class - in the example above for `==`.
10321046saturatePred :: Pred -> [Pred ]
10331047saturatePred p =
10341048 -- [p]
@@ -1307,6 +1321,7 @@ data SolverStage where
13071321 { stageVar :: Var a
13081322 , stagePreds :: [Pred ]
13091323 , stageSpec :: Specification a
1324+ , relevantVariables :: Set Name
13101325 } ->
13111326 SolverStage
13121327
0 commit comments