符号微分的递归方案
Recursion scheme for symbolic differentiation
根据 this excellent series 中的术语,让我们用 Term Expr
表示一个表达式,例如 (1 + x^2 - 3x)^3
,其中数据类型如下:
data Expr a =
Var
| Const Int
| Plus a a
| Mul a a
| Pow a Int
deriving (Functor, Show, Eq)
data Term f = In { out :: f (Term f) }
是否有适合进行符号微分的递归方案?我觉得它几乎是专门针对 Term Expr
的 Futumorphism,即 futu deriveFutu
用于适当的函数 deriveFutu
:
data CoAttr f a
= Automatic a
| Manual (f (CoAttr f a))
futu :: Functor f => (a -> f (CoAttr f a)) -> a -> Term f
futu f = In <<< fmap worker <<< f where
worker (Automatic a) = futu f a
worker (Manual g) = In (fmap worker g)
这看起来不错,除了下划线变量是 Term
s 而不是 CoAttr
s:
deriveFutu :: Term Expr -> Expr (CoAttr Expr (Term Expr))
deriveFutu (In (Var)) = (Const 1)
deriveFutu (In (Const _)) = (Const 0)
deriveFutu (In (Plus x y)) = (Plus (Automatic x) (Automatic y))
deriveFutu (In (Mul x y)) = (Plus (Manual (Mul (Automatic x) (Manual _y)))
(Manual (Mul (Manual _x) (Automatic y)))
)
deriveFutu (In (Pow x c)) = (Mul (Manual (Const c)) (Manual (Mul (Manual (Pow _x (c-1))) (Automatic x))))
没有递归方案的版本如下所示:
derive :: Term Expr -> Term Expr
derive (In (Var)) = In (Const 1)
derive (In (Const _)) = In (Const 0)
derive (In (Plus x y)) = In (Plus (derive x) (derive y))
derive (In (Mul x y)) = In (Plus (In (Mul (derive x) y)) (In (Mul x (derive y))))
derive (In (Pow x c)) = In (Mul (In (Const c)) (In (Mul (In (Pow x (c-1))) (derive x))))
作为这个问题的扩展,是否有一个递归方案来区分和消除 "empty" Expr
s ,例如 Plus (Const 0) x
作为微分的结果 - 在一个传递数据?
查看产品的差异化规则:
(u v)' = u' v + v' u
要使产品与众不同,您需要知道什么?你需要知道子项的导数(u'
,v'
),以及它们的值(u
,v
)。
这正是 paramorphism 给你的。
para
:: Functor f
=> (f (b, Term f) -> b)
-> Term f -> b
para g (In a) = g $ (para g &&& id) <$> a
derivePara :: Term Expr -> Term Expr
derivePara = para $ In . \case
Var -> Const 1
Const _ -> Const 0
Plus x y -> Plus (fst x) (fst y)
Mul x y -> Plus
(In $ Mul (fst x) (snd y))
(In $ Mul (snd x) (fst y))
Pow x c -> Mul
(In (Const c))
(In (Mul
(In (Pow (snd x) (c-1)))
(fst x)))
在同构内部,fst
使您可以访问子项的导数,而 snd
为您提供项本身。
As an extension to this question, is there a recursion scheme for differentiating and eliminating "empty" Exprs such as Plus (Const 0)
x that arise as a result of differentiation -- in one pass over the data?
是的,它仍然是一个paramorphism。最简单的方法是使用智能构造函数,例如
plus :: Term Expr -> Term Expr -> Expr (Term Expr)
plus (In (Const 0)) (In x) = x
plus (In x) (In (Const 0)) = x
plus x y = Plus x y
并在定义代数时使用它们。你也可以将其表达为某种 para-cata 融合。
根据 this excellent series 中的术语,让我们用 Term Expr
表示一个表达式,例如 (1 + x^2 - 3x)^3
,其中数据类型如下:
data Expr a =
Var
| Const Int
| Plus a a
| Mul a a
| Pow a Int
deriving (Functor, Show, Eq)
data Term f = In { out :: f (Term f) }
是否有适合进行符号微分的递归方案?我觉得它几乎是专门针对 Term Expr
的 Futumorphism,即 futu deriveFutu
用于适当的函数 deriveFutu
:
data CoAttr f a
= Automatic a
| Manual (f (CoAttr f a))
futu :: Functor f => (a -> f (CoAttr f a)) -> a -> Term f
futu f = In <<< fmap worker <<< f where
worker (Automatic a) = futu f a
worker (Manual g) = In (fmap worker g)
这看起来不错,除了下划线变量是 Term
s 而不是 CoAttr
s:
deriveFutu :: Term Expr -> Expr (CoAttr Expr (Term Expr))
deriveFutu (In (Var)) = (Const 1)
deriveFutu (In (Const _)) = (Const 0)
deriveFutu (In (Plus x y)) = (Plus (Automatic x) (Automatic y))
deriveFutu (In (Mul x y)) = (Plus (Manual (Mul (Automatic x) (Manual _y)))
(Manual (Mul (Manual _x) (Automatic y)))
)
deriveFutu (In (Pow x c)) = (Mul (Manual (Const c)) (Manual (Mul (Manual (Pow _x (c-1))) (Automatic x))))
没有递归方案的版本如下所示:
derive :: Term Expr -> Term Expr
derive (In (Var)) = In (Const 1)
derive (In (Const _)) = In (Const 0)
derive (In (Plus x y)) = In (Plus (derive x) (derive y))
derive (In (Mul x y)) = In (Plus (In (Mul (derive x) y)) (In (Mul x (derive y))))
derive (In (Pow x c)) = In (Mul (In (Const c)) (In (Mul (In (Pow x (c-1))) (derive x))))
作为这个问题的扩展,是否有一个递归方案来区分和消除 "empty" Expr
s ,例如 Plus (Const 0) x
作为微分的结果 - 在一个传递数据?
查看产品的差异化规则:
(u v)' = u' v + v' u
要使产品与众不同,您需要知道什么?你需要知道子项的导数(u'
,v'
),以及它们的值(u
,v
)。
这正是 paramorphism 给你的。
para
:: Functor f
=> (f (b, Term f) -> b)
-> Term f -> b
para g (In a) = g $ (para g &&& id) <$> a
derivePara :: Term Expr -> Term Expr
derivePara = para $ In . \case
Var -> Const 1
Const _ -> Const 0
Plus x y -> Plus (fst x) (fst y)
Mul x y -> Plus
(In $ Mul (fst x) (snd y))
(In $ Mul (snd x) (fst y))
Pow x c -> Mul
(In (Const c))
(In (Mul
(In (Pow (snd x) (c-1)))
(fst x)))
在同构内部,fst
使您可以访问子项的导数,而 snd
为您提供项本身。
As an extension to this question, is there a recursion scheme for differentiating and eliminating "empty" Exprs such as
Plus (Const 0)
x that arise as a result of differentiation -- in one pass over the data?
是的,它仍然是一个paramorphism。最简单的方法是使用智能构造函数,例如
plus :: Term Expr -> Term Expr -> Expr (Term Expr)
plus (In (Const 0)) (In x) = x
plus (In x) (In (Const 0)) = x
plus x y = Plus x y
并在定义代数时使用它们。你也可以将其表达为某种 para-cata 融合。