|
| 1 | +-- Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. |
| 2 | +-- SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +module ContingentClaims.Valuation.Expression ( |
| 5 | + Expr(..), |
| 6 | + ExprF(..), |
| 7 | + simplify |
| 8 | +) where |
| 9 | + |
| 10 | +import ContingentClaims.Core.Claim (Inequality(..)) |
| 11 | +import ContingentClaims.Valuation.AcquisitionTime(AcquisitionTime(..)) |
| 12 | +import DA.Foldable |
| 13 | +import DA.Traversable |
| 14 | +import Daml.Control.Recursion |
| 15 | +import Prelude hiding (Time, sequence, mapA, const) |
| 16 | + |
| 17 | +-- | Represents an algebraic expression of a t-adapted stochastic process. |
| 18 | +-- t : time parameter. |
| 19 | +-- x : state parameter, typically Decimal (our best approximation of real numbers). |
| 20 | +-- o : reference used to identify observables. |
| 21 | +-- b : type describing elementary processes. |
| 22 | +data Expr t x o b |
| 23 | + = Const x |
| 24 | + -- ^ A constant process. |
| 25 | + | Proc { name : b } |
| 26 | + -- ^ An elementary process which we cannot decompose further. |
| 27 | + -- | Sup { lowerBound: t, tau: t, rv : Expr t } |
| 28 | + -- -- ^ Sup, needs to be reworked using feasible exercise strategies. |
| 29 | + | Sum [Expr t x o b] |
| 30 | + -- ^ Sum process. |
| 31 | + | Neg (Expr t x o b) |
| 32 | + -- ^ Negation process. |
| 33 | + | Mul (Expr t x o b, Expr t x o b) |
| 34 | + -- ^ Multiplication of two processes (`p1 * p2`). |
| 35 | + | Inv (Expr t x o b) |
| 36 | + -- ^ Inverse of a process (`1 / p`). |
| 37 | + | Max [Expr t x o b] |
| 38 | + -- ^ Maximum process. |
| 39 | + | I (Inequality t x o) |
| 40 | + -- ^ Indicator function. I(p) is 1 if p(t) = True, False otherwise, where |
| 41 | + -- `p` is the boolean process corresponding to the provided inequality. |
| 42 | + -- Specifically, this means |
| 43 | + -- - for `o1 ≤ o2`, `p = υ(o1) ≤ υ(o2)` |
| 44 | + -- - for `TimeGte t`, `p(s) = s ≥ t` |
| 45 | + -- - for `TimeLte t`, `p(s) = s ≤ t` |
| 46 | + | E { process : Expr t x o b, time : AcquisitionTime t x o, filtration : AcquisitionTime t x o } |
| 47 | + -- ^ Conditional expectation of `process(time)` conditioned on the filtration F_`t`. |
| 48 | + -- | Snell { process : Expr t x o b, time : AcquisitionTime t x o, predicate : Inequality t x o} |
| 49 | + -- -- ^ Snell envelope of a stochastic process. |
| 50 | + -- -- We need the predicate to identify the feasible region |
| 51 | + -- -- I feel that we need the acquisition time to identify the conditional filtration, but it might not be needed. |
| 52 | + -- | Absorb { process : Expr t x o b, time : AcquisitionTime t x o, predicate : Inequality t x o} |
| 53 | + -- -- ^ Absorb primitive. |
| 54 | + -- -- It feels that absorb hides an expectation, but I need to write this down in formulas for better understanding. |
| 55 | + -- In order to write until valuation explicitly, we need to introduce a new class of boolean processes, namely those that we start observing at a time tau and have never been true since (we can then use an indicator function to transform it to a real process) |
| 56 | + -- We can use the absorb primitive to cover this case, which we can then distribute. across the other primitives. |
| 57 | + deriving (Eq,Show) |
| 58 | + |
| 59 | +-- | Base functor for `Expr`. |
| 60 | +data ExprF t x o b c |
| 61 | + = ConstF x |
| 62 | + | ProcF { name : b } |
| 63 | + -- | Sup { lowerBound: t, tau: t, rv : Expr t } |
| 64 | + | SumF [c] |
| 65 | + | NegF c |
| 66 | + | MulF { lhs : c, rhs : c } |
| 67 | + | InvF c |
| 68 | + | MaxF [c] |
| 69 | + | I_F (Inequality t x o) |
| 70 | + | E_F { process : c, time : AcquisitionTime t x o, filtration : AcquisitionTime t x o } |
| 71 | + deriving (Functor) |
| 72 | + |
| 73 | +instance Recursive (Expr t x o b) (ExprF t x o b) where |
| 74 | + project (Const d) = ConstF d |
| 75 | + project Proc{..} = ProcF with .. |
| 76 | + -- project Sup{..} = SupF with .. |
| 77 | + project (Sum xs) = SumF xs |
| 78 | + project (Neg x) = NegF x |
| 79 | + project (Mul (x,x')) = MulF x x' |
| 80 | + project (Inv x) = InvF x |
| 81 | + project (Max xs) = MaxF xs |
| 82 | + project (I x) = I_F x |
| 83 | + project E{..} = E_F with .. |
| 84 | + |
| 85 | +instance Corecursive (Expr t x o b) (ExprF t x o b) where |
| 86 | + embed (ConstF d) = Const d |
| 87 | + embed ProcF{..} = Proc with .. |
| 88 | + -- embed SupF{..} = Sup with .. |
| 89 | + embed (SumF xs) = Sum xs |
| 90 | + embed (NegF x) = Neg x |
| 91 | + embed (MulF x x') = Mul (x, x') |
| 92 | + embed (InvF x) = Inv x |
| 93 | + embed (MaxF xs) = Max xs |
| 94 | + embed (I_F x) = I x |
| 95 | + embed E_F{..} = E with .. |
| 96 | + |
| 97 | +instance Foldable (ExprF t x o b) where |
| 98 | + foldMap f (ConstF _) = mempty |
| 99 | + foldMap f (ProcF _) = mempty |
| 100 | + -- foldMap f (SupF _ _ x) = f x |
| 101 | + foldMap f (SumF xs) = foldMap f xs |
| 102 | + foldMap f (NegF x) = f x |
| 103 | + foldMap f (MulF x x') = f x <> f x' |
| 104 | + foldMap f (InvF x) = f x |
| 105 | + foldMap f (MaxF xs) = foldMap f xs |
| 106 | + foldMap f (I_F _) = mempty |
| 107 | + foldMap f (E_F x _ _) = f x |
| 108 | + |
| 109 | +instance Traversable (ExprF t x o b) where |
| 110 | + sequence (ConstF d) = pure $ ConstF d |
| 111 | + sequence (ProcF x) = pure $ ProcF x |
| 112 | +-- sequence (SupF t τ fa) = SupF t τ <$> fa |
| 113 | + sequence (SumF [fa]) = (\a -> SumF [a]) <$> fa |
| 114 | + sequence (SumF (fa :: fas)) = s <$> fa <*> sequence fas |
| 115 | + where s a as = SumF (a :: as) |
| 116 | + sequence (SumF []) = error "Traversable ExprF: sequence empty SumF" |
| 117 | + sequence (NegF fa) = NegF <$> fa |
| 118 | + sequence (MulF fa fa') = MulF <$> fa <*> fa' |
| 119 | + sequence (InvF fa) = InvF <$> fa |
| 120 | + sequence (MaxF (fa :: fas)) = s <$> fa <*> sequence fas |
| 121 | + where s a as = MaxF (a :: as) |
| 122 | + sequence (MaxF []) = error "Traversable ExprF: sequence empty MaxF" |
| 123 | + sequence (I_F p) = pure $ I_F p |
| 124 | + sequence (E_F fa t f) = (\a -> E_F a t f) <$> fa |
| 125 | + |
| 126 | +instance (Additive x) => Additive (Expr t x o b) where |
| 127 | + x + y = Sum [x, y] |
| 128 | + negate = Neg |
| 129 | + aunit = Const aunit |
| 130 | + |
| 131 | +instance (Multiplicative x) => Multiplicative (Expr t x o b) where |
| 132 | + (*) = curry Mul |
| 133 | + munit = Const munit |
| 134 | + x ^ y | y > 0 = x * (x ^ pred y) |
| 135 | + x ^ 0 = munit |
| 136 | + x ^ y = Inv x ^ (-y) |
| 137 | + |
| 138 | +instance (Multiplicative x) => Divisible (Expr t x o b) where |
| 139 | + x / y = curry Mul x $ Inv y |
| 140 | + |
| 141 | +-- | This is meant to be a function that algebraically simplifies the FAPF by |
| 142 | +-- 1) using simple identities and ring laws |
| 143 | +-- 2) change of numeraire technique. |
| 144 | +simplify : (Eq x, Eq b, Eq t, Eq o, Multiplicative x) => Expr t x o b -> Expr t x o b |
| 145 | +simplify = |
| 146 | + cata unitIdentity |
| 147 | + -- . cata zeroIdentity |
| 148 | + . cata factNeg |
| 149 | + -- . \case [] -> Const aunit |
| 150 | + -- [x] -> x |
| 151 | + -- xs -> Sum xs |
| 152 | + -- . cata distSum |
| 153 | + -- . ana commuteLeft |
| 154 | + -- . cata mulBeforeSum |
| 155 | + |
| 156 | +-- {- Functions below here are helpers for simplifying the expression tree, used mainly in `simplify` -} |
| 157 | + |
| 158 | +-- | Algebra that simplifies sums, multiplications, expectations involving 0.0. |
| 159 | +-- BUG I need to add an additive typeclass constraint, otherwise aunit is just a pattern match. |
| 160 | +zeroIdentity : ExprF t x o b (Expr t x o b) -> Expr t x o b |
| 161 | +zeroIdentity (MulF (Const aunit) x) = Const aunit |
| 162 | +zeroIdentity (MulF x (Const aunit)) = Const aunit |
| 163 | +zeroIdentity (SumF xs) = Sum $ filter (not . isZero) xs |
| 164 | + where isZero (Const aunit) = True |
| 165 | + isZero _ = False |
| 166 | +zeroIdentity (E_F (Const aunit) _ _) = Const aunit |
| 167 | +zeroIdentity other = embed other |
| 168 | + |
| 169 | +-- | Algebra that simplifies multiplications and divisions by 1.0. |
| 170 | +unitIdentity : (Eq x, Eq b, Eq t, Eq o, Multiplicative x) => ExprF t x o b (Expr t x o b) -> Expr t x o b |
| 171 | +unitIdentity (MulF a b) | a == munit = b |
| 172 | +unitIdentity (MulF a b) | b == munit = a |
| 173 | +unitIdentity (InvF x) | x == munit = munit |
| 174 | +unitIdentity other = embed other |
| 175 | + |
| 176 | +-- | Algebra that collects and simplifies minuses. |
| 177 | +factNeg : ExprF t x o b (Expr t x o b) -> Expr t x o b |
| 178 | +factNeg (NegF (Neg x)) = x |
| 179 | +-- factNeg (MulF (Neg x) (Neg y)) = Mul (x, y) -- [ML] I think this is redundant |
| 180 | +factNeg (MulF (Neg x) y) = Neg $ Mul (x, y) |
| 181 | +factNeg (MulF y (Neg x)) = Neg $ Mul (y, x) |
| 182 | +factNeg (E_F (Neg x) t f) = Neg $ E x t f |
| 183 | +factNeg other = embed other |
| 184 | + |
| 185 | +-- -- | Turn any expression into a list of terms to be summed together |
| 186 | +-- distSum : ExprF t x o b [Expr t x o b] -> [Expr t x o b] |
| 187 | +-- distSum = \case |
| 188 | +-- ConstF x -> [Const x] |
| 189 | +-- SumF xs -> join xs |
| 190 | +-- MulF xs xs' -> curry Mul <$> xs <*> xs' |
| 191 | +-- NegF xs -> Neg <$> xs |
| 192 | +-- E_F xs t -> flip E t <$> xs |
| 193 | +-- I_F xs xs' -> [I (unroll xs, unroll xs')] |
| 194 | +-- ProcF{..} -> [Proc{..}] |
| 195 | +-- where unroll xs = Sum xs |
| 196 | + |
| 197 | +-- | Algebra that changes `(a + b) x c` to `c x (a + b)` |
| 198 | +-- mulBeforeSum : ExprF t x o b (Expr t x o b) -> Expr t x o b |
| 199 | +-- mulBeforeSum (MulF y@Sum{} x) = Mul (x, y) |
| 200 | +-- mulBeforeSum (MulF (Mul (x, y@Sum{})) x') = Mul (Mul (x,x'), y) |
| 201 | +-- mulBeforeSum other = embed other |
| 202 | + |
| 203 | +-- | Algebra that applies commutative property to all multiplications. |
| 204 | +-- commute : ExprF t x o b (Expr t x o b) -> Expr t x o b |
| 205 | +-- commute (MulF a b) = embed $ MulF b a |
| 206 | +-- commute other = embed other |
| 207 | + |
| 208 | +-- | Change e.g. `a x (b x c)` to `(a x b) x c`. |
| 209 | +-- We are not using commutative property, but rather associative --> should rename |
| 210 | +-- commuteLeft : Expr t x o b -> ExprF t x o b (Expr t x o b) |
| 211 | +-- commuteLeft (Mul (a,(Mul (b, c)))) = Mul (a, b) `MulF` c |
| 212 | +-- commuteLeft other = project other |
0 commit comments