我发现解释起来很棘手,但我会通过一个例子尽我所能。
考虑分配给
下面的变量grad
的表达式
from sympy import *
a, x, b = symbols("a x b")
y_pred = a * x
loss = log(1 + exp(- b * y_pred))
grad = diff(loss, x, 1)
grad
具有以下表达式:
-a*b*exp(-a*b*x)/(1 + exp(-a*b*x))
现在我想以两种方式操纵grad
。
1)我希望sympy
尝试重写表达式grad
,使其所有术语都不像
exp(-a*b*x)/(1 + exp(-a*b*x))
。
2)我还希望它尝试重写表达式,使其至少有一个看起来像1./(1 + exp(a*b*x))
的术语。
最后,grad
变为:
-a*b/(1 + exp(a*b*x)
请注意,1./(1 + exp(a*b*x))
相当于exp(-a*b*x)/(1 + exp(-a*b*x))
,但我不想明确提及sympy
:.
我不确定这是否可行,但了解它是否有可能在某种程度上这样做会很有趣。
答案 0 :(得分:1)
您是否只是在寻找--
-- Test of XMaybe and XMonad
--
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Main (main) where
-------------------------------------------------------------------------------
type family BoolAnd a b :: Bool where
BoolAnd True a = a
BoolAnd False a = False
-------------------------------------------------------------------------------
class XMonad (tc :: k -> * -> *) (af :: k) (bf :: k) where
type XResultT tc af bf :: k
(>>~) :: tc af a -> (a -> tc bf b) -> tc (XResultT tc af bf) b
-------------------------------------------------------------------------------
data XMaybe :: Bool -> * -> * where
XNothing :: XMaybe False a
XJust :: a -> XMaybe True a
-- Polymorphism problem in `test` resolved by only having one instance of
-- `XMonad` for `XMaybe`. Still need ResultT to tell the class which type to
-- use for (>>~), but can compute that for all cases with a more generally
-- useful indexed type family. The implementation cases for (>>~) are handled
-- by normal pattern-matching.
--
-- Question - can the compiler optimise away run-time costs for this seemingly
-- resolvable-at-compile-time data constructor matching?
--
-- I suspect not, if only because of the possibility that the first argument
-- is undefined, so that data constructor cannot be forced. It's slightly
-- unfortunate if I'm right - although it's not the main point, one reason
-- for knowing whether XJust or XNothing applies at the type level is to
-- avoid those overheads. Conceptually, `XMaybe` is a compile-time choice
-- between two newtypes. XNothing has no components, but you could add a ()
-- component. The GADT implementation here presumably means the newtype cost
-- model doesn't apply.
instance XMonad XMaybe af bf where
type XResultT XMaybe af bf = BoolAnd af bf
(>>~) XNothing _ = XNothing
(>>~) (XJust x) f = f x
instance Show a => Show (XMaybe f a) where
show (XJust x) = "XJust (" ++ (show x) ++ ")"
show XNothing = "XNothing"
-------------------------------------------------------------------------------
-- Deliberately not using Proxy here.
--
-- The idea is that get and put are optional interfaces. You query for those
-- interfaces in a vaguely COM-like sense, with usage patterns similar to the
-- three examples in the `test` function below, and you do that just before
-- using those interfaces.
--
-- The only reason `get` and `put` aren't provided directly as class members
-- is they might not exist (with the assumption that having lots of classes
-- and lots of constraints would be impractical). So you `queryGet` and/or
-- `queryPut` to access the relevant functions if they exist.
--
-- Since the value you call `queryGet` for is the same value you call `get`
-- for, you should always have a suitable value of the correct type to pass to
-- `queryGet`. So you should be able to write `queryGet x`, as opposed to
-- `queryGet (Proxy :: Proxy a).
--
-- In short, even though `queryGet` and co. don't use the value of their first
-- argument, life is IMO easier in this case if you pretend they do.
--
-- Also, maybe for some other instance, they will - which function *could* be
-- chosen based on the run-time value and that's perfectly valid, even if that
-- option is rarely or never used.
class TestClass a where
type GetEnabled a :: Bool
type PutEnabled a :: Bool
queryGet :: a -> XMaybe (GetEnabled a) (a -> Int)
queryPut :: a -> XMaybe (PutEnabled a) (a -> Int -> a)
-------------------------------------------------------------------------------
newtype TestA = TestA Int deriving Show
newtype TestB = TestB Int deriving Show
newtype TestC = TestC Int deriving Show
instance TestClass TestA where
type GetEnabled TestA = True
type PutEnabled TestA = True
queryGet _ = XJust (\(TestA x) -> x)
queryPut _ = XJust (\(TestA x) y -> TestA (x + y))
instance TestClass TestB where
type GetEnabled TestB = False
type PutEnabled TestB = True
queryGet _ = XNothing
queryPut _ = XJust (\(TestB x) y -> TestB (x + y))
instance TestClass TestC where
type GetEnabled TestC = True
type PutEnabled TestC = False
queryGet _ = XJust (\(TestC x) -> x)
queryPut _ = XNothing
-------------------------------------------------------------------------------
test :: ( TestClass a, Show a
) => a -> IO ()
test x0 = do
putStrLn "--------------------"
putStr " x0 = "
print x0
let x1 = queryGet x0 >>~ \get ->
XJust $ get x0
putStr " x1 (using get only) = "
print x1
let x2 = queryPut x0 >>~ \put ->
XJust $ put x0 13
putStr " x2 (using put only) = "
print x2
let x3 = queryGet x0 >>~ \get ->
queryPut x0 >>~ \put ->
XJust $ (get x0, put x0 13)
putStr " x3 (using get and put) = "
print x3
putStrLn "--------------------"
-------------------------------------------------------------------------------
main :: IO ()
main = do test (TestA 3)
test (TestB 4)
test (TestC 5)
-------------------------------------------------------------------------------
?
simplify
答案 1 :(得分:1)
In [16]: cancel(grad)
Out[16]:
-a⋅b
──────────
a⋅b⋅x
ℯ + 1
执行此操作
-a*b*(1/A)/(1 + 1/A)
这是有效的,因为它将表达式视为A = exp(a*b*x)
,其中cancel
和p/q
将有理函数重写为已取消A = exp(a*b*x)
(请参阅cancel部分在SymPy教程中获取更多信息)。
请注意,这仅适用,因为它使用A = exp(-a*b*x)
而不是cancel
。例如,In [17]: cancel(-a*b*exp(a*b*x)/(1 + exp(a*b*x)))
Out[17]:
a⋅b⋅x
-a⋅b⋅ℯ
────────────
a⋅b⋅x
ℯ + 1
不会在此处进行类似的简化
{{1}}