Skip to content

Commit 9bcce2e

Browse files
optimise how we deal with either specs
1 parent df5f8f4 commit 9bcce2e

File tree

7 files changed

+44
-3
lines changed

7 files changed

+44
-3
lines changed

bench/Constrained/Bench.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
module Constrained.Bench where
1111

1212
import Constrained.API
13+
import Constrained.Generation
14+
import Constrained.Examples.Set
15+
import Constrained.Examples.Map
16+
1317
import Control.DeepSeq
1418
import Criterion
1519
import Data.Map (Map)
@@ -30,6 +34,9 @@ benchmarks =
3034
(giveHint (Nothing, 30) <> trueSpec :: Specification (Tree Int))
3135
, benchSpec 10 30 "roseTreeMaybe" roseTreeMaybe
3236
, benchSpec 10 30 "listSumPair" listSumPair
37+
, benchSpec 10 30 "maybeJustSetSpec" maybeJustSetSpec
38+
, benchSpec 10 40 "eitherKeys" eitherKeys
39+
, benchSimplifySpec "eitherKeys" eitherKeys
3340
]
3441

3542
roseTreeMaybe :: Specification (Tree (Maybe (Int, Int)))
@@ -49,6 +56,11 @@ listSumPair = constrained $ \xs ->
4956
, forAll' xs $ \x y -> [20 <. x, x <. 30, y <. 100]
5057
]
5158

59+
benchSimplifySpec :: HasSpec a => String -> Specification a -> Benchmark
60+
benchSimplifySpec nm spec =
61+
bench ("simplify/" ++ nm) $
62+
nf (show . simplifySpec) spec
63+
5264
benchSpec :: (HasSpec a, NFData a) => Int -> Int -> String -> Specification a -> Benchmark
5365
benchSpec seed size nm spec =
5466
bench (unlines [nm, show (genFromSpecWithSeed seed size spec)]) $

constrained-generators.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ benchmark bench
163163
build-depends:
164164
base,
165165
constrained-generators,
166+
constrained-generators:examples,
166167
containers,
167168
criterion,
168169
deepseq,

examples/Constrained/Examples/Map.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,14 @@ eitherKeys = constrained' $ \ [var| as |] [var| bs |] [var| m |] ->
138138
k `elem_` ls ++. rs
139139
]
140140
]
141+
142+
keysExample :: Specification (Either Int Int)
143+
keysExample = constrained $ \ k ->
144+
[ caseOn k
145+
(branch $ \ a -> a `elem_` as)
146+
(branch $ \ b -> b `elem_` bs)
147+
, reify as (map Left) $ \ ls ->
148+
reify bs (map Right) $ \ rs ->
149+
k `elem_` ls ++. rs
150+
] where as = lit [ 1 .. 10]
151+
bs = lit [ 11 .. 20 ]

src/Constrained/Generation.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ import Prelude hiding (cycle, pred)
101101
-- generators are not flexible enough.
102102
genFromSpecT ::
103103
forall a m. (HasCallStack, HasSpec a, MonadGenError m) => Specification a -> GenT m a
104+
genFromSpecT (ExplainSpec [] s) = genFromSpecT s
105+
genFromSpecT (ExplainSpec es s) = push es (genFromSpecT s)
104106
genFromSpecT (simplifySpec -> spec) = case spec of
105107
ExplainSpec [] s -> genFromSpecT s
106108
ExplainSpec es s -> push es (genFromSpecT s)
@@ -947,7 +949,6 @@ genFromPreds env0 (optimisePred . optimisePred -> preds) = do
947949
(env', plan') <- stepPlan origPlan env plan
948950
go env' plan'
949951
go env0 origPlan
950-
where
951952

952953
-- | Push as much information we can backwards through the plan.
953954
backPropagation :: Set Name -> SolverPlan -> SolverPlan
@@ -1050,7 +1051,10 @@ pinnedBy :: forall a. HasSpec a => Var a -> Pred -> Maybe (Term a)
10501051
pinnedBy x (Assert (Equal t t'))
10511052
| V x' <- t, Just Refl <- eqVar x x' = Just t'
10521053
| V x' <- t', Just Refl <- eqVar x x' = Just t
1054+
pinnedBy x (ElemPred True (V x') (xs NE.:| []))
1055+
| Just Refl <- eqVar x x' = Just (lit xs)
10531056
pinnedBy x (And ps) = listToMaybe $ catMaybes $ map (pinnedBy x) ps
1057+
pinnedBy x (Explain _ p) = pinnedBy x p
10541058
pinnedBy _ _ = Nothing
10551059

10561060
-- ==================================================================================================

src/Constrained/NumOrd.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,6 @@ caseBoolSpec spec cont = case possibleValues spec of
10631063
[b] -> cont b
10641064
_ -> mempty
10651065
where
1066-
-- where possibleValues s = filter (flip conformsToSpec (simplifySpec s)) [True, False]
10671066
-- This will always get the same result, and probably faster since running 2
10681067
-- conformsToSpec on True and False takes less time than simplifying the spec.
10691068
-- Since we are in TheKnot, we could keep the simplifySpec. Is there a good reason to?

src/Constrained/Spec/Map.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,13 @@ instance
179179
fold
180180
[ maybe TrueSpec (leqSpec . max 0) mHint
181181
, size
182-
, maxSpec (cardinality (fstSpec kvs)) -- (mapSpec FstW (mapSpec ToGenericW kvs)))
182+
, maxSpec (cardinality (fstSpec kvs))
183183
, maxSpec (cardinalTrueSpec @k)
184184
, geqSpec 0
185185
]
186186
n <- genFromSpecT size'
187187
let go 0 _ m = pure m
188+
-- go n' ((\ s -> trace (show s) s) -> kvs') m = do
188189
go n' kvs' m = do
189190
mkv <- inspect $ genFromSpecT kvs'
190191
case mkv of

src/Constrained/Syntax.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE ExistentialQuantification #-}
2+
{-# LANGUAGE DataKinds #-}
23
{-# LANGUAGE FlexibleContexts #-}
34
{-# LANGUAGE FlexibleInstances #-}
45
{-# LANGUAGE GADTs #-}
@@ -721,6 +722,7 @@ mkCase tm cs
721722
| Semigroup.getAll $ foldMapList isTrueBinder cs = TruePred
722723
| Semigroup.getAll $ foldMapList (isFalseBinder . thing) cs = FalsePred (pure "mkCase on all False")
723724
| Lit a <- tm = runCaseOn a (mapList thing cs) (\x val p -> substPred (Env.singleton x val) p)
725+
| Just es <- buildElemList cs = ElemPred True tm es
724726
| otherwise = Case tm cs
725727
where
726728
isTrueBinder (Weighted Nothing (_ :-> TruePred)) = Semigroup.All True
@@ -729,6 +731,17 @@ mkCase tm cs
729731
isFalseBinder (_ :-> FalsePred {}) = Semigroup.All True
730732
isFalseBinder _ = Semigroup.All False
731733

734+
buildElemList :: List (Weighted Binder) as -> Maybe (NE.NonEmpty (SumOver as))
735+
buildElemList Nil = Nothing
736+
buildElemList (Weighted Nothing (x :-> ElemPred True (V x') as) :> xs)
737+
| Just Refl <- eqVar x x' =
738+
case xs of
739+
Nil -> Just as
740+
_ :> _ -> do
741+
rest <- buildElemList xs
742+
return $ fmap SumLeft as <> fmap SumRight rest
743+
buildElemList _ = Nothing
744+
732745
-- | Run a `caseOn`
733746
runCaseOn ::
734747
SumOver as ->

0 commit comments

Comments
 (0)