Você escreve matemática em LaTeX. O Sucuri lê como SymPy, e mostra o que entendeu — em matemática de livro, e em código que você pode copiar. Onde a notação deixa dúvida, ele pergunta em vez de adivinhar. É essa a única regra, e tudo aqui sai dela.
Para ver o Sucuri diante de exercícios de listas reais de geometria diferencial — o que resolve, o que não, e por quê —, há a apostila.
Todos os exemplos deste manual são executados pela suíte de testes a cada mudança. O que está escrito aqui como saída é a saída.
1. Escrever e executar
No caderno, escreva na célula e tecle
Shift+Enter. Cada célula que vira matemática ganha um
nome — eq1, eq2 — e é por ele que você se refere a ela
depois.
x^2 + 1
x**2 + 1
2. Quando ele pergunta
Nem toda notação diz o que significa. y'' pode ser a derivada
segunda de y, ou um símbolo chamado “y duas linhas” — as duas se
escrevem igual, e o Sucuri não escolhe por você:
y'' + y = 0
y'' → derivada de ordem 2 de y | símbolo chamado y''
Você responde clicando na leitura certa — ou, melhor, declarando, que responde de uma vez para o caderno inteiro.
A barra de divisão é outro caso. O parser põe no denominador tudo o que vem
colado depois dele — 1/2 x viraria 1/(2x) —, e na escrita corrente
quase sempre se quis o contrário. O Sucuri pergunta; para não perguntar,
escreva \frac{1}{2}, ou um \cdot depois do denominador:
y = 1/2 (x+z)
/2 → a fração multiplica o que vem depois: (…/2)·(…) | o que vem depois vai para o denominador: …/(2·…)
3. Declarar
Declarar não escolhe entre as leituras: dissolve a dúvida. Se
y é função de x, então y' só pode ser
dy/dx — não há o que perguntar.
y = y(x)
y'' + y = 0
Eq(y(x) + Derivative(y(x), (x, 2)), 0)
u = u(t,x) | u é função de t e x |
e = euler | e é o número de Euler, não um símbolo |
a = símbolo | a não é função: a(x+1) é produto |
\mu, \nu = índices | índices tensoriais — índices(3) dá a dimensão; índices(d), uma letra |
T = tensor(0,2) | o tipo do Schutz: 0 formas, 2 vetores |
F = tensor(0,2, antissimétrico) | e a simetria dos slots: simétrico, antissimétrico, riemann |
\omega = forma(2) | uma 2-forma — um (0,2) antissimétrico |
g = métrica | a métrica: baixa e levanta índice, e é simétrica |
g = métrica(-,+,+,+) | com a assinatura, escrita em sinais |
g = métrica(cartesiana) | euclidiana e constante, ∂g = 0; ou (-,+,+,+, constante) |
x = coordenadas | xi, as coordenadas com índice: ∂jxi = δij |
g = det(g) | g sem índice é det gμν: √−g, ln|g| |
g = métrica(…componentes…) | com as componentes da diagonal (seção 8) |
\delta = kronecker | a delta: δμν |
\epsilon = levi-civita(tensor) | ou (símbolo) — os livros não fazem igual |
\nabla = levi-civita | a conexão: ∇g = 0, sem torção |
R = riemann(eq1) | o Riemann, na convenção que eq1 escreve |
R = ricci(eq2) | Rμν e R, contrações do Riemann, na convenção que eq2 escreve |
\Gamma = christoffel(eq1) | os Christoffel, na ordem de slots que eq1 escreve |
R = curvatura | R(U,X)W é o operador de curvatura, sem índice |
\star = hodge | o dual de Hodge (pede a assinatura) |
Parêntese, como em livro. Escrito com o mesmo nome dos dois lados é
tautologia — ninguém escreve u = u(t,x) como equação —, e é essa
repetição que separa declaração de matemática: u(t,x) sozinho
continua sendo uma expressão.
4. Os verbos
São poucos e fechados de propósito. Se aqui se pudesse escrever Python, a ponte que este programa é deixaria de ser obrigatória — e sobraria um Jupyter com passos a mais.
A lista abaixo é a lista inteira: o que não está nela não é verbo. Os nomes
em português e em inglês valem nas duas línguas da interface. As declarações —
métrica, índices, tensor, … — estão na
seção 3.
| Verbo | Em inglês | O que faz |
|---|---|---|
| Equações | ||
resolver(eq) | solve(eq) |
Equação diferencial vai ao solver de EDO, e a solução volta conferida por substituição; equação algébrica dá as raízes. Recusa o que não é igualdade. |
avaliar(eq) | evaluate(eq) |
Faz a conta parada: o valor exato, com a aproximação ao lado;
integral indefinida dá a família. Com índice e métrica com componentes,
dá as componentes; um rótulo de tabela, avaliar(\Gamma^{r}_{tt}),
dá o seu valor (seção 8). |
simplificar(eq) | simplify(eq) |
Simplifica, e o resultado ganha nome. Com índice, usa as simetrias
declaradas, e uma igualdade entre tensores sai True quando
os lados coincidem (seção 7). |
separar(eq) | separate(eq) |
Separa as variáveis de uma EDP supondo um produto, u = T(t)·X(x): as EDOs saem com nome e com a sua solução. Não prova que a superposição dos modos é completa. |
conferir(eq, cand) | check(eq, cand) |
Substitui a candidata na equação: candidata verificada, com resto 0, ou o resto que sobrou. Com um argumento só, recusa. |
exportar(eq) | export(eq) |
O código SymPy que declara, monta e resolve eq — roda sem o Sucuri. |
latex(eq) | latex(eq) |
A escrita em LaTeX, para copiar. |
série(eq, x, n) | series(eq, x, n) |
A série em torno de x = 0 até a ordem n, com o O(xn); numa igualdade, a do lado esquerdo menos o direito. O polinômio ganha nome. Sem os três argumentos, recusa. |
| Notação de índice | ||
contrair(eq) | contract(eq) |
Baixa e levanta índice com a métrica declarada: gμνAν vira Aμ. Recusa quando a métrica não está contraída com nada (seção 7). |
indices(eq) | indices(eq) |
Escreve com índice o que foi escrito sem — ∇UX vira
Uα∇αXμ —, com os índices declarados;
sem eles, recusa (seção 11). \mu, \nu = índices(4) é outra
coisa: a declaração (seção 3). |
expandir(eq)expandir(eq, g) |
expand(eq)expand(eq, g) |
Abre ∇ em ∂ e Γ; com g, abre também Γ pela métrica. Pede a
convenção de Γ declarada, \Gamma = christoffel(eq1). Uma
igualdade que fecha sai True (seção 7). |
independentes(T, eq…) | independent(T, eq…) |
Quantas componentes de T sobram, com as simetrias declaradas e as
equações dadas, na dimensão de índices(n). |
em_componentes(eq) | in_components(eq) |
Confere a identidade com o tensor mais geral que as declarações
permitem e uma métrica qualquer: True ou
False. |
linearizar(eq, h) | linearize(eq, h) |
g = η + εh, até a primeira ordem em ε. Pede
h = tensor(0, 2, simétrico) declarado. |
provar(eq, h1, h2, …) | prove(eq, h1, h2, …) |
O objetivo a partir só das hipóteses nomeadas, linha por linha, com ou sem índice (seções 9 e 10). Quando não acha, diz que não achar não é prova de que é falso. |
| Componentes numa carta | ||
christoffel(g) | christoffel(g) |
Os Γ não nulos da métrica com componentes, na carta declarada
(seção 8). Com nome à esquerda, \Gamma = christoffel(eq1)
não é este verbo: declara a convenção de Γ que eq1 escreve (seção 3). |
riemann(g) | riemann(g) |
As componentes não nulas do Riemann. R = riemann(eq1)
declara a convenção do Riemann que eq1 escreve (seção 3). |
ricci(g) | ricci(g) |
As componentes não nulas de Rμν. R = ricci(eq2)
declara Rμν e R como contrações do Riemann (seção 3). |
escalar(g) | scalar(g) |
O escalar de Ricci. Os quatro aceitam um segundo nome,
escalar(g, \Phi): a conta em primeira ordem em Φ. |
geodesicas(g) | geodesics(g) |
As equações das geodésicas, com parâmetro afim, cada uma com nome; e o que se conserva: g(ẋ, ẋ) e g(∂k, ẋ) para cada coordenada de que a métrica não depende. |
órbitas(g) | orbits(g) |
As geodésicas de uma métrica 2D diagonal com uma coordenada cíclica, por quadratura: dφ/dr e, quando a integral é elementar, a órbita, com nome. Outra dimensão, recusa. |
volume(g, x = a .. b, …) | volume(g, x = a .. b, …) |
∫√|det g|, com um limite por coordenada: o elemento de volume e o valor, com nome. Faltando limite, recusa. |
elemento(g) | element(g) |
O elemento de linha ds². |
cartan(g) | tetrad(g) |
De uma métrica diagonal: a tétrada ea = √|gaa| dxa, as formas de conexão, as de curvatura e o Riemann na base ortonormal. |
em_carta(eq) | in_chart(eq) |
Uma expressão com índice, componente por componente na carta da
métrica declarada; o Riemann e o Ricci entram pelas convenções
declaradas. Numa igualdade, True ou as componentes da
diferença. |
killing(g, X)killing(g, n) |
killing(g, X)killing(g, n) |
Com um campo: ℒXg, e se X é de Killing. Com um número:
os campos de Killing de componentes polinomiais de grau ≤ n. Campo se
declara com X = campo(…) ou covetor(…), nas
componentes da carta. |
colchete(X, Y) | bracket(X, Y) |
[X, Y], na base coordenada. |
nabla(g, A) | nabla(g, A) |
As primeiras e as segundas derivadas covariantes de um campo ou covetor. |
laplaciano(g, A) | laplacian(g, A) |
gik∇i∇kA, componente por componente. |
h = induzida(g, X^1, …) | h = induced(g, X^1, …) |
A métrica induzida — o pull-back de g pela parametrização —, nas coordenadas declaradas por último; h é métrica como outra qualquer. Sem coordenadas novas, recusa. |
restringir(K, h) | restrict(K, h) |
Um campo do espaço de fora, restrito à subvariedade de h e registrado com o mesmo nome. Campo com componente normal, recusa. |
| Formas numa carta | ||
cunha(\alpha, \beta) | wedge(\alpha, \beta) |
α∧β, numa carta: \alpha = forma(x\,dy). Com nome à
esquerda, P = cunha(\alpha, \beta), o resultado vira forma
com nome — vale também para estrela, exterior, interior e lie. |
estrela(\alpha, g) | star(\alpha, g) |
O dual de Hodge pela métrica; estrela(1, g) é o
elemento de volume. |
exterior(\alpha) | exterior(\alpha) |
dα. |
interior(X, \alpha) | interior(X, \alpha) |
ιXα, com X um campo. |
lie(X, \alpha) | lie(X, \alpha) |
ℒXα. |
iguais(\alpha, \beta) | equal(\alpha, \beta) |
True, ou a diferença. Aceita 0:
iguais(E, 0). |
ortonormal(\alpha, g) | ortonormal(\alpha, g) |
α no cobase ortonormal σi = √|gii| dxi. |
resolver
Um verbo só; o objeto decide a conta. Equação diferencial vai ao solver de
EDO, com a solução conferida por substituição; equação
algébrica vai ao solve.
y = y(x)
y'' + y = 0
resolver(eq1)
Eq(y(x), C1*sin(x) + C2*cos(x))
e a linha conferência: substituída na equação, resto 0. Sem ela a resposta não se apresenta como conclusão.
avaliar
\int_0^1 x^2
avaliar(eq1)
1/3
com a aproximação ≈ 0,333333333333 ao lado —
nunca no lugar do valor exato.
Integral indefinida devolve a família, com a constante:
\int \sin x\,dx
avaliar(eq1)
-cos(x)
mostrado como −cos(x) + C: o resultado é a
família inteira, e o código copiável traz uma primitiva dela.
simplificar
\frac{x^2 - 1}{x - 1}
simplificar(eq1)
x + 1
exportar
O pedido mais honesto que um programa destes recebe: me dá o código que você usou. O que sai roda sozinho, sem o Sucuri.
y = y(x)
y'' + y = 0
exportar(eq1)
eq1 = Eq(y(x) + Derivative(y(x), (x, 2)), 0)
junto com as declarações de símbolos, a chamada do solver e a linha que confere a solução.
separar e conferir
Para equações a derivadas parciais. O pdsolve do SymPy resolve
pouco — a equação da onda ele não resolve —, mas separar variáveis e conferir
uma candidata resolvem o problema pela via clássica.
u = u(t,x)
c = símbolo
\frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2}
separar(eq1)
Eq(Derivative(T(t), (t, 2)), k*T(t))
e a equação em x, cada uma com a sua solução — e cada uma
com nome (eq2, eq3), para você continuar:
resolver(eq2).
Separar não resolve a equação, e o resultado diz isso: supõe que a solução é um produto. O que sai são os modos; a solução geral é a superposição deles, e a separação não prova que ela seja completa.
Já conferir faz o caminho inverso de resolver: você
propõe, ele testa.
u = u(t,x)
c = símbolo
F = F(z)
G = G(z)
\frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2}
u = F(x - c t) + G(x + c t)
conferir(eq1, eq2)
candidata verificada
d'Alembert: resto 0. Uma candidata errada sai como candidata NÃO verificada, com o resto que sobrou; e quando o conferidor não consegue testar, ele diz isso em vez de acusar.
provar
O objetivo primeiro, e depois as hipóteses — só as nomeadas. Escrever uma equação no caderno não é afirmá-la, e uma prova que usasse a conta de rascunho da linha de cima não provaria nada.
U = tensor(1, 0)
X = tensor(1, 0)
Y = tensor(1, 0)
\nabla_U X = \nabla_X U
\nabla_Y \nabla_U X = \nabla_Y \nabla_X U
provar(eq2, eq1)
nabla_Y(eq1)
cada linha da resposta diz de que hipótese veio e o que se fez com ela — aqui, ∇Y aplicado aos dois lados de eq1 —, e a soma é conferida de novo antes do ∎. Sem índice, trabalha com a conexão e com formas (seções 9 e 10); quando não acha, diz que não achar não é prova de que é falso.
Com índice, o mesmo verbo. As relações que a busca tira de cada hipótese são as que valem para qualquer equação tensorial: trocar os índices livres (e contraí-los, com a métrica), multiplicar por um tensor, aplicar ∇ uma ou duas vezes. Com Levi-Civita e o Riemann declarados, a primeira identidade de Bianchi entra como teorema, e a prova a cita quando usa.
a, b = índices
T = tensor(2, 0, simétrico)
X = tensor(0, 1)
\nabla = levi-civita
g = métrica
\nabla_a T^{ab} = 0
\nabla_a X_b + \nabla_b X_a = 0
\nabla_a (T^{ab} X_b) = 0
provar(eq3, eq1, eq2)
1/2 · eq2 [a→L_0, b→L_1] × T(-L_0, -L_1)
a corrente de um campo de Killing é conservada: eq1 vezes X, mais ½ eq2 vezes T. As duas notações não se misturam numa prova: hipótese sem índice num objetivo com índice é recusada.
independentes, em_componentes, linearizar
Três verbos para o que a álgebra de índices não alcança sozinha, todos
numa dimensão dada em número — índices(4):
independentes(T, eq…) | quantas componentes de T
sobram, com as simetrias declaradas e as equações dadas (lineares em T).
Zero: só o tensor nulo tem essas propriedades. O Riemann definido pela
conexão — R = riemann(eq), com Levi-Civita — leva a primeira
identidade de Bianchi junto (20 em 4D); um tensor(0,4,riemann)
declarado só tem as simetrias de par, e dá 21. |
em_componentes(eq) | confere a identidade com o tensor mais geral que as declarações permitem e uma métrica qualquer, componente por componente. |
linearizar(eq, h) | g = η + εh até a primeira ordem em ε: abre ∇ em Γ e Γ em ∂g, troca g e ∂g, e corta. |
\mu, \nu, \rho, \sigma = índices(2)
V = tensor(1, 0)
\nabla = levi-civita
g = métrica
\nabla_\mu \nabla_\nu V^\rho - \nabla_\nu \nabla_\mu V^\rho = R^\rho{}_{\sigma\mu\nu} V^\sigma
R = riemann(eq1)
R_{\mu\nu} = R^\rho{}_{\mu\rho\nu}
R = ricci(eq2)
R_{\mu\nu} = \frac{1}{2} R g_{\mu\nu}
em_componentes(eq3)
True
em duas dimensões, o tensor de Einstein é identicamente
nulo. Em índices(3), False.
contrair, indices
contrair baixa e levanta índice com a métrica (seção 7);
indices escreve com índice o que foi escrito sem (seção 11). Os
verbos de componentes — christoffel, riemann,
ricci, escalar — estão na seção 8.
expandir abre ∇ em ∂ e Γ, com índice (seção 7) — e
\Gamma = christoffel(eq1), com um nome à esquerda, não é o verbo
de componentes: é a declaração da convenção de Γ.
5. O que cada resposta quer dizer
| estabelecida | conferida. Pode ser citada como conclusão. |
| sem fonte | o programa achou alguma coisa e não conseguiu confirmar. Não se apresenta como conclusão. |
| não aplicável | é dado, não conclusão — uma tabela, uma separação, um intermediário. |
E as cores: verde decidido ou conferido; âmbar veio de uma regra geral e ninguém olhou aquele caso; vermelho impede de seguir. Nota de alcance — “isto não resolve a equação” — é verde: a conta está certa, o que ela não faz é que precisava ser dito.
6. Quando ele não acha
y = y(x)
y'' = 6 y^2
resolver(eq1)
sem solução encontrada
com os padrões que o SymPy tentou, e o lembrete que
importa: não achar solução não é prova de que não existe.
Para essa outra pergunta existe o módulo korvin, que decide
não-integrabilidade por teoria de Galois — e que não acompanha a versão
online.
7. Tensores com índice
Índice não é expoente, e o parser de LaTeX do SymPy não sabe a diferença:
sem declaração, A^\mu viraria A elevado a μ. Quem decide
é você:
\mu, \nu = índices
g = tensor(0, 2)
g_{\mu\nu} A^\mu A^\nu
g(-L_0, -L_1)*A(L_0)*A(L_1)
todos os índices contraídos. A valência aparece na tela, porque é a primeira coisa que se confere num tensor.
E a consistência vem junto — este é um erro de relatividade, não de digitação, e a olho ninguém vê:
\mu, \nu = índices
A^\mu B_\mu + C^\nu
os termos da soma têm índices livres diferentes
Declarada a métrica, o índice desce e sobe — contrair aplica a
convenção Aμ ≡ gμνAν:
\mu, \nu = índices
g = métrica
A = tensor(1,0)
g_{\mu\nu} A^{\nu}
contrair(eq1)
A(-mu)
Ele exige o g = métrica porque baixar índice é
convenção da métrica, e não de um (0,2) qualquer — e nada na
expressão distingue os dois casos. Sem a declaração, recusa.
Simetria
E a simetria dos slots se declara junto com o tipo. Serve às duas notações:
com índice, simplificar a usa; sem índice, provar.
\mu, \nu = índices
F = tensor(0, 2, antissimétrico)
h = tensor(2, 0, simétrico)
F_{\mu\nu} h^{\mu\nu}
simplificar(eq1)
0
antissimétrico contraído com simétrico. A métrica é simétrica sem precisar dizer; e simetria num (1,1) é recusada — trocar índice de cima com de baixo pede a métrica, e aí é outro tensor.
a, b, c, d = índices
R = tensor(0, 4, riemann)
R_{abcd} - R_{cdab}
simplificar(eq1)
0
as simetrias do Riemann (0,4): antissimétrico em cada par, simétrico na troca dos pares — iguais em todo livro. A identidade cíclica não entra: é teorema, e pede torção nula.
\mu, \nu = índices
T = tensor(0, 2)
T_{(\mu\nu)} + T_{[\mu\nu]} - T_{\mu\nu}
simplificar(eq1)
0
(…) simetriza, […] antissimetriza, com o fator 1/n! de
Wald, MTW e Carroll; o que está entre barras, S_{(\mu|\rho|\nu)},
fica de fora. Sem os índices declarados, recusa: o parser do SymPy
descarta os parênteses e leria T(μν) como Tμν.
Kronecker e Levi-Civita
A delta de Kronecker e o Levi-Civita também se declaram — δ porque
\delta é também variação, e ε porque há duas leituras:
\mu, \nu = índices
\delta = kronecker
A = tensor(1, 0)
\delta^\mu_\nu A^\nu
simplificar(eq1)
A(mu)
e \delta^\mu_\mu vira a dimensão.
\epsilon = levi-civita
levi-civita(símbolo) ou levi-civita(tensor)?
o símbolo vale ±1 em toda carta e não sobe nem desce com
g; o tensor é √|g| vezes o símbolo, e sobe e desce. As duas leituras dão
contas diferentes em contrair.
\mu, \nu, \rho, \sigma = índices
\delta = kronecker
g = métrica(-,+,+,+)
\epsilon = levi-civita(tensor)
\epsilon^{\mu\nu\rho\sigma} \epsilon_{\mu\nu\rho\sigma}
simplificar(eq1)
-24
o sinal é (−1)s, com s os sinais negativos da
assinatura — por isso ela se declara com os sinais, e
métrica(lorentziana) sozinha é recusada. Com o símbolo, é +24
em qualquer assinatura.
Derivada com índice
E a derivada com índice é um objeto próprio, e não um fator — ∂ comuta, ∇ não, e as duas seguem Leibniz:
\mu, \nu = índices
\partial_\mu \partial_\nu \phi - \partial_\nu \partial_\mu \phi
simplificar(eq1)
0
com ∇ no lugar de ∂, não zera: ∇μ∇ν − ∇ν∇μ é torção e curvatura, e nada se supõe.
Com a conexão declarada, o comutador vira curvatura — na convenção da definição que você escreveu:
\mu, \nu, \rho, \sigma = índices
V = tensor(1, 0)
W = tensor(0, 1)
\nabla = levi-civita
\nabla_\mu \nabla_\nu V^\rho - \nabla_\nu \nabla_\mu V^\rho = R^\rho{}_{\sigma\mu\nu} V^\sigma
R = riemann(eq1)
\nabla_\mu \nabla_\nu W_\rho - \nabla_\nu \nabla_\mu W_\rho
simplificar(eq2)
-R(L_0, -rho, -mu, -nu)*W(-L_0)
o sinal e a ordem dos slots do Riemann variam de livro
para livro; riemann(eq1) os lê da identidade escrita. E
\nabla = levi-civita é o que faz ∇g = 0 — sem ela, não.
E ∇ se abre em ∂ e Γ. A ordem dos slots de Γ também varia — Carroll põe o
índice da derivada primeiro, Reall por último —, e por isso também é lida da
definição. expandir(eq) troca cada ∇ por ∂ mais um Γ por índice
(+ no de cima, − no de baixo); expandir(eq, g) escreve também
cada Γ pela métrica, o que só vale — e só se faz — com
\nabla = levi-civita. Numa equação, a resposta é
True quando os dois lados coincidem.
\mu, \nu, \lambda, \sigma = índices
V = tensor(1, 0)
\nabla = levi-civita
g = métrica
\nabla_\mu V^\nu = \partial_\mu V^\nu + \Gamma^\nu{}_{\mu\lambda} V^\lambda
\Gamma = christoffel(eq1)
\partial_\lambda g_{\mu\nu} = g_{\mu\sigma} \Gamma^\sigma{}_{\nu\lambda} + g_{\nu\sigma} \Gamma^\sigma{}_{\mu\lambda}
expandir(eq2, g)
True
∂λgμν = −gμαgνβ∂λgαβ
— o que “inversa” quer dizer — o simplificar aplica sempre
que há métrica declarada.
8. Componentes numa carta
A notação de índice diz a estrutura — que g tem dois
índices embaixo. Não diz o que g vale. Para Christoffel,
Ricci e Riemann é preciso o outro lado: componentes, numa carta. Declare as
coordenadas e depois a métrica, pela diagonal:
x = coordenadas(t, r, \theta, \phi)
g = métrica(-(1 - \frac{2M}{r}), \frac{1}{1 - \frac{2M}{r}}, r^2, r^2 \sin^2\theta)
g é a métrica em (t, r, \theta, \phi), diagonal, com 4 componentes
Schwarzschild. A diagonal, e não \begin{pmatrix},
porque o parser de LaTeX do SymPy não lê matriz — e porque é assim que os
livros dão quase todas as métricas que importam.
Daí saem christoffel, riemann, ricci
e escalar. O que volta são componentes, e por isso a
resposta diz sempre em que coordenadas está: trocar de carta troca todas
elas.
x = coordenadas(t, r, \theta, \phi)
g = métrica(-(1 - \frac{2M}{r}), \frac{1}{1 - \frac{2M}{r}}, r^2, r^2 \sin^2\theta)
ricci(g)
0 componente(s) não nula(s)
Ricci nulo — Schwarzschild é solução do vácuo. Este é o teste de sanidade de toda relatividade, e o programa o faz em segundos. Ao contrário de uma componente, «Ricci é nulo» não depende da carta.
E se a métrica tiver componentes, avaliar dá o outro lado: não a
estrutura, o valor.
x = coordenadas(t, r, \theta, \phi)
g = métrica(-(1 - \frac{2M}{r}), \frac{1}{1 - \frac{2M}{r}}, r^2, r^2 \sin^2\theta)
\mu, \nu = índices
A = tensor(1,0)
g_{\mu\nu} A^{\nu}
avaliar(eq1)
A_{t}
as quatro componentes de Aμ, cada uma em função
das de Aμ — que ninguém declarou, e por isso entram como nomes
(A__t é At na convenção do SymPy, que reentra sem
virar potência).
O que a tabela imprime tem nome, e nome é alvo de verbo:
x = coordenadas(t, r, \theta, \phi)
g = métrica(-(1 - \frac{2M}{r}), \frac{1}{1 - \frac{2M}{r}}, r^2, r^2 \sin^2\theta)
christoffel(g)
avaliar(\Gamma^{r}_{tt})
M*(-2*M + r)/r**3
sem as chaves duplas que a tabela usa — chave é tipografia
do TeX, não identidade. E a componente que vale zero não entra na
tabela (55 zeros escondem as nove que importam) mas responde quando
perguntada: avaliar(\Gamma^{t}_{rr}) dá 0.
9. Sem índice: a conexão
Sem índice, o vetor é o objeto abstrato, e a mesma declaração diz o que
\nabla_U quer dizer: a derivada na direção de U.
U = tensor(1, 0)
X = tensor(1, 0)
\nabla_U \nabla_X U - \nabla_X \nabla_U U
nabla_U(nabla_X(U)) - nabla_X(nabla_U(U))
aplicação, e não produto: a ordem fica na estrutura, e os
dois termos não se cancelam. Sem a declaração o parser leria
X*nabla_{U}, que comuta — e a curvatura sumiria.
\nabla_V X
'V' não foi declarado
∇V e ∇μ se escrevem igual. Quem decide entre direção e índice é a declaração.
Com R = curvatura, R(U,X)W é o operador aplicado a
W, e não R vezes o parêntese. E entre dois vetores o colchete só pode ser o de
Lie:
U = tensor(1, 0)
X = tensor(1, 0)
R = curvatura
R(U,X)U = \nabla_U \nabla_X U - \nabla_X \nabla_U U - \nabla_{[U,X]} U
Eq(R(U, X)(U), nabla_U(nabla_X(U)) - nabla_X(nabla_U(U)) - nabla_{[U, X]}(U))
a declaração diz o papel de R, não o sinal: a ordem dos argumentos e o sinal variam de livro para livro, e para ler isso não importa.
E com a leitura vem a prova. provar recebe o objetivo e as
hipóteses — só as nomeadas: escrever uma equação no caderno não é
afirmá-la.
U = tensor(1, 0)
X = tensor(1, 0)
R = curvatura
[U,X] = 0
\nabla_U U = 0
\nabla_U X - \nabla_X U = [U,X]
R(U,X)U = \nabla_U \nabla_X U - \nabla_X \nabla_U U - \nabla_{[U,X]} U
\nabla_U \nabla_U X = R(U,X)U
provar(eq5, eq1, eq2, eq3, eq4)
provado a partir de eq1, eq2, eq3, eq4
a equação do desvio geodésico. Cada passo da tabela diz de
que hipótese veio e o que se fez com ela — nabla_U(eq3) é eq3
com ∇U aplicado aos dois lados —, e a soma é conferida de novo
antes do ∎. O motor sabe sozinho só o que vale para qualquer conexão —
linearidade, Leibniz —; o sinal de R vem da definição que você deu, e com
o sinal oposto a mesma chamada não prova.
Uma definição vale para qualquer vetor. Com \forall ela se diz
uma vez, e a prova a instancia onde precisar:
U = tensor(1, 0)
X = tensor(1, 0)
R = curvatura
\forall A, B, W: R(A,B)W = \nabla_A \nabla_B W - \nabla_B \nabla_A W - \nabla_{[A,B]} W
\forall A, B: \nabla_A B - \nabla_B A = [A,B]
[U,X] = 0
\nabla_U U = 0
\nabla_U \nabla_U X = R(U,X)U
provar(eq5, eq1, eq2, eq3, eq4)
eq1[A→U, B→X, W→U]
a tabela diz em que instância cada hipótese geral entrou.
O separador depois da lista do ∀ é obrigatório — dois-pontos,
\colon, \quad —, e as variáveis ligadas não
vazam para as linhas de baixo.
Escalar é o que não foi declarado tensor, e \nabla_U f é a
derivada direcional U(f). Todo símbolo que não é número é tratado como
função — o lado seguro: se c for constante, U(c) = 0 é caso particular, e a
prova que precisar disso pede a hipótese.
U = tensor(1, 0)
X = tensor(1, 0)
\nabla_U f = 0
\nabla_U (f X) = f \nabla_U X
provar(eq2, eq1)
eq1·X
Leibniz: ∇U(fX) = U(f)X + f∇UX, e a hipótese escalar entra multiplicada por X. A combinação que fecha uma prova é só com números: multiplicar por função é passo explícito, e de fX = fU não sai X = U — falso onde f se anula.
Com g = métrica, g(X,Y) é o produto escalar —
simétrico e linear em cada slot, sem hipótese. A compatibilidade com a métrica
é hipótese, e com ela e a torção nula sai a fórmula de Koszul:
X = tensor(1, 0)
Y = tensor(1, 0)
Z = tensor(1, 0)
g = métrica
\forall A, B, C: \nabla_A g(B,C) = g(\nabla_A B, C) + g(B, \nabla_A C)
\forall A, B: \nabla_A B - \nabla_B A = [A,B]
2 g(\nabla_X Y, Z) = \nabla_X g(Y,Z) + \nabla_Y g(X,Z) - \nabla_Z g(X,Y) + g([X,Y],Z) - g([X,Z],Y) - g([Y,Z],X)
provar(eq3, eq1, eq2)
g(eq2[A→X, B→Y], Z)
a torção nula posta no primeiro slot de g: uma relação entre vetores levada a uma entre escalares. Sem eq2, a mesma chamada não prova.
10. Formas diferenciais
E as formas diferenciais, sem índice: d, ∧, ιX,
ℒX. \omega = forma(2) declara uma 2-forma;
\mathrm{d} é sempre o operador, e d só quando age
numa forma declarada.
\omega = forma(1)
\eta = forma(2)
\mathrm{d}(\omega \wedge \eta) = \mathrm{d}\omega \wedge \eta - \omega \wedge \mathrm{d}\eta
provar(eq1)
provado a partir de nenhuma hipótese
d², Leibniz graduado, a comutatividade graduada, ι como antiderivação e a fórmula de Cartan valem sem hipótese. η∧η = 0 não passa — η tem grau par.
g = métrica(-,+,+,+)
\star = hodge
F = forma(2)
\star \star F = -F
provar(eq1)
provado a partir de nenhuma hipótese
⋆⋆ = (−1)p(n−p)+s: com assinatura euclidiana a mesma chamada não prova. O Hodge pede a assinatura declarada; a orientação, não — ela troca o sinal de ⋆, e não o de ⋆⋆.
11. De uma notação à outra
E de uma notação à outra: indices escreve com índice o que
foi provado sem.
\mu, \alpha, \beta = índices
U = tensor(1, 0)
X = tensor(1, 0)
\nabla_U X
indices(eq1)
U(L_0)*D_X(-L_0, mu)
Uα∇αXμ. A curvatura
R(U,X)W se traduz na convenção de riemann(eq), e a tradução
diz numa nota o que supôs sobre R sem índice.
12. O caderno
| Novo | apaga o escrito e o acumulado |
| Abrir / Salvar | arquivo de texto, células separadas por %%; abre em
qualquer editor |
| Rodar tudo | refaz tudo a partir do escrito, na ordem |
| Reiniciar | joga fora só o acumulado: eq1 deixa de existir,
e nenhuma linha do que você escreveu se move |
Entre duas células há um + para inserir; no canto de cada uma, um × para apagar, com desfazer na faixa de aviso.
Enter quebra linha; Shift+Enter roda. Numa célula só cabe mais de uma instrução, uma por linha, e cada uma responde na ordem:
\mu, \nu = índices
A = tensor(1,0)
A é tensor do tipo (1,0)
só encadeia quando todas as linhas são instrução reconhecida. Uma equação em LaTeX pode ocupar duas linhas, e parti-la daria duas metades sem sentido no lugar de um erro.
13. O que ele ainda não faz
Dizer isto é parte do trabalho. Nada abaixo falha em silêncio — tudo recusa com o motivo.
- Funções que o parser não conhece:
\operatorname{arsinh},\coth,\left\|·\right\|. O SymPy tem essas funções; o parser de LaTeX é que não as lê. \frac{d}{dx}como operador não é sítio declarado: funciona porque a gramática do SymPy tem uma regra para ela, e onde essa regra não alcança o silêncio volta.- Sistemas de equações: um verbo por vez, uma equação por vez.
- Métrica não diagonal: a declaração pede a diagonal. Kerr, com o seu termo cruzado dt dφ, ainda não entra.
provarencadeia hipóteses por álgebra linear, com uma busca finita: prova que pede uma ideia — introduzir uma quantidade que não aparece no enunciado — não sai, e prova que pede muitas instâncias encadeadas pode demorar. Com índice, vai até ∇∇ das hipóteses.- Formas: a fórmula de dω nos vetores entra como hipótese, porque muda de fator com a normalização; o codiferencial δ = ±⋆d⋆ não vem pronto, porque o sinal é de convenção.
- Tradução: só de sem índice para com índice; ∀ e formas não se traduzem.
O código, as auditorias e a lista completa de limites estão em github.com/RafaelCRdeLima/SUCURI.