Как повысить скорость моделирования броуновского движения по методу Монте-Карло?

#python #montecarlo #stochastic #event-simulation

#python #монтекарло #стохастический #моделирование событий

Вопрос:

Я хочу, чтобы мой код выполнялся быстрее для большего количества итераций и запусков. Прямо сейчас мой код работает слишком медленно, но я не знаю, что изменить, чтобы ускорить его. Я начал с кодирования кинетического моделирования по методу Монте-Карло, затем отредактировал его, чтобы оно стало симуляцией броуновского движения. Мой текущий код не может обрабатывать 10000 запусков по 10000 итераций каждый, что необходимо.

 import numpy as np
import matplotlib.pyplot as plt
import time
%matplotlib inline

runs = int(input("Enter number of runs: "))
N = int(input("Enter number of iterations per simulation: "))

y = 0
R = 10*1  # R is the rate value
t0 = time.time()
for y in range(runs):  # Run the simulation 'runs' times
    T = np.array([0])
    dt = 0
    x = 0.5  # sets values 
    X = np.array([x])
    t = 0
    i = 0

    while t < N:  # N is the number of iterations per run
        i = i   1  # i is number of iterations so far
        z = np.random.uniform(-1, 1, 1)  # sets z to be a random number between -1 to 1 size 1

        if z > (1/3):  # if conditions for z for alpha and gamma, beta 
            x = x   1  # z[]=alpha state then   1
        elif z < (-1/3):
            x = x-1  # z[]=gamma state then - 1
        elif z < (1/3) and z > (-1/3):
            x = x  # z=beta state then   0

        X = np.append(X, x)  # adds new X value to original X array
        X[i]  = X[i-1] * 0.01 * np.random.normal(0, 1, 1) * np.sqrt(dt)  # for Brownian motion with sigma as 0.01
        Z = np.random.uniform(0, 1)  # sets Z to be a random number between 0 and 1
        dt = 1/R * np.log(1/Z)  # formula for dt; R is the rate value
        t = t   dt  # ITERATED TIME
        T = np.append(T, t)
        plt.plot(T, X, lw='0.5', alpha=0.5)

t1 = time.time()
print("final %.10f seconds " % (t1-t0))
  

Комментарии:

1. Пожалуйста, отредактируйте свой код (в основном отступы), чтобы убедиться, что мы правильно его интерпретируем

2. Примечание: это помогло бы, если бы вы переключились на описательные имена переменных. В любом случае, plt.plot нужно ли это делать во внутреннем цикле? Похоже, что это может последовать. Кроме того, T не похоже, что это должно быть np.array , так что сохраняйте T = [] и используйте T.append(t) . Другое дело, похоже, что NumPy по большей части используется для отдельных элементов, что не соответствует его скорости; вы также можете использовать стандартную библиотеку.

3. Стремитесь векторизовать свой код. Вместо, например, 10000 запусков однозначных симуляций (ваше z — единственное число), создайте вектор из 10000 симуляций.

4. @Ry во внутреннем цикле выполняется построение нескольких графиков на одном и том же графике, поскольку мне нужно будет показать, что среднее значение графиков по мере увеличения количества запусков должно приближаться к 0.

5. @pythonnewbie22: Похоже, что вы строите один и тот же график над самим собой с одним новым элементом каждый раз. Похоже, что это должно быть во внешнем цикле после внутреннего цикла.

Ответ №1:

Вот отличный пример быстродействующей симуляции броуновского движения по методу Монте-Карло, которая менее затратна в вычислительном отношении.

В прошлом я делал то же самое, что и вы, и каждый шаг каждой итерации выполнял во вложенных циклах. Возможно, это связано с переключением контекста, запуском через разные библиотеки или просто нехваткой памяти, но выполнение каждого шага кода на каждой итерации определенно привело к снижению производительности и увеличению использования памяти.

В приведенном выше примере автор сначала создает массивы, а затем выполняет соответствующие итерации по ним с помощью одного цикла for. Все случайные числа генерируются и помещаются в массив одновременно. Тогда все возвраты броуновского движения вычисляются одновременно. и т.д. (Представьте сборочную линию — очень эффективное использование ресурсов на каждом этапе и достижение экономии за счет масштаба.) Также важно отметить, что функция plt запускается только один раз (не в цикле) и только после завершения всех итераций.

Этот метод должен допускать гораздо большее количество итераций на гораздо меньшем оборудовании.