Skip to content

Commit 96dc11f

Browse files
Improve shrinking performance
1 parent d20193c commit 96dc11f

File tree

2 files changed

+33
-26
lines changed

2 files changed

+33
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ cabal.project.local~
2222
.HTF/
2323
.ghc.environment.*
2424
*.*.sw*
25+
*.eventlog.json

src/Constrained/Generation.hs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -148,42 +148,48 @@ genFromSpecWithSeed seed size spec = unGen (genFromSpec spec) (mkQCGen seed) siz
148148

149149
-- ----------------------- Shrinking -------------------------------
150150

151+
naiveShrink :: forall a. HasSpec a => a -> [a]
152+
naiveShrink = shrinkWithTypeSpec (emptySpec @a)
153+
151154
-- | Shrink a value while preserving adherence to a `Specification`
152155
shrinkWithSpec :: forall a. HasSpec a => Specification a -> a -> [a]
153-
-- TODO: possibly allow for ignoring the `conformsToSpec` check in the `TypeSpec`
154-
-- case when you know what you're doing
155-
shrinkWithSpec (simplifySpec -> spec) a = filter (`conformsToSpec` spec) $ case spec of
156-
ExplainSpec _ s -> shrinkWithSpec s a
157-
-- TODO: filter on can't if we have a known to be sound shrinker
158-
TypeSpec s _ -> shrinkWithTypeSpec s a
159-
SuspendedSpec x p -> shrinkFromPreds p x a ++ shr a
160-
MemberSpec {} -> shr a
161-
TrueSpec -> shr a
156+
shrinkWithSpec (ExplainSpec _ s) a = shrinkWithSpec s a
157+
shrinkWithSpec (simplifySpec -> spec) a = case spec of
158+
-- TODO: It would be nice to avoid the extra `conformsToSpec` check here and only look
159+
-- at the cant set instead
160+
TypeSpec s _ -> [ a' | a' <- shrinkWithTypeSpec s a, a' `conformsToSpec` spec ]
161+
SuspendedSpec x p -> shrinkFromPreds p x a
162+
-- TODO: it would be nice if there was some better way of doing this
163+
MemberSpec as -> [ a' | a' <- naiveShrink a, a' `elem` as ]
164+
TrueSpec -> naiveShrink a
162165
ErrorSpec {} -> []
163-
where
164-
shr = shrinkWithTypeSpec (emptySpec @a)
166+
-- Should be impossible?
167+
ExplainSpec _ s -> shrinkWithSpec s a
165168

166-
shrinkFromPreds :: HasSpec a => Pred -> Var a -> a -> [a]
169+
shrinkFromPreds :: forall a. HasSpec a => Pred -> Var a -> a -> [a]
167170
shrinkFromPreds p
168171
| Result plan <- prepareLinearization p = \x a -> listFromGE $ do
169172
-- NOTE: we do this to e.g. guard against bad construction functions in Exists
170173
case checkPredE (Env.singleton x a) (NE.fromList []) p of
171174
Nothing -> pure ()
172175
Just err -> explainNE err $ fatalError "Trying to shrink a bad value, don't do that!"
173-
-- Get an `env` for the original value
174-
initialEnv <- envFromPred (Env.singleton x a) p
175-
return
176-
[ a'
177-
| -- Shrink the initialEnv
178-
env' <- shrinkEnvFromPlan initialEnv plan
179-
, -- Get the value of the constrained variable `x` in the shrunk env
180-
Just a' <- [Env.lookup env' x]
181-
, -- NOTE: this is necessary because it's possible that changing
182-
-- a particular value in the env during shrinking might not result
183-
-- in the value of `x` changing and there is no better way to know than
184-
-- to do this.
185-
a' /= a
186-
]
176+
if not $ Name x `appearsIn` p -- NOTE: this is safe because we just checked that p is SAT above
177+
then return $ naiveShrink a
178+
else do
179+
-- Get an `env` for the original value
180+
initialEnv <- envFromPred (Env.singleton x a) p
181+
return
182+
[ a'
183+
| -- Shrink the initialEnv
184+
env' <- shrinkEnvFromPlan initialEnv plan
185+
, -- Get the value of the constrained variable `x` in the shrunk env
186+
Just a' <- [Env.lookup env' x]
187+
, -- NOTE: this is necessary because it's possible that changing
188+
-- a particular value in the env during shrinking might not result
189+
-- in the value of `x` changing and there is no better way to know than
190+
-- to do this.
191+
a' /= a
192+
]
187193
| otherwise = error "Bad pred"
188194

189195
-- Start with a valid Env for the plan and try to shrink it

0 commit comments

Comments
 (0)