Brevi note sui comandi

Esistono ottimi tutorial e libri gratuiti per imparare ad utilizzare Sage, ed anche ottime lezioni video che però sono in lingua inglese. La seguente è una breve panoramica.

Sage è “case sensitive” cioé distingue ma maiuscole e minuscole (cosa comune nei sistemi Unix, incluso MacOSX, ma insolita in Windows), tranne per la funzione di approssimazione numerica N(), l’unità immaginaria I, ed i booleani True e False.

La costante “pi greco” è indicata con pi e il “numero di Nepero” con e.
Gli operatori aritmetici sono indicati, come al solito su PC, con +,-,*,/ e la moltiplicazione va sempre indicata esplicitamente. L’elevamento a potenza si indica con ^ oppure ** oppure, per l’esponenziale di base e, con exp(). Il logaritmo naturale si indica con log(), quello in base n con log(,n). La radice quadrata si indica con sqrt(), quelle superiori con l’elevamento a potenza con esponenti frazionari. Fra le funzioni elementari, le trigonometriche lavorano ovviamente in radianti e, se possibile, restituiscono valori esatti cioé frazioni di pi.

Le operazioni si raggruppano esclusivamente con le parentesi rotonde, poiché le quadre e le graffe sono utilizzate dalla sintassi del linguaggio Python per altri scopi.

Come in molti altri programmi si può iniziare a scrivere un comando e poi premere il tasto TAB per vedere una lista di comandi che incominciano per le lettere digitate.
Per andare a capo senza interrompere la riga, terminarla con “/” (carattere di continuazione. Per scrivere più comandi sulla stessa riga, separarli con “;”.
Quanto scritto immediatamente precedentemente può essere richiamato con il carattere di sottolineantura _.

Per ogni comando sono disponibili delle pagine di manuale (dette docstring), visualizzabile scrivendo un punto interrogativo subito dopo il comando : “comando?”. Si può ricercare un nome all’interno di tutte le pagine di manuale con search_doc(nome) ed è anche possibile vedere il codice sorgente che implementa un comando scrivendo 2 punti interrogativi dopo di esso: “comando??”. Oltre che in locale, il manuale generale di Sage è online a http://www.sagemath.org/doc/reference/

Le variabili simboliche si definiscono con comando var, tranne la “x” che è tale di default.
Possono essere definite delle funzioni matematiche componendo le funzioni predefinite in Sage oppure con i comandi Python lambda e def: gli utenti utilizzeranno nella stragrande maggioranza il primo sistema, ma l’uso di costrutti Python può essere utile, oltrché nello sviluppo, anche a scopo didattico. In generale queste ultime funzioni non saranno però differenziabili né integrabili, a meno di non scrivere noi il codice per tali operatori. Analogamente si possono definire nuovi oggetti, ad esempio l’insieme dei numeri pari, con il comando Python class.

Per richiamare una funzione di libreria si usa la solita sintassi puntata dei linguaggi OOP, ad esempio: maxima.eval(“f:bessel_y(v,w)”).

I calcoli possono simbolici, cioé eseguiti utilizzando le proprietà degli oggetti matematici, ed in tal caso i risultati sono esatti, o numerici, ed in tal caso sono approssimati. Ad esempio una equazione può essere risolta in modo simbolico con il comando solve e numerico con il comando find_root. Chiaramente la soluzione numerica dà sempre un risultato, quella simbolica no, esattamente come quando si svolgono i calcoli a mano (ad esempio per la soluzione di un’equazione algebrica di grado 5). Siccome in generale i metodi numerici sono sensibili alle condizioni iniziali e presentano problemi quali la cancellazione numerica, è meglio usare le funzionalità di calcolo esatto tutte le volte che è possibile farlo, anche se si cerca soltanto un’approssimazione numerica del risultato. Dunque, poiché Sage suppone, ogni volta che scriviamo un numero in notazione decimale, che si tratti di un’approssimazione, è meglio usare la notazione frazionaria rispetto alla decimale nei calcoli che vogliamo esatti.

Per i calcoli simbolici non mancano comandi per eseguire derivate con diff(), integrali indefiniti  (attenzione al fatto che non c’è il “+ C” nel risultato) e definiti con integrate(), risolvere equazioni differenziali con desolve(), polinomi di Taylor con taylor(), limiti con limit(), somme finite e serie con sum(), ecc. Vi sono casi, quali la serie geometrica, in cui il risultato esiste solo per un intervallo di valori: questo fatto va segnalato a Sage con l’istruzione assume(abs(x)<1), altrimenti risponderà, correttamente, che non esiste somma finita per tutti i possibili valori di x.

Se il valore ritornato dal calcolo simbolico non appare come ci aspetteremmo, dare l’istruzione expand() che indica a Sage di dare un’espressione meno compatta di quella che sta offrendo; possiamo fare il contrario con l’istruzione combine(). Altre istruzioni utili nel calcolo simbolico sono collect() e symplify().

Se abbiamo bisogno del codice Latex relativo all’espressione a cui siamo arrivati, per farne copia-incolla in un documento Latex, dare latex(espressione).

In Sage si può scegliere di lavorare su interi, indicati con ZZ, razionali, indicati con QQ, e con quella parte dei reali, RR, e complessi, CC, che è possibile rappresentare in modalità binaria floating-point. Ad esempio sarà utile considerare un polinomio in taluni casi con variabile definita in CC (ad esempio quando ne vogliamo tutte le possibili radici), ed in altri su ZZ (ad esempio per le equazioni diofantee): chiaramente nel primo caso sarà sempre fattorizzabile, nel secondo caso non sempre. Si può anche lavorare sugli interi modulo n, i campi di Galois e molte altre strutture predefinite: esse sono dette “rings”. Le espressioni simboliche generiche appartengono al “Symbolic ring”. Si può sapere a quale “ring” appartiene una variabile simbolica con l’istruzione in: ad esempio (x in RR) varrà True se x è a valori reali, False altrimenti.
A partire dagli insiemi forniti da Sage possiamo definirne altri: ad esempio l’insieme dei polinomi a coefficienti razionali variabile t si definisce con: R.<t> = QQ[‘t’].

Dunque se eseguiamo una divisione fra interi il risultato sarà un intero, e potremo averne il resto con l’operatore modulo %. Infatti è la classe dell’oggetto che determina quale versione del comando sarà utilizzata. In caso di operandi misti uno dei 2 sarà convertito nel tipo dell’altro secondo un meccanismo di regole detto “coercion”. Ad esempio 5 e 5/1 sono oggetti diversi, poiché il loro “parent” è ZZ per il primo, e QQ per il secondo. Ma possiamo chiedere esplicitamente una conversione con QQ(5). Ogni oggetto ha un tipo ed un parent. Le espressioni simboliche hanno parent SR.

Una apparente complicazione è che vi sono tipi Sage e tipi Python (questi non hanno un parent): ad esempio il tipo int di Python non è la stessa cosa del tipo Integer di Sage, ma la conversione fra i due in genere non presenta difficoltà ed è eseguita automaticamente (bisogna tenerne conto in pratica solo se si scrive del codice sorgente). Il tipo di un oggetto è restituito dalla funzione Python type(oggetto).

Operazioni valide sia per numeri che per polinomi sono il calcolo del massimo comun divisore con gcd() e del minimo comune multiplo con lcm(), dei divisori con divisors() e la fattorizzazione con factor().

Un insieme ordinato di valori, cioé un vettore, sarà presentato dal costrutto lista [ , , , ] del linguaggio Python. Una matrice è rappresentata come una sequenza ordinata di vettori, cioé una lista di liste preceduta dal token matrix.

Definito un vettore con a=vector([1,2,3]), la sua norma è norm(a), il suo prodotto interno con un vettore b è a.dot_product(b), quello esterno a.cross_product(b). Possiamo creare uno spazio di matrici 3×3 a valori reali M con M = matrixSpace(RR,3) e richiederne una base con M.basis(), e, scelta una matrice, calcolarne il determinante, gli autovalori ed autovettori, le forme diagonali e canoniche, ecc. La matrice identità si scrive, oltreché come le altre matrici, più rapidamente con Id = identity_matrix(3).

La funzione N() cerca di calcolare esplicitamente l’espressione simbolica contenuta fra parentesi,  restituendo un valore approssimato, se necessario facendo uso di algoritmi di calcolo numerico.
Si può specificare la precisione richiesta, sia come numero di cifre decimali corrette che come numero di bit utilizzati. Se il risultato ritornato da un calcolo è un’approssimazione, Sage lo segnala scrivendo un ? dopo l’ultima cifra significativa.

La rappresentazione grafica di un’espressione è prodotta dalla funzione plot() e dalle sue varianti parametric_plot(), polar_plot(), implicit_plot(), plot_loglog() per grafici in scala logaritmica,  e, per grafici di funzioni in più variabili, plot3d(), contour_plot(), plot_vector_field(), plot_slope_field(), ecc. e il risultato può essere visualizzato a video con show() e/o salvato su file con save(). Il comando plot() ed i suoi simili hanno molti argomenti per selezionare la porzione di dominio e la formattazione del risultato: ad esempio gridlines, frame, legend_label, fill, linestyle. Un grafico in 3D può essere ruotato e ridimensionato interattivamente con il mouse. Più grafici, cioé più istruzioni di tipo plot, possono essere sovrapposti, per facilitare i confronti, semplicemente componendoli con l’operatore +. Infine, se si dispone anziché di una funzione solo di un insieme di valori tabulati, oltre a stamparli con scatter_plot() possiamo richiedere la regressione ad un modello, da impostarsi con model(), con i metodi dei minimi quadrati tramite find_fit().

Infine, se si scrive un numero come 0x11 Sage intende che è in esadecimale, se 0b11 che è in binario, se 011 che è in ottale (quindi attenzione a non mettere inutili zeri davanti ad un numero).