Эффективное сопоставление одного и того же входа с несколькими функциями - PullRequest
0 голосов
/ 04 декабря 2018

Я работаю с большой системой ODE, которую я автоматически создаю.У меня есть state массив длины n, и такое же количество дифференциальных уравнений также хранится в массиве.Здесь их 2, но в реальной системе их было бы больше 100. Дифференциальные уравнения строятся как класс и называются через __call__, альтернативно, ОДУ создаются и вызываются с functools partial.Мне нужно отправить одинаковые state и время t каждой дифференциальной функции в массиве и заполнить вектор производного состояния dstate.Мне интересно, каков самый чистый, самый питонический и, что самое важное, самый быстрый способ сделать это.

import numpy as np
from scipy import integrate
import pandas as pd

class F1:
    def __init__(self):
        pass
    def __call__(self, state):
        return 2 - state[0]**2 * state[1]

class F2:
    def __init__(self):
        pass
    def __call__(self, state):
        return 3 - state[1]*state[0]

fs = np.array([F1(), F2()])
state0 = np.ones(2)*4

def change(t, state):
    """
    This is the function I would like to change for something better!

    Ideally there would be something like: dstate = map(input_to_apply, list_of_functions)
    """
    dstate = np.zeros(2)
    for i,f in enumerate(fs):
        dstate[i] = f(state = state)
    return dstate

sol = integrate.solve_ivp(fun = change, t_span = (0, 15), y0 = state0)
res = pd.DataFrame(sol.y.T, columns = ['A', 'B'])
res.index = sol.t
ax = res.plot()

1 Ответ

0 голосов
/ 05 декабря 2018

Что касается кодирования, (IMO) нет существенных улучшений в том, что вы сделали.Вы можете заменить однолинейные циклы:

def change(t, state):
    return np.array([f(state=state) for f in fs])

Что касается эффективности, отметьте Вызов функций по индексу массива в Python .Лучшее, что вы можете сделать, это объединить функции в одну.В вашем примере:

class F_list:
    def __init__(self):
        pass
    def __call__(self, state):
        return 2 - state[0]**2 * state[1], 3 - state[1]*state[0] 
    def change(self, t, state):
        return self(state)

F = F_list()
sol = integrate.solve_ivp(fun = F.change, t_span = (0, 15), y0 = state0)

Также обратите внимание, что использование def или lambda всегда быстрее, чем __call__, и если вам нужен класс и если у вас нет особой потребности в экземплярах, вы можетеиспользуйте декоратор classmethod, чтобы избежать ненужного создания экземпляра

...