在同情中巧妙地重写表达

时间:2016-02-11 00:54:08

标签: python sympy equation

我发现解释起来很棘手,但我会通过一个例子尽我所能。

考虑分配给

下面的变量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 :.

我不确定这是否可行,但了解它是否有可能在某种程度上这样做会很有趣。

2 个答案:

答案 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),其中cancelp/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}}