2014-08-31 87 views
1

我对二叉树有一个向后递归。在每个节点上,一个未知的C以这样一种方式进入,即在起始节点处我们得到一个公式,A(1,1),取决于C。代码如下:在Matlab中加速符号递归

A=sym(zeros(1,Steps)); 
B=zeros(1,Steps); 
syms C; % The unknown that enters A at every node 
tic 
for t=Steps-1:-1:1 

% Values needed in A and B 
Lambda=1-exp(-(1./S(t,1:t).^b).*h); 
Q=((1./D(t))./(1-Lambda)-d)/(u-d); 
R=normcdf(a0+a1*Lambda); 

% the backward recursion for A and B 
A(1:t)=D(t)*C+D(t)*... 
    (Q.*(1-Lambda).*A(1:t) ... 
     + (1-Q).*(1-Lambda).*A(2:t+1)); 

B(1:t)=Lambda.*(1-R)+D(t)*... 
    (Q.*(1-Lambda).*B(1:t)... 
     + (1-Q.*(1-Lambda).*B(2:t+1))); 
end 

C = solve(A(1,1)==sym(B(1,1)),C); 

此代码大约需要4秒,如果Steps = 104。但是,如果我们删除C并将矩阵A设置为常规双矩阵,则只需要大约0.02秒。因此使用syms可将计算时间增加200倍。这对我来说似乎太多了。任何建议加快这一点?

我用Matlab 2013b上的一台MacBook Air 13英寸的2013年春季。此外,如果你有兴趣在上面的部分(不知道是否是相关的)之前的代码:

a0 = 0.9; 
a1 = -3.2557; 
b = 1.2594; 
S0=18.57; 
sigma=0.6579; 
h=1/104; 
T=1; 
Steps=T/h; 
f=transpose(normrnd(0.04, 0.001 [1 pl])); 
D=exp(-h*f); % discount values 
pl=T/h; % pathlength - amount of steps in maturity 

u=exp(sigma*sqrt(h)); 
d=1/u; 

u_row = repmat(cumprod([1 u*ones(1,pl-1)]),pl,1); 
d_row = cumprod(tril(d*ones(pl),-1)+triu(ones(pl)),1); 
path = tril(u_row.*d_row); 
S=S0*path; 
+0

您能否提供包含所有必需变量的代码?我不认为有很多需要改进的地方,但我会仔细看看是否可以运行代码。 – Daniel 2014-08-31 17:15:03

+0

'f'是未定义的,它是什么?如果你意识到什么是符号数学相对于浮点运算的话,200的因子也不算太坏。但是,是的,有办法加快速度。是否有理由使用符号数学呢?有一件事你可以做到这一点,可能会加速版本是从'for'循环中删除'Lambda','Q'和'R'的所有或部分 - 创建向量和索引。 – horchler 2014-08-31 20:02:47

+0

@Daniel:我的确忘记了包含变量f。但现在已经完成。 – 2014-09-01 07:12:58

回答

0

除非我错过了一些东西,没有必要使用符号数学或使用未知变量。你可以在你的递归关系中有效地假设C = 1并在最后解决实际值。下面是一些其他的改进全码:

rng(1); % Always seed your random number generator 

a0 = 0.9; 
a1 = -3.2557; 
b = 1.2594; 
S0 = 18.57; 
sigma = 0.6579; 
h = 1/104; 
T = 1; 
Steps = T/h; 
pl = T/h; 
f = 0.04+0.001*randn(pl,1); 
D = exp(-h*f); 
u = exp(sigma*sqrt(h)); 
d = 1/u; 

u_row = repmat(cumprod([1 u*ones(1,pl-1)]),pl,1); 
d_row = cumprod(tril(d*ones(pl),-1)+triu(ones(pl)),1); 
pth = tril(u_row.*d_row); 
S = S0*pth; 

A = zeros(1,Steps); 
B = zeros(1,Steps); 
tic 
for t = Steps-1:-1:1 
    Lambda = 1-exp(-h./S(t,1:t).^b); 
    Q = ((1./D(t))./(1-Lambda)-d)/(u-d); 
    R = 0.5*erfc((-a0-a1*Lambda)/sqrt(2)); % Faster than normcdf 

    % Backward recursion for A and B 
    A = D(t)+D(t)*(Q.*(1-Lambda).*A(1:end-1) + ... 
        (1-Q).*(1-Lambda).*A(2:end)); 
    B = Lambda.*(1-R)+D(t)*(Q.*(1-Lambda).*B(1:end-1) + ... 
          (1-Q.*(1-Lambda).*B(2:end))); 
end 
C = B/A 
toc 

这需要大约0.005秒,在我的MacBook Pro运行。当然,你可以做出其他改进。在多个地方有很多变量组合(例如,1-LambdaD(t)*(1-Lambda)),可以计算一次。 Matlab可能会尝试优化这一点。您可以尝试将Lambda,QR移出循环 - 或者至少在外部计算它们的一部分并将结果保存在数组中。

+0

谢谢,我会尽快检查出来。 – 2014-09-02 13:11:45

+0

你完全正确。 'C'可以简单地从递归中取出。谢谢! – 2014-09-03 06:45:25