conclusioni sul corso di tnds -...

34
Laboratorio di trattamento numerico dei dati sperimentali Maurizio Tomasi ﴾turno A2﴿ Giovedì 11 Gennaio 2018

Upload: dangcong

Post on 16-Feb-2019

223 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Laboratorio di trattamento numerico deidati sperimentali

Maurizio Tomasi ﴾turno A2﴿

Giovedì 11 Gennaio 2018

Page 2: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Conclusioni sul corso di TNDS

Page 3: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Come usare quanto imparato nel corso?Presento ora una prospettiva personale di quanto abbiamoimparato nel corso, e di come muoversi quando vi troverete adovere scrivere codici per un laboratorio/tesi/dottorato/etc.

Questo corso vi ha insegnato il linguaggio C++, ma è unapreoccupazione mia e degli altri docenti del corso che non vifermiate ad usare solo esso nella vostra vita accademica elavorativa! Nella maggior parte delle situazioni concrete, esistonoalternative più semplici ed efficienti del C++ ﴾es., Python, R, Julia,Mathematica﴿.

Page 4: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

OOP: una retrospettivaIn questo corso abbiamo visto come sviluppare programmi usandoi concetti della programmazione orientata agli oggetti ﴾OOP,object‐oriented programming﴿, ossia:

1. Incapsulamento ﴾funzioni e variabili stanno insieme in una class ﴿;

2. Ereditarietà ﴾classe derivata da un'altra﴿;3. Polimorfismo ﴾ridefinizione di funzioni  virtual ﴿.

Vediamo in cosa ci sono servite, e quali possibili alternative sonodisponibili alla OOP.

Questo vi sarà utile non solo per preparare l'esame, ma anche perdecidere come scrivere i vostri futuri codici.

Page 5: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Ereditarietà e polimorfismoÈ frequente la necessità di scrivere algoritmi che operino su unafunzione matematica f non nota a priori:

1. Calcolo degli zeri di una funzione;2. Calcolo di derivate;

3. Calcolo di integrali.4. Etc.

La OOP ci ha fornito gli strumenti per fare in modo che questicodici accettassero qualsiasi funzione, definendo una classe FunzioneBase  con un metodo  Eval  virtuale, e poi implementandoclassi derivate.

Vediamo come era possibile fare ciò prima che esistessero letecniche OOP.

Page 6: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Esempio: calcolo di integrali senza OOPdouble integrate(double fn(double), double a, double b) {    // To evaluate `fn` in the body of "integrate", use    //    fn(x)}

È possibile scrivere una funzione come quella sopra, che accetta ininput una funzione qualsiasi e ne calcola l'integrale tra  a  e  b .

Esempio d'uso:

#include <iostream>#include <cmath>

int main() {    std::cout << integrate(std::sin, 0.0, 1.0) << "\n";}

Page 7: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Esempio: calcolo di integrali con OOPCon la OOP le cose si fanno più complicate:

#include <cmath>#include <iostream>

class FunzioneBase {public:        FunzioneBase() {}        virtual double eval(double x) = 0;};

class Sin : public FunzioneBase {public:        Sin() {}        double eval(double x) { return std::sin(x); }};

double integrate(FunzioneBase & fn, double a, double b) {    // To evaluate "fn" in the body of "integrate", use    //    fn.eval(x)}

Page 8: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Parentesi: uso di  operator() Se dà fastidio ricordarsi di chiamare sempre il metodo  eval , il C++ci viene incontro con  operator()  ﴾che è molto elegante!﴿:

class FunzioneBase {public:        FunzioneBase() {}        virtual double operator()(double x) = 0;};

class Sin : public FunzioneBase {public:        Sin() {}        double operator()(double x) { return std::sin(x); }};

double integrate(FunzioneBase fn, double a, double b) {    // To evaluate "fn" in the body of "integrate", use    //    fn(x)}

Page 9: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Esempio: calcolo di integrali con OOPPer giunta, nell'invocare  integrate  dobbiamo prima creare unavariabile di tipo  Sin :

int main() {    Sin funzione;    std::cout << integrate(funzione, 0.0, 1.0) << "\n";}

A prima vista la OOP non sembra un gran guadagno:

1. Ci vogliono più linee di codice per fare la stessa cosa;

2. Dobbiamo creare una variabile  funzione  apposta per invocare integrate .

Qual è il vantaggio di usare la OOP qui?

Page 10: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Vantaggi dell'approccio OOPSupponiamo che ciò che vogliamo integrare non sia la funzione

f(x) = sinx,

ma la funzione

f (x) = sin kx,

per qualche k fissato, e che il nostro programma debba calcolarepiù volte questo integrale, ogni volta con un valore diverso di k.

k

Page 11: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Vantaggi di OOPPossiamo passare il parametro addizionale  k  nel costruttore, inmodo da lasciare  eval  così com'è.

class Sin : public FunzioneBase {    double k;    public:    Sin(double a_k) : k(a_k) {}    double eval(double x) { return std::sin(k * x);}

Fare in modo che  eval  continui ad accettare il solo parametro  x  èfondamentale:  integrate  non saprebbe più come funzionare se il eval  accettasse ora due argomenti:

double Sin::eval(double x, double k) { /* ? */ }

Page 12: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Vantaggi di OOPDiventa a questo punto molto facile calcolare integrali con valoridiversi di k, perché k viene passato al costruttore e  integrate  nonsa neppure che il parametro  k  esista!

int main() {    Sin sin1(1.0);    Sin sin2(2.0);    std::cout << integrate(sin1, 0.0, 1.0) << " "              << integrate(sin2, 0.0, 1.0) << "\n";}

Questo chiarifica anche perché si debba definire una variabile  sin nell'esempio visto prima: perché in essa sono conservati i valori dieventuali parametri ﴾ k , appunto﴿ passati tramite il costruttore.

Ci sono tanti trucchi possibili per ottenere ciò con l'approccio non‐OOP mostrato prima. Però raramente questi trucchi sono eleganti!

Page 13: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Problemi con l'approccio OOP: verbositàLa OOP risolve il problema del passaggio di parametri arbitraricome nel caso di f (x) = sin(k ⋅ x). Questo approccio peròcausa nuovi problemi.

Supponiamo che un collega mi passi il codice di una funzione checalcola lo spettro di brillanza della radiazione fossile:

double planck_law_3K(double frequency) {    // …}

Se volessi usare la mia funzione  integrate  per stimarne l'integralesu ν ﴾ossia σT , la legge di Stefan‐Boltzmann﴿, non potrei passarledirettamente  planck_law : dovrei prima creare una classe PlanckLaw  derivata da  FunzioneBase  e definire in essa un metodo eval  che chiama  planck_law  ﴾rallentando il codice﴿.

k

4

Page 14: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Problemi con l'approccio OOP: gerarchiecomplesseLa tendenza del codice OOP è quella di generare strutturegerarchiche di classi che hanno tutte il medesimo oggetto diorigine ﴾solitamente chiamato  Object ,  TObject  o  CObject ﴿.

Se volessi usare in un mio codice una classe  Pippo  proveniente daun'altra libreria, questa non potrebbe essere facilmente integratanel codice esistente perché ne sfrutti le funzionalità: bisognerebbeprima creare una nuova classe  TPippo  che derivi sia da  Pippo  cheda  TObject , e ricordarsi di usare sempre  TPippo  anziché  Pippo .Non sempre ciò è possibile, o comunque conveniente!

Vediamo storicamente quando è emerso questo problema.

Page 15: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Borland C++ 3.1 ﴾1992﴿

Includeva una libreria OOP in C++ ﴾«Turbo Vision»﴿ per creareinterfacce di testo come quella dell'ambiente di sviluppo. ﴾Ilsottoscritto l'ha usata tantissimo!﴿

Page 16: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Funzionamento di Turbo VisionUn programma Turbo Vision poteva salvare su disco il suo stato. Inquesto modo, quando si faceva ripartire il programma, l'utenteritrovava tutto nello stesso stato ﴾posizione finestre, file aperti…﴿ incui l'aveva lasciato.

Questo era possibile perché ogni classe che definiva gli oggetti delprogramma ﴾finestre di testo, bottoni, dialoghi…﴿ derivava dallaclasse  TObject , che aveva un metodo  save  e un metodo  load .Per salvare lo stato del programma bastava un codice simile aquesto:

TObject **objects;  // Array of pointers to TObjectfor(int i = 0; i < num_of_objects; ++i) {    objects[i]‐>save();}

Page 17: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Gerarchia di classi di Turbo Vision

Page 18: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Borland C++ 3.1 per Windows 3.1 ﴾1992﴿

La versione per Windows del Borland C++ includeva una libreria diclassi ﴾OWL, Object Windows Library﴿ per scrivere programmiWindows. Il sottoscritto ha usato moltissimo anche questa, sia nellasua versione C++ che nella versione inclusa nel Borland Pascal 7.0.

Page 19: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Gerarchia di classi di OWLA differenza di Turbo Vision, con OWL non aveva senso salvaretutte le classi: quelle che lo permettevano erano quindi derivate da TStreamable , che implementava i metodi virtuali  load  e  save .

﴾Borland ObjectWindows for C++ 2.0: Programmer's manual, pag. 7﴿

Page 20: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

ROOT

Anche ROOT ﴾che nasce nel 1994﴿ usa l'approccio di una classe, TObject , alla base della gerarchia di classi.

Page 21: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Microsoft Foundation Classes ﴾1998﴿

Page 22: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Il problema delle gerarchie di classiNei progetti che usano OOP, c'è una enorme proliferazione diclassi, legate tra loro da relazioni spesso complesse. Questo rende ilcodice difficile da comprendere.

Considerate la slide appena vista sulle Microsoft FoundationClasses: è difficile comprenderne la struttura intricata, eppure laslide presenta solo le relazioni tra i tipi di dati! L'implementazionedegli algoritmi ﴾es., come disegnare a video una finestra, cosasuccede quando si preme un bottone a video…﴿ può essereaffrontata solo successivamente alla definizione di questagerarchia!

Page 23: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Alexander StepanovUno dei curatori della libreria C++ STL ﴾Standard Template Library﴿,Alexander Stepanov, si era reso conto che la OOP portava allacreazione di sistemi ingestibili, e pensò a come usare unmeccanismo alternativo, chiamato programmazione generica ﴾v. AnInterview with A. Stepanov﴿.

Stepanov riteneva che nel mondo della programmazione ci sidovesse concentrare innanzitutto sugli algoritmi, e che soloquando questi fossero stati definiti avesse senso pensare al tipo didato su cui essi potessero essere applicati.

L'OOP, al contrario, obbliga a partire dal tipo di dato ﴾ossia, lagerarchia di classi﴿ per definire poi gli algoritmi.

Page 24: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

OOP e C++Bjarne Stroustrup, il creatore del C++, sposò le idee di Stepanov﴾nonostante avesse creato il C++ sull'onda della «moda» dell'OOP﴿:lo standard C++98 include una versione della STL. È la libreria checontiene i file  vector ,  map , etc… Nessuna di queste librerie usa iconcetti OOP di ereditarietà e polimorfismo.

Di fatto, la tendenza del linguaggio C++ negli standard successivial C++98 ﴾ossia, quelli rilasciati nel 2003, 2011, 2014 e 2017﴿ è stataquella di potenziare gli aspetti del linguaggio più legati allaprogrammazione generica e alla metaprogrammazione: poche dellepotenzialità delle versioni più recenti sono legate alla OOP ﴾es., lekeyword  final  e  override ﴿.

Page 25: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Piccolo esperimentoA dimostrazione di ciò, il seguente comando mostra tutti i file dellalibreria standard C++ sui computer del laboratorio che nonimplementano metodi virtuali ﴾che sono il chiaro sintomo dell'usodel polimorfismo﴿:

grep ‐L virtual $(find /usr/include/c++/4.4.7/* ‐type f)

Usando  ‐l  invece di  ‐L , si ottiene la lista complementare.

Il confronto è schiacciante: 631 file contro 54: nella libreria C++fornita da GCC 4.4, le classi che usano il polimorfismo sono menodel 10%!

Page 26: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Integrali senza OOPVediamo come Stepanov suggerirebbe di implementare la funzione integrate :

template<typename Function>double integrate(Function fn, double a, double b) {    // To evaluate `fn` in the body of "integrate", use    //    fn(x)}

Questo è simile al nostro primo tentativo:

double integrate(double fn(double), double a, double b) {    // To evaluate `fn` in the body of "integrate", use    //    fn(x)}

ma usa i template: questo garantisce una versatilità moltomaggiore.

Page 27: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Uso dei templateUna funzione introdotta da

template<typename Function>

dice che tutte le volte che compare  Function , esso è daconsiderarsi un tipo di dato non definito al momento: esso saràprecisato solo nel momento in cui  integrate  verrà effettivamenteusata.

Quando poi, nel  main , il compilatore trova la scrittura

integrate(std::sin, 0.0, 1.0);

allora prova a sostituire a  Function  il tipo di  std::sin , che è unafunzione che accetta un  double  e ritorna un  double , e controlla seil corpo della funzione  integrate  ha senso o no in questo caso.

Page 28: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Uso dei templateConsideriamo per esempio il calcolo dell'integrale col metodo dellamedia:

template<typename Function>double integrate(Function fn, double a, double b) {    double sum = 0.0;    const int N = 1000;    for (int i = 0; i < N; ++i) {        sum += fn(random_uniform(a, b));    }        return sum * (b ‐ a) / N;}

Se si passa come argomento  fn  la funzione  std::sin , ilcompilatore trova che questo è accettabile: sostituendo in fn(random_uniform(a, b))  l'espressione  fn  con  std::sin , siottiene  std::sin(random_uniform(a, b)) , che è un'istruzione lecita.

Page 29: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

ParametriVediamo ora come procedere se, come in precedenza, la funzioneda integrare ha un parametro:

f(x) = sin kx.

In questo caso basta definire una classe con un metodo operator() :

class Sin {    double k;public:    Sin(double m_k) : k(m_k) {}    double operator()(double x) { return std::sin(k * x); }};

come nel caso visto sopra, ma ora  Sin  non è più obbligata adiscendere da  FunzioneBase .

Page 30: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

ParametriSe ora chiamiamo  integrate  in questo modo ﴾C++11﴿:

Sin sin1(1.0);std::cout << integrate(sin1, 1.0, 2.0) << "\n";

il compilatore guarda com'è definita  integrate  e trova che  fn  èusata nella riga

sum += fn(random_uniform(a, b));

Opera allora la sostituzione  fn → sin1  ed ottiene

sum += sin1(random_uniform(a, b));

e siccome  sin1  implementa  operator() , è usabile come se fosseuna funzione. Quindi il compilatore accetta di compilare il codice.

Page 31: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

L'idea della programmazione genericaCon l'approccio OOP, siamo noi, creatori della funzione  integrate ,a decidere quali funzioni possano essere passate a  integrate  equali no: solo le classi derivate da  FunzioneBase  sono accettabili. Diconseguenza, è necessaria una grande cura nel definire bene lagerarchia di classi. ﴾L'articolo «The problem with ROOT» descrivesupposti errori fatti nel definire la gerarchia di classi della primaversione di ROOT, e poi inevitabilmente perpetuatisi in quellesuccessive﴿.

Nella programmazione generica, è invece l'utilizzatore a deciderecosa passare a  integrate : il garante della coerenza è ilcompilatore, che verifica di volta in volta se il costrutto usato sialecito o no. Il programmatore deve quindi pensare a meno dettagli.

Page 32: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Funzioni lambdaIl C++11 ha introdotto le funzioni lambda, che risparmiano lanecessità di implementare una classe  Sin  quando si voglionopassare i parametri:

double k = 2.0;integrate([double x]{return std::sin(k * x);}, 1, 2);

Senza le funzioni lambda, saremmo costretti a definire una classeseparata, come abbiamo visto in precedenza.

Page 33: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Vantaggi e svantaggiRispetto alla OOP, la programmazione generica ha questi vantaggi:

1. Si scrive meno codice;2. Il compilatore è in grado di creare codice più veloce

﴾nell'esempio dell'integrale, circa il 10 %﴿;3. Si scarica sul compilatore l'onere di decidere se si può passare

un certo tipo a una funzione oppure no;

4. Non è necessario definire gerarchie complesse di classi.

Porta però con sè alcuni svantaggi:

1. Solitamente i messaggi di errore del compilatore sono piùcriptici ﴾è sperabile che nel C++20 questo problema siamitigato dall'introduzione dei concepts﴿;

2. Il tempo necessario alla compilazione aumenta.

Page 34: Conclusioni sul corso di TNDS - cosmo.fisica.unimi.itcosmo.fisica.unimi.it/.../AA2017-2018/2018-01-11-lezione-12.pdf · i concetti della programmazione orientata agli oggetti ﴾OOP,

Altri strumentiNel caso in cui dobbiate scrivere codice di analisi per un'attività dilaboratorio o per la vostra tesi, vi consiglio di puntare su uno diquesti strumenti:

1. Python: di questo abbiamo parlato già abbastanza;2. Julia: secondo il sottoscritto, è il cavallo vincente su cui

puntare!

3. GNU R: perfetto per analisi statistiche;4. Mathematica: a pagamento, nel laboratorio di calcolo è

disponibile la licenza. È molto potente nel calcolo simbolico.

La caratteristica che accomuna questi linguaggi è la semplicitàd'uso: sono tutti interattivi, e non richiedono di usare Make né dicompilare il codice prima di eseguirlo. Inoltre, ciascuno di essiconsente di creare plot usando una sola istruzione.