Как уменьшить размер генератора в симпы.Поли? - PullRequest
0 голосов
/ 24 апреля 2020

Учитывая формулу, я хочу преобразовать ее в объект Poly и минимизировать размер генератора. Например, если моя формула равна x^2+x+sqrt(x), я ожидаю, что в генераторе будет только sqrt(x). Но в большинстве моих попыток генератор содержит как x, так и sqrt(x).

from sympy import *
print('first attempt:',Poly('x^2+x+sqrt(x)'))
x=Symbol('x', positive=True)
print('second attempt:',Poly(x**2+x+sqrt(x)))
print('third attempt:',str(Poly({1:1,2:1,4:1},gens=S('sqrt(x)'))))
first attempt: Poly(x**2 + x + (sqrt(x)), x, sqrt(x), domain='ZZ')
second attempt: Poly(x**2 + x + (sqrt(x)), x, sqrt(x), domain='ZZ')
third attempt: Poly((sqrt(x))**4 + (sqrt(x))**2 + (sqrt(x)), sqrt(x), domain='ZZ')

Только третий метод был успешным, но код для него уродлив и сложен для автоматизации (я хочу преобразовать его, потому что я хочу легко извлечь коэффициенты и степени, поэтому он дает мне ничего). Есть ли лучший способ сделать это?

EDIT

Основываясь на ответе smichr, я создал функцию для уменьшения размера генератора.

def _powr(formula):
    if formula.func==Pow:
        return formula.args
    else:
        return [formula,S('1')]
def reducegens(formula):
    pol=Poly(formula)
    newgens={}
    ind={}
    for gen in pol.gens:
        base,pw=_powr(gen)
        coef,_=pw.as_coeff_mul()
        ml=pw/coef
        if base**ml in newgens:
            newgens[base**ml]=gcd(newgens[base**ml],coef)
        else:
            newgens[base**ml]=coef
            ind[base**ml]=S('tmp'+str(len(ind)))
    for gen in pol.gens:
        base,pw=_powr(gen)
        coef,_=pw.as_coeff_mul()
        ml=pw/coef
        pol=pol.replace(gen,ind[base**ml]**(coef/newgens[base**ml]))
    newpol=Poly(pol.as_expr())
    for gen in newgens:
        newpol=newpol.replace(ind[gen],gen**newgens[gen])
    return newpol

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

print(reducegens(S('x^2+x+sqrt(x)')))
print(reducegens(S('x**2+y**2+x**(1/2)+x**(1/3)')))
print(reducegens(S('sqrt(x)+sqrt(z)+sqrt(x)*sqrt(z)')))
print(reducegens(S('sqrt(2)+sqrt(3)+sqrt(6)')))
Poly((sqrt(x))**4 + (sqrt(x))**2 + (sqrt(x)), sqrt(x), domain='ZZ')
Poly((x**(1/6))**12 + (x**(1/6))**3 + (x**(1/6))**2 + y**2, x**(1/6), y, domain='ZZ')
Poly((sqrt(x))*(sqrt(z)) + (sqrt(x)) + (sqrt(z)), sqrt(x), sqrt(z), domain='ZZ')
Poly((sqrt(2)) + (sqrt(3)) + (sqrt(6)), sqrt(2), sqrt(3), sqrt(6), domain='ZZ')

Там первые три примера в порядке, но было бы неплохо представить sqrt (6) как sqrt (2) * sqrt (3), а не как элемент другого генератора.

1 Ответ

0 голосов
/ 24 апреля 2020

Вы можете просто заменить sqrt(x) на y или (используя хитрость символов) заменить его на символ с именем sqrt(y) (или sqrt(y), который я делаю, чтобы показать, что он работает):

>>> from symyp.abc import x, y
>>> from sympy import Symbol
>>> (x**2+x+sqrt(x)).subs(sqrt(x), y)
y**4 + y**2 + y
>>> (x**2+x+sqrt(x)).subs(sqrt(x), Symbol('sqrt(y)'))
sqrt(y)**4 + sqrt(y)**2 + sqrt(y)

Любая форма теперь имеет один символ и создаст Поли с одним генератором.

...