Introduzione a Mathematica

Gianluca Gorni
Università di Udine, Dipartimento di Matematica e Informatica

3. Calcolo letterale, sostituzioni, assegnazioni

Ultima modifica: 14 dicembre 2006

Questo file è concepito principalmente per essere letto interattivamente su schermo. Per questo, e anche per risparmiare spazio, gli output di solito sono omessi. L'utente che legge da schermo li deve rigenerare mandando in esecuzione le celle di input una alla volta.
Qualcuno vorrà stampare per leggere su carta: in tal caso apra i gruppi di celle ed esegua tutte le celle prima di stampare. Le celle si possono eseguire tutte in un sol colpo col menu Kernel>Evaluation>Evaluate Notebook

Inizializzazione

Inizializzazione consigliata:

SetOptions[$FrontEnd, 
        CommonDefaultFormatTypes -> {"Output" -> 
              TraditionalForm}];
$FormatType = TraditionalForm;

Espressioni algebriche

Si possono scrivere formule semplici o complicate. La precedenza delle operazioni è quella convenzionale in matematica. Nel dubbio usare le parentesi tonde.

a + b

a + b + a

a + (b + a)

a + b*c

(a + b)*c

(a + b) c

(a - b)/c

a - b/c

Mathematica non applica automaticamente la proprietà distributiva: per quello usare Expand:

Expand[(a + b) c]

Per applicare una funzione a un'espressione, a volte viene più naturale la sintassi espressione//funzione, invece di funzione[espressione]:

(a + b) c // Expand

Per fattorizzare un'espressione usare Factor:

Factor[(a^2) - (b^2)]

Factor[(x^2) + 3  x*y - 4  (y^2)]

Trabocchetto: se scrivete xy senza niente fra i due caratteri, Mathematica prende xy come il nome di una singola variabile, e non come il prodotto delle due variabili x e y:

Factor[(x^2) + 3  xy - 4  (y^2)]

Ricordarsi di mettere un asterisco, o uno spazio, fra la x e la y.

Un'operazione molto potente è Simplify, che cerca una forma più semplice che può dell'espressione data:

(y^3) - (x^3) + a + 3  (x^2) y - 3  x*(y^2) // Simplify

Se non si è soddisfatti del risultato di Simplify, provare con l'ancora più potente (ma molto più lento) FullSimplify:

(y^3) - (x^3) + a + 3  (x^2) y - 3  x*(y^2) // FullSimplify

Purtroppo anche FullSimplify a volte non si accorge di certe semplificazioni possibili:

1 + (1 - y)^3 // Expand // FullSimplify

Questo output sarebbe quello che ci aspettiamo da Factor, non da Simplify o FullSimplify.

Per raccogliere a denominatore comune un'espressione fratta c'è Together:

Together[(a/(b + c)) + (b/(b - c))]

Mathematica cancella automaticamente un fattore comune esplicito a numeratore e denominatore:

(((x + 1) (x - 1))/(x - 1))

Se il fattore è implicito si può usare Cancel (o anche Simplify):

Cancel[(((x^2) - 1)/(x - 1))]

Ricordarsi che quando si semplifica in questo modo la nuova espressione può non essere esattamente equivalente all'originale. Negli esempi qui sopra le espressioni originali non hanno senso quando x = 1, mentre le semplificate sì.

Sostituire una variabile con un valore dentro una data espressione (slash dot /.)

Quanto vale (x^2) - 2 quando x = (Sqrt[3])? La sintassi per avere una risposta a questiti simili in Mathematica è

espressione /. variabile -> valore

/. in inglese si legge "slash dot". L'interfaccia utente sostituisce automaticamente i due caratteri -> con la freccia ->

(x^2) - 2/.x -> (Sqrt[3])

(Casomai venisse il dubbio, niente paura: la formula scritta tutta in nero funziona uguale).
Come già detto, (((x^2) - 1)/(x - 1)) non ha senso per x = 1:

(((x^2) - 1)/(x - 1))/.x -> 1

mentre la semplificazione non ha problemi col valore x = 1:

Simplify[(((x^2) - 1)/(x - 1))]/.x -> 1

Se vogliamo sostituire dei valori a più di una variabile raccogliamo le assegnazioni fra graffe (una "lista"):

(a^2) - (b^2)/.{a -> 1, b -> -2/3}

Assegnazione di un valore a un simbolo (=)

La sostituzione con "slash dot" vale soltanto sull'espressione corrente, e non ha seguito:

1 + x /. x -> 1

1 + x

Se voglio che d'ora in poi (fino ad esplicito avviso contrario) la x valga 1 posso usare l'assegnazione con =

x = 1

D'ora in avanti il nòcciolo sostituisce d'ufficio la x con 1:

1 + x

Posso cambiare l'assegnazione:

x = 2

1 + x

Se voglio ripristinare la x senza valore posso scrivere Clear[x], o anche x=.

x =.

1 + x

Assegnando un nome a un'espressione posso poi manipolarla senza riscriverla ogni volta:

espr = (((x^2) + x - 2)/((x^2) - 1)) - (3/2) (x^2)

Per esempio ora posso confrontare l'effetto di tre trasformazioni diverse:

Together[espr]

Factor[espr]

Simplify[espr]

oppure posso sostituire diversi valori a x:

espr/.x -> -(Sqrt[2])/3

espr/.x -> 1

Simplify[espr]/.x -> 1

Per sapere se a un simbolo è assegnato un valore, si può eseguire il simbolo in isolamento:

espr = (((x^2) + x - 2)/((x^2) - 1)) - (3/2) (x^2);

espr

oppure anche scrivere punto interrogativo seguito dal simbolo, e poi eseguire:

?espr

Punto e virgola

Se alla fine di un'espressione di input mettiamo un punto e virgola, il nòcciolo la calcola, ma non mostra il risultato sull'interfaccia utente. Provare a eseguire la cella seguente:

Expand[(x - y) (x + y)];

Un caso in cui questo viene comodo è quando si fa un'assegnazione: di solito non ci interessa rivederne il valore nell'output. Confrontate senza e con punto e virgola:

a = 3 + (Sqrt[2] + 3^(1/3))^3

a = 3 + (Sqrt[2] + 3^(1/3))^3;

Si possono anche dare più istruzioni in una stessa cella, separate da punti e virgola. Verranno calcolati in successione, e viene mostrato il risultato soltanto dell'ultimo (se non finisce anche lui col punto e virgola):

Clear[x];
a = x - 1;
b = x^2 - 1;
Simplify[a/b - b/a]

Confrontare con la stessa espressione ma senza i punti e virgola:

Clear[x]
a = x - 1
b = x^2 - 1
Simplify[a/b - b/a]

Esempio: generare polinomi scomponibili su ℤ o ℚ

Come si fa per trovare un polinomio di secondo grado che abbia come radici 1 e 5? Beh, basta scrivere

(x - 1) (x - 5) // Expand

Supponiamo di voler scrivere un eserciziario sulle equazioni di secondo grado. Possiamo generare un polinomio casuale scomponibile sugli interi con

(x - Random[Integer, {-4, 4}]) (x - 
            Random[Integer, {-4, 4}]) // Expand

poli = (x - Random[Integer, {-4, 4}]) (x - 
                Random[Integer, {-4, 4}]) // 
          Expand;
{poli, Factor[poli]}

Forse è il caso di scrivere accanto al polinomio anche la sua scomposizione: per questo usiamo la seguente sintassi:

Ogni volta (beh... forse non ogni volta...) che si manda in esecuzione il comando qui sopra viene un polinomio diverso. Possiamo ripetere il comando per esempio 10 volte con Do:

Do[(x - Random[Integer, {-5, 5}]) (x - 
                Random[Integer, {-5, 5}]) // Expand // 
        Print, 
{10}]

Il seguente comando produce dei polinomi di secondo grado con una radice intera e una razionale:

Do[(x - Random[Integer, {-5, 5}]) (x - 
                Random[Integer, {-5, 5}]/Random[Integer, {1, 5}]) // 
          Expand // Print, 
{10}]

Se vogliamo polinomi a coefficienti interi basta che facciamo denominatore comune con Together e poi prendiamo il numeratore con Numerator:

Do[(x - Random[Integer, {-5, 5}]) (x - 
                    Random[Integer, {-5, 5}]/Random[Integer, {1, 5}]) // 
              Expand // Together // Numerator // 
        Print, 
{10}]

Il seguente comando produce dei polinomi di secondo grado con due radici razionali:

Do[(x - 
                    Random[Integer, {-5, 5}]/
                      Random[Integer, {1, 5}]) (x - 
                    Random[Integer, {-5, 5}]/Random[Integer, {1, 5}]) // 
              Expand // Together // Numerator // 
        Print, 
{10}]

Aggiungiamo anche le scomposizioni:

Do[poli = (x - 
                    Random[Integer, {-5, 5}]/
                      Random[Integer, {1, 5}]) (x - 
                    Random[Integer, {-5, 5}]/Random[Integer, {1, 5}]) // 
              Expand // Together // Numerator; 
{poli, 
          Factor[poli]} // Print, 
{10}]

Esercizi

Espandere (x - 1) (x + 1), e poi (x - 1) ((x^2) + x + 1), e poi (x - 1) ((x^3) + (x^2) + x + 1). Indovinare quindi il risultato dell'espansione di (x - 1) ((x^4) + (x^3) + (x^2) + x + 1).

La divisione è associativa? In altre parole, (a/b)/c = a/(b/c)? Rispondere eseguendo i due membri con Mathematica.  La stessa cosa con la potenza al posto della divisione: (a^(((b^c)))) = ((((a^b)))^c)?

Mathematica come interpreta le espressioni (matematicamente ambigue) a/b/c e a^b^c?

Mandate in esecuzione a/b/.{a->b,b->a}. Una morale: per scambiare fra loro due variabili non c'è bisogno di introdurne una terza ausiliaria.

Eseguire a/b /. a->b /. b->a. Se il risultato vi sorprende pensate che questo equivale per Mathematica a scrivere (a/b /. a->b) /. a->b. Provare poi con a/b/.(a->b/.a->b).

Conoscete la regola ((((a^b)))^c) = (a^(b c))? A prima vista sembrerebbe che Mathematica non ne sappia niente: provate a valutare ((((a^b)))^c) o Simplify[((((a^b)))^c)], o anche FullSimplify[((((a^b)))^c)]. In realtà se Mathematica si rifiuta di applicare la regola c'è un'ottima ragione: la regola diventa falsa quando entrano in gioco i numeri complessi. Provare a valutare ((((a^b)))^c) == 
          (a^(b c)) /. {a -> -1, b -> (3/2), 
          c -> (1/3)}. Mathematica comunque sa che la regola è vera sotto una delle due restrizioni seguenti:
1) a > 0, b ∈ ℝ e c qualsiasi: valutare Simplify[(a^b)^c,{a>0,Element[b,Reals]}];
2) a qualsiasi, ma b, c ∈ ℤ: valutare Simplify[(a^b)^c,Element[{b,c},Integers]].
(A Simplify e FullSimplify si possono aggiungere condizioni. Ne riparleremo).