SymPy中的符号熵最大化

时间:2017-09-06 01:09:24

标签: sympy

物理学中统计力学中熵最大化的一个简单问题如下:

目标是最大化熵函数(在stackexchange中仍然缺少LaTeX?):

H = - sum_x P_x ln P_x

受以下约束:标准化约束

1 = sum_x P_x

和平均能量的约束

U = sum_i E_x P_x

其中索引i在x = 1,2,...,n上运行。 E_x表示系统处于微观状态x时的能量,P_x是系统处于微观状态x的概率。

可以通过Lagrange multipliers的方法获得对这种问题的解决方案。在这种情况下,它的工作原理如下......

首先,拉格朗日定义为

L = H + a(1 - sum_i P_x)+ b(U - sum_i P_x E_x)

这里,a和b是拉格朗日乘数。拉格朗日L是a,b的函数,x = 1,2,...,n的概率P_x。术语a(1 - sum_x P_x)对应于归一化约束,术语b(E - sum_x P_x E_x)对应于平均能量约束。

其次,计算L对于a,b的偏导数和对于不同x = 1,2,...,n的P_x。这导致

dL / da = 1 - sum_x P_x

dL / db = E - sum_x E_x P_x

dL / P_x = dH / P_x - a - b E_x         = - ln P_x - 1 - a - b E_x

第三,我们通过将这些衍生物等同为零来找到解决方案。这是有道理的,因为有2 + n个方程,我们有2 + n个未知数:P_x,a和b。这些方程的解决方案是

P_x = exp( - b E_x)/ Z

,其中

Z = sum_x exp( - b E_x)

和b由关系

隐式确定

E = sum_x P_x E_x =(1 / Z)sum_x exp(-b E_x)E_x

现在已经定义了“数学”问题,让我们说出“计算”问题(这是我想要问的问题)。

计算问题如下:我想在Sympy中重现先前的推导。

这个想法是让这个过程自动化,最终,我可以攻击类似但更复杂的问题。

我已经取得了一些进展。不过,我认为我还没有使用最佳方法。这是我的解决方案。

# Lets attempt to derive these analytical result using SymPy.

import sympy as sy
import sympy.tensor as syt

# Here, n is introduced to specify an abstract range for x and y.
n = sy.symbols( 'n' , integer = True )
a , b = sy.symbols( 'a b' ) # The Lagrange-multipliers.
x = syt.Idx( 'x' , n ) # Index x for P_x
y = syt.Idx( 'y' , n ) # Index y for P_y; this is required to take derivatives according to SymPy rules.

>>> P = syt.IndexedBase( 'P' ) # The unknowns P_x.
>>> E = syt.IndexedBase( 'E' ) # The knowns E_x; each being the energy of state x.
>>> U = sy.Symbol( 'U' ) # Mean energy.
>>> 
>>> # Entropy
>>> H = sy.Sum( - P[x] * sy.log( P[x] ) , x )
>>> 
>>> # Lagrangian
>>> L = H + a * ( 1 - sy.Sum( P[x] , x ) ) + b * ( U - sy.Sum( E[x] * P[x] , x ) )

>>> # Lets compute the derivatives
>>> dLda = sy.diff( L , a )
>>> dLdb = sy.diff( L , b )
>>> dLdPy = sy.diff( L , P[y] )

>>> # These look like
>>> 
>>> print dLda
-Sum(P[x], (x, 0, n - 1)) + 1
>>> 
>>> print dLdb
U - Sum(E[x]*P[x], (x, 0, n - 1))
>>>  
>>> print dLdPy
-a*Sum(KroneckerDelta(x, y), (x, 0, n - 1)) - b*Sum(KroneckerDelta(x, y)*E[x], (x, 0, n - 1)) + Sum(-log(P[x])*KroneckerDelta(x, y) - KroneckerDelta(x, y), (x, 0, n - 1))

>>> # The following approach does not work
>>> 
>>> tmp = dLdPy.doit()
>>> print tmp
-a*Piecewise((1, 0 <= y), (0, True)) - b*Piecewise((E[y], 0 <= y), (0, True)) + Piecewise((-log(P[y]) - 1, 0 <= y), (0, True))
>>>     
>>> sy.solve( tmp , P[y] )
[]

>>> # Hence, we try an ad-hoc procedure
>>> Px = sy.Symbol( 'Px' )
>>> Ex = sy.Symbol( 'Ex' )
>>> tmp2 = dLdPy.doit().subs( P[y] , Px ).subs( E[y] , Ex ).subs( y , 0 )
>>> print tmp2
-Ex*b - a - log(Px) - 1

>>> Px = sy.solve( tmp2 , Px )
>>> print Px
[exp(-Ex*b - a - 1)]

是否有“更好”的方式继续进行?特别是,我不喜欢用Px代替P [y]和用Ex代替E [y]来解决方程。为什么方程不能用P [y]来解决?

0 个答案:

没有答案