将无法向量化的`for`循环转换为稀疏矩阵

时间:2017-11-27 11:02:29

标签: python matlab numpy octave sparse-matrix

有2个盒子和一个小间隙,每个盒子允许每秒1个粒子进入另一个盒子。粒子是从A到B还是从B到A取决于比率Pa / Ptot(Pa:框A中的粒子数,Ptot:两个框中的总粒子数)。

为了加快速度I need to get rid of the for loops,我无法找到一种方法来对它们进行矢量化或将它们变成代表我for循环的稀疏矩阵:

  

你不能矢量化的循环怎么样?迭代n的结果取决于您在迭代n-1,n-2等中计算的结果。您可以定义表示for循环的稀疏矩阵,然后执行稀疏矩阵求解。

但我无法弄清楚如何定义稀疏矩阵。模拟归结为计算:

enter image description here

其中

enter image description here

是在here所述的尝试表达问题时给我带来麻烦的部分。 (注意:括号中的内容是bool操作)

问题

  • 我可以对for循环进行矢量化吗?
  • 如果没有,我该如何定义稀疏矩阵?
  • (红利问题)为什么Python(0.027s)的执行时间 x27 比Octave(0.75s)更快?

注意:我在Python和Octave中实现了模拟,很快就会在Matlab上实现,因此标签是正确的。

八度代码

1; % starting with `function` causes errors

function arr = Px_simulation (Pa_init, Ptot, t_arr)
  t_size = size(t_arr);
  arr = zeros(t_size);   % fixed size array is better than arr = [] 
  rand_arr = rand(t_size);  % create all rand values at once
  _Pa = Pa_init;
  for _j=t_arr()
    if (rand_arr(_j) * Ptot > _Pa)
      _Pa += 1;
    else
      _Pa -= 1;
    endif
    arr(_j) = _Pa;
  endfor
endfunction


t = 1:10^5;

for _i=1:3
  Ptot = 100*10^_i;
  tic()
  Pa_simulation = Px_simulation(Ptot, Ptot, t);
  toc()
  subplot(2,2,_i);
  plot(t, Pa_simulation, "-2;simulation;")
  title(strcat("{P}_{a0}=", num2str(Ptot), ',P=', num2str(Ptot)))
endfor

的Python

import numpy
import matplotlib.pyplot as plt
import timeit
import cpuinfo

from random import random

print('\nCPU: {}'.format(cpuinfo.get_cpu_info()['brand']))


PARTICLES_COUNT_LST = [1000, 10000, 100000]
DURATION = 10**5

t_vals = numpy.linspace(0, DURATION, DURATION)


def simulation(na_initial, ntotal, tvals):
    shape = numpy.shape(tvals)
    arr = numpy.zeros(shape)
    na_current = na_initial

    for i in range(len(tvals)):
        if random() > (na_current/ntotal):
            na_current += 1
        else:
            na_current -= 1
        arr[i] = na_current
    return arr


plot_lst = []
for i in PARTICLES_COUNT_LST:
    start_t = timeit.default_timer()
    n_a_simulation = simulation(na_initial=i, ntotal=i, tvals=t_vals)
    execution_time = (timeit.default_timer() - start_t)
    print('Execution time: {:.6}'.format(execution_time))
    plot_lst.append(n_a_simulation)


for i in range(len(PARTICLES_COUNT_LST)):
    plt.subplot('22{}'.format(i))
    plt.plot(t_vals, plot_lst[i], 'r')

    plt.grid(linestyle='dotted')
    plt.xlabel("time [s]")
    plt.ylabel("Particles in box A")

plt.show()

1 个答案:

答案 0 :(得分:1)

IIUC您可以在cumsum()Octave使用Numpy

八度:

>> p = rand(1, 5);
>> r = rand(1, 5);
>> p
p =

   0.43804   0.37906   0.18445   0.88555   0.58913

>> r
r =

   0.70735   0.41619   0.37457   0.72841   0.27605

>> cumsum (2*(p<(r+0.03)) - 1)
ans =

   1   2   3   2   1

>> (2*(p<(r+0.03)) - 1)
ans =

   1   1   1  -1  -1

另请注意,以下函数将返回值([-1, 1]):

enter image description here