Определите неиспользуемый новый символ внутри области функции

Мне сложно инкапсулировать большую часть логики с возможностью повторного использования при написании sympy кода.

Я хотел бы написать функцию следующим образом:

def compute_integral(fn):
  s = symbols_new() # do not apply lexicographic identity, this symbol identity is unique
  return integrate( fn(s), (s, 0, 1))

Если я просто использую обычный symbols() для создания экземпляра s, я рискую fn иметь тот же символ где-то внутри его определяющего выражения, например, может произойти следующее:

def compute_integral(fn):
  s = symbols("s")
  return integrate(fn(s), (s, 0, 1))

...

import sympy as sp
from sympy.abc import *

t = sp.sin(3 + s)
f = sp.lambdify([x], x**2 + t * s * x)
compute_integral(f) #< ---- symbol s is already present in the function, now the integral will produce the wrong result

То, что я делаю сейчас, чтобы свести к минимуму эту проблему, далеко не идеально:

compute_integral_local_var = 0

def compute_integral(fn):
  global compute_integral_local_var
  compute_integral_local_var += 1
  s = symbols("local_{}".format(compute_integral_local_var))
  return integrate(fn(s), (s, 0, 1))

Я хочу избежать подобных коллизий без добавления специальной глобальной переменной. Есть ли лучшие подходы для достижения такого типа инкапсуляции в API sympy?

Это похоже на «gensym» в Лиспе… может быть, это еще одно ключевое слово для поиска?

dragoncoder047 16.08.2024 15:14

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

jared 16.08.2024 15:54

@jared, потому что, в отличие от выражения, lambdify позволяет применить аргумент, вместо этого выражение само по себе не может интерпретироваться как интегрируемая функция, если только оно не является членом пары (expression, symbol)

UnkemptPanda 16.08.2024 16:25

@jared, когда вы применяете аргумент к lambdify, он возвращает инкапсулированное (полностью символическое) выражение перед передачей integrate

UnkemptPanda 16.08.2024 16:34

Нет, lambdify преобразует символическое выражение Sympy в числовую функцию, которую могут использовать библиотеки, ориентированные на числовые значения, такие как numpy, scipy и mpmath.

jared 16.08.2024 17:50
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я использую последнюю версию Sympy, версию 1.13.2, и предоставленный вами блок кода не запускается: возникает ошибка.

Кажется, существуют некоторые заблуждения, которые я хотел бы прояснить. Рассмотрим этот блок кода:

import sympy as sp
from sympy.abc import s, x

t = sp.sin(3 + s)
print("t:", t)
e = x**2 + t * s * x
print("e:", e)
# t: sin(s + 3)
# e: s*x*sin(s + 3) + x**2

Здесь я создаю два символических выражения: t и e. t содержит символьную функцию sin, а e состоит из t. Вы можете рассматривать e как функцию, но в терминологии Sympy e — это символическое выражение.

Далее в вашем примере вы выполнили что-то вроде этого:

f = sp.lambdify([x], e)

который создает числовую функцию, которая будет оцениваться NumPy. Затем вы попытались символически проинтегрировать эту числовую функцию, что абсолютно неверно. С помощью SymPy вы можете выполнять только символическую интеграцию символических выражений.

Если все, что вы пытаетесь выполнить, — это символическое интегрирование, то этой команды достаточно:

sp.integrate(e, (x, 0, 1))
# s*sin(s + 3)/2 + 1/3

Если вы хотите объединить несколько символических выражений в одном диапазоне, вы можете создать собственную функцию:

def compute_integral(expr, sym):
    return sp.integrate(expr, (sym, 0, 1))

print(compute_integral(e, x))
# s*sin(s + 3)/2 + 1/3

print(compute_integral(t, x))
# sin(s + 3)

Обновлено:

Судя по небольшим деталям, которыми вы поделились, лямбда-функция Python и символы Dummy Sympy могут дать то, что вы хотите. Символ Dummy гарантированно уникален: он используется, когда необходим временный символ или когда имя символа не важно.

def compute_integral(func):
    s = sp.Dummy()
    return sp.integrate(func(s), (s, 0, 1))

t = sp.sin(3 + s)
f = lambda x: x**2 + t * s * x
compute_integral(f)
# s*sin(s + 3)/2 + 1/3

Пожалуйста, пожалуйста, пожалуйста: не используйте функции, созданные с помощью lambdify, в качестве аргументов функций Sympy: обычно это не работает. Вы привели следующий пример:

from sympy.abc import r, s
sp.lambdify([r], r**2)(s).diff(s)
# out: 2*s

Вам повезло: числовая функция, сгенерированная lambdify, содержит только простые операции Python (в данном случае умножение). Если исходное символическое выражение содержит другие функции, такие как sin, cos, exp и т. д., вы получите ошибку:

sp.lambdify([r], sin(r))(s).diff(s)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
AttributeError: 'Symbol' object has no attribute 'sin'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
Cell In[50], line 1
----> 1 sp.lambdify([r], sin(r))(s).diff(s)

File <lambdifygenerated-4>:2, in _lambdifygenerated(r)
      1 def _lambdifygenerated(r):
----> 2     return sin(r)

TypeError: loop of ufunc does not support argument 0 of type Symbol which has no callable sin method

действительно, пару (expression, symbol) можно интерпретировать как функцию (хотя семантика менее ясна). В этом случае, конечно, его можно заставить работать, однако проблема остается, если 1) мы хотим использовать новый символ и 2) хотим быть уверены, что новый символ отсутствует на других объектах, которыми манипулируют, тогда у вас есть прибегнуть к вышеупомянутым уловкам (и из вашего ответа я делаю вывод, что ничего подобного gensym на sympy не существует)

UnkemptPanda 16.08.2024 16:29

не следуя вашему комментарию о том, что lambdify становится «числовой функцией». На самом деле очень легко продемонстрировать контрпример: sp.lambdify([r], r**2)(s).diff(s) возвращает 2*s

UnkemptPanda 16.08.2024 16:37

Мать драконов, что я только что увидел... В SymPy вы многого не понимаете. Дайте мне полчаса на редактирование ответа.

Davide_sd 16.08.2024 16:39

@UnkemptPanda обновил ответ.

Davide_sd 16.08.2024 16:57

Если вы не против, чтобы в названиях ваших символов было немного тарабарщины, вы можете посмотреть uuid.

import uuid

def compute_integral(fn):
  s = symbols(f"s_{uuid.uudi4()}")  # will get something like 's_5a324a9c-510d-42d1-8fa8-7a613e3e093f'
  return integrate(fn(s), (s, 0, 1))

Теоретически это не предотвращает конфликт имен на 100%, но практически это довольно близко к 100%.

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

UnkemptPanda 16.08.2024 16:30

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

UnkemptPanda 16.08.2024 16:32

Другие вопросы по теме