Simplificar e obter derivada parcial para uma sequência polinomial


8

Introdução

Escreva um programa para calcular a derivada parcial de um polinômio (possivelmente multivariado) com relação a uma variável.

Desafio

Derivadas são ferramentas matemáticas muito importantes que foram amplamente aplicadas em física, química, biologia, economia, psicologia e muito mais para lidar com todos os tipos de problemas. Expressões com múltiplas variáveis ​​também são muito comuns.

No escopo deste desafio, uma sequência polinomial ("polystr") é definida pelo seguinte BNF (formato Backus – Naur):

<polystr> ::= <term> | <term><plusminus><polystr>

<plusminus> ::= "+" | "-"

<term> ::= <coeff> | <coeff><baseterm> | <baseterm>

<baseterm> ::= <variable> | <variable><exponent> | <baseterm><baseterm>

<coeff> ::= positive_integer

<exponent> ::= positive_integer

<variable> ::= lowercase_ASCII_letters

Onde positive_integere lowercase_ASCII_letterssão bastante auto-explicativos.

Por exemplo, A cadeia 3x2y-x3y-x2y+5significa 3*(x^2)*y-(x^3)*y-(x^2)*y+5. Os termos dados na entrada podem aparecer em qualquer ordem, e as variáveis ​​em cada termo também podem aparecer em qualquer ordem. Por exemplo, 5-yx2-x3y+y3x2também é uma entrada válida e é de fato o mesmo que o exemplo anterior.

A regra para obter derivada parcial é apenas fazê-lo termo a termo. Se a variável aparecer não aparecer no termo, a derivada será zero. Caso contrário, o coeficiente do termo é multiplicado pelo expoente dessa variável e, em seguida, o expoente da variável é diminuído de um. Os expoentes para outras variáveis ​​não são alterados. Isso está apenas seguindo a definição em matemática. Além disso, se o expoente resultante for zero, remova a variável do termo.

Por exemplo, para tirar a derivada parcial de 5z-z2y2-5w3yem relação a y. O processo a seguir é realizado (de acordo com o BNF definido acima, o "coeficiente" é considerado um número positivo, ou seja, os sinais são considerados separadamente)

          5z          -   z2y2        - 5w3y

Coeff                 1->1*2=2      5->5*1=5
Expon                 2->2-1=1      1->1-1=0
Term                  -   2yz2         - 5w3 
      (y is not here            (expon 0->y removed)
     so the term is 0)

O resultado é -2yz2-5w3y.

Por outro lado, se a expressão acima é derivada parcial em relação a a, o resultado é 0porque não aestá em nenhum dos termos.

Sua tarefa é escrever uma função ou um programa completo para calcular essa derivada. Ele deve pegar uma sequência polinomial e um único caractere (a variável a qual derivar) e retornar a derivada da forma mais simples.

"Forma mais simples" significa três coisas.

  1. O número 0(não o dígito) não deve aparecer na saída, a menos que a saída seja justa 0. Portanto, nem 0+10ynem 3-y0zserá uma saída válida e deve ser transformada em 10ye 3-z, respectivamente.

  2. O número 1não deve aparecer como expoente ou coeficiente, mas pode aparecer como um termo independente.

  3. Os termos com exatamente o mesmo conjunto de variáveis ​​e expoentes devem ser mesclados, o que significa que 3a2b5-4b5a2não é uma saída válida e deve ser -a2b5. Mais informações sobre entrada e saída podem ser encontradas na seção "Especificações".

Casos de teste

Input
Output

2xy+4ax-5+7mx4-4-7x4m, x
2y+4a

4upv+5u2v3w4-4w4u2v3+qr-v,v
4up+3u2v2w4-1

12ux-7x2m3+ab5,q
0

-a+10ca11y-1nv3rt3d-poly, a
-1+110ca10y

1y+1x3y, y
1+x3

Especificações

  • A entrada pode ser obtida através de formulários padrão . Em outras palavras, você pode considerar a entrada como uma string, uma lista de caracteres, uma matriz aninhada de coeficientes, variáveis ​​(possivelmente indicadas pelo valor ASCII menos 'a' ou algo parecido) e expoentes, etc. Você também pode mudar a string para 2*x^3y^2ou semelhante em vez de 2x3y2.

No entanto, não use a entrada [2,0,0,0,1,0,0,3,0,0,...0](uma matriz de 27 elementos) para o termo 2dgou qualquer outro formato detalhado que enumere as 26 letras como esta. Seu formato de entrada também deve poder tratar abe bacomo entradas diferentes (portanto, o formato da matriz de 27 elementos é inválido devido a essa restrição também).

  • Cada variável (letra) aparecerá apenas uma vez em cada termo da entrada, o que significa xxque não aparecerá e sempre será apresentado como x2, nem algo parecido a3b4a2.

  • Para reiterar, os termos na entrada podem aparecer em qualquer ordem.

  • Você também pode escolher o formato de saída, desde que o formato detalhado mencionado acima seja evitado. No entanto, a saída deve sempre estar na forma mais simples, conforme definido acima. Assim como a entrada, os termos na saída podem aparecer em qualquer ordem, e as variáveis ​​em cada termo também podem aparecer em qualquer ordem e não precisam ser consistentes entre os termos. Isso significa que pu+2up2é uma saída válida. O sinal para o termo líder pode ser positivo ou negativo e -y+3xe 3x-ysão ambos válidos, assim é +3x-y.

  • A entrada é sempre fornecida de forma que todos os coeficientes e expoentes na saída sejam menores que 2 32 -1, ou o maior número inteiro que seu idioma pode suportar, o que for menor. Afirmar que o maior número inteiro que seu idioma pode manipular é excessivamente pequeno e trivializar o desafio se enquadra na categoria de brechas padrão.

  • Isso é , o menor número de bytes vence.

  • Como sempre, as brechas padrão se aplicam aqui.

Edit: Como a maioria das respostas até agora são internas que fazem todo o desafio, e, apesar de saber que existem componentes internos, não tenho a intenção de banir essas internas desde o início, nem o tenho agora. Farei com que os critérios de vencimento sejam baseados em cada idioma, ou seja, a submissão com o mínimo de bytes em cada idioma vence nesse idioma. Adicionarei um snippet padrão para um catálogo se houver envios suficientes. Sinta-se livre para continuar enviando built-in para mostrar o poder do seu idioma, mas não hesite em enviar suas respostas não integradas, mesmo que seja muito mais longo e seu idioma não tenha um embutido. Código de golfe feliz no seu idioma favorito!


@JonathanFrech O segundo e o terceiro termo na entrada podem ser mesclados. Juntos, eles dão o segundo termo no resultado.
Weijun Zhou 27/02

Ah ok. No seu primeiro exemplo, por que -9aparece na saída?
Jonathan Frech 27/02

1
A única razão pela qual você pode mesclar a saída é porque a entrada já pode ser mesclada. Isso faz com que isso seja realmente uma combinação de 2 problemas independentes take derivativeemerge
Ton Hospel

Presumo forma mais simples implica também no exponent 1, embora você não parecem afirmar isso
Ton Hospel

@ JonathanFrech Isso é um erro de digitação. Fixo.
Weijun Zhou 27/02

Respostas:


2

Python 2 , 252 245 bytes

o,d=input()
D={};s=''
for c,t in o:T=`sorted(t)`;D[T]=D.get(T,0)+c
for t in D:
 c,t=D[t],dict(eval(t))
 if(d in t)*c:e=t[d];c*=e;t[d]=e-1;s+=('%+d '%c)[:~((-2<c<2)*sum(t.values())>0)]+''.join((v+`t[v]`*(t[v]>1))*(t[v]>0)for v in t)
print s or'0'

Experimente online!

Recebe entrada como uma lista aninhada de coeficientes e termos:

[
 [coeff1, [[var1_1,exp1_1],
           [var1_2,exp1_2],
           ... ]
 ],
 [coeff2, [[var2_1,exp2_1], ...]],
 ...
]

Por exemplo, o primeiro exemplo ( 5z-z2y2-5w3y) é dado como:

[
 [ 5, [['z', 1]          ] ], 
 [-1, [['z', 2], ['y', 2]] ],
 [-5, [['w', 3], ['y', 1]] ]
]

O rodapé contém uma função que analisa uma string de entrada para o formato de entrada desejado: parse(s).


Editar:

  • Recebe entrada em vez de função

2

Retina , 249 233 bytes

(.)(?=.*¶\1$)
$&_
L`.\w*
G`_
^\b
+
%O`._?\d*
_\d+
*
\b[a-z]
1$&
\b(\d+)(?=.*?(_+))
$1*$2
O$`(.)_+(.+)
$2$1
+`((\+|-)_+)(.*)¶\2(_+\3)\b
$1$4
+`\+_(_*(.*)¶-)_(_*\2\b)
+$1$3
G`\b_
\b_+
$.&
_(__+)
$.1
^\+|¶|(.)__|._
$1
\b1([a-z])
$1
^$
0

Experimente online! O link inclui casos de teste. Explicação:

(.)(?=.*¶\1$)
$&_

Adicione um _após cada ocorrência da variável especificada.

L`.\w*

Divida a entrada em termos.

G`_

Mantenha apenas os termos que referenciaram a variável.

^\b
+

Prefixe a +se o primeiro termo não tiver um sinal.

%O`._?\d*

Classifique cada termo em ordem alfabética. (O sinal corresponde, mas isso não é um problema; ele classifica no início de qualquer maneira.)

_\d+
*

Converta todos os expoentes da variável em unário.

\b[a-z]
1$&

Coloque um prefixo temporário 1 para esses termos sem um multiplicador.

\b(\d+)(?=.*?(_+))
$1*$2

Multiplique o multiplicador pelo expoente da variável, deixando o resultado em unário.

O$`(.)_+(.+)
$2$1

Classifique todos os termos.

+`((\+|-)_+)(.*)¶\2(_+\3)\b
$1$4

Adicione termos do mesmo sinal.

+`\+_(_*(.*)¶-)_(_*\2\b)
+$1$3

Subtrair termos de sinais diferentes.

G`\b_

Remova os termos que foram cancelados por um termo de um sinal diferente.

\b_+
$.&

Converta o multiplicador novamente em decimal.

_(__+)
$.1

Decrementar expoentes maiores que três e converter novamente em decimal.

^\+|¶|(.)__|._
$1

a) Remova um +sinal inicial b) Junte todos os termos novamente juntos c) converta quadrados da variável na variável plana d) remova a variável se ela não tiver um expoente.

\b1([a-z])
$1

Remova o 1 temporário, a menos que não haja mais nada para multiplicar.

^$
0

Se não houver termos restantes, o resultado será zero.

O suporte a termos duplicados custa quase metade da minha contagem de bytes. Solução anterior de 123 bytes que não deduplicou os termos:

(.)(?=.*¶\1$)
$&_
L`.\w*
G`_
_\d+
*
\b[a-z]
1$&
\b(\d+)(?=.*?(_+))
$.($1*$2
_(__+)
$.1
^\+|¶|(.)__|._
$1
\b1([a-z])
$1
^$
0

Experimente online! Explicação:

(.)(?=.*¶\1$)
$&_

Adicione um _após cada ocorrência da variável especificada.

L`.\w*

Divida a entrada em termos.

G`_

Mantenha apenas os termos que referenciaram a variável.

_\d+
*

Converta todos os expoentes da variável em unário.

\b[a-z]
1$&

Coloque um prefixo temporário 1 para esses termos sem um multiplicador.

\b(\d+)(?=.*?(_+))
$.($1*$2

Multiplique o multiplicador pelo expoente da variável.

_(__+)
$.1

Decrementar expoentes maiores que três e converter novamente em decimal.

^\+|¶|(.)__|._
$1

a) Remova um +sinal inicial b) Junte todos os termos novamente juntos c) converta quadrados da variável na variável plana d) remova a variável se ela não tiver um expoente.

\b1([a-z])
$1

Remova o 1 temporário, a menos que não haja mais nada para multiplicar.

^$
0

Se não houver termos restantes, o resultado será zero.


Impressionante, mas você precisa mesclar esses dois termos no seu exemplo de TIO.
Weijun Zhou

1
@WeijunZhou Desculpe, eu tinha esquecido esse pouco das especificações. Deixe-me pensar sobre isso ...
Neil

@ WeijunZhou Ugh, isso me custou muitos bytes, mas acho que estou funcionando.
Neil

Muito obrigado pelo seu impressionante trabalho duro. Acho que esse é um bom ponto para eu começar a aprender Retina.
Weijun Zhou


0

Physica , 3 bytes

Isso não usa nenhum novo recurso. e sua alternativa somente ASCII, Differentiateforam introduzidas há mais de 10 dias .

Demo

Supõe que a expressão e a variável são passadas como uma sequência. Código de teste:

f = ∂

Print[f['2*x*y+4*a*x-5+7*m*x^4-4-7*x^4*m'; 'x']]
Print[f['4*u*p*v+5*u^2*v^3*w^4-4*w^4*u^2*v^3+q*r-v'; 'v']]
Print[f['-a+10*c*a^11*y-1*n*v^3*r*t^3*d-p*o*l*y'; 'a']]

Saída exata:

4*a + 2*y
4*p*u + 3*u**2*v**2*w**4 - 1
110*a**10*c*y - 1

Formato de expressão: *para multiplicação, **exponenciação +e -adição e subtração de acordo.

Physica - Demonstração Visual



Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.