Skip to content

Commit 00c8f12

Browse files
authored
[ perf ] Use even smaller state in the derivator closuring
2 parents 9a7c695 + 92d898a commit 00c8f12

11 files changed

Lines changed: 53 additions & 74 deletions

File tree

docs/source/explanation/derivation/design.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import public Deriving.DepTyCheck.Gen
88
-- Empty body derivation
99
export
1010
DeriveBodyForType where
11-
canonicBody sig n = pure [ callCanonic sig n implicitTrue (replicate _ implicitTrue) .= `(empty) ]
11+
canonicBody sig n = pure $ pure [ callCanonic sig n implicitTrue (replicate _ implicitTrue) .= `(empty) ]
1212
-->
1313

1414
# Design of derivation

examples/sorted-tree-naive/tests/gens/print/expected

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[] E
88
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[] NodeLT - used final order: [#2 (prf2), #6, #8, #4 (prf1), #7]
99
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0, 1] EmptyLT - used final order: []
1010
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0, 1] NodeLT - used final order: [#6, #7, #8]
11+
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0] EmptyLT - used final order: []
12+
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0] NodeLT - used final order: [#2 (prf2), #6, #8, #4 (prf1), #7]
13+
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n)] LTEZero - used final order: [#0 (right)]
14+
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n)] LTESucc - used final order: [#2]
1115
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllGT[] EmptyGT - used final order: [#0 (ref)]
1216
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllGT[] NodeGT - used final order: [#7, #6, #4 (prf1), #2 (prf2), #8]
1317
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] Z - used final order: []
1418
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] S - used final order: [#0]
15-
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0] EmptyLT - used final order: []
16-
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllLT[0] NodeLT - used final order: [#2 (prf2), #6, #8, #4 (prf1), #7]
1719
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllGT[0, 1] EmptyGT - used final order: []
1820
LOG deptycheck.derive.least-effort:7: Data.SortedBinTree.SortedBinTree.AllGT[0, 1] NodeGT - used final order: [#6, #7, #8]
19-
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n)] LTEZero - used final order: [#0 (right)]
20-
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n)] LTESucc - used final order: [#2]
2121
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n), 1(m)] LTEZero - used final order: []
2222
LOG deptycheck.derive.least-effort:7: Data.Nat.LTE[0(n), 1(m)] LTESucc - used final order: [#2]
2323
MkArg MW ExplicitArg (Just "^outmost-fuel^") (var "Data.Fuel.Fuel")

src/Deriving/DepTyCheck/Gen/ForAllNeededTypes/Impl.idr

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
||| A bridge between a single act of derivation (for a single type) and a user derivation task
22
module Deriving.DepTyCheck.Gen.ForAllNeededTypes.Impl
33

4-
import public Control.Monad.Either
5-
import public Control.Monad.Reader
64
import public Control.Monad.State
7-
import public Control.Monad.State.Tuple
8-
import public Control.Monad.Writer
9-
import public Control.Monad.RWS
105

116
import public Data.DPair
12-
import public Data.List.Map
7+
import public Data.List.Set
138
import public Data.SortedMap
14-
import public Data.SortedMap.Extra
15-
import public Data.SortedSet
169

1710
import public Decidable.Equality
1811

@@ -24,9 +17,8 @@ import public Deriving.DepTyCheck.Gen.ForOneType.Interface
2417

2518
ClosuringContext : (Type -> Type) -> Type
2619
ClosuringContext m =
27-
( MonadState (ListMap GenSignature Name) m -- gens already asked to be derived
28-
, MonadState (List (GenSignature, Name), List (GenSignature, Name)) m -- two queues of gens to be derived, one for known types, one the unknown ones
29-
, MonadState (SortedSet TypeInfo) m -- type names that were asked for deriving their weighting function
20+
( ListSet GenSignature -- gens already asked to be derived
21+
, MonadState (ListSet GenSignature, ListSet GenSignature) m -- two queues of gens to be derived, one for known types, one the unknown ones
3022
)
3123

3224
nameForGen : GenSignature -> Name
@@ -41,32 +33,31 @@ lookupLengthChecked intSig m = lookup intSig m >>= \(extSig, name) => (name,) <$
4133
Yes prf => Just $ Element extSig prf
4234
No _ => Nothing
4335

44-
deriveAll : NamesInfoInTypes => ConsRecs => DeriveBodyForType => DerivationClosure m => ClosuringContext m => Elaboration m =>
45-
List (Decl, Decl) -> m $ List (Decl, Decl)
46-
deriveAll acc = do
47-
(toDeriveKnown, toDeriveUnknown) <- get {stateType=(List _, List _)}
48-
put ([], toDeriveUnknown)
49-
derived <- (++ acc) <$> for toDeriveKnown deriveOne
36+
deriveAll : NamesInfoInTypes => ConsRecs => (cc : ClosuringContext m) => DeriveBodyForType => DerivationClosure m => Elaboration m =>
37+
ListSet TypeInfo -> List (Decl, Decl) -> m (ListSet TypeInfo, List (Decl, Decl))
38+
deriveAll weightFunTys decls {cc=(alreadyDerived, _)}= do
39+
(toDeriveKnown, toDeriveUnknown) <- mapHom ((`difference` alreadyDerived) . normalise) <$> get {stateType=(ListSet _, ListSet _)}
40+
put (empty, toDeriveUnknown)
41+
(weightFunTys, decls) <- bimap (foldl insert' weightFunTys . join) (decls ++) . unzip <$> for (toList toDeriveKnown) deriveOne
5042
if not $ null toDeriveKnown
51-
then assert_total deriveAll derived
43+
then assert_total $ deriveAll {cc=(alreadyDerived `union` toDeriveKnown, %search)} weightFunTys decls
5244
else if null toDeriveUnknown
53-
then pure derived
45+
then pure (weightFunTys, decls)
5446
else do
55-
(niit, cr) <- updateNamesAndConsRecs $ targetType . fst <$> toDeriveUnknown
56-
put (toDeriveUnknown, [])
57-
assert_total $ deriveAll @{niit} @{cr} derived
47+
(niit, cr) <- updateNamesAndConsRecs $ targetType <$> toList toDeriveUnknown
48+
put (toDeriveUnknown, empty)
49+
assert_total $ deriveAll @{niit} @{cr} {cc=(alreadyDerived `union` toDeriveUnknown, %search)} weightFunTys decls
5850
where
59-
deriveOne : (GenSignature, Name) -> m (Decl, Decl)
60-
deriveOne (sig, name) = do
51+
deriveOne : GenSignature -> m (List TypeInfo, Decl, Decl)
52+
deriveOne sig = do
53+
let name = nameForGen sig
6154
-- derive declaration and body for the asked signature. It's important to call it AFTER update of the map in the state to not to cycle
6255
let genFunClaim = export' name $ canonicSig sig
63-
genFunBody <- logBounds Info "deptycheck.derive.type" [sig] $ def name <$> canonicBody sig name
64-
pure (genFunClaim, genFunBody)
56+
(tyWithWeightFuns, genFunBody) <- logBounds Info "deptycheck.derive.type" [sig] $ canonicBody sig name
57+
pure (tyWithWeightFuns, genFunClaim, def name genFunBody)
6558

6659
DeriveBodyForType => ClosuringContext m => Elaboration m => SortedMap GenSignature (ExternalGenSignature, Name) => DerivationClosure m where
6760

68-
needWeightFun = modify . SortedSet.insert
69-
7061
callGen sig fuel values = do
7162

7263
-- look for external gens, and call it if exists
@@ -75,28 +66,15 @@ DeriveBodyForType => ClosuringContext m => Elaboration m => SortedMap GenSignatu
7566
logValue Details "deptycheck.derive.closuring.external" [sig] "is used as an external generator" $
7667
(callExternalGen extSig name (var outmostFuelArg) $ rewrite lenEq in values, Just (_ ** extSig.gendOrder))
7768

78-
-- get the expression of calling the internal gen, derive if necessary
79-
internalGenCall <- do
80-
81-
-- look for existing (already derived) internals, use it if exists
82-
let Nothing = List.Map.lookup sig !get
83-
| Just name => pure $ callCanonic sig name fuel values
84-
85-
-- nothing found, then derive! acquire the name
86-
let name = nameForGen sig
87-
88-
-- remember that we're responsible for this signature derivation
89-
modify $ List.Map.insert sig name
69+
-- put to derivation queue if necessary
70+
when (not $ List.Set.contains sig %search) $ do
9071

9172
-- remember the task to derive
92-
modify {stateType=(List _, List _)} $ if isTypeKnown sig.targetType then mapFst $ (::) (sig, name) else mapSnd $ (::) (sig, name)
93-
94-
-- return the name of the newly derived generator
95-
pure $ callCanonic sig name fuel values
73+
modify $ if isTypeKnown sig.targetType then mapFst $ normalise . List.Set.insert sig else mapSnd $ normalise . List.Set.insert sig
9674

9775
-- call the internal gen
9876
logValue DetailedDebug "deptycheck.derive.closuring.internal" [sig] "is used as an internal generator"
99-
(internalGenCall, Nothing)
77+
(callCanonic sig (nameForGen sig) fuel values, Nothing)
10078

10179
--- Canonic-dischagring function ---
10280

@@ -106,7 +84,7 @@ declName : Decl -> String
10684
declName $ IClaim $ MkFCVal _ $ MkIClaimData {type = MkTy {ty, _}, _} = show ty
10785
declName $ IData _ _ _ $ MkData {n, _} = show n
10886
declName $ IData _ _ _ $ MkLater {n, _} = show n
109-
declName $ IDef fc nm cls = ?declName_rhs_2
87+
declName $ IDef _ nm _ = show nm
11088
declName $ IParameters _ _ [] = "P"
11189
declName $ IParameters _ _ (d::_) = declName d
11290
declName $ IRecord _ _ _ _ $ MkRecord {n, _} = show n
@@ -121,10 +99,10 @@ runCanonic : DeriveBodyForType => NamesInfoInTypes => ConsRecs =>
12199
SortedMap ExternalGenSignature Name -> (forall m. DerivationClosure m => m a) -> Elab (a, List Decl)
122100
runCanonic exts calc = do
123101
let exts = SortedMap.fromList $ exts.asList <&> \namedSig => (fst $ internalise $ fst namedSig, namedSig)
124-
((_, _, weightingFuns), (x, derived)) <- runStateT
125-
(empty, (empty, empty), empty @{TypeInfoOrdByName})
126-
[| (calc, deriveAll []) |]
127-
{stateType=(ListMap GenSignature Name, (List (GenSignature, Name), List (GenSignature, Name)), SortedSet TypeInfo)}
102+
(x, weightingFuns, derived) <- evalStateT
103+
(empty, empty)
104+
[| (calc, deriveAll (empty @{TypeInfoEqByName}) []) |]
105+
{stateType=(ListSet GenSignature, ListSet GenSignature)}
128106
{m=Elab}
129107
let derived = sortBy (compare `on` declName . fst) $ derived ++ mapMaybe deriveWeightingFun (Prelude.toList weightingFuns)
130108
let (defs, bodies) = unzip derived

src/Deriving/DepTyCheck/Gen/ForAllNeededTypes/Interface.idr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import public Deriving.DepTyCheck.Gen.Signature
1111

1212
public export
1313
interface Monad m => DerivationClosure m where
14-
needWeightFun : ConsRecs => TypeInfo -> m ()
1514
callGen : NamesInfoInTypes => ConsRecs =>
1615
(sig : GenSignature) -> (fuel : TTImp) -> Vect sig.givenParams.size TTImp -> m (TTImp, Maybe (gend ** Vect gend $ Fin gend))
1716
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +19,6 @@ interface Monad m => DerivationClosure m where
2019

2120
export
2221
DerivationClosure m => MonadTrans t => Monad (t m) => DerivationClosure (t m) where
23-
needWeightFun = lift . needWeightFun
2422
callGen sig fuel params = lift $ callGen sig fuel params
2523

2624
-------------------

src/Deriving/DepTyCheck/Gen/ForOneType/Impl.idr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ DeriveBodyRhsForCon => DeriveBodyForType where
5757
let Just consRecs = lookupConsWithWeight sig
5858
| Nothing => fail "INTERNAL ERROR: unknown type for consRecs: \{show sig.targetType.name}"
5959

60-
-- ask to derive all needed weigthing functions, if any
61-
traverse_ needWeightFun $ mapMaybe (usedWeightFun . snd) consRecs
60+
-- compute all needed weigthing functions, if any
61+
let typesWithWeightFun = mapMaybe (usedWeightFun . snd) consRecs
6262

6363
-- decide how to name a fuel argument on the LHS
6464
let fuelArg = "^fuel_arg^" -- I'm using a name containing chars that cannot be present in the code parsed from the Idris frontend
@@ -67,7 +67,7 @@ DeriveBodyRhsForCon => DeriveBodyForType where
6767
let outmostRHS = fuelDecisionExpr fuelArg $ map @{Compose} weightExpr consRecs
6868

6969
-- return function definition
70-
pure [ canonicDefaultLHS' interimNamesWrapper sig n fuelArg .= local (consClaims ++ consBodies) outmostRHS ]
70+
pure $ MkPair typesWithWeightFun [ canonicDefaultLHS' interimNamesWrapper sig n fuelArg .= local (consClaims ++ consBodies) outmostRHS ]
7171

7272
where
7373

src/Deriving/DepTyCheck/Gen/ForOneType/Interface.idr

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ import public Deriving.DepTyCheck.Gen.Signature
1111

1212
public export
1313
interface DeriveBodyForType where
14-
canonicBody : DerivationClosure m => Elaboration m => NamesInfoInTypes => ConsRecs => GenSignature -> Name -> m $ List Clause
14+
canonicBody : DerivationClosure m => Elaboration m => NamesInfoInTypes => ConsRecs => GenSignature -> Name -> m (List TypeInfo, List Clause)
15+
-- ^^^^^^^^^^^^^
16+
-- /
17+
-- used types with weight functions

tests/derivation/_common/AlternativeCore.idr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ numberedArgs bind = Fin.tabulate $ (if bind then bindVar else var) . UN . Basic
1414

1515
export
1616
[EmptyBody] DeriveBodyForType where
17-
canonicBody sig n = pure [ callCanonic sig n implicitTrue irrelevantArgs .= `(empty) ]
17+
canonicBody sig n = pure $ pure [ callCanonic sig n implicitTrue irrelevantArgs .= `(empty) ]
1818

1919
export
2020
[CallSelf] DeriveBodyForType where
21-
canonicBody sig n = pure
21+
canonicBody sig n = pure $ pure
2222
[ callCanonic sig n (var `{Dry}) irrelevantArgs .= `(empty)
2323
, callCanonic sig n (var `{More} .$ bindVar "fuel") (numberedArgs True) .= fst !(callGen sig (var "fuel") $ numberedArgs False)
2424
]
@@ -58,7 +58,7 @@ Show XS where
5858
export
5959
[Ext_XS] DeriveBodyForType where
6060
canonicBody sig n =
61-
pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXS <$> ~(!(callStrGen $ var "fuel"))) ]
61+
pure $ pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXS <$> ~(!(callStrGen $ var "fuel"))) ]
6262

6363
--- Two (string) arguments taken from external ---
6464

@@ -72,7 +72,7 @@ Show XSS where
7272
export
7373
[Ext_XSS] DeriveBodyForType where
7474
canonicBody sig n =
75-
pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXSS <$> ~(!(callStrGen $ var "fuel")) <*> ~(!(callStrGen $ var "fuel"))) ]
75+
pure $ pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXSS <$> ~(!(callStrGen $ var "fuel")) <*> ~(!(callStrGen $ var "fuel"))) ]
7676

7777
--- Two (string and nat) arguments taken from external ---
7878

@@ -86,7 +86,7 @@ Show XSN where
8686
export
8787
[Ext_XSN] DeriveBodyForType where
8888
canonicBody sig n =
89-
pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXSN <$> ~(!(callStrGen $ var "fuel")) <*> ~(!(callNatGen $ var "fuel"))) ]
89+
pure $ pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkXSN <$> ~(!(callStrGen $ var "fuel")) <*> ~(!(callNatGen $ var "fuel"))) ]
9090

9191
--- Dependent type's argument + a constructor's argument taken from external ---
9292

@@ -101,4 +101,4 @@ export
101101
export
102102
[Ext_X'S] DeriveBodyForType where
103103
canonicBody sig n =
104-
pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkX'S <$> ~(!(callStrGen $ var "fuel"))) ]
104+
pure $ pure [ callCanonic sig n (bindVar "fuel") irrelevantArgs .= `(MkX'S <$> ~(!(callStrGen $ var "fuel"))) ]

tests/derivation/least-effort/print/gadt/003 right-to-left nondet/expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkY1 - used final order: [#
44
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkY2 - used final order: [#3, #4]
55
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[1] MkXG_4 - used final order: []
66
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[1] MkXG_5 - used final order: []
7-
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[0] MkXG_4 - used final order: []
8-
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[0] MkXG_5 - used final order: [#0 (m)]
97
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[] MkXG_4 - used final order: []
108
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[] MkXG_5 - used final order: [#0 (m)]
9+
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[0] MkXG_4 - used final order: []
10+
LOG deptycheck.derive.least-effort:7: DerivedGen.X_GADT[0] MkXG_5 - used final order: [#0 (m)]
1111
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] Z - used final order: []
1212
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] S - used final order: [#0]
1313
MkArg MW ExplicitArg (Just "^outmost-fuel^") (var "Data.Fuel.Fuel")

tests/derivation/least-effort/print/order/002 complex order/expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ LOG deptycheck.derive.least-effort:7: DerivedGen.X[0(n), 1] X0 - used final orde
55
LOG deptycheck.derive.least-effort:7: DerivedGen.X[0(n), 1] X2 - used final order: []
66
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] Y0 - used final order: [#0 (bs), #1 (i)]
77
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] Y2 - used final order: [#0 (bs)]
8+
LOG deptycheck.derive.least-effort:7: DerivedGen.BS[0(n)] MkBS - used final order: []
89
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FZ - used final order: []
910
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FS - used final order: [#1]
10-
LOG deptycheck.derive.least-effort:7: DerivedGen.BS[0(n)] MkBS - used final order: []
1111
MkArg MW ExplicitArg (Just "^outmost-fuel^") (var "Data.Fuel.Fuel")
1212
.=> local
1313
{ decls =

tests/derivation/least-effort/print/order/010 tuned order/expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkYSimple - user-imposed: [
44
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkYSimple - used final order: [#0 (n), #2 (a), #1 (bef), #3 (aft)]
55
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkYComplex - user-imposed: [#5 (a)]
66
LOG deptycheck.derive.least-effort:7: DerivedGen.Y[] MkYComplex - used final order: [#0, #2 (x), #4 (v), #5 (a), #1 (n), #3 (bef), #6 (aft)]
7-
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FZ - used final order: []
8-
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FS - used final order: [#1]
9-
LOG deptycheck.derive.least-effort:7: DerivedGen.X[0] MkX - used final order: []
107
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] Z - used final order: []
118
LOG deptycheck.derive.least-effort:7: Prelude.Types.Nat[] S - used final order: [#0]
9+
LOG deptycheck.derive.least-effort:7: DerivedGen.X[0] MkX - used final order: []
10+
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FZ - used final order: []
11+
LOG deptycheck.derive.least-effort:7: Data.Fin.Fin[0(n)] FS - used final order: [#1]
1212
MkArg MW ExplicitArg (Just "^outmost-fuel^") (var "Data.Fuel.Fuel")
1313
.=> local
1414
{ decls =

0 commit comments

Comments
 (0)