相同的代码在Mathematica中有效,但在Matlab中则无效

时间:2018-05-20 21:29:33

标签: matlab wolfram-mathematica

我在下面发布的代码有问题。从这段代码中我知道会发生什么:我需要只有一个(正)特征值等于1,而无论a的值是多少,我的名称qfi必须等于4(因为a的值增加我必须增加模式的数量以获得正确的结果,但这是预期的。并不是那样,但是,例如,如果我有一个= 10的150模式得到qfi 3.99986,这是好的)。

此代码在Mathematica中运行完美。问题是我需要编写比这更复杂的东西,我不知道如何正确使用mathematica,所以我想使用matlab。但是在Matlab中它根本不起作用,即使在一切都被很好地定义的情况下(因为如果我在Matlab中增加模式的数量,我在矩阵中得到NaN)。例如,对于a = 2的模式= 100(这是一个很好的模式数量),我得到qfi 80.0000。

所以,如果有人发现错误,我会发布这两个代码。我想这与精度有关,但我在网上发现的关于提高精度的内容提到了符号工具箱。还有别的我可以做的吗?

我很抱歉发布了整个代码,但我已经挣扎了几天。

Mathematica代码:(复制得不太好)

modes = 100;

a = 2;

neg = 0;

(* the (l,m) element of the matrix *)

g[l_, m_] := (a^(l + m) E^-a^2)/Sqrt[Factorial[l]*Factorial[m]]

ρ = N[Table[g[l, m], {l, 0, modes}, {m, 0, modes}]];

tr = Tr[ρ]

ρnorm = ρ*(1/tr);

(*I find the eigenvalues and vectors. We want 1 eigenvalue equal to 1 and 
  all the others 0 *)

eige = Eigenvalues[ρnorm];

eige = Chop[eige];

vec = Eigenvectors[ρnorm];

vec = Chop[vec];

For[i = 0, i <= modes, i++, x = eige[[i]]; If[x < 0, neg = neg + 1]];

neg

0

Length[eige] - Count[eige, 0]

1

Max[eige]

1.

(* A second matrix like the first one *)

deriv[k_, n_] := (a^(-1 + k + n) E^-a^2 (-2 a^2 + k + n))/ Sqrt[k! n!]

derρ = N[Table[deriv[k, n], {k, 0, modes}, {n, 0, modes}]];

derρ = Chop[derρ];

L = 0;

For[i = 0, i <= modes, i++;
 For[j = 0, j <= modes , modes, j++;
   If[eige[[i]] + eige[[j]] != 0,
    (*I multiply eigenvectors with the derρ matrix *)
    rd = vec[[i]].derρ.tra[vec[[j]]];
    rd = Chop[rd];
    rd = rd[[1]];

    (*I multiply an eigenvector with the transpose of an other one and \
         I create the L matrix *)
    L = L + rd/(eige[[i]] + eige[[j]])*tra[vec[[i]]].{vec[[j]]}
    ]]]


    L = 2*L;
    L = Chop[L];

    qfi = Tr[ρnorm.L.L]

    4.

MatLab代码(rhodiff =derρ):

modes=100;
acc=1e-15;
a=2;
rho=zeros(modes,modes);
rhodiff=zeros(modes,modes);

for l=1:modes
    for m=1:modes
    rho(l,m)=(a^(l+m-2))*exp(-a^2)/(sqrt(factorial(l-1)*factorial(m-1)));
    end
end

tr=trace(rho);
rhonorm=rho/tr;

[V,D]=eig(rhonorm);
D(abs(D)<acc)=0;

for l=1:modes
    for m=1:modes
    rhodiff(l,m)=(a^(l+m-1))*(-2*a^2+l+m)*exp(-a^2)/(sqrt(factorial(l-1)*factorial(m-1)));
    end
 end

 L=zeros(modes,modes);

 for i=1:modes
    for j=1:modes
        if D(i,i)+D(j,j)~=0
        rd=((V(:,i)')*rhodiff*V(:,j));   
        rd(abs(rd)<acc)=0; 

        L=L+(((rd/(D(i,i)+D(j,j))))*V(:,i)*V(:,j)');
        L(abs(L)<acc)=0;
        end
    end
end

L=2*L;
qfi=trace(rhonorm*L*L)

1 个答案:

答案 0 :(得分:2)

问题几乎肯定是由于精确度。在Matlab中,默认为双精度。在您的代码中,您一度在计算s = self.surrounding() surroundingBool = [False if i == None else True for i in s] r1 = random.random() r2 = random.random() r3 = random.random() if r1 <= 0.333: if r3 < 0.5 and not surroundingBool[4]: self.x += 1 elif not surroundingBool[3]: self.x -= 1 elif r1 <= 0.666: if r3 < 0.5 and not surroundingBool[6]: self.y += 1 elif not surroundingBool[1]: self.y -= 1 else: if r2 < 0.25 and not surroundingBool[7]: self.x += 1 self.y += 1 elif r2 < 0.5 and not surroundingBool[2]: self.x += 1 self.y -= 1 elif r2 < 0.75 and not surroundingBool[5]: self.x -= 1 self.y += 1 elif not surroundingBool[0]: self.x -= 1 self.y -= 1 self.x %= width self.y %= height self.pos = self.y * width + self.x 。这是一个非常大的数字。

在Matlab中,该数字的表示将限制为双精度。在Mathematica中,因为它是一个整数,我的猜测是它可以精确地表示这个数字。

最好的做法是让你的计算在数值上更稳定。最好的方法是转换表单的表达式

factorial(modes-1)*factorial(modes-1)

进入产品,这样你就不必在内存中真正拥有一些非常大的数字。例如,似乎上述表达式可以等效地写为

(a^(l+m-2))*exp(-a^2)/(sqrt(factorial(l-1)*factorial(m-1)))

此版本从未要求您计算类似exp(-a^2) * prod( a ./ sqrt(1:l-1) ) * prod( a ./ sqrt(1:m-1) )的内容,这些内容无法以双精度精确表示。

我没有检查过,但它看起来像你的另一个表达

factorial(100)

可以写成

(a^(l+m-1))*(-2*a^2+l+m)*exp(-a^2)/(sqrt(factorial(l-1)*factorial(m-1)))