Как стать автором
Обновить

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

Если формулы — полиномы, возможно вам стоит numexpr попрбовать. Будет в 10 раз проще и в 100 раз быстрее.

Спасибо, формулы по сути полиномы, да. Пробовал numexpr. Почему-то с первого тыка не завелся, поэтому я его отложил. Т.е. лямбда-функция создалась, но работать отказывается при вызове:
>>ValueError: bytes must be in range(0, 256)
#это на фоне KeyError: ('8.348841409877572e-… длинная ошибка, до которой руки не дошли. Есть идеи как правильно пользовать?

Попробуйте сгенерить формулу без явных констант в тексте — может с парсингом что-то не так.

Обнаружил, что если убрать последние 4 члена (3 несвободных и 1 свободный) или более, то все работает. Но если убрать только 3 или менее — то вылетает с обозначенными ошибками. Может на длину полинома ограничение?
Кстати, тесты при использовании numexpr не дали обещанной производительности:

subs cycle (1000): lambdify Elapsed time: 0.482 sec (против numpy 0.026 sec)

redis_get + cloudpickle_loads_lambdifyed_expr + subs cycle (1000): Elapsed time: 2.396 sec (против numpy 1,721)
Вероятно, с учетом ограничений и результатов тестов, придется отказаться от numexpr.

Я не знаю, что и как вы делаете, но ваша формула (укороченная на 3 члена) считается за 30 микросекунд в 1 строчку numexpr.evaluate(long_formula_as_a_string). A numexpr.re_evaluate() вообще отрабатывает за 22 микросекунды.


Что в 1000 раз быстрее вашего текущего подхода с лямбда-функциями, на создание которых уходит еще в 10 тысяч раз больше времени.

Надеюсь вы обратили внимание, что каждый тест прогоняется 1000 раз? И можете ли вы дать кусок кода? Я не силен в numexpr. Спасибо

Так я привел код. Все, что вам нужно — это:


x1_, x2_, x3_, x4_, x5_, x6_, x7_ = ... # значения переменных
numexpr.evaluate(long_formula_as_a_string)

или можно чуть иначе:


variables_dict = dict(zip(variables_names, variables_values))
numexpr.evaluate(long_formula_as_a_string, local_dict=variables_dict)
Так я и думал. Ну не может то, что на входе в виде формулы-строки, переменных в виде строк и их значений считаться быстрее, чем уже составленное дерево операций. Вот результаты расчетов:
numexpr (1000): cycle Elapsed time: 0.535 sec (против subs cycle (1000): lambdify Elapsed time: 0.026 sec).
Факт — штука упрямая…

Упрямы обычно криворукие необразованые дилетанты… а факты бывают разные.


Ваш подход:


  • сначала надо откомпилировать выражение, это занимает 426 миллисек на 1 итерацию
    expr = sympify(expr_txt)
  • затем создать лямдба-функцию, на это уйдет 114 миллисек на 1 итерацию
    func = lambdify(tuple(symbols_list), expr, 'numpy')
  • и только после этого выполнять расчеты, 26 микросек на 1 итерацию
    func(*[1 for i in range(len(symbols_set))])
    Все это вместе отнимает 540 миллисек.

Или можно взять numexpr, тогда потребуется только одна операция


  • скопилировать и вычислить выражение за 30 микросекунд
    numexpr.evaluate(long_formula_as_a_string, local_dict=variables_dict)
    Все это вместе отнимает 30 микросекунд.

Теперь рассчитаем, во сколько раз быстрее numexpr:
540 миллисекунд / 30 микросекунд = 18000


numexpr быстрее в 18 тысяч раз!

Вы, видимо, не слишком внимательно читали статью. Первые два пункта, которые вы обозначили, рассчитываются лишь однажды. Критично время самих расчетов (п.3). И прекращайте вводить людей в заблуждение — нет там 30 микросекунд. Вот с какого потолка вы эти результаты берете? Не бывает чудес. Разве что вы на мейнфрейме считаете. У меня полсек ВАШ код отработал (1000 итераций).

Я в свое время для решения похожей задачи на С представлял формулу в обратной польской записи после всяческих нормализаций вроде этой. В таком случае, вычисление произвольного полинома сводилось к последовательному применению функций из списка к стеку заполненному входными данными. Если поиграться с numpy'ем, но наверное можно и в батчах это делать. Тогда функция — это перестановка входных данных в стеке и список атомарных операций на этим стеком, вроде «сложить два верхних элемента».
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории