Tsallis熵的约束最小化

计算科学 算法
2021-12-25 12:43:41

当应用于 Tsallis 熵时,我正在寻找使用最大熵原理找到速度分布。

Tsallis 熵定义为:

ST=1q1(1f(p)qdp)

我有以下约束:

f(p)dp=1pf(p)dp=0p2f(p)dp=1p3f(p)dp=0

使用这些约束并结合拉格朗日乘子,的方程变为:ST

ST=1q1(1f(p)qdp)+λ0(f(p)dp1)+λ1(pf(p)dp)+λ2(p2f(p)dp1)+λ3(p3f(p)dp)

相对于的变化并将其等同于 0,分布函数变为: STf(p)

f(p)=[(q1q)(λ0+λ1p+λ2p2+λ3p3)]1q1

然后整个问题归结为求解拉格朗日乘数。但是,我无法使用 Newton-Raphson 解决这个问题。谁能给我一些关于如何继续解决这个问题的指示。我的包含前三个约束的 MATLAB Newton Raphson 代码如下所示。任何帮助,将不胜感激:

%Here we use Newton_Solver

clear all;
clc;


%Initial Trials
lambda(1,1) = -1.5;
lambda(2,1) = 0.0;
lambda(3,1) = 0.09;
lambda(4,1) = 0.09;

ll = -5;
ul = 5;
steps = 10000;
iter = 1500;
i = 0;
q = 1.5; %Tsallis q index
while(i<iter)
    func_val = zeros(4,1);
    Jacobian_mat = zeros(4,4);

    avg_v0 = 0.0;
    avg_v1 = 0.0;
    avg_v2 = 0.0;
    avg_v3 = 0.0;
    avg_v4 = 0.0;
    avg_v5 = 0.0;
    avg_v6 = 0.0;    
    for(j=1:steps)
        p = ll+(ul-ll)*j/steps;
        temp = (lambda(1) + lambda(2)*p + lambda(3)*p*p + lambda(4)*p*p*p)*(q-1)/q;
        temp = temp^(1/(q-1));
        temp = temp*(ul-ll)/steps;

        func_val(1) = func_val(1) + temp;
        func_val(2) = func_val(2) + temp*p;
        func_val(3) = func_val(3) + temp*p*p;
        func_val(4) = func_val(4) + temp*p*p*p;

        temp1 = lambda(1) + lambda(2)*p + lambda(3)*p*p + lambda(4)*p*p*p;
        temp1 = temp1^((2-q)/(q-1));
        temp1 = temp1*((q-1)/q)^(1/(q-1))/(q-1);
        temp1 = temp1*(ul-ll)/steps;

        avg_v0 = avg_v0 + temp1;
        avg_v1 = avg_v1 + temp1*p;
        avg_v2 = avg_v2 + temp1*p*p;
        avg_v3 = avg_v3 + temp1*p*p*p;
        avg_v4 = avg_v4 + temp1*p*p*p*p;
        avg_v5 = avg_v5 + temp1*p*p*p*p*p;
        avg_v6 = avg_v6 + temp1*p*p*p*p*p*p;

    end

    Jacobian_mat(1,1) = avg_v0;    
    Jacobian_mat(1,2) = avg_v1;   
    Jacobian_mat(1,3) = avg_v2;
    Jacobian_mat(1,4) = avg_v3;

    Jacobian_mat(2,1) = avg_v1;    
    Jacobian_mat(2,2) = avg_v2;
    Jacobian_mat(2,3) = avg_v3;
    Jacobian_mat(2,4) = avg_v5;

    Jacobian_mat(3,1) = avg_v2;    
    Jacobian_mat(3,2) = avg_v3;
    Jacobian_mat(3,3) = avg_v4;
    Jacobian_mat(3,4) = avg_v5;

    Jacobian_mat(4,1) = avg_v3;    
    Jacobian_mat(4,2) = avg_v4;
    Jacobian_mat(4,3) = avg_v5;
    Jacobian_mat(4,4) = avg_v6;

    func_val(1) = func_val(1) - 1.0;
    func_val(2) = func_val(2) - 0.0;
    func_val(3) = func_val(3) - 1.0;
    func_val(4) = func_val(4) - 0.0;

    Jacobian_inv = Jacobian_mat^(-1);
    lambda = lambda - Jacobian_inv*func_val*1.0;

    Disp_val = ['Step is: ',num2str(i), ' Lambda 1 values:', num2str(lambda(1,1))];
    Disp_val1 = ['Step is: ',num2str(i), ' Lambda 2 values:', num2str(lambda(2,1))];
    Disp_val2 = ['Step is: ',num2str(i), ' Lambda 3 values:', num2str(lambda(3,1))];
    Disp_val3 = ['Step is: ',num2str(i), ' Lambda 4 values:', num2str(lambda(4,1))];
    Disp_val4 = ['Step is: ',num2str(i), ' AVG 1 values:', num2str(func_val(1) + 1.0)];
    Disp_val5 = ['Step is: ',num2str(i), ' AVG 2 values:', num2str(func_val(2) + 0.0)];
    Disp_val6 = ['Step is: ',num2str(i), ' AVG 3 values:', num2str(func_val(3) + 1.0)];
    Disp_val7 = ['Step is: ',num2str(i), ' AVG 4 values:', num2str(func_val(4) + 0.0)];

    disp(Disp_val);
    disp(Disp_val1);
    disp(Disp_val2);
    disp(Disp_val3);
    disp(Disp_val4);
    disp(Disp_val5);
    disp(Disp_val6);
    disp(Disp_val7);
    disp(' ');
    i = i+1;
end
1个回答

大概,你想最大化熵,所以在你上面介绍的阐述之后,你有类似的东西:

minλ0,,λ31q1(1[(q1q)(λ0+λ1p+λ2p2+λ3p3)]qq1dp)

你想做无约束的最小化。在这里,我使用的事实是大多数优化问题都被视为最小化问题,并且maxxg(x)=minxg(x)

我对您的代码的主要评论是:

  • 如果可以的话,不要手动执行牛顿法(用于方程求解)。人们把它搞砸了,在设置收敛容差时,库例程更加健壮。fsolveMATLAB 将其作为优化工具箱的一部分包含在例程中。你可能没有那个工具箱(工具箱很贵,所以个人和机构不一定有),在这种情况下,我鼓励你找到另一个工具箱(Python 肯定有,Octave 可能)。
  • 出于同样的原因,请勿手动执行牛顿法(用于无约束优化)。MATLAB 再次将此例程作为优化工具箱的一部分。您可以通过调用它fminunc数值算法中的错误可能非常微妙,并且会以深远的方式影响您的结果。通过消除另一个错误来源,使用库可以节省大量时间。
  • 一般来说,不要计算矩阵的显式逆。建立并求解一个等效线性系统。在 MATLAB 中,为此目的使用反斜杠运算符。
  • 如果收敛是一个问题并且您必须手动编写牛顿方法,请考虑构建类似线搜索的稳健性,并添加一些容错检查,因此您不必运行所有 1500 次迭代。这些功能通常包含在库中,所以就像我说的那样,访问一个而不是自己编写这些(这是另一个错误来源,而且很耗时)。
  • 向量化您对积分的评估。就此而言,如果可能,请对所有函数评估进行矢量化。您明确地循环遍历所有内容,并逐个元素地构造数组。这些过程很慢,因为您无法利用从已编译库链接的任何快速 MATLAB 例程。
  • 模块化你的代码。您应该能够将您的目标函数、梯度和 Hessian 评估移动到它们自己的函数中(或者如果您想重用集成中的信息,也可以是计算两个或三个这些量的组合函数)。以这种方式重构您的代码将使其更易于阅读和测试。
  • 使您的代码自我记录。明智地添加评论。人们会花更多的时间阅读你的代码而不是你编写它。很难通过您的部分代码,因为我不知道avg_v0应该是什么意思,除了,嗯,它是某种平均水平。如果您的主要受众是您的应用领域中的某个人,那么这种命名方式可能很好。您已将代码发布到通用计算科学留言板上,因此我鼓励您将其提供给通用计算科学家。我也不知道是什么temp意思,除了它是一个临时变量。
  • 测试你的代码。如果您已将代码模块化,您应该能够使用单元测试以自动化方式对其进行测试。MATLAB xUnit 是一个很好的库。更高版本的 MATLAB 内置了单元测试功能。您应该能够使用的值构造示例,qλii=0,,3这样您就可以根据您可以手动分析计算的值检查目标函数、梯度和 Hessian 的评估。为此,您还可以使用 Maple、Mathematica、Sage 或 SymPy 等计算机代数系统(在此过程中,实际导出梯度和 Hessian 函数,以减少另一个错误来源:数学差)。测试意味着编写更多的代码,但也意味着调试更容易,因为您有更多的诊断方法可以用来查找错误,以及识别这些错误的更系统的方法。
  • 看看Software Carpentry,它讨论了很多关于测试、模块化、自记录代码等的观点。(免责声明:我为 Software Carpentry 做了一些志愿者工作。)