python中动作的数值最小化

计算科学 计算物理学 软件
2021-12-11 22:27:11

我想找到轨迹x(t)最小化动作S=titfL(x(t),x˙(t))dt数字上。

我试图通过离散化动作来做到这一点,因此它更像是一个接受向量而不是函数的函数。更准确地说,给定轨迹的初始猜测{xi}我试图找到轨迹{xi}最小化总和i=0N1m2Δt(xi+1xi)2k2xi2Δt(这是 SHO 操作的离散化版本)然后我使用 scipy 的向下单纯形法/nelder-mead 最小化函数来执行此操作,但是它无法正常工作。

我正在关注一个参考,它说轨迹的初始猜测可以是初始位置x0其余位置可以是初始位置加上围绕问题长度尺度的变化x0+δj,j=1,,N1. (此处为第 39 页)。但是它仍然不起作用。我试图使变化更小,但仍然不起作用。似乎要让它发挥作用,我需要为它提供一个与实际轨迹相当接近的近似值,但这违背了练习的目的。这是代码:

import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt

%matplotlib inline

t_i = 0
t_f = 7
N = 100
delta_t = (t_f - t_i)/N
m = 1
k = 1

def action(x, N, m, delta_t, k):
    """
    This function will take in an array of positions x_i w/ x_i = x(t_i). Then it computes the action for this trajectory.
    We want to, given an initial position and a guess for the rest of the components, find the set of x_i which minimizes
    the action, and return it. Scipy 'optimize' does it. See the first example in the documentation for a similar problem.
    """
    tot = np.array([])
    for i in range (0,N-1):
            np.append(tot,((m/(2*delta_t))*((x[i+1]-x[i])**2)-((k*delta_t)/2)*((x[i])**2)))
    return np.sum(tot)

x_0 = np.ones(100)
var = np.random.rand(100)
x0 = x_0 + var

res = minimize(action, x0, args=(N, m, delta_t, k), method='Nelder-Mead',options={'disp': True})

time = np.linspace(0,7,100)

fig = plt.figure()
axes = fig.add_axes([0,0,1.25,1])
axes.plot(time,res.x)
2个回答

我要指出,为了解决任何功能最小化问题,您需要指定初始条件。在这种情况下,最小化对应于二阶系统,因此您必须指定运动的初始值和结束值,或初始值和一阶导数(或您真正喜欢的任何其他条件对)。

没有这个,就不能保证你能找到一个极值,这让我想到了下一点:一般来说,与动作变化相关的运动方程只确定一个极值,而不一定是一个最小值。所以配置空间中的这个点可能是一个最小值、最大值,甚至是一个鞍点。

为了补充第一点,让我指出这个PSE 帖子,它计算 SHO 在极值处的动作值(它们固定初始和最终位置)。请注意,对于结束时间的某些值,t,作为开始/结束位置的函数,动作的值可以任意变为负值。因此,对于某些值t,如果你不固定开始和结束位置(不固定你的初始值),最小化器会给你奇怪的答案,因为事实是当开始/结束位置去无穷大时,动作的值会变为负无穷大.

所有这些实际上只是为了指出边界条件在形成适定变分问题中的必要性。

如果您可以访问 Jackson 的 E&M 书籍的最新副本,这也可能会引起您的兴趣:他付出了一些努力来包括基本的数值方法。我相信其中一个本质上是按照您的建议进行精确操作的方法,但是针对的是静电场。我认为,在场论中,对边界条件的需求在数值应用中变得更加明显,而在 ODE 中有时很容易忘记它们。

我不会抱怨形式主义——我不知道它是否会起作用。

但是,目前它确实不起作用,因为您的操作始终为 0: np.append 不附加元素,它返回一个附加元素的数组。所以你的tot数组总是空的:

将行更改为:

tot=np.append(tot,  .... )

或使用类似数组的形式(更快):

def action(x, N, m, delta_t, k):

    f= (m/2./delta_t)*(np.diff(x))**2-k*delta_t/2*(np.array(x)[:-1])**2
    return f.sum()

它也不会快速收敛 - 所以你必须设置

options={"disp":True, "maxiter": N_iter}

在您最小化的调用中,N_iter 足够大以使其收敛。

您似乎也总是在同一方向上选择随机位移,我会使用

var=np.random.randn() 

[正常位移从x0] 要么

var = 0.5-np.random.rand(100)

在 (-0.5, 0.5) 有位移。

另外,也许噪音很大?1±1是很多噪音。也许做1±0.2或类似的初学者?

希望这有帮助。

这是我的结果(蓝色输入,橙色输出),噪声为 var = 0.1*(0.5-np.random.rand(100)),更多步数 (N=1000) 和 N_iter=50000(仍然没有收敛虽然..但这是您深入了解您的程序的第一步!)

在此处输入图像描述