Ecco le funzioni di questa libreria:

ada(la,per)   cambiacoord(tn,InFunDiN,NuoveC,metrica)   cambiasesso(lista,litipi,gff,gmm)   cambiatipi(tn,nuovitipi,metrica)   commentalo(tn,comme)   commento(tn)   diffcov(tn,metrica,nome)   dimensione(tn)   divergenza(tn,ki,metrica)   fa_ch122(g22,listavariabili)   fa_ch222(g220)   fa_diff(tn,variabili,comme)   fa_metrica(mg,listavariabili)   fa_r1222(t22,listavariabili)   fa_r22(t22,listavariabili)   fa_r2222(t22,listavariabili)   fa_tenergiaimpulso(tpotvet,metrica)   fondetatb(ta,tb,nome)   indici(tn)   listadatensore(tn)   knbl22a(info)   knbl22b(info)   nonmetricap(metrica)   ordine(tn)   permuta(tn,per,com)   rapportolistetensori(ta,tb)   ricci_22(t22,variabili)   riemann_1222(t22,variabili)   riemann_2222(t22,variabili)   scala(ta,ia,tb,ib)   semplimetrica(metrica)   semplimetricatrig(metrica)   tassegna(tn,val,p)   tcontrov(lv,metrica)   tcov(lv,metrica)   tdueantisim(tn,metrica)   tduetracciazero(tn,metrica)   tensoredalista(lista,tipi,comme,ndim)   tensorp(tn)   ticambiotutto(tn,metrica)   tmat11(mat,metrica)   tmat12(mat,metrica)   tmat21(mat,metrica)   tmat22(mat,metrica)   tmeno(tena,tenb)   tnsemplifica(tn)   tnsemplificatrig(tn)   tprod(tscala,tenb)   traccia(tn,ih,ik)   tsca(sc,metrica)   tsomma(tena,tenb)   tvale(tn,p)   zerotensor(tipi,comme,ndim)  

Da leggere:

General Relativity An Introduction for Physicists
Authors:
M. P. Hobson, University of Cambridge
G. P. Efstathiou, University of Cambridge
A. N. Lasenby, University of Cambridge
Date Published: February 2006 / format: Hardback / isbn: 9780521829519

Versione aggiornata della mia antica libreria tensoriale del 2010

Qualche antico caso prova... camuffato da file .html.

Convenzioni usate in questa vecchia e nuova libreria

Un tensore è una lista di oggetti vari (atomici, liste o matrici) lunga almeno 2 ma solitamente 3 se il tensore ha rango pari e di più se ha rango dispari.

L'ultimo elemento della lista DEVE OBBLIGATORIAMENTE essere una lista ossia la lista informativa della natura del tensore.

La lunghezza della lista, che ha scopi informativi, dell'ultimo elemento, diminuita di 2, è il rango del tensore ( un tensore di rango 0 è uno scalare ossia, in pratica non sarebbe un tensore, un tensore di rango 1 è detto vettore, un tensore di rango 2 è detto matrice ).

Il penultimo elemento della lista dell'ultimo elemento è un commento di qualsiasi tipo, un numero o una stringa o una lista etc. In questo modo posso commentare le proprietà del tensore, attribuirgli un nome per identificarlo etc...

L'ultimo elemento della lista dell'ultimo elemento è la dimensione dello spazio per il tensore considerato che deve valere almeno 2 ossia sono ammessi tensori in spazi almeno bidimensionali ossia il tempo e lo spazio.

I precedenti elementi indicano la natura degli indici del tensore( uso una antica convenzione che poi ho modificato ) . La distinzione base è tra indici covarianti indicati da cifre pari ed indici controvarianti da cifre dispari...

I tensori di rango dispari sono memorizzati in una lista lunga almeno quanto la dimensione dello spazio + 1 dato che l'ultimo elemento deve contenere la lista informativa. I tensori di rango 1 ossia i vettori hanno elementi, tranne l'ultimo, che contengono i valori delle corrispondenti componenti del vettore. Se invece i tensori sono di rango dispari maggiore di 1, gli elementi sono matrici se di rango 3 o matrici di matrici se di rango 5 etc...

I tensori di rango pari sono memorizzati in una lista di almeno due elementi ossia il primo elemento è una matrice o una matrice di matrice o una matrice di matrice di matrice etc. mentre l'ultimo, ossia almeno il secondo, contiene la lista informativa. Se sono scalari ossia hanno rango zero, il primo elemento nella lista non è una matrice ma il valore dello scalare e la lista informativa, come al solito, è il secondo o comunque l'ultimo elemento.

append(list_1, ... , list_n) e rest(expr,n) sono importanti funzione standard di Maxima per la manipolazione di liste.

La append consente di concatenare un numero arbitrario di liste, list_1, ..., list_n.

Per l'altra, il manuale di wxMaxima spiega in inglese come funziona:

Returns expr with its first n elements removed if n is positive and its last −n elements removed if n is negative. If n is 1 it may be omitted.    expr     may be a list, matrix, or other expression...

Dunque, usando la rest(expr,n) si elimina l'ultimo elemento della lista che costituisce il tensore e che ha solo scopo informativo sulla natura degli indici e sulla dimensione dello spazio in cui il tensore è stato definito. Quindi si può trattare quello che resta della lista come un qualsiasi oggetto algebrico di wxMaxima ossia, nelle verifiche, controllare se la differenza tra due tensori è esattamente zero.

Funzioni della libreria

Le elenco in ordine alfabetico...
Mancanze ed ultime aggiunte ... Fra poco sarà disponibile il calcolo dell'invariante quadratico di un qualsiasi tensore, importante, tra l'altro, nel caso del tensore di Riemann ossia l'invariante di Erich Justus Kretschmann. Il calcolo del campo elettrico ottenuto dal potenziale vettore viene fatto antisimmetrizzando un vettore di rango 2 con la tdueantisim ed ora si può fare il calcolo del tensore EnergiaInpulso che serve per dimostrare la correttezza delle singolarità della Relatività Generale ossia i buchi neri. L'importantissimo tensore EnergiaImpulso si ottiene con una funzione che crea un tensore di rango 2 con traccia nulla ossia con la tduetracciazero o, per fare tutto automaticamente, si usa la fa_tenergiaimpulso.
  1. ada(la,per)
    funzione che attua una permutazione direttamente sulla lista da permutare in modo da ottenere il risultato della permutazione su una lista la che può contenere qualsiasi tipo di dati inizialmente ordinati e come risultato, scambiati di posto tramite la permutazione per.
  2. cambiacoord(tn,InFunDiN,NuoveC,metrica)
    Funzione per il cambiamento del sistema di coordinate. Bisogna specificare ovviamente il tensore tn da modificare esprimendolo, come risultato, nelle nuove coordinate, poi le funzioni che esprimono le vecchie coordinate in funzione delle nuove ossia la lista InFunDiN , poi i simboli delle nuove coordinate ossia la lista NuoveC ed infine la metrica valida per il tensore da modificare, usata per sapere quali erano le espressioni delle vecchie coordinate.
  3. cambiasesso(lista,litipi,gff,gmm)
    Questa è la funzione applicata dalla ticambiotutto(tn,metrica) ma, dato che lavora su tensori scritti in forma di lista ed ha bisogno di ricevere in input l'indicazione del tipo di indici da attribuire alla lista , consente calcoli esplorativi senza bisogno di precalcolare la metrica ossia fare derivate.
    Per questo scopo la cambiasesso deve ricevere come terzo argomento gff ossia la matrice da considerare come tensore metrico covariante ossia totalmente femminile e come quarto argomento gmm ossia la inversa della gff che dunque considera come tensore metrico controvariante ossia totalmente maschile.
  4. cambiatipi(tn,nuovitipi,metrica)
    Questa funzione cambia il sesso degli indici del tensore tn passato come primo argomento. Bisogna specificare la lista dei nuovitipi degli indici per cui, solo se gli indici vecchi sono di tipo diverso da quello voluto, viene fatto il cambiamento. Come terzo argomento va passata la metrica da cui trarre il tensore metrico totalmente femminile ossia covariante ed il tensore metrico totalmente maschile ossia controvariante.
  5. commentalo(tn,comme)
    Per inserire un commento nel tensore, uso la commentalo ossia questa funzione... Il secondo argomento comme può essere qualsiasi cosa, numero, stringa, lista etc...
  6. commento(tn)
    Il commento che ogni tensore contiene e che può essere una stringa ma anche un numero o una lista o un qualsiasi oggetto, è estraibile in questo modo...
  7. diffcov(tn,metrica,nome) :
    derivata covariante di un tensore di qualunque tipo : si tratta di una funzione fondamentale ossia l'essenza del calcolo tensoriale. Riporto in seguito ulteriori commenti...
  8. dimensione(tn)
    Ogni tensore contiene, come si è detto, la dimensione dello spazio a cui si riferisce. Per ottenere questo dato si può usare questa funzione...
  9. divergenza(tn,ki,metrica)
    Crea la funzione divergenza di un tensore rispetto ad un dato indice ki, nota la metrica e dunque la dimensione, l'ordine del tensore e il tensore metrico controvariante. Fa uso della derivata covariante per cui questa funzione è applicabile a qualunque tensore di rango positivo.
    La funzione ha un nome comprensibile per chi fa uso del normale calcolo vettoriale ossia calcola la divergenza di un vettore. In pratica, supponendo di partire da un vettore maschio ossia controvariante, la divergenza si fa in questo modo: si calcola la derivata covariante del vettore e quindi si ottiene una matrice ossia un tensore di rango 2, il cui primo indice è maschio ed il secondo, prodotto dalla derivata, è femmina. Poi calcolo la traccia di questa matrice ossia la somma degli elementi diagonali e cosí ottengo uno scalare che appunto è la divergenza del vettore. Questa operazione può essere generalizzata partendo non da un vettore ma da un tensore di qualsiasi altro rango e questo vuol dire che un tensore ha tante divergenze quanto è il suo rango. Dunque una matrice, ossia un tensore di rango 2, ha due divergenze diverse, a meno che la matrice non sia simmetrica o antisimmetrica...
  10. fa_ch122(g22,listavariabili)
    Per fare simboli di Christoffel di seconda specie basta avere il tensore metrico totalmente femminile ossia covariante e la lista delle variabili usate nel sistema di riferimento ossia , per esempio, in spazi deformati dalla presenza di masse ma asintoticamente cartesiani la listavariabili potrebbe essere [ t,x,y,z ].
  11. fa_ch222(g220)
    Se si dispone dello pseudo tensore di rango 3 ottenuto derivando tutti gli elementi del del tensore metrico femminile g22 ottenendo g220 ( usare la fa_diff(g22,variabili,comme) ), il calcolo del Simbolo di Christoffel di prima specie è un calcolo di pura algebra e dunque puè essere fatto in modo molto veloce...
    Questa funzione, opportunamente tradotta in altri linguaggi incapaci di fare direttamente calcolo simbolico ma solo numerico, consente di lavorare per esempio anche in Javascript definendo esplicimamente le funzioni di g220.
  12. fa_diff(tn,variabili,comme) :
    derivata preliminare ossia non qualificata come covariante , di un tensore di qualsiasi rango. Richiede l'uso di una permutazione finale perché spontaneamente aggiungerebbe l'indice 0 all'inizio e non alla fine degli indici del tensore.
  13. fa_metrica(mg,listavariabili)
    Il calcolo differenziale tensoriale si basa su una funzione, fametrica, che genera la metrica usata per calcolare la derivata covariante. Questa funzione deve ricevere in argomento una matrice che, per sicurezza, viene simmetrizzata e usata come tensore metrico covariante della metrica.
    "Ha creato un vettore di più di undici elementi:"),
    • [1] : lista delle variabili
    • [2] : tensore metrico covariante
    • [3] : tensore metrico controvariante
    • [4] : derivate prime del tens. metrico cov.
    • [5] : derivate seconde del tens. m. cov.
    • [6] : simboli di Christoffel di prima specie
    • [7] : simboli di Christoffel di seconda specie
    • [8] : Riemann col solo primo indice controvariante
    • [9] : Riemann totalmente covariante
    • [10]: Ricci totalmente covariante
    • [11]: sqrt(abs(determinate del tens.metr.cov.)
    Nel vettore creato da questa funzione fa_metrica sono conservate anche alcune costanti importanti per l'elettromagnetismo e per l'astrofisica e la cosmologia.
  14. fa_r1222(t22,listavariabili)
    Genera il tensore di Riemann col primo indice controvariante.
    Ora trascrivo il tensore di Riemann con la formula dell'HEL Hobson,Efstathiou,Lasenby ISBN 9780521829519 a pag. 158. La formula ricopiata dal libro è questa:
    r1d2a2b2c = ch1d2a2a0b -
                ch1d2a2b0c +
                ch1e2a2c*ch1d2e2b -
                ch1e2a2b*ch1d2e2c
    
    Il nome degli indici però non mi piace e preferisco usare come nomi a,b,c,d sostituti di d,a,b,c ed inoltre usare il nome j al posto del nome e, per cui la formula diventa:
    r1a2b2c2d = ch1a2b2d0c -
                ch1a2b2c0d +
                ch1j2b2d*ch1a2j2c -
                ch1j2b2c*ch1a2j2d
    
    In linguaggio wxMaximese non interpongo i nomi degli indici alle cifre indicatrici di tipo ma scrivo i nomi tra parentesi quadre:
    r1222[a,b][c,d]:ch1220[a,b][d,c]-
                    ch1220[a,b][c,d]+
                    ch122[j][b,d]*ch122[a][j,c]-
                    ch122[j][b,c]*ch122[a][j,d]
    
    Per fare il calcolo bisogna disporre sia del simbolo di Christoffel di seconda specie che dello pseudotensore delle sue derivate.
    Spezzo il calcolo in due parti in modo che sia possibile partire o dal tensore metrico covariante o dai simboli di Christoffel di seconda specie.
  15. fa_r22(t22,listavariabili)
    Definisco il tensore di Ricci totalmente femminile, ossia doppiamente covariante seguendo ancora la definizione dell' HEL.
    In pratica fa la traccia tra il primo indice, maschile, e l'ultimo, femminile.
  16. fa_r2222(t22,listavariabili)
    Genera il tensore di Riemann totalmente covariante.
    Lo calcola in forma totalmente covariante senza fare uso delle derivate dei simboli di Christoffel, in base a quanto sta scritto sull' HEL.
    r2a2b2c2d = (g2b2c0d0a-
                 g2a2c0d0b+
                 g2a2d0b0c-
                 g2b2d0a0c )/2 +
                 ch1j2b2c*ch2j2a2d -
                 ch1j2b2d*ch2j2a2c
    
    ovvero in wxMaximese:
    r2222[a,b][c,d] = ( g2200[b,c][a,d] -
                        g2200[a,c][b,d] +
                        g2200[a,d][b,c] -
                        g2200[b,d][a,c] )/2 +
                        ch122[j][a,d]*ch222[j][b,c] -
                        ch122[j][a,c]*ch222[j][b,d]
    
    Il tensore di Riemann in forma totalmente covariante evidenzia le sue simmetrie. E' antisimmetrico scambiando gli indici della prima coppia ed è antisimmetrico scambiando gli indici della seconda coppia mentre è simmetrico scambiando le coppie tra loro.
    Per queste simmetrie il calcolo del tensore di Riemann potrebbe essere molto più veloce evitando inutili ricalcoli ma qui ...non si bada a spese...
  17. fa_tenergiaimpulso(tpotvet,metrica)
    Per trovare il tensore energia impulso NON NORMALIZZATO, partendo da un potenziale vettore, ossia un tensore di rango 1, faccio questa comoda funzioncina.
  18. fondetatb(ta,tb,nome)
    Importante funzione per fondere due tensori anche di diverso rango ottenendo un tensore di rango somma dei ranghi.
    Notare che i due tensori possono essere anche di rango zero per cui il risultato non aumenta di rango ma viene semplicemente moltiplicato per lo scalare del tensore di rango zero.
  19. indici(tn)
    ovvero la natura degli indici del tensore tn. Se pari sono femminili ossia covarianti e se dispari sono maschili ossia controvarianti.
  20. listadatensore(tn)
    Per estrarre TUTTI gli elementi di un tensore mettendoli in una lista. Notare che il tensore può essere anche di rango zero ossia uno scalare da cui si ottiene una lista con un solo elemento.
  21. knbl22a(info)
    Metrica di Kerr Newman nel sistema di riferimento di Boyer e Lindquist.
    L'argomento info serve solo per produrre stampe di spiegazione se è una stringa.
    Questa versione contiene solo espressioni razionali e non trigonometriche in modo da facilitare le semplificazioni delle formule da parte di wxMaxima.
    Si ha la possibilità di dare un valore numerico alle costanti, tipo cw ossia la velocità della luce, Gw ossia la costante di gravitazione universale ed Lw che è richiesto dal Sistema di Misura Internazionale per definire la permeabilità magnetica.
    La massa è indicata da Mw, La carica da Qw e lo spin da aw.
    Oltre alla matrice del tensore metrico e alla lista delle coordinate questa funzione fornisce l'espressione del potenziale vettore elettromagnetico in forma covariante ossia femminile per consentire il calcolo del campo elettromagnetico e del tensore EnergiaImpulso necessario per verificare l'equazione di Einstein ossia verificare che la metrica di Kerr Newman nel sistema di riferimento di Boyer e Lindquist si riferisce veramente ad un buco nero ossia una soluzione singolare della R.G. Dunque, da questo vettore è possibile calcolarlo usando la fa_tenergiaimpulso.
    Viene messa a disposizione anche la espressione dell'invariante quadratico del tensore di Riemann ottenuto mediante la metrica ottenuta da questa matrice ossia lo scalare di Erich Justus Kretschmann. In questo modo, ricalcolandolo, si può verificare che le varie funzioni coinvolte nel calcolo funzionino bene.
  22. knbl22b(info)
    Metrica di Kerr Newman nel sistema di riferimento di Boyer e Lindquist.
    L'argomento info serve solo per produrre stampe di spiegazione se è una stringa.
    Versione apparentemente semplice ma con uso di funzioni trigonometriche che rendono difficili le semplificazioni delle formule da parte di wxMaxima.
    Si ha la possibilità di dare un valore numerico alle costanti, tipo cw ossia la velocità della luce, Gw ossia la costante di gravitazione universale ed Lw che è richiesto dal Sistema di Misura Internazionale per definire la permeabilità magnetica.
    La massa è indicata da Mw, La carica da Qw e lo spin da aw.
  23. nonmetricap(metrica)
    L'ultimo valore della lista della metrica è sempre lo stesso e serve a capire se la lista della metrica è veramente stata creata dalla funzione fa_metrica.
  24. ordine(tn) o meglio, rango del tensore tn.
    L'ordine di un tensore è ottenibile con la seguente funzione che, per ragioni di velocità, non effettua nessuna verifica della correttezza del tensore tn passato in argomento.
  25. permuta(tn,per,com) :
    La funzione importantissima che permuta gli indici di un qualsiasi tensore creando un altro tensore con gli indici permutati in base all'ordinamento specificato dalla lista per. La lista per deve indicare da dove è stato preso il dato che compare in quella posizione.
    Per esempio [3,1,2,4] indica che il dato che compare come primo indice è quello che prima era situato in colonna 3, come secondo dato quello che prima stava in colonna 1 etc. La rotazione degli indici sa fa con [2,3,4,1].
  26. rapportolistetensori(ta,tb)
    Questa funzione serve ad evitare sbrodolate nella stampa dei tensore. Se credo che due tensori sono tra loro uguali o almeno proporzionali faccio il controllo e se veramente lo sono... ottenngo stime molto concise...
  27. ricci_22(t22,variabili)
    Utilizza la libreria alternativa non ricorsiva. Dal tensore metrico covariante mi fornisce subito il tensore di Ricci covariante.Utilizza la libreria alternativa non ricorsiva. Dal tensore metrico covariante mi fornisce subito il tensore di Ricci covariante.
  28. riemann_1222(t22,variabili)
    Versione alternativa della fa_r1222(t22,listavariabili).
    Bisogna chiamare la riemann_1222 passandogli il tensore metrico covariante t22 e la lista dei nomi delle variabili del sistema di riferimento listavariabili e lei fa tutto... Questa funzione è utile perché è più semplice di quella ricorsiva ed adatta ad essere riempita di stampe di controllo...
  29. riemann_2222(t22,variabili)
    Calcola il tensore di Riemann in forma totalmente femminile ossia covariante ossia fa lo stesso calcolo della fa_r2222(t22,listavariabili) ma sembra più veloce essendo meno generale dato che non fa uso di funzioni ricorsive ma utilizza il costrutto for.
    Il primo argomento, t22 è il tensore metrico totalmente femminile.
  30. scala(ta,ia,tb,ib) :
    Prodotto scalare generalizzato. Attenzione... è posizionale e per ottenere gli indici nell'ordine voluto bisogna poi riordinare il risultato con la funzione permuta.
  31. semplimetrica(metrica)
    Per semplificare ulteriormente l'intera metrica quando di sono funzioni polinomiali e razionali ma NON ci sono funzioni trigonometriche.
  32. semplimetricatrig(metrica)
    Per semplificare ulteriormente l'intera metrica quando ci sono funzioni trigonometriche
  33. tassegna(tn,val,p)
    Assegna il valore val ad un particolare elemento del tensore tn specificato dalla lista p la cui lunghezza deve essere uguale al rango del tensore tn.
  34. tcontrov(lv,metrica)
    Crea un vettore, tensore di rango 1 maschile ossia controvariante, ben fatto. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
    Il primo argomento, lv è una lista di valori che vengono assegnati al vettore ossia tensore di rango 1 così creato...
  35. tcov(lv,metrica)
    Crea un vettore, tensore di rango 1 femminile ossia covariante, ben fatto. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
    Il primo argomento, lv è una lista di valori che vengono assegnati al vettore ossia tensore di rango 1 così creato...
  36. tdueantisim(tn,metrica)
    Questa funzione serve soprattutto a fare il tensore campo elettromagnetico dalla derivata covariante del potenziale vettore elettromagnetico. In pratica fa il tensore antisimmetrico di un tensore assegnato che deve essere di rango due ossia essere una matrice. Se i tipi dei due indici non sono uguali li rende provvisoriamente uguali e poi, dopo avere antisimmetrizzato, li rimette come erano nel tensore assegnato.
    In pratica, assegnato il vettore campo elettromagnetico, lo si deriva con la diffcov e il risultato lo si antisimmetrizza con questa funzione.
  37. tduetracciazero(tn,metrica)
    Questa sembrerebbe una funzione piuttosto insolita ossia, dato un tensore di rango due ossia una matrice, sottrargli un opportuno tensore ( in pratica il tensore metrico ) fatto in modo che la traccia del tensore risultato sia nulla. Questa funzione e' FONDAMENTALE per costruire il tensore Energia Impulso del campo elettromagnetico che compare nell'equazione di Einstein per definire il corretto valore del tensore di Ricci-Curbastro.
  38. tensoredalista(lista,tipi,comme,ndim)
    Crea un tensore del tipo voluto, prelevando i dati da una lista che se è troppo breve viene riutilizzata ciclicamente e naturalmente, se è troppo lunga, viene usata solo parzialmente.
    Il secondo argomento specifica il rango del tensore e il tipo di ogni suo indice, maschile ossia controvariante se dispari e femminile ossia covariante se pari.
    Il terzo argomento è un commento di qualsiasi tipo.
    Il quarto argomento ossia ndim specifica il numero delle dimensioni dello spazio e deve essere un intero maggiore di 1.
    Notare che questa funzione non richiede l'uso della metrica e dunque è molto più flessibile di altre funzioni che fanno sostanzialmente cose simili...
    La tensoredalista accetta anche un dato non lista che tratta come lista ed è possibile anche generare tensori di rango zero ossia scalari ma con informazioni sul loro nome e sul numero delle dimensioni dello spazio in cui vanno usati.
  39. tensorp(tn)
    Raccogliamo i vari test di buona definizione in questa funzione tensorp(tn) che dà risultato true se tn è un tensore ben fatto e false se tn non è un tensore o è un tensore mal fatto.
  40. ticambiotutto(tn,metrica)
    Dato un tensore tn di qualsiasi rango la ticambiotutto calcola il tensore che ha tutti gli indici di tipo diverso ossia se un dato indice è di tipo covariante ossia femminile il corrispondente indice sarà di tipo controvariante ossia maschile e viceversa.
    Sarebbe possibile fare questo calcolo usando la cambiatipi(tn,nuovitipi,metrica) che è più flessibile e sfrutta varie funzioni di questa libreria ma la ticambiotutto applica altre funzioni e dunque potrebbe servire per fare la verifica dello stesso calcolo fatto con la cambiatipi.
  41. tmat11(mat,metrica)
    Crea un tensore di rango 2 ( in pratica una matrice ), totalmente maschile ossia controvariante, data una matrice e la metrica. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista degli oggetti della metrica viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
    Forse è meglio usare la flessibilissima funzione tensoredalista(lista,tipi,comme,ndim) che richiede più argomenti ma non obbliga a calcolare la metrica.
  42. tmat12(mat,metrica)
    Crea un tensore di rango 2 ( in pratica una matrice ), col primo indice maschile ossia controvariante, ed il secondo femminile ossia covariante, data una matrice di valori e la metrica. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista degli oggetti della metrica viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
  43. tmat21(mat,metrica)
    Crea un tensore di rango 2 ( in pratica una matrice ), col primo indice femminile ossia covariante, ed il secondo maschile ossia controvariante, data una matrice di valori e la metrica. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista degli oggetti della metrica viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
  44. tmat22(mat,metrica)
    Crea un tensore di rango 2 ( in pratica una matrice ), totalmente femminile ossia covariante, data una matrice di valori e la metrica. Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista degli oggetti della metrica viene generata da una apposita funzione fa_metrica(matrice,listavariabili).
  45. tmeno(tena,tenb)
    Fa la differenza tra due tensori con uguale dimensione, ordine e tipo di indici.
  46. tnsemplifica(tn)
    Per semplificare ulteriormente un tensore tn quando di sono funzioni polinomiali e razionali ma NON ci sono funzioni trigonometriche.
  47. tnsemplificatrig(tn)
    Per semplificare ulteriormente un tensore tn quando ci sono funzioni trigonometriche.
  48. tprod(tscala,tenb)
    Moltiplica un tensore di rango 0 ossia uno scalare tscala per un tensore di qualsiasi rango ossia tenb. Una funzione molto semplice ma comoda...
  49. traccia(tn,ih,ik)
    Generalizzazione del calcolo della traccia di una matrice ossia un tensore di rango 2. Il rango del tensore deve essere maggiore di 1 e i due indici ih e ik devono essere di tipo diverso, uno maschile ossia controvariante ed uno femminile ossia covariante.
  50. tsca(sc,metrica)
    Crea un tensore scalare ossia un normale scalare ma con la struttura di un tensore di rango 0. L'argomento sc rappresenta il valore dello scalare ma per creare il tensore bisogna sapere in quante dimensioni verrà usato ossia bisogna specificare la metrica definita dalla funzione fa_metrica(matrice,lista_variabili).
    Forse è meglio usare la flessibilissima funzione tensoredalista(lista,tipi,comme,ndim) che richiede più argomenti ma non obbliga a calcolare la metrica. In questo caso l'argomento lista deve essere una lista vuota ossia [ ].
  51. tsomma(tena,tenb)
    Fa la somma tra due tensori con uguale dimensione, ordine e tipo di indici.
  52. tvale(tn,p)
    Trova il valore di un particolare elemento del tensore tn specificato dalla lista p la cui lunghezza deve essere uguale al rango del tensore tn.
  53. zerotensor(tipi,comme,ndim)
    Questa funzione genera un tensore con elementi tutti nulli, con indici di valore prescelto specificati nella lista tipi, con commento arbitrario specificato dall'argomento comme e di dimensione spazio-temporale assegnata ossia ndim che deve essere un intero maggiore di 1.

La derivazione covariante

Per convenzione la cifra che segnala un indice ottenuto da derivazione covariante è 8 e quello trasformato in controvariante è 9. Dunque xx28 è un vettore covariante ( xx2 ) diventato tensore del secondo ordine per derivazione covariante ed analogamente xx18 è un vettore controvariante ( xx1), derivato covariantemente. Se alzo l'ultimo indice di xx28 ottengo xx29, etc...

Dato che la derivazione covariante produce tensori, è possibile derivare qualsiasi tensore usando i simboli di Christoffel in due modi diversi a seconda della natura covariante o controvariante di un dato indice.

Per fare la derivazione occorrono tanti simboli di Christoffel quanti sono gli indici del tensore e dunque per derivare uno scalare non occorrono simboli di Christoffel ossia la derivazione di uno scalare coincide con quella ordinaria.

Esaminiamo i due casi distinti usando le convenzioni della presente libreria che impone che i tensori di qualunque ordine siano delle liste di qualcosa, scalari o matrici e che l'ultimo elemento della lista sia a sua volta una lista che contiene informazioni sulla natura degli indici del tensore.

Dunque:

A[a] è uno scalare o un vettore del primo ordine. Se è uno scalare esiste solo A[1] mentre se è un vettore esistono anche le componenti A[2]...A[nd] dove nd è il numero di dimensioni dello spazio, ovvero 3 in meccanica classica e 4 in meccanica relativistica. B[a][b,c] è un tensore del secondo o del terzo ordine. C[a][b,c][d,e] è un tensore del quarto o del quinto ordine.

Per accedere alla lista dei tipi degli indici bisogna prendere l'ultimo elemento del primo indice ossia A[length(A)] o B[length(B)] o C[length[C)] è la lista dei tipi degli indici, qualunque sia l'ordine del tensore A o B o C.

L'ultima delle componenti, se il tensore ha ordine pari è sempre 2 mentre se ha ordine dispari è sempre data da nd+1. In pratica però è meglio non fare affidamento su questa regola e prendere sempre l'ultimo indice della lista perché in questo modo è possibile usare anche liste più lunghe del minimo indispensabile e memorizzare negli elementi sovrabbondanti i dati che si desidera associare in più al tensore.

Notare che in Maxima è ammesso omettere gli indici tra parentesi quadra per cui se scrivo B[1] ottengo l'unica o la prima matrice del tensore B ( o un singolo dato numerico se B è uno scalare o un vettore); la matrice ( o scalare) è l'unica se B è un tensore di ordine pari ossia ad esempio uno scalare o un tensore del secondo ordine ed è la prima se B è un tensore di ordine dispari ossia, per esempio un vettore o un tensore del terzo ordine.

Per la derivata di un vettore covariante A2, ossia di un tensore di ordine 1 dove la cifra 2 ricorda che il suo primo ed unico indice è covariante, la formula è questa:

A2a8b = A2a0b - ch1j2a2b*A2j

ovvero in Maximese ( essendo 8 la cifra che indica derivata covariante ) :

A28[1][a,b] = A20[1][a,b] - ch122[j][a,b]*A2[j]

dove la cifra 0 specifica la derivata preliminare e ch122 rappresenta il simbolo di Christoffel di seconda specie avente la cifra 1 che ricorda che il suo primo indice è (pseudo)controvariante e la cifra 2 che ricorda che il secondo e terzo indice sono (pseudo)covarianti.

Per la derivata di un tensore del secondo ordine totalmente covariante A22, la formula è questa:

A2a2b8c = A2a2b0c - ch1j2a2c*A2j2b - ch1j2b2c*A2a2j

ovvero in Maximese, dato il tensore A[1][a,b] ottengo:

A228[a][b,c] = A220[a][b,c] - ch122[j][a,c]*A22[1][j,b] - ch122[j][b,c]*A22[1][a,j]

per cui è facile intuire la regola generale da applicarsi ad un tensore di ordine qualsiasi.

La derivata di un tensore del terzo ordine totalmente covariante ossia A222, la formula è questa:

A2a2b2c2d = A2a2b2c0d - ch1j2a2d*A2j2b2c - ch1j2b2d*A2a2j2c - ch1j2c2d*A2a2b2j

ovvero in Maximese, dato il tensore A[a][b,c]:

A2228[1][a,b][c,d] = A2220[1][a,b][c,d] - ch122[j][a,d]*A222[j][b,c] - ch122[j][b,d]*A222[a][j,c] - ch122[j][c,d]*A222[a][b,j]

A questo punto è facile generalizzare il metodo a tensori di qualsiasi ordine.

La derivata di un vettore controvariante si fa invece in questo modo ( usando uno dei due indici pseudocovarianti del simbolo di Christoffel che è uno pseudo tensore) :

A1a8b = A1a0b + ch1a2j2b*A1j

Notare che il simbolo di Christoffel è simmetrico nei suoi due ultimi indici trattati come covarianti, per cui avrei potuto scrivere anche in questo modo ( è solo una questione estetica )

A1a8b = A1a0b + ch1a2b2j*A1j

ossia in Maximese, detto A1[a] il vettore da derivare ho la seguente formula

A18[1][a,b] = A10[1][a,b] + ch122[a][j,b]*A1[j]

La derivata di un tensore del secondo ordine totalmente controvariante A1a1b si fa, di conseguenza in questo modo:

A1a1b8c = A1a1b0c + ch1a2j2c*A1j1b + ch1b2j2c*A1a1j

ossia in Maximese, dato A11[1][a,b] si ha:

A118[a][b,c] = A110[a][b,c] + ch122[a][j,c]*A11[1][j,b] + ch122[b][j,c]*A11[1][a,j]

Attenzione: il primo contributo è dato da A11[1][j,b] che non è equivalente a A11[1][b,j] a meno che il tensore del secondo ordine non sia, in pratica, una matrice simmetrica.

[wxMaxima: comment end ] */ /* [wxMaxima: title start ]

Libreria tensoriale di Giampaolo Bottoni

[wxMaxima: title end ] */ /* [wxMaxima: comment start ]

@ Indice generale commentato

[wxMaxima: comment end ] */ /* [wxMaxima: comment start ]
  1. ada(la,per)
  2. cambiacoord(tn,InFunDiN,NuoveC,metrica)
  3. cambiasesso(lista,litipi,gff,gmm)
  4. cambiatipi(tn,nuovitipi,metrica)
  5. commentalo(tn,comme)
  6. commento(tn)
  7. diffcov(tn,metrica,nome)
  8. dimensione(tn)
  9. divergenza(tn,ki,metrica)
  10. fa_ch122(g22,listavariabili)
  11. fa_ch222(g220)
  12. fa_diff(tn,variabili,comme)
  13. fa_metrica(mg,listavariabili)
  14. fa_r1222(t22,listavariabili)
  15. fa_r22(t22,listavariabili)
  16. fa_r2222(t22,listavariabili)
  17. fa_tenergiaimpulso(tpotvet,metrica)
  18. fondetatb(ta,tb,nome)
  19. indici(tn)
  20. knbl22a(info)
  21. knbl22b(info)
  22. listadatensore(tn)
  23. nonmetricap(metrica)
  24. ordine(tn)
  25. permuta(tn,per,com)
  26. rapportolistetensori(ta,tb)
  27. ricci_22(t22,variabili)
  28. riemann_1222(t22,variabili)
  29. riemann_2222(t22,variabili)
  30. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]
  31. scala(ta,ia,tb,ib)
  32. semplimetrica(metrica)
  33. semplimetricatrig(metrica)
  34. tassegna(tn,val,p)
  35. tcontrov(lv,metrica)
  36. tcov(lv,metrica)
  37. tdueantisim(tn,metrica)
  38. tduetracciazero(tn,metrica)
  39. tensoredalista(lista,tipi,comme,ndim)
  40. tensorp(tn)
  41. ticambiotutto(tn,metrica)
  42. tmat11(mat,metrica)
  43. tmat12(mat,metrica)
  44. tmat21(mat,metrica)
  45. tmat22(mat,metrica)
  46. tmeno(tena,tenb)
  47. tnsemplifica(tn)
  48. tnsemplificatrig(tn)
  49. tprod(tscala,tenb)
  50. traccia(tn,ih,ik)
  51. tsca(sc,metrica)
  52. tsomma(tena,tenb)
  53. tvale(tn,p)
  54. zerotensor(tipi,comme,ndim)
[wxMaxima: comment end ] */ /* [wxMaxima: title start ]

Aggiorna su disco la libreria solo se lo si vuole

[wxMaxima: title end ] */ /* [wxMaxima: comment start ]
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Versione con ampliamenti nell' aprile 2014
   [wxMaxima: comment end   ] */

/* [wxMaxima: section start ]

Premessa: struttura del tensore

[wxMaxima: section end ] */ /* [wxMaxima: comment start ] Un tensore e' una lista di oggetti vari (atomici, liste o matrici). L'ultimo elemento della lista deve essere una lista. La lunghezza della lista dell'ultimo elemento e' l'ordine del tensore + 2. Il penultimo elemento della lista dell'ultimo elemento e' un commento di qualsiasi tipo, un numero o una stringa o una lista etc. L'ultimo elemento della lista dell'ultimo elemento e' la dimensione dello spazio per il tensore considerato. I precedenti elementi indicano la natura degli indici del tensore ossia se sono controvarianti ovvero maschili (1), covarianti ovvero femminili (2), derivativi ordinari(0), derivati covarianti femminili (8), derivati covarianti maschili (9), personalizzati ( altre cifre escluse 0,1,2,8,9 ). [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Con questa definizione e' possibile trattare come tensore anche uno scalare che ha questa struttura: [valore,[commento,dimensione_spazio]] [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La dimensione_spazio minima ammessa e' 2 mentre per descrivere lo spazio tridimensionale deve essere: dimensione_spazio:3 Per descrivere gli spazi relativistici pseudoeuclidei ed eventuale segnatura [+,-,-,-] ossia con la prima dimensione temporale e le restanti tre spaziali, deve essere: dimensione_spazio:4 [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] I tensori, date le scelte di programmazione ora fatte, si distinguono tra tensori con un numero dispari di indici e tensori con un numero pari di indici. Se il tensore ha numero di indici pari viene usato, ovvero contiene dati opportuni, solo il primo elemento del tensore mentre se il numero degli indici e' dispari, vengono usati i primi elementi da 1 a dimensione_spazio. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Un vettore e' un tensore di ordine ossia rango 1 con questa struttura, nel caso in cui la dimensione dello spazio sia 2: [v1,v2,[i1,commento,2]] Se la dimensione dello spazio vale 3 il vettore ha questa struttura: [v1,v2,v3,[i1,commento,3]] Se la dimensione dello spazio vale 4 il vettore ha questa struttura: [v1,v2,v3,v4,[i1,commento,4]] Il valore di i1 e' 1 se il vettore e' controvariante che, per ragioni mnemoniche e per l'iniziale "m" bene identificabile, chiamo Maschile ed e' 2 se e' covariante che, per contrapposizione e iniziale distinta, chiamo "Femminile" .... etc. [wxMaxima: comment end ] */ /* [wxMaxima: subsect start ]

Operazioni di eventuale salvataggio su file

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Specifico il file in cui scrivo la nuova libreria: [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ salvoqui:"c:/zmaxima/libtensori.mc"; /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Aggiorna questa libreria solo a richiesta ossia se la variabile aggiornolibreria e' stata definita e non e' un numero ma una stringa qualsiasi. [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ /* Per aggiornare la libreria ufficiale modificare qui */ aggiornolibreria:false; /* [wxMaxima: input end ] */ /* [wxMaxima: input start ] */ if stringp(aggiornolibreria) then (if atom(path_iniziale) then writefile(salvoqui), print("Riscrive il file ",salvoqui)) else ( print("aggiornolibreria non e' una stringa"), print("quindi NON riscrive il file ",salvoqui))$ /* [wxMaxima: input end ] */ /* [wxMaxima: input start ] */ print(["Ora comincio a lavorare su ",salvoqui])$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Scelgo dove mettere i file con estensione .mc e .mac [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ cartellalavoro:"C:/zmaxima/###.{mc,mac}"$ print("Voglio usare, per lavorare, questa cartella: ", cartellalavoro)$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] E' consigliabile, prima di modificarlo, di salvare il valore del path di default di Maxima. [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ ( if atom(path_iniziale) then (path_iniziale: file_search_maxima) )$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Amplio il path iniziale aggiungendogli una cartella. Con questo trucco posso ricaricare varie volte questo documento senza il problema di modificare ogni volta il path di ricerca. [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ file_search_maxima: cons(cartellalavoro,path_iniziale)$ display(file_search_maxima)$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Notare che non e' obbligatorio ampliare il path per fare una load senza indicare dove sta il file... Ma qui si prende in considerazione anche questa possibilita' mettendo la libreria nella cartellalavoro che ho deciso di usare. [wxMaxima: comment end ] */ /* [wxMaxima: section start ]

Data della versione: annomesegiornooraminuto

[wxMaxima: section end ] */ /* [wxMaxima: comment start ] Per sapere riconoscere la versione di libreria usata [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ libmia:[[20140427205959,"tens2014a"]]; /* [wxMaxima: input end ] */ /* [wxMaxima: section start ]

Funzioni algebriche

[wxMaxima: section end ] */ /* [wxMaxima: comment start ] Le definisco, anche se banali, per permettere di manipolare il tensore senza bisogno di conoscere la disposizione dei suoi dati ossia la sua concreta struttura. [wxMaxima: comment end ] */ /* [wxMaxima: subsect start ]

Funzioni di informazione

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] L'ordine o meglio il rango ovvero la classe di un tensore e' ottenibile con la seguente funzione che, per ragioni di velocita', non effettua nessuna verifica della correttezza del tensore tn passato in argomento. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ ordine(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    ordine(tn):=block([],
        length(tn[length(tn)])-2
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("ordine(tn)",libmia);
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Il commento che ogni tensore contiene e che puo' essere
una stringa ma anche un numero o una lista o un
qualsiasi oggetto, e' estraibile in questo modo:
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ commento(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    commento(tn):=block([u],
        u:length(tn),
        tn[u][length(tn[u])-1])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("commento(tn)",libmia);
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Per inserire un commento comme nel tensore, uso la
commentalo:
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ commentalo(tn,comme)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    commentalo(tn,comme):=block([u],
        u:length(tn),
        tn[u][length(tn[u])-1]:comme,tn[u] )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("commentalo(tn,comme)",libmia);
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Ogni tensore contiene, come si e' detto, la dimensione
dello spazio a cui si riferisce. Per ottenere questo
importante dato si puo' usare questa funzione:
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ dimensione(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    dimensione(tn):=block([],
        tn[length(tn)][length(tn[length(tn)])])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("dimensione(tn)",libmia);
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Per estrarre dal tensore la lista dei tipi dei suoi indici
(covarianti/femminili, controvarianti/maschili, etc.) senza
bisogno di sapere la organizzazione interna dei dati del
tensore, si puo' usare questa funzione:
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ indici(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    indici(tn):=block([],
        rest(tn[length(tn)],-2))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("indici(tn)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Indichiamo con tn un generico tensore ed esaminamo
i test che ogni funzione, quando non ci sono
esigenze di prestazioni, potrebbe fare per
controllare che la struttura del tensore e' corretta.

Raccogliamo i test nella funzione tensorp(tn)
che da' risultato true se tn e' un tensore
ben fatto e false se tn non e' un tensore o e' un
tensore mal fatto.
La tensorp utilizza in modo ricorsivo la
matrixxp che opera su matrici di matrici.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tensorp(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    matrixxp(tn,o,n):=block([basta,smetti],
       basta:false,smetti:true,
       if o>1 then (
          smetti:false,
          if not(matrixp(tn)) then basta:true,
          if length(tn[1])#n then basta:true
          ),
       if basta then return(false),
       if smetti then return(true),
       matrixxp(tn[1,1],o-2,n)
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    tensorp(tn):=block([u,o,n,pd],
      if not(listp(tn)) then return(false),
      u:length(tn),
      if not(listp(tn[u])) then return(false),
      o:length(tn[u])-2,
      if 0>o then return(false),
      n:floor(tn[u][o+2]),
      if 2>n then return(false),
      pd:mod(o,2),
      if pd=0 then ( if u>n then return(false))
      else if n>u-1 then return(false),
      if matrixxp(tn[1],o,n) then return(true),
      false )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tensorp(tn)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
La funzione zerotensor genera un tensore con elementi
tutti nulli, con indici di valore prescelto,
con commento arbitrario e di dimensione assegnata.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ zerotensor(tipi,comme,ndim)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    zerotensor(tipi,comme,ndim):=block([tn,j,o,u,nd],
       if not(listp(tipi)) then
          return("Errore, non lista tipi"),
       o:length(tipi), nd:floor(ndim),
       if 2>nd then
          return("Errore, dimensione inferiore a 2"),
       if o=0 then return([0,[comme,nd]]),
       if mod(o,2)=0 then tn:makelist(0,j,1,2)
       else tn:makelist(0,j,1,nd+1),
       u:length(tn),
       tn[u]:append(makelist(tipi[j],j,1,o),[comme,nd]),
       for j:1 thru u-1 do tn[j]:zeromatmat(o,nd),
       tn
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    zeromatmat(o,nd):=block([tr,omm,j,k],
       if 2>o then return(0),
       tr:zeromatrix(nd,nd),
       omm:o-2,
       for j:1 thru nd do
       for k:1 thru nd do
           tr[j,k]:zeromatmat(omm,nd),
       tr )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("zerotensor(tipi,comme,ndim)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

Funzioni per generare facilmente tensori da scalari, liste o matrici

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Per metrica si intende una lista di tensori utili per gestire una data metrica. La lista viene generata da una apposita funzione fa_metrica(matrice,listavariabili) definita qui in seguito. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La funzione tsca crea un tensore scalare ossia di rango zero, usando info della metrica che dunque deve essere stata precalcolata ma e' possibile usare, al posto di questa semplice funzione, la funzione tensoredalista(lista,tipi,comme,ndim) [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ tsca(sc,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tsca(sc,metrica):=block([],
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        [sc,["(scal)",dimensione(metrica[2])]])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tsca(sc,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
La funzione tcov crea un vettore covariante/femminile ,
data una lista e la metrica. Meglio usare anche qui la
funzione tensoredalista(lista,tipi,comme,ndim) che non
richiede il precalcolo della metrica.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tcov(lv,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tcov(lv,metrica):=block([nl,nd],
        if not(listp(lv)) then
           return("Non lista"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        nl:length(lv),
        nd:dimensione(metrica[2]),
        append( makelist(lv[1+mod(j-1,nl)],j,1,nd),
          [[2,"(v2)",nd]]) )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tcov(lv,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Crea un vettore ( tensore di rango 1) controvariante/maschile,
data la lista e la metrica.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tcontrov(lv,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tcontrov(lv,metrica):=block([nl,nd],
        if not(listp(lv)) then
           return("Non lista"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        nl:length(lv),
        nd:dimensione(metrica[2]),
        append( makelist(lv[1+mod(j-1,nl)],j,1,nd),
          [[2,"(v2)",nd]]) )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tcontrov(lv,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Crea un tensore di rango 2, totalmente controvariante,
data una matrice e la metrica. Sono funzioni alternative
alla preferibile tensoredalista(lista,tipi,comme,ndim)
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tmat11(mat,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tmat11(mat,metrica):=block([],
        if not(matrixp(mat)) then
           return("Non matrice"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        [mat,[1,1,"(tm11)",dimensione(metrica[2])]])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tmat11(mat,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Crea un tensore di rango 2, misto ossia controvariante,
covariante, data una matrice e la metrica.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tmat12(mat,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tmat12(mat,metrica):=block([],
        if not(matrixp(mat)) then
           return("Non matrice"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        [mat,[1,2,"(tm12)",dimensione(metrica[2])]])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tmat12(mat,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Crea un tensore di rango 2, misto ossia covariante,
controvariante, data una matrice e la metrica.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tmat21(mat,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tmat21(mat,metrica):=block([],
        if not(matrixp(mat)) then
           return("Non matrice"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        [mat,[2,1,"(tm11)",dimensione(metrica[2])]])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tmat21(mat,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Crea un tensore di rango 2, totalmente covariante/femminile,
data una matrice e la metrica.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tmat22(mat,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tmat22(mat,metrica):=block([],
        if not(matrixp(mat)) then
           return("Non matrice"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        [mat,[2,2,"(tm22)",dimensione(metrica[2])]])$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tmat22(mat,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

Operazioni di somma, differenza e prodotto per scalare, tra tensori.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Somma di due tensori con uguale dimensione, rango e tipo di indici. Una funzione di interesse pratico per non avere bisogno di conoscere la struttura interna dei tensori. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ tsomma(tena,tenb)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tsomma(tena,tenb):=block(
       [oa,ob,na,nb,ina,inb,stop],
       if not(tensorp(tena)) then
          return("Errore: primo arg. non tensore"),
       if not(tensorp(tenb)) then
          return("Errore: secondo arg. non tensore"),
       oa:ordine(tena), ob:ordine(tenb),
       if oa#ob then
          return("Errore: tensori di ordine diverso"),
       na:dimensione(tena),  nb:dimensione(tenb),
       if na#nb then
          return("Errore: tensori di dimensione diversa"),
       ina:indici(tena), inb:indici(tenb),
       stop:false,
       for j:1 thru oa do if mod(ina[j]+inb[j],2)=1
           then stop:true,
       if stop then
          return("Errore: indici incongruenti"),
       append(ratsimp(rest(tena,-1)+rest(tenb,-1)),
          [append(ina,["(Somma tensori)",na])])
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tsomma(tena,tenb)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Differenza tra due tensori con uguale dimensione,
rango e tipo di indici.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tmeno(tena,tenb)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tmeno(tena,tenb):=block(
       [oa,ob,na,nb,ina,inb,stop],
       if not(tensorp(tena)) then
          return("Errore: primo arg. non tensore"),
       if not(tensorp(tenb)) then
          return("Errore: secondo arg. non tensore"),
       oa:ordine(tena), ob:ordine(tenb),
       if oa#ob then
          return("Errore: tensori di ordine diverso"),
       na:dimensione(tena),  nb:dimensione(tenb),
       if na#nb then
          return("Errore: tensori di dimensione diversa"),
       ina:indici(tena), inb:indici(tenb),
       stop:false,
       for j:1 thru oa do if mod(ina[j]+inb[j],2)=1
           then stop:true,
       if stop then
          return("Errore: indici incongruenti"),
       append(ratsimp(rest(tena,-1)-rest(tenb,-1)),
          [append(ina,["(Differenza tra tensori)",na])])
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tmeno(tena,tenb)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Prodotto di un tensore scalare ossia di rango zero, per un
qualsiasi tensore della  stessa dimensione.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tprod(tscala,tenb)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tprod(tsc,tenb):=block(
       [tscala,oa,ob,na,nb,inb],
       if not(tensorp(tenb)) then
          return("Errore: secondo arg. non tensore"),
       if tensorp(tsc) then tscala:tsc
       else tscala:[tsc,["(scal)",dimensione(tenb)]],
       oa:ordine(tscala), ob:ordine(tenb),
       if oa#0 then
          return("Errore: non scalare"),
       na:dimensione(tscala),  nb:dimensione(tenb),
       if na#nb then
          return("Errore: tensori di dimensione diversa"),
       inb:indici(tenb),
       append(ratsimp(tscala[1]*rest(tenb,-1)),[append(indici(tenb),
          ["(Prodotto scalare*tensore)",nb])])
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tprod(tsc,tenb)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

tassegna e tvale : per assegnare o conoscere valori di singoli elementi.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Per non dovere specificare gli indici accoppiandoli. Assegna un dato ad un elemento di matrice di matrice oppure trova il valore di quell'elemento. Sono funzioni ricorsive: [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ assegnam(mt,o,val,p):=block([], if o=length(p) then ( mt[p[o-1],p[o]]:val, return(true)), assegnam(mt[p[o-1],p[o]],o+2,val,p) )$ /* [wxMaxima: input end ] */ /* [wxMaxima: input start ] */ valem(miot,o,p):=block([], if o=length(p) then return(miot[p[o-1],p[o]]), valem(miot[p[o-1],p[o]],o+2,p) )$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Assegna un valore ad un elemento del tensore oppure trova il valore di quell'elemento. L'argomento p deve essere una lista lunga quanto il rango del tensore ed i suoi elementi non devono sconfinare ossia essere valori compresi tra 1 e la dimensione dello spazio utilizzato. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ tassegna(tn,val,p)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tassegna(tn,val,p):=block([o],
        o:length(tn[length(tn)])-2,
        if length(p)#o then
        return("errore: incongruenza di indici"),
        if o=0 then ( tn[1]:val,return(true)),
        if o=1 then ( tn[p[1]]:val, return(true)),
        if mod(o,2)=0 then assegnam(tn[1],2,val,p)
        else assegnam(tn[p[1]],2,val,rest(p))
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tassegna(tn,val,p)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tvale(tn,p)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tvale(tn,p):=block([o],
        o:length(tn[length(tn)])-2,
        if length(p)#o then
        return("errore: incongruenza di indici"),
        if o=0 then return(tn[1]),
        if o=1 then return(tn[p[1]]),
        if mod(o,2)=0 then valem(tn[1],2,p)
        else (
            valem(tn[p[1]],2,rest(p)))
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tvale(tn,p)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

permuta : permutazione di indici di un tensore

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Ecco la funzione che permuta gli indici di un qualsiasi tensore creando un altro tensore con gli indici permutati in base all'ordinamento specificato dalla lista per. La lista per deve indicare da dove e' stato preso il dato che compare in quella posizione. Per esempio usando un tensore di rango 4, la lista [3,1,2,4] indica che il dato che compare come primo indice e' quello che prima era situato in colonna 3, come secondo dato quello che prima stava in colonna 1 etc. La rotazione degli indici si fa, nel caso di un tensore di rango 4, con [2,3,4,1]. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ permuta(tn,per,comm)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    permuta(tn,per,comm):=block([tr,u,o,a,b,j,nd,va,vb,id],
        if not(tensorp(tn))
           then return("Errore, non tensore"),
        if not(listp(per)) then
           return("Errore, non lista permutazioni"),
        u:length(tn),o:length(tn[u])-2,
        if 2>o then return("Applicabile da ordine 2 in su"),
        if o#length(per) then
           return("Errore, lista permutazioni incongruente"),
        j:1,for a:1 thru o-1 do for b:a+1 thru o do
            if per[a]=per[b] then j:0,
        if j=0 then return("Permutazione errata"),
        nd:tn[u][o+2],
        va:makelist(0,j,1,o),
        vb:makelist(0,j,1,o),
        id:makelist(0,j,1,o),
        for j:1 thru o do id[j]:tn[u][per[j]],
        tr:zerotensor(id,comm,nd),
        funfor(tr,tn,va,vb,per,1,o,nd),
        tr
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    Faccio un ciclo for in forma ricorsiva...
       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    funfor(ta,tb,va,vb,per,n,m,nd):=block([j,np],
       if n=m then (
          for j:1 thru nd do (
             va[n]:j,
             vb[per[n]]:j,
             tassegna(ta,tvale(tb,vb),va) ))
       else (
          np:n+1,
          for j:1 thru nd do (
              va[n]:j,
              vb[per[n]]:j,
              funfor(ta,tb,va,vb,per,np,m,nd))
             )
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("permuta(tn,per,com)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Funzione per trovare, applicandola, come e' permutata
una lista ossia data una lista e una permutazione di tutti
gli elementi della lista, cosa diventa la lista permutata.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ ada(la,per)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    ada(la,per):=block([n,j,k,lr],
        n:length(per),
        if n#length(la) then return("Disuguale lunghezza liste"),
        for j:1 thru n-1 do for k:j+1 thru n do if
           per[j]=per[k] then return("Indici duplicati"),
        lr:makelist(0,j,1,n),
        for j:1 thru n do lr[j]:la[per[j]],
        lr)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("ada(la,per)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

tensoredalista : per creare un tensore usando una lista per inizializzarlo

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Crea un tensore del tipo voluto, prelevando i dati da una lista che, se e' troppo breve, viene riutilizzata ciclicamente e ovviamente, se e' troppo lunga, viene usata solo parzialmente. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ora la tensoredalista accetta anche un dato non lista che tratta come lista ed e' possibile anche generare tensori di rango zero ossia scalari ma con informazioni sul loro nome e sul numero delle dimensioni dello spazio in cui vanno usati [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ tensoredalista(lista,tipi,comme,ndim)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    forlista(tb,vb,n,m,nd,lista,dove):=block([j,np],
       if n=m then (
          for j:1 thru nd do (
             vb[n]:j,
             dove[1]:mod(dove[1],length(lista))+1,
             tassegna(tb,lista[dove[1]],vb) ))
       else (
          np:n+1,
          for j:1 thru nd do (
              vb[n]:j,
              forlista(tb,vb,np,m,nd,lista,dove))
             )
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    tensoredalista(lista,tipi,comme,ndim):=block(
        [usolista,tr,dove,m,vb,j],
        if listp(lista) then usolista:lista
        else usolista:[lista],
        if 1>length(tipi) then
           return([usolista,[comme,ndim]]),
        tr:zerotensor(tipi,comme,ndim),
        dove[1]:0,
        m:length(tipi),
        vb:makelist(0,j,1,m),
        forlista(tr,vb,1,m,ndim,usolista,dove),
        tr)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tensoredalista(lista,tipi,comme,ndim)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

listadatensore : per estrarre gli elementi di un tensore mettendoli in una lista

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Estrae gli elementi di un tensore producendo una lista. Notare che il tensore puo' essere anche di rango zero ossia uno scalare da cui si ottiene una lista con un solo elemento. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ listadatensore(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    forinlista(lista,tb,vb,n,m,nd,dove):=block([j,np],
       if n=m then (
          for j:1 thru nd do (
             vb[n]:j,
             dove[1]:mod(dove[1],length(lista))+1,
             lista[dove[1]]:tvale(tb,vb)))
       else (
          np:n+1,
          for j:1 thru nd do (
             vb[n]:j,
             forinlista(lista,tb,vb,np,m,nd,dove))
             )
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    listadatensore(tn):=block([lista,u,o,dove,vb,j],
        u:length(tn),o:length(tn[u])-2,
        if 1>o then return([tn[1]]),
        nd:tn[u][o+2],
        dove[1]:0,
        vb:makelist(0,j,1,o),
        lista:makelist(0,j,1,nd^o),
        forinlista(lista,tn,vb,1,o,nd,dove),
        lista)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("listadatensore(tn)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

traccia : generalizzazione del calcolo della traccia di una matrice.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] traccia di un tensore, generalizzazione di quella di una matrice... Si tratta di una funzione importantissima e bisogna ricordare che, per fare questa funzione, i due indici specificati debbono essere di tipo diverso ossia maschile uno e femminile l'altro o viceversa. Insomma la traccia e' una funzione eterosessuale...;-) [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ traccia(tn,ih,ik)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fortraccia(tr,vr,tn,vn,h,k,n,nn,m,nd):=block([j,np,nnp,ss],
       if n=m then (
          ss:0,
          for j:1 thru nd do (
             vn[h]:j,vn[k]:j,
             ss:ss+tvale(tn,vn)),
             tassegna(tr,ss,vr))
       else (
          np:n+1, nnp:nn+1,
          if nnp=h then nnp:nnp+1,
          if nnp=k then nnp:nnp+1,
          for j:1 thru nd do (
             vr[np]:j,
             vn[nnp]:j,
             fortraccia(tr,vr,tn,vn,h,k,np,nnp,m,nd))
             )
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    traccia(tn,ih,ik):=block([u,o,nd,vr,vb,h,k,tipi,i,j],
        if not(tensorp(tn)) then
           return("Errore: non tensore"),
        u:length(tn),o:length(tn[u])-2,nd:tn[u][o+2],
        if 2>o then return("Errore, ordine inferiore a 2"),
        if ih=ik then return("Errore, indici uguali"),
        h:min(ih,ik),k:max(ih,ik),
        if k>o then
           return(["Errore, indice superiore ad ordine",k,o]),
        vb:makelist(0,j,1,o),vr:[],
        if o>2 then vr:makelist(0,j,1,o-2),
        tipi:indici(tn),
        if tipi[h]=tipi[k] then
            print("Attenzione: indici dello stesso tipo"),
        tr:zerotensor(vr,"ridotto",nd),
        i:0,for j:1 thru o do (
            if j#h then if j#k then (
               i:i+1,
               tr[u][i]:tipi[j])),
        fortraccia(tr,vr,tn,vb,h,k,0,0,o-2,nd),
        tr)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("traccia(tn,ih,ik)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

scala : generalizzazione del prodotto scalare tra vettori e tra matrici.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Prodotto scalare generalizzato. Attenzione... e' posizionale e per ottenere gli indici nell'ordine voluto bisogna poi riordinare il risultato con la funzione permuta. Anche la funzione scala e' una funzione eterosessuale ossia l'indice del primo tensore deve essere di sesso diverso da quello del secondo tensore. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ scala(ta,ia,tb,ib)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    forscala(tr,vr,ta,va,tb,vb,h,k,n,nn,ma,m,nd):=block(
       [j,np,nnp,ss],
       if n=m then (
          va[h]:1,
          vb[k]:1,
          ss:0,
          for j:1 thru nd do (
             va[h]:j,vb[k]:j,
             ss:ss+tvale(ta,va)*tvale(tb,vb)),
             tassegna(tr,ss,vr))
       else (
          np:n+1, nnp:nn+1,
          if nnp=h then nnp:nnp+1,
          if nnp=k+ma then nnp:nnp+1,
          for j:1 thru nd do (
             vr[np]:j,
             if nnp>ma then vb[nnp-ma]:j
             else va[nnp]:j,
             forscala(tr,vr,ta,va,tb,vb,h,k,np,nnp,ma,m,nd))
             )
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    scala(ta,ia,tb,ib):=block(
        [ua,oa,ub,ob,ur,ot,nd,vr,va,vb,tipa,tipb,i,j],
        if not(tensorp(ta)) then
           return("Errore: ta non tensore"),
        if not(tensorp(tb)) then
           return("Errore: tb non tensore"),
        ua:length(ta),oa:length(ta[ua])-2,nd:ta[ua][oa+2],
        if 1>oa then return("Errore, ordine ta inferiore a 1"),
        ub:length(tb),ob:length(tb[ub])-2,
        if nd#tb[ub][ob+2] then
           return("Errore, dimensioni diverse"),
        if 1>ob then return("Errore, ordine tb inferiore a 1"),
        if ia>oa then
           return(["Errore, indice superiore ad ordine",ia,oa]),
        if ib>ob then
           return(["Errore, indice superiore ad ordine",ib,ob]),
        va:makelist(0,j,1,oa),vb:makelist(0,j,1,ob),
        ot:oa+ob-2,
        vr:[],if ot>0 then vr:makelist(0,j,1,ot),
        tipa:indici(ta),tipb:indici(tb),
        if tipa[ia]=tipb[ib] then
            print("Attenzione: indici dello stesso tipo"),
        tr:zerotensor(vr,"prod-scalare",nd),
        ur:length(tr),
        i:0,for j:1 thru oa+ob do (
           if j>oa then ( if (j-oa)#ib then (
              i:i+1,
              tr[ur][i]:tipb[j-oa]))
           else if j#ia then (
              i:i+1,
              tr[ur][i]:tipa[j])),
        forscala(tr,vr,ta,va,tb,vb,ia,ib,0,0,oa,ot,nd),
        tr)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("scala(ta,ia,tb,ib)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

[wxMaxima: comment end ] */ /* [wxMaxima: section start ]

Funzioni per il calcolo differenziale

[wxMaxima: section end ] */ /* [wxMaxima: comment start ]
Queste funzioni fanno uso della derivazione simbolica fattibile
in ambienti dove e' definita, tipo Maxima o Mathematica etc..
   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_diff : derivata ordinaria di un tensore

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ]

La fa_diff e' una funzione di ENORME IMPORTANZA ANCHE SE NON effettua la derivazione tensoriale Qualificata detta anche covariante ma quella Preliminare che e' fattibile solo da programmi come Maxima o Mathematica capaci di fare derivazioni simboliche.

Per fare la derivata Qualificata ossia Veramente Tensoriale, normalmente capace di aggiungere un indice femmine ossia covariante al tensore differenziato, bisogna usare la diffcov [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Richiede l'uso di una permutazione finale perche' spontaneamente aggiungerebbe l'indice 0 all'inizio e non alla fine. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_diff(tn,variabili,comme)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_diff(tn,variabili,comme):=block([tn0,tnn,indi,o,j],
        tnn:rest(tn,-1),
        o:ordine(tn),
        indi:indici(tn),
        nd:dimensione(tn),
        if mod(o,2)=0 then (
           tn0:makelist(0,j,1,nd+1),
           for j:1 thru nd do
           tn0[j]:ratsimp(diff(tnn[1],variabili[j])),
           tn0[nd+1]:append(cons(0,indi),[comme,nd])
           )
        else (
           tn0:[0,append(cons(0,indi),[comme,nd])],
           tn0[1]:ratsimp(matrix(diff(tnn,variabili[1]))),
           for j:2 thru nd do
           tn0[1]:addrow(tn0[1],
                  ratsimp(matrix(diff(tnn,variabili[j]))))
           ),
        if o>0 then
           permuta(tn0,makelist(mod(j,o+1)+1,j,1,o+1),comme)
        else tn0
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_diff(tn,variabili,comme)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_ch222 : Simboli di Christoffel di prima specie

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Il simbolo di Christoffel di prima specie, uno pseudo tensore di rango 3 richiede il precalcolo delle derivate del tensore metrico covariante rispetto alle coordinate. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] g220 ossia il tensore metrico totalmente femminile derivato preliminarmente dalla fa_diff, deve essere considerato valido dalla tensorp(tn) [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Notare che scritta in questo modo la fa_ch222 e' facilmente traducibile in altri ambienti dove non e' possibile fare derivate in modo simbolico [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_ch222(g220)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_ch222(g220):=block([g022,g202],
         if controllo then print("Inizia fa_ch222"),
         g022:permuta(g220,[2,3,1],"-"),
         g202:permuta(g022,[2,3,1],"-"),
         append((+rest(g220,-1)+rest(g022,-1)-rest(g202,-1))/2,
         [[2,2,2,"Christoffel prima specie",dimensione(g220)]])
         )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_ch222(g220)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_ch122 : Per fare i simboli di Christoffel di seconda specie

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Eleva il primo indice.. e fa il simbolo di Christoffel di seconda specie. Anche in questo caso il secondo e il terzo indice sono scambiabili. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Qui invece la funzione richiede solo la matrice del tensore metrico totalmente femminile ed effettua la derivazione usando la fa_diff [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_ch122(g22,listavariabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_ch122(g22,listavariabili):=block([g11,g220],
       if controllo then print("Inizia fa_ch222"),
       g11: [ratsimp(invert(g22[1])),
            [1,1,"-",dimensione(g22)]],
       g220: fa_diff(g22,listavariabili,"g220"),
       ratsimp(scala(g11,2,fa_ch222(g220),1))
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_ch122(g22,listavariabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_r1222 : genera il tensore di Riemann col primo indice controvariante.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Ho applicato vari metodi per includere nel nome del tensore le informazioni del tipo ( o se si vuole, sesso) degli indici. Posso alternare la cifra dell'indice ( pari se femminile, dispari se maschile) al carattere usato nell'indice ossia , per esempio, nel caso del tensore di Riemann di rango 4 posso scrivere r1d2a2b2c per indicare che l'indice d e' maschile mentre a, b e c sono femminili. Tuttavia questo modo di caratterizzare un tensore e' criticabile perche' il nome degli indici non e' una proprieta' stabile del tensore ossia possono venire usati altri nomi di indici riferendosi allo stesso tensore. Pertanto, in epoca successiva al 2010, ho optato per scrivere tutte di seguito le cifre e poi i nomi degli indici ossia scrivere r1222dabc e, scrivendo realmente il sorgente in un linguaggio di programmazione, scrivere ovviamente solo r1222. Qui pero' lascio la vecchia modalita' di scrittura che, teoricamente, essendo le cifre usabili come separatori, consentirebbe di scrivere nomi di indici multicarattere. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ora calcolo il tensore di Riemann con la formula dell'HEL Hobson,Efstathiou,Lasenby ISBN 9780521829519 a pag. 158. Ricopio esattamente la formula dal libro: r1d2a2b2c = ch1d2a2a0b - ch1d2a2b0c + ch1e2a2c*ch1d2e2b - ch1e2a2b*ch1d2e2c Il nome degli indici pero' non mi piace e preferisco usare come nomi a,b,c,d sostituti di d,a,b,c ed inoltre usare il nome j al posto del nome e, per cui la formula diventa: r1a2b2c2d = ch1a2b2d0c - ch1a2b2c0d + ch1j2b2d*ch1a2j2c - ch1j2b2c*ch1a2j2d In linguaggio Maximese non interpongo i nomi degli indici alle cifre indicatrici di tipo ma scrivo i nomi tra parentesi quadre: r1222[a,b][c,d]:ch1220[a,b][d,c]- ch1220[a,b][c,d]+ ch122[j][b,d]*ch122[a][j,c]- ch122[j][b,c]*ch122[a][j,d] Per fare il calcolo bisogna disporre sia del simbolo di Christoffel di seconda specie che dello pseudotensore delle sue derivate. Spezzo il calcolo in due parti in modo che sia possibile partire o dal tensore metrico covariante o dai simboli di Christoffel di seconda specie. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_r1222(t22,listavariabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_r1222(t22,listavariabili):=block(
       [nd,g22,g11,g220,g022,g202,ch222,ch122],
       if controllo then print("Inizia fa_r1222"),
       if not(tensorp(t22)) then
          return("Primo argomento non tensore"),
       nd:dimensione(t22),
       g22:[ratsimp((t22[1]+transpose(t22[1]))/2),[2,2,"(g22)",nd]],
       g11:[ratsimp(invert(g22[1])),[1,1,"(g11)",nd]],
       g220:fa_diff(g22,listavariabili,"(g220)"),
       g022:permuta(g220,[2,3,1],"-"),
       g202:permuta(g022,[2,3,1],"-"),
       ch222:append((rest(g220,-1)+rest(g022,-1)-rest(g202,-1))/2,
             [[2,2,2,"Christoffel prima specie",dimensione(g220)]]),
       ch122:scala(g11,2,ch222,1),
       fa_ch_r1222(ch122,listavariabili))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_ch_r1222(ch122,listavariabili):=block(
       [r1222,ch1a2b2c2d,ch1a2b2d2c,xabcd,xacbd,xadbc],
       if controllo then print("Inizia fa_ch_r1222"),
       ch1a2b2c2d:fa_diff(ch122,listavariabili,"ch1a2b2c2d"),
       ch1a2b2d2c:permuta(ch1a2b2c2d,[1,2,4,3],"ch1a2b2d2c"),
       xabcd:scala(ch122,3,ch122,1),
       xacbd:permuta(xabcd,[1,3,2,4],"xacbd"),
       xadbc:permuta(xabcd,[1,4,3,2],"xadbc"),
       r1222:[ch1a2b2d2c[1]-ch1a2b2c2d[1]+ xacbd[1] - xadbc[1],
             [1,2,2,2,"(r1222)",dimensione(ch122)]]
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_r1222(t22,listavariabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
VERIFICA:
Le funzioni della libreria alternativa, usabile
per calcolare il tensore di Riemann r1222 sono queste
che non sono ricorsive e non gestiscono gli indici.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ riemann_1222(t22,variabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    der2(t2,variabili):=block([t3,nd,j],
       nd:length(variabili),
       t3:makelist(0,j,1,nd),
       for j:1 thru nd do
           t3[j]:diff(t2,variabili[j]),
       t3)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    chris222(g22,variabili):=block([g220,ss,tn],
       g220:r3(der2(g22,variabili)),
       ss:r3(g220),
       tn:g220+ss,
       ss:r3(ss),
       ratsimp((tn-ss)/2)
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    chris122(g22,variabili):=block([g11],
    g11:invert(g22),
    ch222:chris222(g22,variabili),
    transpose(g11.ch222)[1]
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    r3(t3):=block([nd,j,k,h,t3n],
     nd:length(t3),
     t3n:makelist(ident(nd),j,1,nd),
     for j:1 thru nd do
     for k:1 thru nd do
     for h:1 thru nd do
       t3n[j][k,h]:t3[h][j,k],
     t3n
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    r4(t4):=block([nd,i,j,k,h,t4n],
    nd:length(t4),
    t4n:genmatrix(lambda([i,j],ident(nd)),nd,nd),
    for i:1 thru nd do
    for j:1 thru nd do
    for k:1 thru nd do
    for h:1 thru nd do
       t4n[i,j][k,h]:t4[h,i][j,k],
    t4n
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    der3(t3,variabili):=block([t4,t4d,nd,j],
       if not(listp(t3)) then (print(["Errore",t3]),
       return("Non lista t3")),
       nd:length(variabili),
       t4d:der2(t3,variabili),
       t4:matrix(t4d[1]),
       for j:2 thru nd do
         t4:addrow(t4,t4d[j]),
       ratsimp(t4))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    Bisogna chiamare la riemann_1222 passandogli il tensore metrico
    covariante e lei fa tutto...
    Questa funzione e' utile perche' e' piu' semplice di quella
    ricorsiva ed adatta ad essere riempita di stampe di controllo...
       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    riemann_1222(t22,variabili):=block(
       [g22,ch122,ch1220,r1222,nd,a,b,c,d,j,sp],
       if not(tensorp(t22)) then
          return("Primo argomento non tensore"),
       nd:dimensione(t22),
       g22:ratsimp((t22[1]+transpose(t22[1]))/2),
       ch122:chris122(g22,variabili),
       ch1220:r4(der3(ch122,variabili)),
       r1222:genmatrix(lambda([i,j],ident(nd)),nd,nd),
       for a:1 thru nd do
       for b:1 thru nd do
       for c:1 thru nd do
       for d:1 thru nd do (
          sp:ch1220[a,b][d,c]-ch1220[a,b][c,d],
          for j:1 thru nd do sp:sp+
               ch122[j][b,d]*ch122[a][j,c]-
               ch122[j][b,c]*ch122[a][j,d],
          r1222[a,b][c,d]:sp),
       [ ratsimp(r1222),[1,2,2,2,"(r1222)",nd]]
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("riemann_1222(t22,variabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_r2222 : genera il tensore di Riemann totalmente covariante.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Con questa formula evito di dovere usare le derivate dei simboli di Christoffel ma posso utilizzare direttamente le derivate seconde del tensore metrico. Questa formula inoltre e' utile per verificare il risultato ottenuto usando l'altra, piu' popolare in letteratura. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Calcolo il tensore di Riemann in forma totalmente covariante, in base a quanto sta scritto sull' HEL. r2a2b2c2d = (g2b2c0d0a- g2a2c0d0b+ g2a2d0b0c- g2b2d0a0c )/2 + ch1j2b2c*ch2j2a2d - ch1j2b2d*ch2j2a2c ovvero in Maximese r2222[a,b][c,d] = ( g2200[b,c][a,d] - g2200[a,c][b,d] + g2200[a,d][b,c] - g2200[b,d][a,c] )/2 + ch122[j][a,d]*ch222[j][b,c] - ch122[j][a,c]*ch222[j][b,d] Il tensore di Riemann in forma totalmente covariante evidenzia le sue simmetrie. E' antisimmetrico scambiando gli indici della prima coppia ed e' antisimmetrico scambiando gli indici della seconda coppia mentre e' simmetrico scambiando le due coppie tra loro. Per queste simmetrie il calcolo del tensore di Riemann potrebbe essere molto piu' veloce evitando inutili ricalcoli ma qui ...non si bada a spese... ma si preferisce puntare ad un algoritmo semplice il piu' possibile. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_r2222(t22,listavariabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_r2222(t22,listavariabili):=block(
       [nd,g22,xg11,g11,g220,g022,g202,ch222,ch122,g2200],
       if controllo then print("Inizia fa_r2222"),
       if not(tensorp(t22)) then
          return("Primo argomento non tensore"),
       nd:dimensione(t22),
       g22:[ratsimp((t22[1]+transpose(t22[1]))/2),
           [2,2,"(g22)",nd]],
       xg11:trigsimp(ratsimp(invert(g22[1]))),
       g11:[xg11,[1,1,"(g11)",nd]],
       g220:fa_diff(g22,listavariabili,"(g220)"),
       g022:permuta(g220,[2,3,1],"-"),
       g202:permuta(g022,[2,3,1],"-"),
       ch222:append(ratsimp((rest(g220,-1)+
             rest(g022,-1)-rest(g202,-1))/2),
             [[2,2,2,"Christoffel prima specie",dimensione(g220)]]),
       ch122:scala(g11,2,ch222,1),
       g2200:fa_diff(g220,listavariabili,"(yabcd) ovvero g2200"),
       fa_poi_r2222(ch222,ch122,g2200)
            )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_poi_r2222(ch222,ch122,g2200):=block(
       [zabcd,zadbc,zacbd,ybcad,yacbd,yadbc,ybdac],
       if controllo then print("Inizia fa_poi_r2222"),
       zabcd:scala(ch122,1,ch222,1),
       zadbc:permuta(zabcd,[1,3,4,2],"(zadbc)"),
       zacbd:permuta(zabcd,[1,3,2,4],"(zacbd)"),
       ybcad:permuta(g2200,[3,1,2,4],"(ybcad)"),
       yacbd:permuta(g2200,[1,3,2,4],"(yacbd)"),
       yadbc:permuta(g2200,[1,3,4,2],"(yadbc)"),
       ybdac:permuta(g2200,[3,1,4,2],"(ybdac)"),
       [ratsimp((ybcad[1]-yacbd[1]+yadbc[1]-ybdac[1])/2
                 +zadbc[1]-zacbd[1]),
         [2,2,2,2,"(r2222)",nd]] )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_r2222(t22,listavariabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Il tensore di Riemann e' IMPORTANTISSIMO anche se richiede
calcoli FATICOSISSIMI e difficilmente verificabili a mano.
Per sicurezza includo nella libreria parecchi modi di calcolarlo..

Ecco la funzione tratta della altra libreria...
Sembra piu' veloce essendo meno generale dato che non fa uso
di funzioni ricorsive ma utilizza il costrutto for.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ riemann_2222(t22,variabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    riemann_2222(t22,variabili):=block(
       [ss,tn,nd,g22,ch222,ch122,
       g2200,r2222,a,b,c,d,j],
       if not(tensorp(t22)) then
          return("Primo argomento non tensore"),
       nd:dimensione(t22),
       g22:ratsimp((t22[1]+transpose(t22[1]))/2),
       g220:r3(der2(g22,variabili)),
       ss:r3(g220),
       tn:g220+ss,
       ss:r3(ss),
       ch222:ratsimp((tn-ss)/2),
       ch122:transpose(invert(g22).ch222)[1],
       g2200:r4(der3(g220,variabili)),
       r2222:genmatrix(lambda([i,j],ident(nd)),nd,nd),
       for a:1 thru nd do
       for b:1 thru nd do
       for c:1 thru nd do
       for d:1 thru nd do (
          ss:(g2200[b,c][a,d] - g2200[a,c][b,d] +
              g2200[a,d][b,c] - g2200[b,d][a,c] )/2,
          for j:1 thru nd do ss:ss+
             ch122[j][a,d]*ch222[j][b,c] -
             ch122[j][a,c]*ch222[j][b,d],
          r2222[a,b][c,d]:ss),
       [ ratsimp(r2222),[2,2,2,2,"(r2222)",nd]]
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("riemann_2222(t22,variabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

fa_r22 : genera il tensore di Ricci totalmente covariante.

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Il tensore di Gregorio Ricci Curbastro e' fondamentale nella Relativita' Generale e dunque il suo calcolo va attuato anche da funzioni specifiche anche se potrebbe essere dedotto in modo generale dal tensore di Riemann. Qui si fa esattamente questo ma senza richiedere all'utilizzatore della libreria come fare... [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Definisco il tensore di Ricci doppiamente covariante seguendo ancora la definizione dell' HEL. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fa_r22(t22,listavariabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_r22(t22,listavariabili):=block([],
        if controllo then print("Inizia fa_r22"),
        traccia(fa_r1222(t22,listavariabili),1,4)
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_r22(t22,listavariabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Utilizza la libreria alternativa non ricorsiva.
Dal tensore metrico covariante mi fornisce subito
il tensore di Ricci covariante.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ ricci_22(t22,variabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    ricci_22(t22,variabili):=block(
       [nd,r1222,ric22,a,b,sp,j],
        if not(tensorp(t22)) then
           return("Primo argomento non tensore"),
        nd:dimensione(t22),
        r1222:riemann_1222(t22,variabili)[1],
        r22:zeromatrix(nd,nd),
        for a:1 thru nd do
        for b:a thru nd do (
            sp:0,
            for j:1 thru nd do sp:sp+r1222[j,a][b,j],
            r22[a,b]:sp,
            r22[b,a]:sp
            ),
        [ ratsimp(r22),[2,2,"(Ricci 22)",nd ] ]
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]
fa_metrica: costruttore di metrica. Genera
una lista che include tutto quello che
serve per fare derivate covarianti.
   [wxMaxima: subsect end   ] */

/* [wxMaxima: comment start ]
Il calcolo differenziale tensoriale si basa su una
funzione riassuntiva, fametrica, che genera la metrica usata,
tra l'altro, per calcolare la derivata covariante.
Calcolata una volta per tutte questa funzione, la sua
lista, che rappresenta il risultato, puo' essere usata
ovunque serva fare calcoli tensoriali di vario tipo
e per vari scopi.
Questa funzione deve ricevere in argomento una matrice
che, per sicurezza, viene simmetrizzata e usata come
tensore metrico covariante della metrica ed ovviamente
va indicata la lista dei nomi usati per le
coordinate spazio_temporali. 
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ fa_metrica(mg,listavariabili)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_metrica(mg,listavariabili):=block(
       [metrica,nd,m2,m3,m4,m4,m6,m7,m8,m9,ma,mb,costanti],
       if not(matrixp(mg)) then
          return("Errore, primo arg. non matrice"),
       if not(listp(listavariabili)) then
          return("Errore, secondo arg. non lista variabili"),
       if length(listavariabili)#length(mg) then
          return("Errore: incongruenza ",
          " tra matrice e lista variabili")
       else nd:length(listavariabili),
       if controllo then print("Inizia g22"),
       m2: [ratsimp((mg + transpose(mg) )/2),
           [2,2,"(tensore metrico covariante)",nd]],
       m2: trigsimp(m2),
       if controllo then print("Inizia g11"),
       m3: [ratsimp(invert(m2[1])),
           [1,1,"(tensore metrico controvariante)",nd]],
       if controllo then print("Inizia g220"),
       m4: fa_diff(m2,listavariabili,"g220"),
       if controllo then print("Inizia g2200"),
       m5: fa_diff(m4,listavariabili,"g2200"),
       m6: fa_ch222(m4),
       commentalo(m6,"(Christoffel prima specie)"),
       if controllo then print("Inizia ch122"),
       m7: scala(m3,2,m6,1),
       commentalo(m7,"(Christoffel seconda specie)"),
       m8: fa_r1222(m2,listavariabili),
       m9: fa_r2222(m2,listavariabili),
       if controllo then print("Inizia r22"),
       ma: traccia(m8,1,4),
       commentalo(ma,"(Ricci totalmente covariante)"),
       mb:[ratsimp(sqrt(abs(determinant(m2[1])))),
          ["sqrt(|determinant(g22)|)",nd]],
       costanti:[
          [8*%pi*Gw/cw^4,["kweinstein",nd]],
          [4*%pi/Lw,["muwz",nd]],
          [Lw/(4*%pi*cw^2),["epswz",nd]],
          [cw^2/Lw,["kwcou",nd]],
          [bfloat(299792458),["[m/s] cwluce",nd] ],
          [bfloat(10000000),["[C^2/(kg*m)] Lwnumerica",nd]],
          [bfloat(22468879468420441/2500000),
          ["[kg*m^3/(s*C)^2] kwcoulomb",nd]],
          [bfloat(4*%pi/10000000),
          ["[kg*m/C^2] ossia [Henry/m] muwzero ",nd]],
          [bfloat(7*8*729*773),["[s] awgregoriano",nd]],
          [bfloat(667428/10^16),
          ["[m^3/(kg*s^2)] Gwuniversale",nd]],
          [bfloat(60221415*10^16),["[adim.] nwavogadro",nd]],
          [bfloat(1602176487/10^28),["[C] qwelet",nd]],
          [bfloat(91093826/10^38),["[kg] mwelet",nd]],
          [bfloat(166053886/10^35),["[kg] mwuatom",nd]],
          [bfloat(149597870700),["[m] uwastro",nd]],
          [bfloat(19891*10^26),["[kg] mwsole",nd]],
          [bfloat(19891*10^26/332946),["[kg] mwterra",nd]],
          [bfloat(73483*10^18),["[kg] mwluna",nd]],
          [bfloat(6371*10^3),["[m] rwterra",nd]]
        ],
       metrica:[listavariabili,m2,m3,m4,m5,m6,m7,m8,m9,ma,mb,
          costanti,7*%pi*%gamma],
       infometrica(),
       metrica)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    Per conoscere il significato dei vari elementi della
    lista del risultato della fa_metrica ...
       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    infometrica():=block([],
       print("Ha creato un vettore di piu' di undici elementi:"),
       print("[1] : lista delle variabili"),
       print("[2] : tensore metrico covariante"),
       print("[3] : tensore metrico controvariante"),
       print("[4] : derivate prime del tens. metrico cov."),
       print("[5] : derivate seconde del tens. m. cov."),
       print("[6] : simboli di Christoffel di prima specie"),
       print("[7] : simboli di Christoffel di seconda specie"),
       print("[8] : Riemann col solo primo indice controvariante"),
       print("[9] : Riemann totalmente covariante"),
       print("[10]: Ricci totalmente covariante"),
       print("[11]: sqrt(abs(determinate del tens.metr.cov.))"),
       print("[12...] : varie costanti utili...")
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_metrica(mg,listavariabili)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
IMPORTANTE: L'ultimo valore della lista della metrica e'
sempre lo stesso e serve a capire se la lista della metrica
e' veramente stata creata dalla funzione fa_metrica.

Usando la nonmetricap si puo' controllare se la lista passata
in argomento e' veramente una lista della metrica.

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ nonmetricap(metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    nonmetricap(metrica):=block([errata],
     if not(listp(metrica)) then (
     print("Errore: la metrica deve essere una lista"),
     return(true)),
     errata:is(metrica[length(metrica)]#(7*%pi*%gamma)),
     if errata then print("Questa non e' una metrica !"),
     return (errata))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("nonmetricap(metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

Derivata covariante

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Questa e' ovviamente una operazione FONDAMENTALE nel calcolo tensoriale dove non basta fare la derivata PRELIMINARE di un tensore ma occorre modificare il risultato per ottenere come risultato non uno PSEUDO tensore ma un VERO TENSORE tramite appunto al derivata covariante che preferisco chiamare QUALIFICATA ossia sicuramente capace di creare un vero tensore di rango incrementato di una unita' se la derivazione e' parziale e non totale ossia rispetto alle coordinate e non ad un qualche scalare invariante. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Per convenzione la cifra che segnala un indice ottenuto da derivazione covariante e' 8 e quello trasformato in controvariante e' 9. Dunque xx28 e' un vettore covariante ( xx2 ) diventato tensore del secondo ordine per derivazione covariante ed analogamente xx18 e' un vettore controvariante ( xx1), derivato covariantemente. Se alzo l'ultimo indice di xx28 ottengo xx29, anche lui un vero tensore perche' la derivata Qualificata detta covariante genera sempre veri tensori etc... [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Dato che la derivazione covariante produce tensori, e' possibile derivare qualsiasi tensore usando i simboli di Christoffel in due modi diversi a seconda della natura covariante/femminile o controvariante/maschile di un dato indice. Per fare la derivazione occorrono tanti simboli di Christoffel quanti sono gli indici del tensore e dunque PER DERIVARE UNO SCALARE NON OCCORRONO SIMBOLI DI Christoffel ossia la derivazione di uno scalare coincide con quella ordinaria. Esaminiamo i due casi distinti usando le convenzioni della presente libreria che impone che i tensori di qualunque ordine siano delle liste di qualcosa, scalari o matrici e che l'ultimo elemento della lista sia a sua volta una lista che contiene informazioni sulla natura degli indici del tensore. Dunque: In Maximese A[a] e' uno scalare o un vettore del primo ordine. Se e' uno scalare esiste solo A[1] mentre se e' un vettore esistono anche le componenti A[2]...A[nd] dove nd e' il numero di dimensioni dello spazio, ovvero 3 in meccanica classica e 4 in meccanica relativistica. In Maximese B[a][b,c] e' un tensore del secondo o del terzo ordine ossia rango. C[a][b,c][d,e] e' un tensore del quarto o del quinto ordine ossia rango. Per accedere alla lista dei tipi degli indici bisogna prendere l'ultimo elemento del primo indice ossia A[length(A)] o B[length(B)] o C[length[C)] e' la lista dei tipi degli indici, qualunque sia l'ordine ossia rango del tensore A o B o C. L'ultima delle componenti, se il tensore ha rango pari, e' sempre 2 mentre se ha rango dispari e' sempre data da nd+1. In pratica pero' e' meglio non fare affidamento su questa regola e prendere sempre l'ultimo indice della lista perche' in questo modo e' possibile usare anche liste più lunghe del minimo indispensabile e memorizzare negli elementi sovrabbondanti i dati che si desidera associare in piu' al tensore. Notare che in Maxima e' ammesso omettere gli indici tra parentesi quadra per cui se scrivo B[1] ottengo l'unica o la prima matrice del tensore B ( o un singolo dato numerico se B e' uno scalare o un vettore); la matrice ( o scalare) e' l'unica se B e' un tensore di rango pari ossia ad esempio uno scalare o un tensore del secondo ordine ed e' la prima se B e' un tensore di ordine dispari ossia, per esempio un vettore o un tensore del terzo ordine. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Per la derivata di un vettore covariante A2, ossia di un tensore di ordine 1 dove la cifra 2 ricorda che il suo primo ed unico indice e' covariante, la formula e' questa: A2a8b = A2a0b - ch1j2a2b*A2j ovvero in Maximese ( essendo 8 la cifra che indica derivata covariante ) : A28[1][a,b] = A20[1][a,b] - ch122[j][a,b]*A2[j] dove la cifra 0 specifica la derivata ordinaria e ch122 rappresenta il simbolo di Christoffel di seconda specie avente la cifra 1 che ricorda che il suo primo indice e' (pseudo)controvariante ossia maschile e la cifra 2 che ricorda che il secondo e terzo indice sono (pseudo)covarianti. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Per la derivata di un tensore del secondo ordine totalmente covariante A22, la formula e' questa: A2a2b8c = A2a2b0c - ch1j2a2c*A2j2b - ch1j2b2c*A2a2j ovvero in Maximese, dato il tensore A[1][a,b] ottengo: A228[a][b,c] = A220[a][b,c] - ch122[j][a,c]*A22[1][j,b] - ch122[j][b,c]*A22[1][a,j] per cui e' facile intuire la regola generale da applicarsi ad un tensore di ordine qualsiasi. Si noti che la struttura in termini di liste e' la stessa tra tensore di rango 2 e tensore di rango 3 ma nel caso del tensore di rango 2, solo l'elemento 1 contiene dati mentre nel caso del tensore di rango 3 sono definiti anche gli elementi 2,..,nd essendo nd il numero delle dimensioni dello spazio considerato ( ossia il valore della traccia del tensore metrico ). [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La derivata di un tensore del terzo ordine totalmente covariante ossia A222, la formula e' questa: A2a2b2c2d = A2a2b2c0d - ch1j2a2d*A2j2b2c - ch1j2b2d*A2a2j2c - ch1j2c2d*A2a2b2j ovvero in Maximese, dato il tensore A[a][b,c] cambia la struttura della lista e si ha : A2228[1][a,b][c,d] = A2220[1][a,b][c,d] - ch122[j][a,d]*A222[j][b,c] - ch122[j][b,d]*A222[a][j,c] - ch122[j][c,d]*A222[a][b,j] A questo punto e' facile generalizzare il metodo a tensori di qualsiasi ordine. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La derivata di un vettore controvariante ossia maschile si fa invece in questo modo ( usando uno dei due indici pseudocovarianti del simbolo di Christoffel che, ripeto, e' uno pseudo tensore) : A1a8b = A1a0b + ch1a2j2b*A1j Notare che il simbolo di Christoffel e' simmetrico nei suoi due ultimi indici trattati come covarianti, per cui avrei potuto scrivere anche in questo modo ( e' solo una questione estetica ) A1a8b = A1a0b + ch1a2b2j*A1j ossia in Maximese, detto A1[a] il vettore da derivare ho la seguente formula: A18[1][a,b] = A10[1][a,b] + ch122[a][j,b]*A1[j] [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La derivata di un tensore del secondo ordine totalmente controvariante A1a1b si fa, di conseguenza in questo modo: A1a1b8c = A1a1b0c + ch1a2j2c*A1j1b + ch1b2j2c*A1a1j ossia in Maximese, dato A11[1][a,b] si ha: A118[a][b,c] = A110[a][b,c] + ch122[a][j,c]*A11[1][j,b] + ch122[b][j,c]*A11[1][a,j] Attenzione: il primo contributo e' dato da A11[1][j,b] che non e' equivalente a A11[1][b,j] a meno che il tensore del secondo ordine non sia, in pratica, una matrice simmetrica. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ diffcov(tn,metrica,nome)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    diffcov(tn,metrica,nome):=block([indi,o,ch122,tr,lp,j,temp],
        if not(tensorp(tn))
           then return("Errore: non tensore"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        indi:indici(tn),
        o:ordine(tn),
        if dimensione(tn)#dimensione(metrica[2]) then
           return("Errore, dimensioni incongruenti"),
        ch122:metrica[7],
        tr:rest(fa_diff(tn,metrica[1],"-"),-1),
        lp:makelist(mod(j,o+1)+1,j,1,o+1),
        lp[1]:1,lp[o+1]:2,
        for j:1 thru o do (
            if mod(indi[j],2)=0 then (
                tr:tr-rest(permuta(scala(ch122,1,tn,j),lp,o),-1)
                )
            else (
                tr:tr+rest(permuta(scala(ch122,2,tn,j),lp,o),-1)
                ),
            temp:lp[j],lp[j]:lp[j+1],lp[j+1]:temp
            ),
        endcons(append(indi,
           [8,nome,dimensione(tn)]),ratsimp(tr))
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("diffcov(tn,metrica,nome)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

Per mettere alla dura prova questa libreria proviamo a indicare qui come verificare alcune identita' che dovrebbero sussistere SEMPRE.

[wxMaxima: comment end ] */ /* [wxMaxima: comment start ] A pag. 344, formula (92,4), il Landau afferma. La somma ciclica di qualsiasi terna di indici del tensore di Riemann r2222 deve essere sempre nulla. In altre parole : r2222[1][a,b][c,d] + r2222[1][a,d][b,c] + r2222[1][a,c][d,b] = 0 Supponiamo di aver calcolato r2222.... [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Usando la funzione permuta si ottiene in generale un tensore del quarto ordine che, a quanto dice il Landau ma non solo lui, dovrebbe risultare totalmente nullo. Con le funzioni di questa libreria si dovrebbe fare cosi' sfruttando la funzione rest di Maxima, per eliminare l'ultimo elemento della lista ossia quello che contiene le informazioni sui tipi degli indici: rest(r2222,-1)+ rest(permuta(r2222,[1,3,4,2],""),-1)+ rest(permuta(r2222,[1,4,2,3],""),-1); [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Per provare la "seconda identità di Luigi Bianchi 1865/1928" ( http://it.wikipedia.org/wiki/Luigi_Bianchi ) ossia la seguente relazione: r12228[a][b,c][d,e] + r12228[a][b,e][c,d] + r12228[a][b,d][e,c] = 0 bisogna fare la derivata covariante del tensore di Riemann col solo primo indice controvariante ossia prelevarlo dalla metrica. Con questa libreria si fa cosi': r12228:ratsimp(diffcov(r1222,metrica,"r12228"))$ Notare che questo e' un calcolo lungo perche' si tratta di calcolare un tensore del quinto ordine ossia con 4^5 = 1024 componenti! [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Noto r12228, ecco come va calcolata la seconda identita' di Bianchi con la libreria ossia permutando gli indici. In quattro dimensioni questo tensore del quinto ordine ha 1024 componenti che dovrebbero risultare tutte nulle! idbianchi:rest(r12228,-1)+ rest(permuta(r12228,[1,2,4,5,3],""),-1)+ rest(permuta(r12228,[1,2,5,3,4],""),-1)$ Stupefacente! Provare per constatare che vengono tutti zeri come deve essere... [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Mi sembra che questo risultato sia una buona dimostrazione della correttezza della libreria... [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ora uso l'invariante del tensore di Ricci_Curbastro ( http://it.wikipedia.org/wiki/Gregorio_Ricci-Curbastro ) ossia r1i2i che ho chiamato rinva. Supponiamo di aver gia' calcolato il tensore di Ricci totalmente covariante ossia r22. Allora, supponendo che g11 sia il tensore metrico controvariante, trasformo Ricci in forma mista: r12: scala(g11,2,r22,1)$ rinva : traccia(scala(g11,2,r22,1),1,2)$ Derivando covariantemente lo scalare rinva, usando la metrica appropriata, si ottiene un vettore ossia: rinva8: ratsimp(diffcov(rinva,metrica,"rinva8"))$ Notare che si sarebbe ottenuto lo stesso vettore usando la derivata ordinaria ossia usando la fa_diff(tn,listavariabili,comme) nel seguente modo: rinva0 : fa_diff(rinva,listavariabili,"rinva0") infatti in caso di scalari la derivata covariante coincide con la derivata ordinaria. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La derivata covariante del tensore di Ricci in forma mista e' data da r128 ossia r128:ratsimp(diffcov(scala(g11,2,r22,1), metrica,"r128"))$ [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] L'identita' che dobbiamo verificare e' la seguente: 2*r128[a][b,a]-rinva8[b] = 0 Con questa libreria si fa cosi': ratsimp(2*rest(traccia(r128,1,3),-1)-rest(rinva8,-1)); NONO ANCORA che con la rest(list,-1) si taglia via dalla lista il suo ultimo elemento ossia quello che contiene le info sul tipo di indici del tensore. Quello che resta e' dunque qualcosa di trattabile algebricamente. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Se quindi viene un vettore di zeri e' un trionfo... ;-) E, fatte le verifiche, viene proprio un vettore di zeri e dunque, salvo bachi nascosti, tutto, fino qui... FUNZIONA! [wxMaxima: comment end ] */ /* [wxMaxima: subsect start ]

Divergenza di un tensore

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Crea la funzione divergenza di un tensore rispetto ad un dato indice, nota la metrica e dunque la dimensione, l'ordine del tensore e il tensore metrico controvariante. Fa uso della derivata covariante per cui questa funzione e' applicabile a qualunque tensore di ordine positivo. La divergenza di un tensore di fa calcolando la derivata qualificata ( ossia covariante ) del tensore e poi contraendo un dato indice del tensore con l'ultimo creato dalla derivata. Pertanto un vettore ha una sola divergenza ossia il primo indice contratto col secondo creato dalla derivazione ma un tensore di rango due, ossia una matrice, possiede due divergenze a meno che la matrice non sia simmetrica o antisimmetrica. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ divergenza(tn,ki,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    divergenza(tn,ki,metrica):=block([k,tm,j],
        if not(tensorp(tn)) then
           return("Errore: non tensore"),
        if not(numberp(ki)) then
           return("Errore: non numero intero"),
        if nonmetricap(metrica)
           then return("Errore: non metrica"),
        k:floor(ki),
        if 1>k then
           return("Errore: indice non positivo"),
        j:indici(tn),
        if k>length(j) then
           return("Errore: indice troppo elevato"),
        if mod(j[k],2)=1 then tm:diffcov(tn,metrica,"(div)")
        else ( tm:scala(metrica[3],1,tn,k),
               tm:diffcov(tm,metrica,"(div)")),
        traccia(tm,k,ordine(tm))
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("divergenza(tn,ki,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: section start ]

Funzioni nuove della v2 e della v3

[wxMaxima: section end ] */ /* [wxMaxima: comment start ] Per fare sperimentazioni della correttezza della libreria e' opportuno disporre della matrice del tensore metrico di tipo piu' generale ossia dotato di massa, carica elettrica e di spin. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Metrica di Kerr Newman nel sistema di riferimento di Boyer e Lindquist. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Versione "a" facente uso di espressioni solo razionali, senza funzioni trigonometriche e con la possibilita' di dare un valore numerico alle costanti, tipo cw ossia la velocita' della luce, Gw ossia la costante di gravitazione universale ed Lw che e' richiesto dal Sistema di Misura Internazionale per definire la permeabilita' magnetica. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ knbl22a(info)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    knbl22a(info):=block([Materiaw,Roqw,Deltaw,Sigqw,g22,av2,
    Kretschmann],
    Materiaw:Gw*(2*Mw*rw-Qw^2/Lw)/cw^2,
    Roqw:rw^2+(aw*hw)^2,
    Deltaw:rw^2-Materiaw+aw^2,
    Sigqw:(rw^2+aw^2)^2-aw^2*Deltaw*(1-hw^2),
    g22:ratsimp(diag_matrix(cw^2*(Deltaw-aw^2*(1-hw^2))/Roqw,
    -Roqw/Deltaw, -Roqw/(1-hw^2),-Sigqw*(1-hw^2)/Roqw)),
    g22[1,4]:aw*cw*Materiaw*(1-hw^2)/Roqw,
    g22[4,1]:g22[1,4],
    g22:ratsimp(g22),
    av2:[rw*Qw*cw^2/(Lw*rw^2+Lw*(aw*hw)^2),0,0,
    -Qw*cw*rw*aw*(1-hw^2)/(Lw*rw^2+Lw*(aw*hw)^2)],
    Kretschmann:8*Gw^2*(
    rw^4*(7*Qw^4-12*Lw*Mw*Qw^2*rw+6*(Lw*Mw)^2*rw^2)-
    2*(aw*hw)^2*rw^2*(17*Qw^4-
      60*Lw*Mw*Qw^2*rw+45*(Lw*Mw)^2*rw^2)+
    (aw*hw)^4*(7*Qw^4-60*Lw*Mw*Qw^2*rw+90*(Lw*Mw)^2*rw^2)-
    6*(aw*hw)^6*(Lw*Mw)^2)/(cw^4*Lw^2*((aw*hw)^2+rw^2)^6),
    if stringp(info) then (
    print("Tensore metrico ",info),
    print("Coordinate usate : [tw,rw,hw,pw]"),
    print("Costanti : cw,Gw,Lw"),
    print("Invarianti : Mw,Qw,aw"),
    print("Non sono nulli :"),
    print(g22[1,1]," ossia [1,1];"),
    print(g22[2,2]," ossia [2,2];"),
    print(g22[3,3]," ossia [3,3];"),
    print(g22[4,4]," ossia [4,4];"),
    print(g22[4,1]," ossia [4,1] ossia [1,4];"),
    print(av2," ossia Potenziale Vettore Elettromagnetico;"),
    print(Kretschmann," ossia invariante quadratico;")
    ),
    return ([ratsimp(g22),[tw,rw,hw,pw],av2,Kretschmann]))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("knbl22a(info)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Versione apparentemente piu' semplice ma con uso di
funzioni trigonometriche che rendono difficili, per Maxima, le
semplificazioni delle formule
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ knbl22b(info)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    knbl22b(info):=block([g22],
    g22:matrix(
    [1-(2*m*r-q^2)/(r^2+a^2-a^2*sin(h)^2),
    0,0,-(a*(q^2-2*m*r)*sin(h)^2)/(r^2+a^2-a^2*sin(h)^2)],
    [0,-(r^2+a^2-a^2*sin(h)^2)/(r^2-2*m*r+q^2+a^2),0,0],
    [0,0,-(r^2+a^2-a^2*sin(h)^2),0],
    [-(a*(q^2-2*m*r)*sin(h)^2)/(r^2+a^2-a^2*sin(h)^2),0,0,
    -(sin(h)^2*((r^2+a^2)^2 - sin(h)^2*a^2*(r^2-2*m*r+q^2+a^2)))/
    (r^2+a^2-a^2*sin(h)^2)]),
    if stringp(info) then (
    print("Tensore metrico ",info),
    print("Coordinate usate : [t,r,h,p]"),
    print("Invarianti : m,q,a"),
    print("Non sono nulli :"),
    print(g22[1,1]," ossia [1,1];"),
    print(g22[2,2]," ossia [2,2];"),
    print(g22[3,3]," ossia [3,3];"),
    print(g22[4,4]," ossia [4,4];"),
    print(g22[4,1]," ossia [4,1] ossia [1,4];")),
    return([trigsimp(g22),[t,r,h,p]]))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("knbl22b(info)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: subsect start ]

Per semplificare i tensori

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Per semplificare un singolo tensore o per semplificare l'intera metrica se NON CI SONO funzioni trigonometriche. Qualche volta questa ulteriore semplificazione consente di riuscire ad ottenere risultati simbolici in calcoli successivi. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ tnsemplifica(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tnsemplifica(tn):=block([j],
    if mod(ordine(tn),2)=0 then
    ( tn[1]:ratsimp(tn[1]),
    print("semplificato  pari"))
    else (
    for j:1 step 1 thru dimensione(tn) do (
    tn[j]:ratsimp(tn[j])),
    print("semplificato  dispari"))
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tnsemplifica(tn)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ semplimetrica(metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    semplimetrica(metrica):=block([j,nk],
    if nonmetricap(metrica)
           then return("Errore: non metrica"),
    print("Semplifica la metrica : coordinate  ",metrica[1]),
    for nk:2 step 1 thru length(metrica)-1
    do tnsemplifica(metrica[nk]),
    print("Semplificazione finita")
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("semplimetrica(metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Per semplificare un singolo tensore o per
semplificare l'intera metrica quando CI SONO
funzioni trigonometriche...
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tnsemplificatrig(tn)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tnsemplificatrig(tn):=block([j],
    if mod(ordine(tn),2)=0 then
    ( tn[1]:trigsimp(tn[1]),
    print("semplificato  pari"))
    else (
    for j:1 step 1 thru dimensione(tn) do (
    tn[j]:trigsimp(tn[j])),
    print("semplificato  dispari"))
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tnsemplificatrig(tn)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ semplimetricatrig(metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    semplimetricatrig(metrica):=block([j,nk],
    if nonmetricap(metrica)
           then return("Errore: non metrica"),
    print("Semplifica la metrica : coordinate  ",metrica[1]),
    for nk:2 step 1 thru length(metrica)-1
    do tnsemplificatrig(metrica[nk]),
    print("Semplificazione finita")
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("semplimetricatrig(metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

Importante funzione per fondere due tensori anche di diverso rango ottenendo un tensore di rango somma dei ranghi.

[wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Notare che i due tensori possono essere anche di rango zero per cui il risultato non aumenta di rango ma viene semplicemente moltiplicato per lo scalare del tensore di rango zero [wxMaxima: comment end ] */ /* [wxMaxima: comment start ]

@ fondetatb(ta,tb,nome)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fondetatb(ta,tb,nome):=block([ltna,na,ina,ltnb,nb,inb,
        ltnv,tab],
        if (not tensorp(ta)) then (
           print("Non tensore primo argomento"),
           return ([]) ),
        if (not tensorp(tb)) then (
           print("Non tensore secondo argomento"),
           return ([]) ),
        if not(dimensione(ta)=dimensione(tb)) then (
           print("Tensori di dimensione diversa"),
           return ([]) ),
        ltna:listadatensore(ta),
        ltnb:listadatensore(tb),
        na:length(ltna),
        nb:length(ltnb),
        tab=[0],
        ltnv:makelist(0,na*nb),
        for k:1 step 1 thru na do( for j:1 step 1 thru nb
           do (ltnv[j+(k-1)*nb]:ltna[k]*ltnb[j])),
        ina:rest(ta[length(ta)],-2),
        inb:rest(tb[length(tb)],-2),
        tab:tensoredalista(ltnv,append(ina,inb),nome,dimensione(ta)),
        return (tab)
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fondetatb(ta,tb,nome)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Questa funzione cambiatipi, cambia il sesso degli indici
del tensore tn passato come primo argomento.
Bisogna specificare la lista dei nuovi tipi degli
indici per cui, se gli indici vecchi sono di tipo
diverso da quello voluto, viene fatto il cambiamento.
Come terzo argomento va passata la metrica da cui trarre
il tensore metrico totalmente femminile ossia
covariante ed il tensore metrico totalmente maschile
ossia controvariante

Questa funzione e' molto comoda perche' evita all'utilizzatore
di questa libreria la conoscenza di come fare questa trasformazione
usando altre funzioni di questa stessa libreria.

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ cambiatipi(tn,nuovitipi,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    cambiatipi(tn,nuovitipi,metrica):= block([wt,pwt,mwt,
    itrovati,litr,miaper,i,j,k],
    if nonmetricap(metrica)
           then return("Errore: non metrica"),
    wt:tn,
    itrovati:indici(wt),
    litr:length(itrovati),
    if is(litr#length(nuovitipi)) then (
        print(sconcat("Errata lista nuovi tipi ",
          litr," # ",length(nuovitipi))),
        print("Errata lista nuovi tipi"),
        return (wt) ),
    for j:1 step 1 thru litr do (
       if is(mod(nuovitipi[j],2)#mod(itrovati[j],2)) then (
       miaper:makelist(i,i,litr),
       k:miaper[1],
       miaper[1]:miaper[j],
       miaper[j]:k,
       pwt:permuta(wt,miaper,"xPerm"),
       if is(mod(nuovitipi[j],2)=0) then (
          mwt:scala(metrica[2],2,pwt,1))
          else (
          mwt:scala(metrica[3],2,pwt,1)),
       wt:permuta(mwt,miaper,"xPerm"))
       ),
    return (ratsimp(wt)))$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("cambiatipi(tn,nuovitipi,metrica)",libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Funzione per il cambiamento del sistema di coordinate
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Bisogna specificare ovviamente il tensore tn da
modificare esprimendolo, come risultato, nelle nuove coordinate,
poi le funzioni che esprimono le vecchie coordinate in
funzione delle nuove ossia la lista InFunDiN ,
poi i simboli delle nuove coordinate ossia la
lista NuoveC ed infine la metrica valida per il
tensore da modificare, usata per sapere quali erano
le espressioni delle vecchie coordinate
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ cambiacoord(tn,InFunDiN,NuoveC,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    cambiacoord(tn,InFunDiN,NuoveC,metrica):=block([MD,
       wt,pwt,mwt,itrovati,litr,miaper,i,j,k],
       if nonmetricap(metrica)
           then return("Errore: non metrica"),
       MD:jacobian(InFunDiN,NuoveC),
       tTMD:tmat21(transpose(MD),metrica),
       tIMD:tmat12(invert(MD),metrica),
       wt:tn,
       itrovati:indici(wt),
       litr:length(itrovati),
       for j:1 step 1 thru litr do (
          miaper:makelist(i,i,litr),
          k:miaper[1],
          miaper[1]:miaper[j],
          miaper[j]:k,
          pwt:permuta(wt,miaper,"xPerm"),
          if is(mod(itrovati[j],2)=0) then (
             mwt:scala(tTMD,2,pwt,1))
             else (
             mwt:scala(tIMD,2,pwt,1)),
          wt:permuta(mwt,miaper,"xPerm")),
       for j:1 step 1 thru length(metrica[1]) do (
          mwt:trigsimp(ev(wt,metrica[1][j]=InFunDiN[j])),
          wt:mwt),
       return (wt)
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("cambiacoord(tn,InFunDiN,NuoveC,metrica)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Dato un tensore di qualsiasi rango la ticambiotutto
calcola il tensore che ha tutti gli indici di tipo
diverso ossia se un dato indice e' di tipo covariante
ossia femminile il corrispondente indice sara' di tipo
controvariante ossia maschile e viceversa.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Sarebbe possibile fare questo calcolo usando la
cambiatipi(tn,nuovitipi,metrica) che e' piu' flessibile
e sfrutta varie funzioni di questa libreria
ma la ticambiotutto applica altre funzioni e dunque
potrebbe servire anche per fare la verifica dello stesso
calcolo fatto con la cambiatipi.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ ticambiotutto(tn,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    ticambiotutto(tn,metrica):=block([lista,litipi,
       gff,gmm,listan,tipin,i],
       if nonmetricap(metrica)
           then return("Errore: non metrica"),
       lista:listadatensore(tn),
       litipi:indici(tn),
       gff:metrica[2][1],
       gmm:metrica[3][1],
       listan:cambiasesso(lista,litipi,gff,gmm),
       tipin:makelist((2+mod(1+litipi[i],2)),i,length(litipi)),
       return(tensoredalista(listan,tipin,"tipicambiati",
             dimensione(tn)))
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("ticambiotutto(tn,metrica)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
La cambiasesso(lista,litipi,gff,gmm) e' la funzione
applicata dalla ticambiotutto(tn,metrica) ma, dato che
lavora su tensori scritti in forma di lista ed ha bisogno
di ricevere in input l'indicazione del tipo di indici
da attribuire alla lista , consente calcoli esplorativi
senza bisogno di precalcolare la metrica ossia
fare derivate.
Per questo scopo la cambiasesso deve ricevere come
terzo argomento gff ossia la matrice da considerare
come tensore metrico totalmente covariante ossia
totalmente femminile e come quarto argomento gmm ossia
la inversa della gff che dunque considera come tensore
metrico controvariante ossia totalmente maschile.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ cambiasesso(lista,litipi,gff,gmm)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    cambiasesso(lista,litipi,gff,gmm):=block([base,quanti,
       ncifre,motipi,listan,lidove,aa,vale,lecifre,
       ll,j,h,k],
    if not(listp(lista)) then return(
              "Non lista il primo argomento"),
    if not(listp(litipi))then return(
               "Non lista il secondo argomento"),
    if not(matrixp(gff)) then return(
               "Non matrice il terzo argomento"),
    base:length(gff),
    quanti:length(lista),
    if is(quanti#base^length(litipi)) then
       return(["Errore quanti :",quanti,
       " base^length(litipi) :",base^length(litipi)]),
    ncifre:length(litipi),
    motipi:makelist(mod(litipi[1+ncifre-i],2),i,ncifre),
    listan:makelist(0,quanti),
    lidove:makelist(0,quanti),
    for k:1 step 1 thru quanti do(
        vale:k-1,
        lecifre:makelist(0,ncifre),
        for j:1 step 1 thru ncifre do(
            aa:mod(vale,base),
            vale:(vale-aa)/base,
            lecifre[j]:aa+1
            ),
        lidove[k]:lecifre
        ),
    for k:1 step 1 thru quanti do(
        aa:lista[k],
        lecifre:lidove[k],
        for h:1 step 1 thru quanti do (
            ll:lidove[h],
            vale:aa,
            for j:1 step 1 thru ncifre do(
               if motipi[j]=0 then
                    vale:vale*gmm[ll[j],lecifre[j]]
               else vale:vale*gff[ll[j],lecifre[j]]
               ),
            listan[h]:listan[h]+vale
            )
        ),
    return(listan)
    )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("cambiasesso(lista,litipi,gff,gmm)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Questa funzione, rapportolistetensori, serve ad evitare
sbrodolate nella stampa dei tensore.
Se credo che due tensori sono tra loro uguali o
almeno proporzionali, faccio il controllo e se veramente
lo sono ottenngo stime molto concise...
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ rapportolistetensori(ta,tb)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    rapportolistetensori(ta,tb):=block([lta,ltb,ltt,
       ra,rb,nuni],
       if not(tensorp(ta)) then
          return("Primo argomento NON tensore"),
       if not(tensorp(tb)) then
          return("Secondo argomento NON tensore"),
       if(ordine(ta)#ordine(tb)) then
          return("Tensori di rango diverso"),
       if(dimensione(ta)#dimensione(tb)) then
          return("Dimensione spaziotemporale diversa"),
       lta:listadatensore(ta),
       ltb:listadatensore(tb),
       ltt:makelist(0,length(lta)),
       nuni:0,
       for j:1 step 1 thru length(ltt) do(
        ra:ratsimp(lta[j]),
        rb:ratsimp(ltb[j]),
        if is(rb=0) then ( if is(ra=0) then (ltt[j]:1,
          nuni:nuni+1) else ltt[j]:ra/DivisoZero )
        else (ltt[j]:ratsimp(ra/rb),
          if is(ltt[j]=1) then nuni:nuni+1)),
        if nuni=length(ltt) then
          return(sconcat("Tutti uguali ",nuni," elementi"))
        else return(ltt)
        )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("rapportolistetensori(ta,tb)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Questa funzione, tdueantisim, fa il tensore antisimmetrico
di un tensore assegnato che deve essere di rango due ossia
essere una matrice. Se i tipi dei due indici
non sono uguali li rende provvisoriamente uguali
e poi, dopo avere antisimmetrizzato, li rimette come erano
nel tensore assegnato.
Si tratta di una funzione utilissima per calcolare
il tensore elettromagnetico partendo dalla derivata
qualificata del potenziale vettore del campo elettromagnetico.

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tdueantisim(tn,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tdueantisim(tn,metrica):=block([indi,inda,indb,
       asim,pro],
       if not(tensorp(tn)) then
          return("Primo argomento NON tensore"),
       if nonmetricap(metrica)
           then return("Errore: non metrica"),
       indi:indici(tn),
       if is(length(indi)#2) then
          return("Tensore non di rango 2"),
       inda:2-mod(indi[1],2),
       indb:2-mod(indi[2],2),
       if inda=indb then (
          asim:ratsimp(tn[1]-transpose(tn[1])),
          pro:[asim,[inda,indb,"Asim",dimensione(tn)]]
          )
       else (
          asim:cambiatipi(tn,[inda,inda],metrica),
          pro:ratsimp(asim[1]-transpose(asim[1])),
          asim:[pro,[inda,inda,"Asim",dimensione(tn)]],
          pro:cambiatipi(asim,[inda,indb],metrica)
          ),
       return(pro)
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tdueantisim(tn,metrica)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Questa sembrerebbe una funzione piuttosto insolita
ossia, dato un tensore di rango due ossia una matrice,
sottrargli un opportuno tensore ( in pratica
il tensore metrico ) fatto in modo che la traccia del
tensore risultato sia nulla.
Questa funzione e' FONDAMENTALE per costruire il
tensore Energia Impulso del campo elettromagnetico
che compare nell'equazione di Einstein per definire
il corretto valore del tensore di Gregorio Ricci-Curbastro.
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ tduetracciazero(tn,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    tduetracciazero(tn,metrica):=block([tmisto,indi,
       traccia,tnotra],
       if not(tensorp(tn)) then (
          print("Errore: Primo arg. NON tensore"),
          return(false)
          ),
       if nonmetricap(metrica) then (
          print("Errore: Secondo arg. NON metrica"),
          return(false)
          ),
       indi:indici(tn),
       if is(length(indi)#2) then (
          print("Errore: tensore non di rango 2"),
          return(false)
          ),
       tmisto:cambiatipi(tn,[1,2],metrica),
       traccia:ratsimp(mat_trace(tmisto[1])/dimensione(tn)),
       tmisto[1]:ratsimp(tmisto[1]-traccia*ident(dimensione(tn))),
       tnotra:cambiatipi(tmisto,indi,metrica),
       return(ratsimp(tnotra))
       )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("tduetracciazero(tn,metrica)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
Per trovare il tensore energia impulso
NON NORMALIZZATO, partendo da un potenziale vettore, ossia
un tensore di rango 1, faccio questa comoda funzioncina.

Evito di obbligare l'utilizzatore di questa libreria a
sapere come fare questo calcolo....
   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]

@ fa_tenergiaimpulso(tpotvet,metrica)

       [wxMaxima: comment end   ] */
    
    /* [wxMaxima: input   start ] */
    fa_tenergiaimpulso(tpotvet,metrica):=block([pvf,
         tnsff,tcampoff,tcampomf,tqmf],
         if not(tensorp(tpotvet)) then (
             print("Errore: Primo arg. NON tensore"),
             return(false)
             ),
         if nonmetricap(metrica) then (
             print("Errore: Secondo arg. NON metrica"),
             return(false)
             ),
         if is(length(indici(tpotvet))#1) then
             return("Tensore non di rango 1"),
         pvf:cambiatipi(tpotvet,[2],metrica),
         tnsff:ratsimp(diffcov(pvf,metrica,"gradiente")),
         tcampoff:tdueantisim(tnsff,metrica),
         tcampomf:cambiatipi(tcampoff,[1,2],metrica),
         tqmf:scala(tcampomf,2,tcampomf,1),
         return(tduetracciazero(tqmf,metrica))
         )$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: input   start ] */
    libmia:cons("fa_tenergiaimpulso(tpotvet,metrica)",
           libmia)$
    /* [wxMaxima: input   end   ] */
    
    /* [wxMaxima: comment start ]
    

   [wxMaxima: comment end   ] */

/* [wxMaxima: comment start ]
In complesso le funzioni attualmente definite in questa
libreria sono queste:
   [wxMaxima: comment end   ] */

/* [wxMaxima: input   start ] */
libmia:sort(libmia);
/* [wxMaxima: input   end   ] */

/* [wxMaxima: subsect start ]

Conclusione...provvisoria

[wxMaxima: subsect end ] */ /* [wxMaxima: comment start ] Chiunque ami le formule matematiche ricche di simmetrie non puo' non ammirare la bellezza della matrice del tensore di Ricci quando la metrica e' quella di Reissner Nordstrom ma non nella forma originale bensi' nella forma proposta da Schild. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] La matrice del tensore metrico, nel caso della variante di Schild, non e' piu' diagonale bensi' piena e questo ha un effetto piuttosto... devastante sulla velocita' del calcolo effettuato da Maxima.... ma il risultato e' il poter fare calcoli in coordinate "quasi cartesiane" visto che al tendere all'infinito della distanza dal buco nero la metrica ritorna ad essere quella pseudoeuclidea della Relativita' Speciale [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Anche se i normali buchi neri macroscopici ( quello al centro della via Lattea, ad esempio ) sono neutri ritengo molto opportuno ipotizzare che il buco nero gigantesco abbia la carica di almeno un elettrone... per i seguenti motivi. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] In Relativita' lo stesso problema fisico puo' essere trattato con infinite metriche diverse... come nella Meccanica Classica. Infatti, anche in Meccanica Classica si possono usare i piu' disparati sistemi di riferimento che producono, derivando lo Jacobiano, diversissimi tensori metrici. Cito a memoria... sistema cilindrico, sferico, parabolico, toroidale, ellissoidale etc... Di tutti questi sistemi e di molti altri, con il package ctensor di Maxima e' possibile calcolare l'appropriato tensore metrico. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Quello pero' che NON CAMBIA e' il valore del prodotto scalare ossia il modulo delle forze in azione. In Relativita', giustamente, piu' che di "scalare" si parla di "invariante" perche' appunto, una quantita' invariante non cambia qualunque sia il sistema di riferimento e dunque la sua metrica associata. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ad una data distanza dal buco nero esiste una forza necessaria per impedire che l'oggetto cada nel buco nero. Se anche il buco nero ha la carica di un solo elettrone, dato che la forza elettrostatica repulsiva dipende dal prodotto delle due cariche ( dello stesso segno ) dei due oggetti che si respingono.... dunque esistera' sempre una carica della particella tale da impedire che la particella acceleri verso il buco nero ossia cada in esso. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ma l'entita' di questa carica e' UN INVARIANTE ! ed e' un invariante il modulo della forza necessaria per impedire alla particella ferma di cominciare ad accelerare [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Numericamente il problema ossia il calcolo di questa forza e' facile perche' si tratta di risolvere un problemino di ELETTROSTATICA, sia pure in uno spazio deformato dalla presenza del grande ( o piccolo ) buco nero. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Siccome la forza e' un vettore, il suo modulo e' un invariante e dunque non cambia qualunque sia il sistema di riferimento ( da cui deriva la metrica ) che sto usando. [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Insomma ..non importa che stia usando, in pratica, la metrica di Schwarzschild o quella di Reissner Nordstrom o quella di chiunque altro inventi una sua metrica... Si pensi a quella del reverendo Lemaitre: http://en.wikipedia.org/wiki/Lemaitre_metric IL MODULO DELLA FORZA CHE EQUILIBRA L'ACCELERAZIONE DI GRAVITA' NON CAMBIA ossia LA RELATIVITA' NON E' ASSOLUTAMENTE RELATIVA ma INVARIANTE ed ASSOLUTA ! [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Ma anche senza ricorrere a buchi neri dotati di carica, basta pensare all'invariante proposto nel lontano 1915 da Erich Justus Kretschmann (July 14, 1887 in Berlin -1973). Citato a pagina 250 dell' HEL ( Hobson, Efstathiou,Lasenby : ISBN 9780521829519 ). Vedere: http://en.wikipedia.org/wiki/Erich_Kretschmann. Si tratta dell'invariante quadratico del tensore di Riemann che non diventa zero neppure in qualsiasi punto dello spazio in quel punto privo di materia e/o energia ma in uno spazio anche leggermente distorto da un pur remoto buco nero neutro... Ma un invariante NON DIPENDE DAL SISTEMA DI RIFERIMENTO USATO per cui rappresenta un parametro indipendente da ogni osservatore che osservi , da lontano o da vicino, l'evoluzione del sistema di buchi neri piu' o meno massicci e piu' o meno dotati di carica elettrica e di spin. [wxMaxima: comment end ] */ /* [wxMaxima: subsect start ]

Chiusura eventuale file di salvataggio.

[wxMaxima: subsect end ] */ /* [wxMaxima: input start ] */ print("Fine della libreria tensoriale. Vedere libmia")$ /* [wxMaxima: input end ] */ /* [wxMaxima: input start ] */ if stringp(aggiornolibreria) then ( closefile(), print("Chiude il file ",salvoqui )) else print("AMEN")$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ] Non resta che utilizzare questa libreria effettuando un load(salvoqui). [wxMaxima: comment end ] */ /* [wxMaxima: comment start ] Fa qualche print per fare capire come si deve fare per riscrivere su disco questa libreria... [wxMaxima: comment end ] */ /* [wxMaxima: input start ] */ print("Aggiorna la libreria solo se ", "la variabile aggiornolibreria ", "e' una stringa e non un numero o e' indefinita")$ print("Ora aggiornolibreria vale : ",aggiornolibreria)$ print("Se ha aggiornato la libreria ora la ha scritta ", " nel file ",salvoqui)$ print("=============================================")$ /* [wxMaxima: input end ] */ /* [wxMaxima: comment start ]
Per usare questo file con http://maxima.sourceforge.net/ cancellare l'estensione .html e lasciargli l'estensione .wxm

Amen versione 3 del generatore della lib. tensoriale

[wxMaxima: comment end ] */ /* Maxima can't load/batch files which end with a comment! */ "Created with wxMaxima"$

Verifiche della validità di questa libreria

Verifica della prima identità di Luigi Bianchi

A pag. 344, formula (92,4), per esempio il Landau afferma:

La somma ciclica di qualsiasi terna di indici del tensore di Riemann r2222 deve essere sempre nulla.
In altre parole tenendo fisso il primo indice a e facendo girare gli altri tre   b, c e d   si dovrebbe ottenere, scrivendo in pseudolinguaggio maximese :

r2222[1][a,b][c,d] + r2222[1][a,d][b,c] + r2222[1][a,c][d,b] == 0

Ma applichiamo in concreto questa libreria usando la funzione intrinseca di wxMaxima rest(lista,-1) che serve a scartare l'ultimo elemento della lista che contiene il tensore ossia l'elemento che contiene le informazioni sulla natura del tensore:

print( rest(r2222,-1)+ rest(permuta(r2222,[1,3,4,2],""),-1)+ rest(permuta(r2222,[1,4,2,3],""),-1))$

Si deve ottenere una montagna di zeri...

Verifica della seconda identità di Luigi Bianchi

Vedere: http://it.wikipedia.org/wiki/Tensore_di_Riemann e http://en.wikipedia.org/wiki/Einstein_tensor e da meditare ed applicare questa interessantissima pagina che spiega come fa a curvare lo spazio non un campo elettromagnetico ma un campo scalare ossia generato da un potenziale scalare e non da un potenziale vettore: http://en.wikipedia.org/wiki/Scalar_field_solution

La somma ciclica di qualsiasi terna di indici del tensore di Riemann r22228 deve essere sempre nulla.
In altre parole tenendo fisso il primo ed il secondo indice   a e b  e facendo girare gli altri tre   c, d   ed   e   si dovrebbe ottenere, scrivendo in pseudolinguaggio maximese :

r12228[a][b,c][d,e] + r12228[a][b,e][c,d] + r12228[a][b,d][e,c] == 0

e lo stesso dicasi, per esempio, se si abbassa il primo indice ossia si deriva in modo covariante r2222 e non r1222

r22228[a][b,c][d,e] + r22228[a][b,e][c,d] + r22228[a][b,d][e,c] == 0

Usiamo dunque, per esempio, questa libreria per calcolare la derivata covariante di r1222. Si fa così usando la funzione intrinseca di wxMaxima   ratsimp( ... )   che serve a fare semplificazioni di espressioni algebriche razionali...

r12228:ratsimp(diffcov(r1222,metrica,"r12228"))$

Notare che è un calcolo lungo perché si tratta di calcolare un tensore del quinto ordine ossia con 45 ossia 1024 componenti!

Noto r12228, ecco come va calcolata la seconda identità di Luigi Bianchi con questa libreria ossia permutando gli indici. In quattro dimensioni questo tensore del quinto ordine ha 1024 componenti che dovrebbero risultare tutte nulle, URKA!

idlbianchi:rest(r12228,-1)+ rest(permuta(r12228,[1,2,4,5,3],""),-1)+ rest(permuta(r12228,[1,2,5,3,4],""),-1)$

E naturalmente si avrebbe ottenuta una valanga di 1024 zeri anche lavorando non a partire da r1222 ma da r2222 ossia:

idlbianchif:rest(r22228,-1)+ rest(permuta(r22228,[1,2,4,5,3],""),-1)+ rest(permuta(r22228,[1,2,5,3,4],""),-1)$

http://www.elegio.it/max/

In questa immagine SVG uso l'elemento defs unito a symbol e ad use e scrivo testi grandi e belli.. {circle r="300" cx="30000" cy="18000" fill="red" /}