Оптимизация алгоритма

gregori38

Новичок
Пользователь
Ноя 17, 2024
3
0
1
Привет!
Я полный новичок в программировании, и мне нужно оптимизировать алгоритм так, чтобы он работал намного быстрее. У меня есть система дифференциальных уравнений для функций u, i, v с четырьмя параметрами beta, delta, p, c. Сначала я задал значения коэффициентов и с помощью численного метода получил значения всех трех функций, записанные в три соответствующих массива. Затем я пытаюсь решить обратную задачу: у нас есть три массива значений функций, и, используя эти значения, мы пытаемся найти коэффициенты. Для этого я написал функцию get_coefficients(u_values, i_values, v_values, t_end). Я реализовал наиглупейший способ. Я установил 4 отрезка, в пределах которых параметры могут изменяться. И тупо прогнал значения коэффициентов через четыре цикла while и с постоянным шагом.
ОС -Windows
Python 3.8
Пишу в jupiter
Код:
Python:
EPSILON = 1*pow(10, -8)

# Задаем параметры
beta = 1.59*pow(10, -8)
delta = pow(10, -6)
p = 23.91
c = pow(10, -8)

# Задаем начальные условия
u = 70000
i = 0
v = 7000

# Задаем временной интервал и шаг
t = 0
t_end = 100
dt = 0.01

# Создаем списки для сохранения значений u,i,v и времени
time = []
u_values = []
i_values = []
v_values = []

while t < t_end:
    # Подсчет инкрементов для u, i, v
    du1 = dt * (- beta * u * v)
    di1 = dt * (beta * u * v - delta * i)
    dv1 = dt * (p * i - c * v)

    du2 = dt * (- beta * (u + du1/2) * (v + dv1/2))
    di2 = dt * (beta * (u + du1/2) * (v + dv1/2) - delta * (i + di1/2))
    dv2 = dt * (p * (i + di1/2) - c * (v + dv1/2))

    du3 = dt * (- beta * (u + du2/2) * (v + dv2/2))
    di3 = dt * (beta * (u + du2/2) * (v + dv2/2) - delta * (i + di2/2))
    dv3 = dt * (p * (i + di2/2) - c * (v + dv2/2))

    du4 = dt * (- beta * (u + du3) * (v + dv3))
    di4 = dt * (beta * (u + du3) * (v + dv3) - delta * (i + di3))
    dv4 = dt * (p * (i + di3) - c * (v + dv3))

    # Обновляем значения u, i, v
    u += (du1 + 2*du2 + 2*du3 + du4) / 6
    i += (di1 + 2*di2 + 2*di3 + di4) / 6
    v += (dv1 + 2*dv2 + 2*dv3 + dv4) / 6

    # Сохраняем текущие значения
    time.append(t)
    u_values.append(u)
    i_values.append(i)
    v_values.append(v)

    # Обновляем время
    t += dt


def get_coefficients(u_values, i_values, v_values, t_end):
    n = 5

    coeff = []

    points = []
    u_val = []
    i_val = []
    v_val = []

    beta_begin = 1.59*pow(10, -8)
    delta_begin = 0.1*pow(10, -6)
    p_begin = 20
    c_begin = 0.1*pow(10, -8)

    beta_end = 1.69*pow(10, -8)
    delta_end = 1.1*pow(10, -6)
    p_end = 24.91
    c_end = 1.1*pow(10, -8)

    dbeta = 1*pow(10, -10)
    ddelta = 1*pow(10, -7)
    dp = 0.01
    dc = 1*pow(10, -9)

    beta_f = beta_begin
    delta_f = delta_begin
    p_f = p_begin
    c_f = c_begin

    previous = 0
    for i in range(n):
        points.append(previous + t_end/5)
        previous = points[-1]

    while beta_f <= beta_end:
        print(beta_f)
        while delta_f <= delta_end:
            while p_f <= p_end:
                while c_f <= c_end:

                    u_val = []
                    i_val = []
                    v_val = []

                    u_example = []
                    i_example = []
                    v_example = []

                    # Задаем начальные условия
                    u_f = 70000
                    i_f = 0
                    v_f = 7000

                    # Задаем временной интервал и шаг
                    t_f = 0
                    dt_f = 0.01

                    # Создаем списки для сохранения значений u,i,v и времени
                    time_f = []

                    while t_f < t_end:
                        # Подсчет инкрементов для u, i, v
                        du1_f = dt_f * (- beta_f * u_f * v_f)
                        di1_f = dt_f * (beta_f * u_f * v_f - delta_f * i_f)
                        dv1_f = dt_f * (p_f * i_f - c_f * v_f)

                        du2_f = dt_f * \
                            (- beta_f * (u_f + du1_f/2) * (v_f + dv1_f/2))
                        di2_f = dt_f * (beta_f * (u_f + du1_f/2) *
                                        (v_f + dv1_f/2) - delta_f * (i_f + di1_f/2))
                        dv2_f = dt_f * (p_f * (i_f + di1_f/2) -
                                        c_f * (v_f + dv1_f/2))

                        du3_f = dt_f * \
                            (- beta_f * (u_f + du2_f/2) * (v_f + dv2_f/2))
                        di3_f = dt_f * (beta_f * (u_f + du2_f/2) *
                                        (v_f + dv2_f/2) - delta_f * (i_f + di2_f/2))
                        dv3_f = dt_f * (p_f * (i_f + di2_f/2) -
                                        c_f * (v_f + dv2_f/2))

                        du4_f = dt_f * \
                            (- beta_f * (u_f + du3_f) * (v_f + dv3_f))
                        di4_f = dt_f * (beta_f * (u_f + du3_f) *
                                        (v_f + dv3_f) - delta_f * (i_f + di3_f))
                        dv4_f = dt_f * (p_f * (i_f + di3_f) -
                                        c_f * (v_f + dv3_f))

                        # Обновляем значения u, i, v
                        u_f += (du1_f + 2*du2_f + 2*du3_f + du4_f) / 6
                        i_f += (di1_f + 2*di2_f + 2*di3_f + di4_f) / 6
                        v_f += (dv1_f + 2*dv2_f + 2*dv3_f + dv4_f) / 6

                        # Сохраняем текущие значения
                        time_f.append(t_f)
                        u_val.append(u_f)
                        i_val.append(i_f)
                        v_val.append(v_f)

                        # Обновляем время
                        t_f += dt_f

                    index = []
                    for i in range(len(time_f)):
                        for j in range(len(points)):
                            if abs(time_f[i] - points[j]) < 0.001:
                                index.append(i)

                    u_standard = [u_values[index[0]], u_values[index[1]],
                                  u_values[index[2]], u_values[index[3]]]
                    i_standard = [i_values[index[0]], i_values[index[1]],
                                  i_values[index[2]], i_values[index[3]]]
                    v_standard = [v_values[index[0]], v_values[index[1]],
                                  v_values[index[2]], v_values[index[3]]]

                    u_example = [u_val[index[0]], u_val[index[1]],
                                 u_val[index[2]], u_val[index[3]]]
                    i_example = [i_val[index[0]], i_val[index[1]],
                                 i_val[index[2]], i_val[index[3]]]
                    v_example = [v_val[index[0]], v_val[index[1]],
                                 v_val[index[2]], v_val[index[3]]]



                    count = 0
                    for i in range(n-1):
                        if (u_standard[i] - u_example[i]) < EPSILON and (i_standard[i] - i_example[i]
                                                                         ) < EPSILON and (v_standard[i] - v_example[i]) < EPSILON:
                            count += 1

                    if count == n-1:
                        coeff.append([beta_f, delta_f, p_f, c_f])

                    c_f += dc

                c_f = c_begin
                p_f += dp

            p_f = p_begin
            delta_f += ddelta

        delta_f = delta_begin
        beta_f += dbeta

    print(coeff)


get_coefficients(u_values, i_values, v_values, t_end)

В результате функция сработала корректно, но, конечно, работает она очень медленно, несмотря на то, что отрезки крайне малы. Есть ли какие-то готовые известные алгоритмы оптимизации или функции в каких-то библиотеках, чтобы это работало быстрее, и желательно работало на полуинтервалах [0, + бесконечность). Спасибо за любую помощь!
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 663
474
83
посмотрите в строну numpy, scipy
 
  • Мне нравится
Реакции: gregori38

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 663
474
83
чтобы он работал намного быстрее.
что значит намного быстрее? есть какая то цель? порог?
 

gregori38

Новичок
Пользователь
Ноя 17, 2024
3
0
1
что значит намного быстрее? есть какая то цель?
Да, цель есть. Сейчас коэффициенты перебираются на очень маленьких отрезках (порядка 10^-8 степени), хотелось бы сильно расширить эти отрезки, в идеале до полуинтервалов [0, +бесконечность). Но я столкнулся с проблемой, что даже при увеличении границ отрезков лишь в 10^8 раз ( то есть отрезки выглядят как [1.59,1.69], и т.д. ) программа считает очень долго (даже за один день, она не выдаст ответ), и это на компьютере с оперативной памятью в 128ГБ
 

gregori38

Новичок
Пользователь
Ноя 17, 2024
3
0
1
О, спасибо большое!
 

Форум IT Специалистов