物理学中统计力学中熵最大化的一个简单问题如下:
目标是最大化熵函数(在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]来解决?