Courses
Starting from 2021 the course are migrated to the MOODLE interface. You can find the new courses at the link.
Old courses
- Computational Methods for Mechatronics
- Calcolo numerico e programmazione
- Modeling and simulation of mechatronic systems
- Numerical optimization
Course of Computational Methods for Mechatronics [140466] (AA 2020/2021)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link of the course are the following
Corso di Calcolo numerico e programmazione - [145725] (AA 2020/2021)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link of the course are the following
Course of Modeling and simulation of mechatronic systems [140469] (AA 2020/2021)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link of the course is the following
P.h.D. Course of Numerical optimization (AA 2020/2021)
Algorithms and practical implementation
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Computational Methods for Mechatronics
- Calcolo numerico e programmazione
- Modeling and simulation of mechatronic systems
Course of Computational Methods for Mechatronics [140466] (AA 2010/2020)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
Corso di Calcolo numerico e programmazione - [145725] (AA 2019/2020)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
Course of Modeling and simulation of mechatronic systems [140469] (AA 2019/2020)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
- Computational Methods for Mechatronics
- Tecniche di programmazione avanzata
- Modeling and simulation of mechatronic systems
- Scientific Programming in C++
Course of Computational Methods for Mechatronics [140466] (AA 2018/2019)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
Corso di Tecniche di programmazione avanzata (AA 2018/2019)
To access the course Tecniche di programmazione avanzata [145480] you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Google Classroom: link
Course of Modeling and simulation of mechatronic systems [140469] (AA 2018/2019)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
P.h.D. Course of Scientific Programming in C++ (AA 2018/2019)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Computational Methods for Mechatronics
- Fondamenti di Informatica e Calcolo Numerico
- Modeling and simulation of mechatronic systems
Course of Computational Methods for Mechatronics [140466] (AA 2017/2018)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
Corso di Fondamenti di Informatica e Calcolo Numerico [140447] (AA 2017/2018)
Per accedere al corso devi avere un account (di posta) della Università di Trento (e.g. bartolomeo.pestalozzi@studenti.unitn.it) essere iscritti al corso ed aver effettuato l’accesso con google.
Il link è il seguente
Course of Modeling and simulation of mechatronic systems [140469] (AA 2017/2018)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Computational Methods for Mechatronics
- Fondamenti di Informatica e Calcolo Numerico
- Modeling and simulation of mechatronic systems
- Numerical optimization
Course of Computational Methods for Mechatronics [140466] (AA 2016/2017)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following link
Corso di Fondamenti di Informatica e Calcolo Numerico [140447] (AA 2016/2017)
Per accedere al corso devi avere un account (di posta) della Università di Trento (e.g. bartolomeo.pestalozzi@studenti.unitn.it) essere iscritti al corso ed aver effettuato l’accesso con google.
Il link è il seguente
Course of Modeling and simulation of mechatronic systems [140469] (AA 2016/2017)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
P.h.D. Course of Numerical optimization (AA 2016/2017)
Algorithms and practical implementation
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Computational Methods for Mechatronics
- Informatica e programmazione
- Fondamenti di Informatica e Calcolo Numerico
- Modeling and simulation of mechatronic systems
- Scientific Programming in C++
Course of Computational Methods for Mechatronics [140466] (AA 2015/2016)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following link
Corso di Informatica e programmazione (AA 2015/2016)
Per accedere al corso Informatica e programmazione [140143] devi avere un account (di posta) della Università di Trento (e.g. bartolomeo.pestalozzi@studenti.unitn.it) essere iscritti al corso ed aver effettuato l’accesso con google.
Il link è il seguente link
Corso di Fondamenti di Informatica e Calcolo Numerico [140447] (AA 2015/2016)
Per accedere al corso devi avere un account (di posta) della Università di Trento (e.g. bartolomeo.pestalozzi@studenti.unitn.it) essere iscritti al corso ed aver effettuato l’accesso con google.
Il link è il seguente
Course of Modeling and simulation of mechatronic systems [140469] (AA 2015/2016)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
P.h.D. Course of Scientific Programming in C++ (AA 2015/2016)
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Calcolo Numerico
- Fondamenti di Informatica e Calcolo Numerico
- Modeling and simulation of mechatronic systems
- Numerical optimization
Corso di Calcolo Numerico (AA 2014/2015)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Martedì | 17 - 19 | PC201 |
Venerdì | 10 - 13 | B105 |
Mini riassunto comandi MATLAB
Eliminazione di Gauss (6 marzo 2015)
Foglio Maple: 2015-03-06-LU_example.mw.zip
File formato PDF: 2015-03-06-LU_example.pdf
Foglio Maple: 2015-03-06-LU_example2.mw.zip
File formato PDF: 2015-03-06-LU_example2.pdf
Interpolazione metodo di Newton (13 marzo 2015)
Foglio Maple: 2015-03-13-INTERPOLAZIONE_example.mw.zip
File formato PDF: 2015-03-13-INTERPOLAZIONE_example.pdf
Foglio Maple: 2015-03-13-DD_update.mw.zip
File formato PDF: 2015-03-13-DD_update.pdf
Integrazione numerica (27 marzo 2015)
Foglio Maple: 2015-03-27-STIMA_integrazione.mw.zip
File formato PDF: 2015-03-27-STIMA_integrazione.pdf
Foglio Maple: 2015-03-27-STIMA_integrazione2.mw.zip
File formato PDF: 2015-03-27-STIMA_integrazione2.pdf
Stima convergenza metodo di Newton e Secanti (10 aprile 2015)
Foglio Maple: 2015-04-10-STIMA_convergenza_Newton_e_Secanti.mw.zip
File formato PDF: 2015-04-10-STIMA_convergenza_Newton_e_Secanti.pdf
Costruzione metodi basati su Taylor (8 maggio 2015)
Foglio Maple: 2015-05-08-ODE_TAYLOR_1.mw.zip
File formato PDF: 2015-05-08-ODE_TAYLOR_1.pdf
Foglio Maple: 2015-05-08-ODE_TAYLOR_2.mw.zip
File formato PDF: 2015-05-08-ODE_TAYLOR_2.pdf
Metodo di Runge Kutta in MATLAB (15 maggio 2015)
Regione di stabilità (22 maggio 2015)
Regione di stabilità metodo di Collatz, errore locale metodo multistep.
Foglio Maple: 2015-05-22-COLLATZ_region.mw.zip
File formato PDF: 2015-05-22-COLLATZ_region.pdf
Foglio Maple: 2015-05-22-MULTISTEP_errore_locale.mw.zip
File formato PDF: 2015-05-22-MULTISTEP_errore_locale.pdf
Verifica ordine RK, stabilità metodo BDF e RK (29 maggio 2015)
Foglio Maple 2015-05-29-CONTROLLO_ORDINE_RK_2STADI.mw.zip
File formato PDF: 2015-05-29-CONTROLLO_ORDINE_RK_2STADI.pdf
Foglio Maple: 2015-05-29-REGIONE_RK38.mw.zip
File formato PDF: 2015-05-29-REGIONE_RK38.pdf
Prova intermedia del 14 aprile 2015
- Testo della provetta in formato PDF: pdf
Prova intermedia dell’8 giugno 2015
- Testo della provetta in formato PDF: pdf
Compito del 6 luglio 2015
- Testo del compito in formato PDF: pdf
Compito del 4 febbraio 2016
- Testo del compito in formato PDF: pdf
Appunti di Calcolo Numerico
Libri
- Alfio Quarteroni, Fausto Saleri, Paola Gervasio
Calcolo Scientifico, Esercizi e problemi + risolti con MATLAB e Octave
Collana UNITEXT, Springer, ISBN 978-88-470-2745-9 - Josef Stoer, R. Bulirsch
Introduction to Numerical Analysis
Springer, ISBN: 978-1-4757-2274-1 - V. Comincioli
Analisi numerica: Metodi Modelli Applicazioni
981 pp. Apogeo, Feltrinelli Milano, 2005
Corso di Fondamenti di Informatica e Calcolo Numerico [140447] (AA 2014/2015)
Orario delle lezioni
GIORNO | ORA | AULA | GRUPPO |
---|---|---|---|
Lunedì | 9 - 11 | B107 | A-Z |
Mercoledì | 11 - 13 | A101 | A-Z |
Giovedì | 14 - 16 | A101 | A-Z |
Orario di laboratorio
GIORNO | ORA | AULA | GRUPPO |
---|---|---|---|
Martedì | 11 - 14 | B106 | A-L |
Venerdì | 13 - 16 | B106 | M-Z |
Libri consigliati
- Alfio Quarteroni, Fausto Saleri, Paola Gervasio
Calcolo Scientifico, Esercizi e problemi risolti con MATLAB e Octave
Collana UNITEXT, Springer, ISBN 978-88-470-2745-9 - Josef Stoer, R. Bulirsch
Introduction to Numerical Analysis
Springer, ISBN: 978-1-4757-2274-1 - Alfio Quarteroni, Riccardo Sacco, Fausto Saleri, Paola Gervasio
Matematica Numerica
Collana UNITEXT, Springer, ISBN 978-88-470-5644-2
Altri libri suggeriti
- V. Comincioli
Analisi numerica: Metodi Modelli Applicazioni
981 pp. Apogeo, Feltrinelli Milano, 2005 - James F. Epperson
Introduzione all’Analisi numerica - Teoria, metodi, algoritmi
McGraw-Hill Companies, 2003 ISBN: 9788838672255 - Alfio Quarteroni, Fausto Saleri, Paola Gervasio
Calcolo Scientifico, Esercizi e problemi risolti con MATLAB e Octave
Collana UNITEXT, Springer, ISBN 978-88-470-2745-9 - Josef Stoer, R. Bulirsch
Introduction to Numerical Analysis
Springer, ISBN: 978-1-4757-2274-1
Gli esempi e le esercitazioni sia di informatica che di calcolo numerico sono fatte nel linguaggio Ruby
. L’interprete Ruby
é disponibile sulle piattaforme Windows, Linux e OSX.
Installare Ruby (Windows)
Per il sistema operativo windows l’interprete Ruby
può essere scaricato da questo link
Una volta installato ruby l’interprete è immediatamente disponibile usando la finestra di comando di Ruby
.
Qui c’è un filmato su come si installa Ruby
e sul lancio della finestra di comando.
I programmi in Ruby
sono dei semplici file di testo. Per scrivere questi file conviene usare un editor di testo con colorazione della sintassi che conosce la grammatica di Ruby
come ad esempio Notepad++ oppure Editra.
Installare Ruby (Linux)
Per il sistema operativo Linux l’interprete Ruby
è già disponibile oppure basta usare il gestore di pacchetti per installarlo.
In alternativa si può usare rvm, leggi qui per ulteriori dettagli.
Installare Ruby (OSX)
Ruby sui sistemi piu resenti è gia installato. Per vedere se é disponibile digitare which ruby
da terminale (leggete qui se non capite quello che state leggendo). Se Ruby
è presente nel sistema il comando risponde con la path dove è installato Ruby
.
Se Ruby
non è presente per prima cosa occorre che Xcode sia installato. Poi la cosa più semplice è installare Homebrew per poi installare Ruby
con il comando brew install ruby
.
Lezione 9 marzo 2015
Lezione 12 marzo 2015
Lezione 16 marzo 2015
Lezione 19 marzo 2015
Lezione 23 marzo 2015
Lezione 30 marzo 2015
Lezione 9 aprile 2015
Lezione 20 aprile 2015
Lezione 23 aprile 2015
La lezione non verrà resa disponibile
Lezione 27 aprile 2015
Lezione 30 aprile 2015
Lezione 4 maggio 2015
Lezione 7 maggio 2015
Lezione 11 maggio 2015
Lezione 14 maggio 2015
Lezione 18 maggio 2015
Lezione 21 maggio 2015
Lezione 25 maggio 2015
Lezione 28 maggio 2015
Lezione 4 giugno 2015
Lezione 8 giugno 2015
Modalità esame
L’esame del corso consiste in 3 prove, uno test di 30 domande per Fondamenti di Informatica uno scritto per la parte di Calcolo Numerico e una prova di Programmazione nel linguaggio Ruby. Per passare l’esame si devono superare le tre prove ed il voto finale è ottenuto dalla media (pesata) dei tre voti.
La parte di Fondamenti di Informatica è gestita dal prof. Colazzo.
Prova pratica al calcolatore
La prova prova pratica ha un tempo limite di 3 ore. Al candidato verrà richiesto di scrivere uno script in Ruby che risolve un semplice problema proposto. Se lo script non funziona la prova non è superata. Se lo script funziona il voto è determinato da:
Chiarezza espositiva (indentazione, commenti)
Eleganza della soluzione (algoritmo scelto, compattezza dello script etc)
Robustezza della soluzione (controlli aggiuntivi, messaggi di errore etc)
Prova scritta
La prova prova scritta ha un tempo limite di 3 ore. In questa prova verranno proposti degli esercizi sugli argomenti di calcolo numerico.
Esami scritti svolti
Prima caccia al tesoro in Ruby
Quest’anno in forma sperimentale una parte dell’esame di Fondamenti di informatica e calcolo numerico ed in particolare la parte di programmazione in Ruby può essere svolta sotto la forma di una gara di programmazione. I dettagli della gara sono stati dati a lezione in ogni caso al seguente link: Sito della gara si trovano le informazioni per iscriversi e partecipare alla gara.
Coppa per i vincitori
Per stimolare la competizione tra i gruppi una copia personalizzata della seguente coppa:
Verrà assegnata ad ogni componente del gruppo dei vincitori. La coppa è stata progettata e realizzata da Matteo Ragni che ha anche progettato e realizzato tutta la struttura informatica della gara.
Vincitori
Dopo aver visto e rivisto i vari elaborati non siamo riusciti a trovare un vincitore ma 3 gruppi a parimerito. Il task 4 che era costruire un giocare virtuale di Master Mind
è stato affrontato più o meno nello stesso modo dai vincitori. Chi ha fatto una implementazione migliore del task 4 ha fatto una implementazione peggiore del task 3 mentre il migliore algoritmo di giocare virtuale di Master Mind
ha tempi molto lunghi nella sua realizzazione. In sintesi ecco i vincitori:
id:
dd337302dbe62693a86cc31be5732ab3
, Luca Rebizziid:
61fd0ee11157b5c4d58c455d10725299
, Valentin Bernardid:
bd3707f03e4cb62acef8a14d7e7bffbc
, Federico Santacatterina, Riccardo Bertollo
i vincitori potranno se vogliono realizzare la loro coppa con la macchina taglio laser e l’aiuto dell’inarrivabile Matteo Ragni. I dettagli verranno dati alla correzione del compito scritto di luglio prevista per il 20/21 luglio (verrà mandata una email con i dettagli a tutti gli iscritti compreso i voti per singolo gruppo).
Voti per gruppo
Qui di seguito trovate i voti assegnati agli elaborati per i singoli gruppi. Per mantenere un po’ di finta privacy per trovare il vostro voto dovete sapere il vostro id usato per la gara e in corrispondenza trovate il voto.
Identificatore gruppo | Voto |
---|---|
02ea4ba1f675febbce42107d5d4bab76 |
28 |
04f2558e0522369a6dd159d36be412d3 |
27 |
1a3ea16b55911d84a0232e06c570e2df |
29 |
1a4d43247f4421bc4421beb56e3e7a2e |
28 |
1c407439fdf7757630cf0fe401f1458d |
27 |
30ab7fc3bec2ccadf6ff0e83e4706455 |
29 |
3138db5405770d41f67e021c318f7b80 |
27 |
327bd5083b280a09658d534a64b8cd00 |
30 |
35c5192f1c55d368f27a95fe03c1fbdd |
28 |
3c9187a4b05fb12ca9e9007e83b02387 |
28 |
3de19eabe0a1d99107da77b80dbcd227 |
28 |
3df9ef35499c7ff9fd813f495ed645d7 |
28 |
458831f2e0d10ba89ad64817246dea05 |
22 |
54edbf9f7c360f7f7474e41db975ef9d |
28 |
5ee5e977a2802a8d404a35e697a6ae7e |
27 |
61fd0ee11157b5c4d58c455d10725299 |
30 |
634e45f0862cc14db1904c04ea7c8eb0 |
29 |
6c76b7ca48974bab5193c42b604514c3 |
24 |
6e013c1e2045e8b581b2b2f35ba97e25 |
30 |
76272159515ceaf8b714f76162946039 |
27 |
7a088ae324777621984de2b83bbbc2ed |
29 |
7c1d6d55b3e4f9d2d093d7b6e032e9fd |
29 |
7e87bf54d7e797e807edb380ef1970a4 |
24 |
8224479d2e81a9c58749fc9b765d1d29 |
27 |
8e09ead9d7c0bf5e55a00e5c5f05ad29 |
22 |
95811872518bf1735126c99f665789d5 |
29 |
9cb645447f6f6ac592b63f0403dba23a |
30 |
a1b87c6545e0be2ae2acc6147f725ea2 |
27 |
a275577d373ada21f860de863d103e2d |
24 |
a87870f7a93d6f6707fc597a135c3d15 |
28 |
a90c51e92fe5b656bbbf9c78eedbc66d |
27 |
ae8767dbb110de748708f947ed38eda2 |
29 |
b1f42d85b7aa9b3d531533f8e503dc30 |
29 |
bd3707f03e4cb62acef8a14d7e7bffbc |
30 |
c518742120bbfdf900d10f27b4d932cf |
23 |
d45914660c890fa94a2dbc04704c08b9 |
29 |
dd337302dbe62693a86cc31be5732ab3 |
30 lode |
e0140645cbdf9932a5768e94609c58e1 |
29 |
ea97ab4834c3d0e25138b6b7ae20a979 |
28 |
f9176819ea59dc66f75aeca3953f3963 |
28 |
Aggiornamento
Dopo una verifica incrociata molto blanda ho trovato un caso chiaro di copiatura tra i gruppi
ebb897b0916f99db3c30c60333454b86
2fe929c58d281d4f87093e954e2e305f
fb26fa95fa38e4c9c0b27fe1beb37473
Course of Modeling and simulation of mechatronic systems [140469] (AA 2014/2015)
DAY | TIME | ROOM |
---|---|---|
Monday | 9 - 11 | B102 |
Wednesday | 9 - 12 | B104 |
Thursday | 9 - 12 | B105 |
Lesson of March 11, 2015
Lesson of March 12, 2015
Maple sheet in a zip archive: DAEPendoloTaylorNonStabilizzato.mw.zip
Maple sheet in a pdf: DAEPendoloTaylorNonStabilizzato.pdf
Lesson of March 18, 2015
Maple sheet in a zip archive: DAEPendoloTaylorStabilizzato.mw.zip
Maple sheet in a pdf: DAEPendoloTaylorStabilizzato.pdf
Lesson of April 1, 2015
Lesson of April 22, 2015
Lesson of April 29, 2015
Lesson of May 20, 2015
P.h.D. Course of Numerical optimization (AA 2014/2015)
Algorithms and practical implementation
Doctoral school in Materials, Mechatronics and Systems Engineering
To access the course you must have an institutional account (e.g. bartolomeo.pestalozzi@studenti.unitn.it) have course subscription and be logged with google.
The link is the following
- Calcolo Numerico
- Numerical Methods for Dynamic Systems and Control
- Fondamenti di Informatica e Calcolo Numerico
- Scientific Programming in C++
Corso di Calcolo Numerico (AA 2013/2014)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11 - 14 | A206 |
Martedì | 9 - 11 | PC201 |
Mini riassunto comandi MATLAB
Eliminazione di Gauss (17 febbraio 2014)
Foglio Maple example-2014-02-17a.zip
File formato PDF: example-2014-02-17a.pdf
Foglio Maple example-2014-02-17b.zip
File formato PDF: example-2014-02-17b.pdf
Zeri di funzione (10 marzo 2014)
Foglio Maple example-2014-03-10.zip
File formato PDF: example-2014-03-10.pdf
Integrazione numerica (17 marzo 2014)
Foglio Maple example-2014-03-17a.zip
File formato PDF: example-2014-03-17a.pdf
Foglio Maple example-2014-03-17b.zip
File formato PDF: example-2014-03-17b.pdf
Differenze divise (4 marzo 2014)
File: differenze_divise.m:
%
% funzione che calcola le differenze divise
% INPUT x vettore con le ascisse (dei punti di interpolazione)
% y vettore con le odinate (dei punti di interpolazione)
%
% OUTPUT dd differenze divise, vedi referenza....
%
%
function dd = differenze_divise( x, y )
% controllo dati:
% 1 - controllo che siano vettori colonna
if size(x,2) ~= 1 | size(y,2) ~=1
error('x e y devono essere vettori colonna');
end
% 2 - controllo che abbiano la stessa dimensione
if size(x,1) ~= size(y,1)
error('x e y devono avere la stessa dimensione');
end
% numero di righe di x ed y
n = size(x,1) ;
% allocazione vettore dd, tramite copiatura del vettore y
% dd ora contiene le differenze divise di ordine 0,
% cio� dd(i)=f(x(i))=y(i)
dd = y ;
% loop differenze divise
for k=1:n
for j=n:-1:k+1
if x(j) == x(j-k)
error('le componenti di x devono essere tutte distinte') ;
end
dd(j) = (dd(j)-dd(j-1))/(x(j)-x(j-k)) ;
end
end
% ora dd contiene le differenze divise
end
File: interp_poly.m:
%
% funzione che calcola il polinomio interpolante
% INPUT x, vettore con le ascisse (dei punti di interpolazione)
% y, vettore con le odinate (dei punti di interpolazione)
%
% OUTPUT coeffs, coefficenti del polinomio
%
function coeffs = interp_poly( x, y )
% calcolo differenze divise
dd = differenze_divise( x, y );
n = size(y,1) ; % numero di righe di y
% omega = 1
omega = zeros( n, 1 ) ;
omega(1) = 1 ;
% polinomio nullo
coeffs = zeros( n, 1 ) ;
for k=1:n
coeffs = coeffs + dd(k)*omega ;
% moltiplicare omega * (x-x(k))
omega = [ 0 ; omega(1:end-1) ] -x(k)*omega ;
% ^
% |
% moltiplicazione per x
end
end
File: test.m:
% polinomio soluzione 1+x+x^3
x = [0 1 -3 2]';
y = [1 3 -29 11]';
dd = differenze_divise(x, y) ;
dd
% polinomio interpolante
coeffs = interp_poly( x, y ) ;
coeffs
Prova intermedia del 15 aprile 2014
- Testo della provetta in formato PDF: prova-2014-04-15.pdf
Prova intermedia del 6 giugno 2014
- Testo della provetta in formato PDF: prova-2014-06-06.pdf
Prova scritta del 7 luglio 2014
- Testo della prova in formato PDF: cnum-2014-07-07.pdf
Prova scritta del 28 luglio 2014
- Testo della prova in formato PDF: cnum-2014-07-28.pdf
Prova scritta del 29 agosto 2014
- Testo della prova in formato PDF: cnum-2014-08-29.pdf
Prova scritta del 16 gennaio 2105
- Testo della prova in formato PDF: cnum-2015-01-16.pdf
Prova scritta del 13 febbario 2105
- Testo della prova in formato PDF: cnum-2015-02-13.pdf
Appunti di Calcolo Numerico
Libri
- Alfio Quarteroni, Fausto Saleri, Paola Gervasio
Calcolo Scientifico, Esercizi e problemi + risolti con MATLAB e Octave
Collana UNITEXT, Springer, ISBN 978-88-470-2745-9 - Josef Stoer, R. Bulirsch
Introduction to Numerical Analysis
Springer, ISBN: 978-1-4757-2274-1 - V. Comincioli
Analisi numerica: Metodi Modelli Applicazioni
981 pp. Apogeo, Feltrinelli Milano, 2005
Course of Numerical Methods for Dynamic Systems and Control [140155] (AA 2013/2014)
Lessons timetable
DAY | TIME | ROOM |
---|---|---|
Wednesday | 9 - 12 | B104 |
Thursday | 9 - 11 | B104 |
Friday | 11 - 14 | B104 |
Numerical Solution of Differential Algebraic Equations Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Laplace table and Z table with KKT resume
Example from lesson of September 26, 2013
Maple sheet in a zip archive lesson-2013-09-26a.mw.zip
Maple sheet in a pdf: lesson-2013-09-26a.mw.pdf
Maple sheet in a zip archive lesson-2013-09-26b.mw.zip
Maple sheet in a pdf: lesson-2013-09-26b.mw.pdf
Example from lesson of October 9, 2013
Maple sheet in a zip archive lesson-2013-10-09.mw.zip
Maple sheet in a pdf: lesson-2013-10-09.mw.pdf
Maple sheet in a zip archive lesson-2013-10-09b.mw.zip
Maple sheet in a pdf: lesson-2013-10-09b.mw.pdf
Example from lesson of October 10, 2013
Maple sheet in a zip archive - lesson-2013-10-10.mw.zip
Maple sheet in a pdf: - lesson-2013-10-10.mw.pdf
Maple sheet in a zip archive - lesson-2013-10-10b.mw.zip
Maple sheet in a pdf: - lesson-2013-10-10b.mw.pdf
Example from lesson of October 18, 2013
Maple sheet in a zip archive - lesson-2013-10-18a.mw.zip
Maple sheet in a pdf: - lesson-2013-10-18a.mw.pdf
Maple sheet in a zip archive - lesson-2013-10-18b.mw.zip
Maple sheet in a pdf: - lesson-2013-10-18b.mw.pdf
Maple sheet in a zip archive - lesson-2013-10-18c.mw.zip
Maple sheet in a pdf: - lesson-2013-10-18c.mw.pdf
Example from lesson of October 23, 2013
Maple sheet in a zip archive - lesson-2013-10-23.mw.zip
Maple sheet in a pdf: - lesson-2013-10-23.mw.pdf
Example from lesson of October 30, 2013
Maple sheet in a zip archive - lesson-2013-10-30a.mw.zip
Maple sheet in a pdf: - lesson-2013-10-30a.mw.pdf
Maple sheet in a zip archive - lesson-2013-10-30b.mw.zip
Maple sheet in a pdf: - lesson-2013-10-30b.mw.pdf
Tables and summary for the written exams
Exam of January 14, 2014
- Text in PDF format with solutions: nmdsc-2014-01-14.pdf
Exam of February 7, 2014
- Text in PDF format with solutions: nmdsc-2014-02-07.pdf
Exam of July 7, 2014
- Text in PDF format with solutions: nmdsc-2014-07-07.pdf
Corso di Fondamenti di Informatica e Calcolo Numerico [140447] (AA 2013/2014)
- Timetable
- Libri
- Ruby
- Modalità esame
- Esami svolti
- FAQ
- Lezione 1
- Lezione 2
- Lezione 3
- Lezione 4
- Lezione 5
- Lezione 6
- Lezione 7
- Lezione 8
- Lezione 10
- Lezione 11
- Lezione 12
- Lezione 13
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 11 - 14 | A101 |
Giovedì | 13 - 16 | B104 |
Orario di ricervimento
GIORNO | ORA | AULA |
---|---|---|
Mercoledi | 9 - 11 |
Problema
L’aula PC201 ha 60 posti mentre la B106 ne ha 130, gli studenti sono 170.
L’aula B106 à libera il venerdì ma fare lezione il venerdì allo studente piace meno di farla lunedì.
Come distribuire la rottura di scatole in modo omogeneo?.
Soluzione (improved)
Si dividono gli studenti in 3 gruppi A-DA (59 studenti), DE-PA (57 studenti), PE-Z (55 studenti) e a rotazione 2 gruppi fanno lezione il venerdì e 1 gruppo il lunedì
ORARIO LABORATORIO
GIORNO | ORA | AULA | GRUPPO |
---|---|---|---|
Venedì 7 marzo | 15 - 18 | B106 | (A-DA) + DE-PA) |
Lunedì 10 marzo | 15 - 18 | PC201 | (PE-Z) |
Venedì 14 marzo | 13.30 - 16.30 | B106 | (A-DA) + (PE-Z) |
Lunedì 17 marzo | 15 - 18 | PC201 | (DE-PA) |
Lunedì 24 marzo | 16 - 19 | B106 | (PE-Z) + (DE-PA) |
Lunedì 24 marzo | 16 - 19 | PC201 | (A-DA) |
Lunedì 7 aprile | 16 - 19 | B106 | (A-DA) + (DE-PA) |
Lunedì 7 aprile | 16 - 19 | PC201 | (PE-Z) |
Lunedì 28 aprile | 16 - 19 | B106 | (A-DA) + (PE-Z) + (DE-PA) |
Venerdì 9 maggio | 13.30 - 16.30 | B106 | (A-Z) |
Lunedì 12 maggio | 16 - 18 | B106 | (A-Z) |
Venerdì 16 maggio | 13.30 - 16.30 | B106 | (A-Z) |
Lunedì 19 maggio | 16 - 18 | B106 | (A-Z) |
Venerdì 23 maggio | 13.30 - 16.30 | B106 | (A-Z) |
Lunedì 26 maggio | 16 - 18 | B106 | (A-Z) |
Venerdì 30 maggio | 13.30 - 16.30 | B106 | (A-Z) |
Venerdì 6 giugno | 16 - 18 | B106 | (A-Z) |
Libri consigliati
- Alfio Quarteroni, Fausto Saleri, Paola Gervasio
Calcolo Scientifico, Esercizi e problemi risolti con MATLAB e Octave
Collana UNITEXT, Springer, ISBN 978-88-470-2745-9 - Josef Stoer, R. Bulirsch
Introduction to Numerical Analysis
Springer, ISBN: 978-1-4757-2274-1 - Mini riassunto comandi MATLAB
Ruby
Gli esempi e le esercitazioni sia di informatica che di calcolo numerico sono fatte nel linguaggio Ruby
. L’interprete Ruby
é disponibile sulle piattaforme Windows, Linux e OSX.
Installare Ruby (Windows)
Per il sistema operativo windows l’interprete Ruby
può essere scaricato da questo link
Una volta installato ruby l’interprete è immediatamente disponibile usando la finestra di comando di Ruby
.
Qui c’è un filmato su come si installa Ruby
e sul lancio della finestra di comando.
I programmi in Ruby
sono dei semplici file di testo. Per scrivere questi file conviene usare un editor di testo con colorazione della sintassi che conosce la grammatica di Ruby
come ad esempio Notepad++ oppure Editra.
Installare Ruby (Linux)
Per il sistema operativo Linux l’interprete Ruby
è già disponibile oppure basta usare il gestore di pacchetti per installarlo.
In alternativa si può usare rvm, leggi qui per ulteriori dettagli.
Installare Ruby (OSX)
Ruby sui sistemi piu resenti è gia installato. Per vedere se é disponibile digitare which ruby
da terminale (leggete qui se non capite quello che state leggendo). Se Ruby
è presente nel sistema il comando risponde con la path dove è installato Ruby
.
Se Ruby
non è presente per prima cosa occorre che Xcode sia installato. Poi la cosa più semplice è installare Homebrew per poi installare Ruby
con il comando brew install ruby
.
Modalità esame
L’esame del corso è diviso in 2 parti, la parte di Fondamenti di Informatica e la parte di Calcolo Numerico con Programmazione. Per passare l’esame si deve superare sia la parte di Fondamenti di Informatica che la parte di Calcolo Numerico con Programmazione.
La parte di Fondamenti di Informatica è gestita dal prof. Colazzo e il voto finale è ottenuto (in genere) dalla media dei due voti.
Per quanto riguarda Calcolo Numerico con Programmazione l’esame si divide in una prova pratica al calcolatore e uno scritto.
Prova pratica al calcolatore (max 15 punti)
La prova prova pratica ha un tempo limite di 3 ore.
Al candidato verrà richiesto di scrivere uno script in Ruby che risolve un semplice problema proposto.
Se lo script non funziona la prova non è superata.
Se lo script funziona il voto è determinato da:
Chiarezza espositiva (indentazione, commenti)
Eleganza della soluzione (algoritmo scelto, compattezza dello script etc)
Robustezza della soluzione (controlli aggiuntivi, messaggi di errore etc)
Prova scritta (max 15 punti)
La prova prova scritta ha un tempo limite di 2 ore.
In questa prova verranno proposti degli esercizi sugli argomenti di calcolo numerico.
In voto finale per la parte di Calcolo Numerico con Programmazione è dato dalla somma dei punteggi ottenuti con la prova pratica al calcolatore e la prova scritta.
Ruby
Calcolo Numerico
FAQ ovvero le domande più ricorrenti
Email con richiesta di aiuto su programmi e/o esercizi.
Non rispondo alla email di questo tipo. Per spiegazioni o dubbi esiste il ricevimento. Motivo? Un minuto a parlare sono 10 minuti per scrivere male una riposta, spesso una risposta scritta non basta. A volte la domanda è cosi mal posta che servirebbe un intervento divino per capire la richiesta.
No, se hai passato una parte dell’esame non occorre rifarla se termini l’e same nell’anno accademico.
Ho passato la parte di Ruby ma non sono pronto, non mi sento preparato, ho male alla pancia etc e non posso/non voglio fare la parte di calcolo numerico nella stessa sessione. Posso farlo al prossimo
Se hai passato una parte dell’esame poi fare la successiva al prossimo appello anche se lo sconsiglio, sempre se termini l’esame nell’anno accademico.
Mi è arrivato il messaggio con ESSE3 con il voto della parte X o il voto finale devo accettare il voto?
E che ne so, se ti piace il voto accetta o non fare niente. Se non ti piace e pensi di fare meglio rifiuta.
Ho passato il test a quiz, il test di programmazione e lo scritto devo proprio venire alla discussione/visione del compito? Non basta aspettare a casa il voto con ESSE3?
Ognuno fa quello che vuole e non è necessario venire. In ogni caso venire alla discussione/visione del compito permette di correggere eventuali (rare) sviste e capire cosa si è sbagliato.
Non sono venuto alla discussione/visione del compito. Mi facevano male le papille gustative, ho avuto un attacco di pecola, mi hanno contattato per il premio Nobel. Mi manda via email delucidazioni sul perché il mio fantastico compito non è stato ritenuto tale?
Spiegare anche una semplice cosa via email richiede molto impegno specialmente per spiegare cose che si capiscono con una figura, una formula o semplicemente mostrando l’elaborato. Quindi tali richieste vengono semplicemente ignorate.
Non sono venuto alla discussione/visione del compito per i motivi visti sopra, non capisco come dai voti X, Y, Z il voto finale sia W.
Il voto come spiegato più volte durante le lezioni e durante le esercitazioni viene calcolato come media del voto per la parte di “fondamenti di informatica” e del voto per la parte di “calcolo numerico”. La media troncata all’intero più basso è la base per il voto finale. A questo voto base applico un algoritmo segreto per alzare di uno due punti il voto finale.
Ho preso X come voto finale. Vorrei migliorare il voto rifacendo la parte Y.
Sarebbe stato meglio venire alla discussione/visione del compito segnalando l’intenzione di non accettare il voto cosi risparmiavo la fatica di inserirlo in esse3. A questo punto basta rifiutare il voto con esse3 e iscriversi all’appello sucessivo.
Ho accettato il voto X su ESSE3 da trenta secondi è scaduta la sessione come mai non trovo il voto sul mio file di carriera?
La procedura di registrazione e lunga e faticosa, prima di allarmarsi della mancanza del voto aspettate qualche settimana, poi se il voto non è; nel vostro file segnalate la cosa alla segreteria studenti.
Lezione del 24/3/2014
Per eseguire gli esempi da un terminale scrivere
ruby script.rb
dove script.rb
è il nome dello script da eseguire.
Primi esempio, il classico Hello World
File: ex1.1_hello_world.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Primi esempio, il classico Hello World
puts 'Hello World'
Secondo esempio, assegnazione, somma
File: ex1.2_assegnazione_somma.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Secondo esempio, assegnazione, somma
a = 123
b = 11
c = a+b
puts c
Terzo esempio, concatenazione
File: ex1.3_concatenazione.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Terzo esempio, concatenazione
a = "pippo"
b = "pluto"
c = a+b
puts c
Quarto esempio, istruzioni condizionali
File: ex1.4_istruzioni_condizionali.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Quarto esempio, istruzioni condizionali
#
# Esempio calcolo radici di
# a * x^2 + b * x + c = 0
#
a = 1
b = 2
c = 3
#
# calcolo discriminante
#
delta = b^2 - 4 * a * c
if delta >= 0 then
# caso radici reali
sdelta = Math.sqrt(delta)
x1r = (-b+sdelta)/(2*a) ;
x2r = (-b-sdelta)/(2*a) ;
x1i = 0 ;
x2i = 0 ;
else
sdelta = Math.sqrt(-delta)
x1r = -b/(2*a) ;
x2r = -b/(2*a) ;
x1i = sdelta/(2*a) ;
x2i = -sdelta/(2*a) ;
end
puts "Prima radice:"
print "Parte reale = ", x1r, "\n"
print "Parte imaginaria = ", x1i, "\n"
puts "Seconda radice:"
puts "Parte reale = #{x2r}"
puts "Parte imaginaria = #{x2i}"
Quinto esempio, stesso del precedente ma con funzione
File: ex1.5_funzione_calcolo_radici.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Quinto esempio, come ex1.4.rb ma con funzione
#
# Esempio calcolo radici di
# a * x^2 + b * x + c = 0
#
def radici_quadratica(a,b,c)
#
# calcolo discriminante
#
delta = b^2 - 4 * a * c
if delta >= 0 then
# caso radici reali
sdelta = Math.sqrt(delta)
x1r = (-b+sdelta)/(2*a) ;
x2r = (-b-sdelta)/(2*a) ;
x1i = 0 ;
x2i = 0 ;
else
sdelta = Math.sqrt(-delta)
x1r = -b/(2*a) ;
x2r = -b/(2*a) ;
x1i = sdelta/(2*a) ;
x2i = -sdelta/(2*a) ;
end
return [x1r,x1i,x2r,x2i]
end
res = radici_quadratica(1,2,3)
puts "Prima radice:"
print "Parte reale = ", res[0], "\n"
print "Parte imaginaria = ", res[1], "\n"
puts "Seconda radice:"
puts "Parte reale = #{res[2]}"
puts "Parte imaginaria = #{res[3]}"
Sesto esempio, uso del ciclo while
File: ex1.6_calcolo_fattoriale.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Esempio calcolo fattoriale
#
r = 1
i = 4
while i > 0 do
r = r * i
i = i - 1
end
puts r
Settimo esempio, uso dei vettori
File: ex1.7_vettori.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Settimo esempio, uso dei vettori
#
# Esempio trova il massimo
#
# inizializza vettore
a = [1,-2,3,189,-23,2,34,46,343,12] ;
# preparazione
l = a.length
m = a[0]
i = 1
while i < l do
m = a[i] if m < a[i]
i = i + 1
end
puts "Il massimo e`: #{m}"
puts "Usando metodo Ruby: #{a.max}"
Ottavo esempio, semplice ordinamento con Bubble-Sort
File: ex1.8_ordinamento_bubble_sort.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Ottavo esempio, semplice ordinamento con Bubble-Sort
#
# Esempio ordinamento di un vettore
#
# inizializza vettore
a = [1,-2,3,189,-23,2,34,46,343,12] ;
# preparazione
l = a.length
i = 0
while i < l-1 do
imin = i # candidato minimo=primo elemento del sottovettore
j = i+1
while j < l do
imin = j if a[j] < a[imin]
j = j+1
end
# a[imin] e` minimo del sottovettore da i fino ultimo elemento
# scambio a[imin] con a[i]
c = a[i]
a[i] = a[imin]
a[imin] = c
i = i+1
end
puts "Il vettore ordinato e` #{a}"
Nono esempio, fattoriale in forma ricorsiva
File: ex1.9_fattoriale_ricorsivo.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Nono esempio, fattoriale in forma ricorsiva
#
# Esempio fattoriale (versione ricorsiva)
#
# definisco funzione fattoriale
def fatt(n)
if n < 1 then
return 1 ;
else
return n*fatt(n-1) ;
end
end
n = 10 ;
puts "Fattoriale #{n} = #{fatt(n)}\n" # uso funziona fattoriale
Decimo esempio, fattoriale in forma ricorsiva con stampe per visualizzare la ricorsione
File: ex1.10_fattoriale_ricorsivo_puts.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Decimo esempio, fattoriale in forma ricorsiva con stampe per visualizzare la ricorsione
#
# Esempio fattoriale (versione ricorsiva)
# con livello di chiamata
#
# definisco funzione fattoriale
def fatt(n)
puts "Entra fatt(#{n})" ;
res = 1 ;
res = n*fatt(n-1) if n > 1 ;
puts "Esce fatt(#{n})" ;
return res ;
end
n = 10 ;
fn = fatt(n) ;
puts "Fattoriale #{n} = #{fn}\n" # uso funziona fattoriale
Undicesimo esempio, funzione di Ackerman
File: ex1.11_funzione_ackerman_ricorsiva.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Undicesimo esempio, funzione di Ackerman
#
# Esempio funzione di Ackerman (versione ricorsiva)
#
def ackerman(m,n)
puts "ackerman(#{m},#{n})" ;
if m == 0 then
return n+1 ;
else
if n == 0 then
return ackerman(m-1,1) ;
else
return ackerman(m-1,akerman(m,n-1)) ;
end
end
end
a = ackerman(3,4) ;
puts "ackerman = #{a}\n"
Lezione del 3/3/2014
Identificatori di variabili costanti
:
File ex2.1_costanti.rb
File: ex2.1_costanti.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Identificatori di variabili "costanti"
#
# creazione di una costante
#
Pippo = "Pippo e` amico di Topolino" # definisco la costante Pippo
#
# Provo a riassegnarla
#
Pippo = "Pippo NON e` amico di Topolino" # errore cerco di assegnare un valore ad una costante
Il problema 3n+1
File: ex2.2_problema_3npiu1.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Esempio, funzione 3n+1 di Collatz
#
# definisco la funzione collatz che accetta un solo
# argomento n
def collatz(n)
if n.even? then
# blocco eseguito se n e` numero pari
return n/2 # esco restituendo il valore n/2
else
# blocco eseguito se n e` numero dispari
return 3*n+1 # esco restituendo il valore 3*n+1
end
end
n = ARGV[0].to_i ; # primo argomento per inizializzare n
k = 0 ;
while n > 1 do
k = k+1
n = collatz(n)
puts "k = #{k}, n = #{n}"
end
=begin
Per ottenere il grafico eseguire lo script e salvare l'output su file.
Ad esempio su Linux e OSX ruby ex2.3.rb > a.dat su WINDOWS ruby ex2.3.rb e poi
copiare l'output su un file. Usando gnuplot dare il comando:
plot [2:] 'a.dat' u 1:2 with lines
=end
Esempio di `if’ multipli
File ex2.3_if_multipli.rb
File: ex2.3_if_multipli.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Esempio, funzione 3n+1 di Collatz
#
# definisco la funzione collatz che accetta un solo
# argomento n
def collatz(n)
if n.even? then
# blocco eseguito se n e` numero pari
return n/2 # esco restituendo il valore n/2
else
# blocco eseguito se n e` numero dispari
return 3*n+1 # esco restituendo il valore 3*n+1
end
end
#
# dato n conta le iterate fatte con Collatz
#
def iter(n)
k = 0
while n>1 do
k = k+1
n = collatz(n)
end
return k
end
n = ARGV[0].to_i ; # primo argomento per inizializzare n
#
# ciclo per j da 1 a n
#
puts "n\titer"
for j in (1..n) do
it = iter(j)
puts "#{j}\t#{it}"
end
Stesso esempio ma usando elsif
File ex2.4_elsif.rb
File: ex2.4_elsif.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# funzione a tratti, modo 1
#
def funz(x)
if x <= 1 then
return 1
else
if x <= 2 then
return 2
else
if x <= 4 then
return 3
else
if x <= 6 then
return 4
else
if x <= 8 then
return 5
else
return 6
end
end
end
end
end
end
#
# funzione a tratti, modo 2
#
def funz2(x)
if x <= 1 then
return 1
elsif x <= 2 then
return 2
elsif x <= 4 then
return 3
elsif x <= 6 then
return 4
elsif x <= 8 then
return 5
else
return 6
end
end
for i in (0..100) do
x = i/10.0
puts "x = #{x}, funz(x) = #{funz(x)}, funz2(x) = #{funz2(x)}"
end
Esempio verifica se un numero é primo
File: ex2.5_numero_primo.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# funzione che verifica se un numero intero e` primo
#
def isprime?(n)
for i in (2..n-1) do
if (n%i) == 0 then # divisione senza resto -> non primo!
return false ;
end
end
return true ;
end
nmax = ARGV[0].to_i
nmax = 2 if nmax < 2
for i in (2..nmax) do
if isprime?(i) then
puts "i=#{i} e` primo"
else
puts "i=#{i} NON e` primo"
end
end
Calcolo dei numeri primi: il crivello di Eratostene:
File ex2.6_crivello_erastotene.rb
File: ex2.6_crivello_erastotene.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Programma crivello di Eratostene per
# la ricerca dei numeri primi
#
n = ARGV[0].to_i # leggo da linea di comando n
n = 2 if n < 2 # trucchetto per evitare n < 1
# alloco vettore con n+1 elementi
okprime = Array.new(n+1)
# riempio vettore con booleani = true
for i in (0..n) do
okprime[i] = true
end
k = 2 ; # parto con 2 e` numero primo
while k < n do
# elimino tutti i multipli di k come numeri primi
i = 2
while i*k <= n do
okprime[i*k] = false
i = i+1 ;
end
# cerco prossimo numero primo
k = k+1 ;
while (k < n) and not okprime[k] do
k = k+1
end
end
#
# stampo numeri primi
#
for i in (0..n) do
puts "#{i}" if okprime[i]
end
Lezione del 7/3/2014
Riassuntino stringhe
:
File 3.1_intro_strings.rb
File: 3.1_intro_strings.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
str = "Ciao mondo!"
puts str
# stringhe interpolate e non
str_ni = 'questa e` \n una stringa \t non interpolata'
puts str_ni
p str_ni # una stampa piu` completa
# p str_ni equivale a puts str_ni.inspect
puts str_ni.inspect
puts ""
str_i = "questa e` \n una stringa \t interpolata"
puts str_i
# interpolare variabili nelle stringhe
eta = 5
nome = 'rex'
str_ni = 'il mio cane #{nome} ha #{eta} anni (non interpolata)'
str_ni = "il mio cane #{nome} ha #{eta} anni (si interpolata)"
puts ""
# concatenare stringhe
str = 'ora'
puts str
str += ' concateniamo' # equivale a str = str + ' sono'
puts str
str << " le"
puts str
str.concat " stringhe"
puts str
puts ""
# il punto esclamativo: alcune funzioni sono disponibili ANCHE
# nella forma con il punto esclamativo finale.
# In tal caso, le operazioni effettuate sulla variabile sono
# applicate direttamente su essa.
# Convertiamo una stringa da minuscolo a maiuscolo
str = "convertimi a maiuscolo"
puts "str.upcase #{str.upcase}"
puts "str #{str}" # str e` minuscola
puts "str.upcase! #{str.upcase!}"
puts "str #{str}" # str e` maiuscola
puts ""
# NOTA: per vedere le funzioni di default che e` possibile
# usare con le stringhe e` possibile digitare nell'irb: puts String.methods.sort
# ripetere una stringa
str = "ciao "*5
puts str
puts "\n"*2
Riassuntino Array
File 3.2_intro_array.rb
File: 3.2_intro_array.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 Universita` di Trento. Tutti i diritti riservati. #
#-------------------------------------------------------------------------#
puts 'INIZIALIZZAZIONE'
# array vuoto
ary = []
ary1 = Array.new
# visualizza tutti i metodi nativi degli array
puts ary.methods.sort
puts "\n"
# controlla cos'e` ary
puts "la variabile ary e` un #{ary.class}\n"
# controlla se l'array e` vuoto
puts "l'array ary e` vuoto? #{ary.empty?}\n"
ary2 = Array.new(20)
puts "ary2 e` un array di 20 elementi, tutti nulli:\n#{ary2}\n\n"
# size / length (they are the same!)
puts 'Posso controllare la dimensione di ary2 con:'
puts "ary2.size ---> #{ary2.size}"
puts "ary2.length ---> #{ary2.length}"
puts ""
ary3 = Array.new(6, 4)
puts "ary3 e` un array di 6 elementi, tutti uguali a 4:\n#{ary3}"
puts ""
ary4 = Array.new(3, 'hello')
puts "ary4 e` un array di 3 elementi, tutti uguali a 'hello':\n#{ary4}"
puts ""
puts "In alternativa, posso generare un array di 'n' elementi tutti uguali a X, con il comando: [X]*n
se n=6 e X=2 scrivero` [2]*6:
#{[2]*6}"
puts ""
ary5 = Array(0..6)
puts "ary5 e` un array di una sequenza di numeri crescenti:\n#{ary5}"
puts ""
puts "_"*30
puts "CICLI NEGLI ELEMENTI DELL'ARRAY"
puts "a) ciclo 'for'"
for i in 0 .. ary5.length-1
puts ary5[i]
end
puts "b) ciclo 'each'"
ary5.each do |e|
puts e
end
puts "c) ciclo 'each' versione compatta"
ary5.each{ |e| puts e }
puts "_"*30
puts 'COPIARE ARRAY'
puts '>>> modo sbagliato:'
puts "ary5 vale #{ary5}"
copy_ary5 = ary5
puts "copy_ary5 vale #{copy_ary5}"
puts ''
puts "Cambio il 4(to) elemento in copy_ary5 a 999"
copy_ary5[4] = 999
puts "copy_ary5 vale #{copy_ary5}"
puts "ma ora ary5 vale #{ary5}"
puts ''
puts '>>> modo corretto:'
ary5 = Array(0..6)
puts "ary5 vale #{ary5}"
copy_ary5 = ary5.dup
puts "copy_ary5 vale #{copy_ary5}"
puts ''
puts "Cambio il 4(to) elemento in copy_ary5 a 999"
copy_ary5[4] = 999
puts "copy_ary5 vale #{copy_ary5}"
puts "ora ary5 vale #{ary5}"
Problema 1
Trovare i numeri perfetti minori di 1000
Definizione
Un numero perfetto è un intero uguale alla somma dei suoi divisori (escluso se stesso). Ad esempio 6 è un numero perfetto infatti i suoi divisori 1, 2, 3 hanno somma 6.
Problema 2
Trovare le coppie di numeri amicabili minori di 10000
Definizione
Una coppia di numeri interi sono detti amicabili se la somma dei divisori di primo (escluso se stesso) è uguale al secondo e viceversa. Ad esempio
220 è divisibile per 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 e 110 e la loro somma risulta 284;
284 è divisibile per 1, 2, 4, 71, 142 e la loro somma risulta 220.
quindi 220 e 284 è una coppia di numeri amicabili. Altre coppie di numeri amicabili sono 184 e 1210, 2620 e 2924, 5020 e 5564, 17296 e 18416.
Soluzione al problema 1:
File: 3.3_perfect_numbers.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 Universita` di Trento. Tutti i diritti riservati. #
#-------------------------------------------------------------------------#
=begin
Calcola i numeri perfetti minori di `10000`
Un numero perfetto e` un intero uguale alla somma dei suoi divisori (escluso se stesso).
Ad esempio 6 e` un numero perfetto infatti i suoi divisori 1, 2, 3 hanno somma 6.
=end
# numeri perfetti: 6, 28, 496, 8128, 33550336
#____________________________
def is_perfect?(n)
# accumulo i divisori
acc = 1 # 1 e` sicurmente un divisore
for i in 2..n/2 do # se i > n/2 di sicuro non divide n
acc += i if (n%i) == 0 # accumulo i divisori
end
return acc == n # se acc == n allora il numero e` perfetto
end
# cerco i numeri perfetti tra 1 e 10000
(1..10000).each do |n|
puts n if is_perfect?(n)
end
Soluzione al problema 2
File: 3.4_amicable_numbers.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 Universita` di Trento. Tutti i diritti riservati. #
#-------------------------------------------------------------------------#
=begin
Calcola le coppie di numeri amicabili minori di `10000`
Una coppia di numeri interi sono detti amicabili se la somma dei
divisori di primo (escluso se stesso) e` uguale al secondo e viceversa.
=end
nmax = 10000
#____________________________
def divisor_sum(n)
# accumulo i divisori
acc = 1 # 1 e` sicurmente divisore
for i in 2..n/2 do # se i > n/2 di sicuro non divide n
acc += i if (n%i) == 0 # accumulo i divisori
end
return acc
end
divisor_table = Array.new(nmax+1) ;
puts "costruisco tabella dei divisori"
(1..nmax).each { |n| divisor_table[n] = divisor_sum(n) ; }
puts "cerco numeri amicabilie perfetti"
(1..nmax).each do |n|
m = divisor_table[n] ; # da n a m somma dei suoi divisori
if m == n then
puts "#{n} numero perfetto"
elsif m <= nmax then
n1 = divisor_table[m] ; # n1 e` somma dei divisori di m
# se n=n1 allora n e` somma dei divisori di m e viceversa
puts "#{n} -- #{m} amicabili" if n == n1
end
end
Lezione del 14/3/2014
Riassuntino hash
File 4.1_intro_hash.rb
File: 4.1_intro_hash.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# una hash e` un Array indicizzato, nel quale per accedere ad ogni elemento
# non uso il numero dell'indice corrispondente, bensì una chiave.
# Quest'ultima tipicamente e` un Symbol.
### I SIMBOLI
# i Symbol rappresentano nomi all'interno dell'interprete di Ruby. sono così definiti:
s = :a
# posso ottenere simboli a partire da stringhe, convertendo una stringa in un simbolo
str = "simbolo"
sym1 = str.to_sym
puts sym1
#oppure, in modo equivalente
sym2 = str.intern
puts sym2
# questo secondo metodo rende più chiaro che si sta cercando la
# rappresentazione interna all'interprete di 'str' se la mia stringa
# comprende anche spazi bianchi, il simbolo che ottengo diventa:
str = 'il mio simbolo'
sym = str.to_sym
puts sym
# però vedo che il mio simbolo non e` elegante, in quanto a causa
# degli spazi bianchi nella stringa, Ruby mantiene le virgolette
# Se ho una stringa con spazi bianchi e la voglio convertire in
# un simbolo la cui rappresentazione sia più elegante e comprensibile
# posso fare in modo di mettere degli 'underscore' al posto degli spazi bianchi
sym = str.gsub(/\s+/, "_").downcase.to_sym
puts sym
# il comando '.gsub(/\s+/, "_")' sostituisce gli spazi bianchi nella
# stringa con degli underscore "_". Questa operazione e` effettuata
# ricorrendo alle espressioni regolari (le vedremo più avanti).
# Per il momento vi basti sapere che nell'esempio qui mostrato
# l'espressione regolare e` '/\s+/' e mi permette di trovare tutti
# gli spazi bianchi nella stringa.
# Posso anche convertire i numeri in simboli.
# Tuttavia, non esiste un metodo .to_sym per i numeri,
# infatti Ruby mi da un errore se scrivo:
a = 3
a.to_s.to_sym # oppure a.intern
puts a
# quello che devo fare e` prima rappresentare 'a' come una
# stringa ('to_s') e poi come un simbolo ('to_sym'):
a = 3
puts a.to_s.to_sym
# questo e` necessario perche` i simboli sono il modo con cui
# l'interprete di Ruby rappresenta i NOMI (i.e. le stringhe).
# Per i numeri la logica interna di rappresentazione e` diversa.
# Per questo motivo in generale non ha mai senso convertire numeri a simboli.
### LE HASH
# Definisco una hash in Ruby 1.8.7
cane = { :nome => "Rex", :anni => 7} # noi useremo sempre questa notazione
# definisco una hash in Ruby > 2.0.0
gatto = { nome: "Cesar", anni: 3}
# posso aggiungere dinamicamente chiavi alla mia hash
cane[:razza] = :dalmata
# in una hash posso mettere anche degli Array
cane[:colore] = ["nero", "bianco"]
puts cane
# Posso anche creare una hash vuota e aggiungere dinamicamente elementi
io = {}
io[:nome] = "Maximiliano"
io[:sesso] = :maschio
# La hash può avere delle chiavi che puntano ad altre hash
io[:animali] = {:c => cane, :g => gatto}
puts io
# in questo caso, per sapere quanti anni ha il mio cane dovrò digitare
io[:animali][:c][:anni]
# Fino ad ora abbiamo visto che le chiavi sono dei Simboli,
# tuttavia posso definire come chiavi qualsiasi cosa:
h = {
:sym => "simbolo",
3 => 33 ,
"stringa" => true,
[1,2,3] => ["uno", "due", "tre", "quattro"],
{:a => 'a'} => "hash nella hash"
}
# ma la maggior parte delle volte usare chiavi che non sono
# simboli e` molto scomodo e può portare ad errori:
puts h[:sym]
puts h[3]
puts h[2] # questo mi da nil perche` non ho nessuna chiave pari a '2'
puts h['stringa']
puts h[ [1,2,3] ]
puts h[ {:a => 'a'} ]
### ITERARE IN UNA HASH
# Per ottenere il numero degli elementi nella hash, posso usare '.size' o '.length'
puts cane.size
# se ho hash annidate, il metodo '.size' (o '.length')
# mi restituisce il numero degli elementi nella hash "radice"
puts io.size
# Dal momento che non posso accedere agli elementi della hash
# con degli indici interi, non posso iterare nella hash con un ciclo FOR.
# Per iterare nella hash sono costretto ad usare il metodo '.each'
cane.each do |chiave, valore|
puts "#{chiave} corrisponde a #{valore}"
end
# in modo compatto:
cane.each{ |chiave, valore| puts "#{chiave} corrisponde a #{valore}" }
# posso iterare soltanto nelle chiavi della hash:
cane.each_key do |k|
puts "#{k} e` una chiave di 'cane'"
end
# oppure posso iterare soltanto nei valori della hash
cane.each_value{ |v| puts "#{v} e` un valore della hash 'cane'" }
# tutti gli altri metodi delle hash sono visibili con il solito comando:
puts cane.methods.sort
Esercizi sulle Hash
File 4.2_esercizi_hash.rb
File: 4.2_esercizi_hash.rb:
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# A) Usare le hash per costruire un elenco telefonico
elenco = [
{:nome => "Carlo",
:cognome => "Rossi",
:numero => 1231231230,
:mail => 'carlo.rossi@mail.it'},
{:nome => "Stefan",
:cognome => "Benz",
:numero => 22211223,
:mail => 'ste123@mail.de'},
{:nome => "Maria",
:cognome => "Callas",
:numero => 444001231,
:mail => 'callas@mail.com'}
]
# A.1) Per ogni persona nell'elenco, farsi stampare
# sul terminale la descrizione, formattata come:
# "NOME COGNOME: tel. NUMERO , mail MAIL"
puts "Esempio 1"
elenco.each do |elem|
# elem contiene la hash i-esime del array elenco
# dove i va da 0 a elenco.length-1
# estraggo valori della hash
n = elem[:nome]
c = elem[:cognome]
tel = elem[:numero]
m = elem[:mail]
# stampo come richiesto
puts "#{n} #{c}: tel. #{tel}, mail #{m}"
end
# A.2) Farsi stampare sul terminale la descrizione di ogni
# contatto nell'elenco telefonico (come nell'es. A.1),
# ma ordinando i cognomi in ordine alfabetico
#
# MODO COMPLICATO
#
# step 1, extraggo i cognomi e li riordino.
# Il metodo collect cotruisce un Array iterando sugli elementi del vettore
cognomi = elenco.collect { |elem| elem[:cognome] }
cognomi.sort! # il metodo sort riordina l'array
# step 2, costruisco una mappa che dal cognome trova
# la posizione nel vettore elenco
map_to_position = {}
elenco.each_with_index { |elem,i| map_to_position[elem[:cognome]] = i }
# each_with_index oltre che a prendere l'elemento
# aggiunge un secondo argomento con la sua posizione
# step 3, stampa lista ordinata
puts "Esempio 2"
cognomi.each do |c| # c contiene il cognome
pos = map_to_position[c] # dal cognome trovo la posizione
elem = elenco[pos] # prendo la Hash dall'elenco
# stampo come richiesto
puts "#{elem[:nome]} #{elem[:cognome]}: tel. #{tel = elem[:numero]}, mail #{elem[:mail]}"
end
#
# MODO SEMPLICE
#
# riordino il vettore elenco, non posso usare elenco.sort!
# perche sort! non sa come confrontare 2 hash
# devo quindi indicare all'interprete come
# confrontare sue hash
elenco.sort! { |a,b| a[:cognome] <=> b[:cognome] }
# il blocco {} restituisce
# -1 se a < b (secondo le nostre regole)
# 0 se a == b (secondo le nostre regole)
# +1 se a > b (secondo le nostre regole)
# l'operatore <=> applicato a 2 stringhe s1 e s2 restituisce
# -1 se s1 < s2, 0 se s1 == s2 ed +1 se s1 > s2
puts "Esempio 3"
elenco.each do |elem|
# elem contiene la hash i-esime del array elenco
# dove i va da 0 a elenco.length-1
# stampo come richiesto
puts "#{elem[:nome]} #{elem[:cognome]}: tel. #{tel = elem[:numero]}, mail #{elem[:mail]}"
end
Lezione del 24/3/2014
Riassuntino file
File 5.1_intro_files.rb
File: 5.1_intro_files.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
=begin
Un File e` un'astrazione di qualsiasi oggetto file accessibile dal programma,
ed e` associato con la classe IO File la quale include i metodi del modulo
FileTest come metodi di classe, permettendo di scrivere (per esempio)
File.exist?("foo")
=end
##########################################
#### CREAZIONE DI UN FILE ################
##########################################
# Posso creare un file mediante il comando:
nomefile = "testfile.txt"
puts "Creazione e scrittura di file di testo"
file = File.open( nomefile, "r+")
# Nota: "w" e` usato per scrivere il file (eventualmente creandolo se non
# esiste già)
# "r" e` usato per leggere il file
# "r+" sia per leggere che per leggere il file
# "a" per aggiungere linee alla fine del file
# Ci aggiungo stringhe in questo modo
file.puts "Questa e` una prova"
ary = [123456.654321, 22222.1111, -42421.123]
file.puts "123.4\tciao\t#{ary}"
# E alla fine devo sempre ricordarmi di chiudere il file!
# Cosi` mi assicuro che tutti i dati bufferizzati sono scritti
# e che rilascio tutte le risorse computazionali utilizzate.
file.close
##########################################
#### LETTURA DA FILE #####################
##########################################
puts "\nPrimo metodo per leggere i file"
# In alternativa, Ruby mi permette di fare tutto con un unico comando,
# un unico BLOCCO. Questa funzione si chiama 'open', ed invece di restituirmi
# un nuovo 'oggetto' File richiama il blocco definito, passandoci
# come argomento il nuovo file aperto.
File.open(nomefile, "r") do |file|
file.each do |line|
puts line
end
end
# Questa seconda opzione ha pro e contro:
# pro: se sbaglio a programmare ed il mio codice da un errore mentre scrivo il file,
# EVITO DI TENERE IL FILE APERTO (non ho bisogno di chiamare il '.close')
# contro: e` una notazione meno flessibile e devo tenere le operazioni che
# effettuo sul file in righe di codice tra loro vicine.
puts "\nSecondo metodo per leggere i file"
# In alternativa, per leggere il file posso usare:
File.open(nomefile, "r") do |file|
while line = file.gets
puts line
end
end
puts "\nTerzo metodo per leggere i file"
# Se combino l'idea dell'iteratore nel file,
# con il secondo metodo di lettura dei file, posso usare 'IO.foreach':
IO.foreach(nomefile){ |line| puts line }
File 5.2_file_dati.rb
File: 5.2_file_dati.rb:
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#__________________________________________________________________________
# 1. Leggere il file 'log.txt', e salvare ogni colonna in una hash dove la
# corrispondente chiave e` ottenuta dall'intestazione del file.
# Farsi restiuire le chiavi della hash 'dati' e la dimensione della
# colonna con i dati sul tempo
#__________________________________________________________________________
file = 'log.txt'
puts "Caricamento dei dati in #{file}"
# verifico se il file esiste
esiste = File.exists? file
raise ArgumentError, "Il file #{file} non esiste" unless esiste
str_frmt = " %.2f |"*9
str_frmt.chop!
str_frmt += "\n"
dati = {}
File.open(file, 'r') do |file|
intestazione = file.gets.split " "
intestazione.each_with_index do |s, i|
dati[s.to_sym] = []
dati[i] = dati[s.to_sym] # cosi` ho due modi per accedere allo stesso array:
# con una chiave o con un indice!
end # intestazione.each
file.each_line do |line|
parole = line.split " "
# stampo a video la stringa letta
print str_frmt % parole
# converto ogni parola nella linea in un Float (numero con la virgola)
parole.each_with_index{|s, i| dati[i] << s.to_f}
end # file.each...
end # File.open...
# Siccome non accedero` piu` a 'dati' mediante numeri ma soltanto con i simboli,
# cancello tutte le coppie chiave-valore le cui chiavi siano interi
dati.each_key{|k| dati.delete k if k.is_a? Integer}
#__________________________________________________________________________
# 2. Calcolare il valore medio e la deviazione standard di ogni colonna
# nella hash 'dati'. Trascurare le chiavi della hash 'dati' che sono numeri interi.
# Per una migliore rappresentazione arrotondare i numeri alla terza cifra significativa
#__________________________________________________________________________
puts "Calcolo media e varianza dei dati"
def mean(ary)
is_array = ary.is_a? Array
is_number = ary.first.is_a? Numeric
msg = "Posso calcolare la media solo di un array di numeri"
raise ArgumentError, msg unless is_array && is_number
s = ary.inject(0){|sum, x| sum+x}
l = ary.size
return s/l
end
def std(ary)
m = mean(ary)
l = ary.size
sq = ary.inject(0){|sum, x| sum + (x-m)**2}
return Math::sqrt(sq/l)
end
puts "="*40
dati.each{|k,v| puts "#{k}\t: media #{mean(v).round(3)}, std #{std(v).round(3)}" unless k.is_a? Integer}
puts "="*40
#__________________________________________________________________________
# 3. Trasporre la matrice salvata in 'log.txt', salvandola in un file chiamato 'log.trasp.txt'
#__________________________________________________________________________
puts "Trasposizione dei dati"
tr_file = File.new('log.trasp.txt', 'w')
dati.each do |k, v|
str = k.to_s << " "
str << v.inject(){|sum, x| sum.to_s+" "+x.to_s}
tr_file.puts str
end
tr_file.close
File di Log
Problema N.1
Leggere un file ascii che contiene una prima riga di intestazione con i nomi delle colonne. Le successive righe contengono le colonne dei dati. Il file letto va memorizzato in una hash le cui chiavi sono i nomi dello colonne della intestazione.
Una volta letto e memorizzato il file calcolare media e deviazione standard di ogni colonna.
Problema N.2:
Una volta letto il file del problema N.1 trasporre i dati e salvarli su un’altro file. Cioè la prima colonna diventa la prima riga, la seconda colonna diventa la seconda riga e cosi via.
Problema N.3:
Leggere un file ascii, separare i vari paragrafi cioè i blocchi di parole in linee consecutive non contenenti linee vuote. Salvare ogni paragrafo in un vettore e farsi stampare sul terminale il numero di paragrafo il numero di parole che contiene. Compattare (giustificare) ogni paragrafo in modo che riempia al meglio 80 colonne. Salvare su un altro file il file giustificato.
Lezione del 7/4/2014
Problema N.3 (lezione precedente)
Leggere un file ascii, separare i vari paragrafi cioè i blocchi di parole in linee consecutive non contenenti linee vuote.
Salvare ogni paragrafo in un vettore e farsi stampare sul terminale il numero di paragrafo il numero di parole che contiene. Compattare (giustificare) ogni paragrafo in modo che riempia al meglio 80 colonne. Salvare su un altro file il file giustificato.
Possibile soluzione (versione semplice)
File 5.3_giustificazione_testo_semplice.rb
File: 5.3_giustificazione_testo_semplice.rb:
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#__________________________________________________________________________
# 1. Leggere il file 'testo.txt', salvare ogni paragrafo in una hash
# e farsi stampare sul terminale ogni riga.
# Durante questa operazione fare in modo di trascurare le righe
# corrispondenti all'autore, data, e titolo del documento
#__________________________________________________________________________
file = 'testo.txt'
# verifico se il file esiste
esiste = File.exists? file
raise ArgumentError, "Il file #{file} non esiste" unless esiste
ht = {:testo => []}
n_linee_vuote = 0
IO.foreach(file) do |line|
# stampo la linea
puts line
# pulisco la linea dai terminatori di stringa
line.chomp!
# salvo il testo in un array
ht[:testo] << line if n_linee_vuote >= 2
# conto il numero delle linee vuote
n_linee_vuote += 1 if line.empty?
end
#__________________________________________________________________________
# 2. Contare e farsi stampare il numero di paragrafi, parole e di caratteri
# (inclusi spazi bianchi) nel file.
#__________________________________________________________________________
ht[:n_paragrafi] = ht[:testo].size
ht[:n_parole] = 0
ht[:n_caratteri] = 0
ht[:testo].each do |paragrafo|
# numero di caratteri
ht[:n_caratteri] += paragrafo.size
ht[:n_parole] += paragrafo.split(" ").size
end
puts "_"*40
puts "Il testo contiene:\n\t#{ht[:n_paragrafi]} paragrafi\n\t#{ht[:n_parole]} parole\n\t#{ht[:n_caratteri]} caratteri"
puts "_"*40
#__________________________________________________________________________
# 3. Giustificare il testo con una larghezza della pagina pari a
#__________________________________________________________________________
ht[:larghezza_testo] = 100 # numero di caratteri in una linea
# quando non posso aggiungere caratteri per completare la mia linea,
# aggiungo spazi bianchi dopo ogni parola a partire da sinistra.
def riempi_stringa(str, lunghezza)
raise ArgumentError, "Il primo argomento deve essere una stringa" unless str.is_a? String
raise ArgumentError, "Il secondo argomento deve essere un intero" unless lunghezza.is_a? Integer
l = str.size
nsb = lunghezza-l # numero di spazi bianchi da aggiungere
return str if nsb == 0
par = str.chomp.split " "
i = 1
while nsb > 0
# post poni uno spazio bianco alla fine di ogni parola
par[i].insert(0, " ")
i += 1
nsb -= 1
end
nuova_linea = par.join " "
l = nuova_linea.size
# se le parole nella linea sono meno degli spazi bianchi,
# aggiungo spazi bianchi dopo l'ultima parola
nsb = lunghezza-l # numero di spazi bianchi da aggiungere
nuova_linea << " "*nsb
l = nuova_linea.size
begin
msg = "La lunghezza della linea #{nuova_linea.inspect} di #{l} non e` compatibile con #{lunghezza}"
raise RuntimeError, msg unless l == lunghezza
rescue
binding.pry
end
nuova_linea << "\n" # la linea deve andare accapo
return nuova_linea
end # def
# Separo ogni parola in ogni paragrafo nel testo
testo_separato = []
ht[:testo].each{|par| testo_separato << par.split(" ") }
# Giustifico il testo. Ogni array (i.e. paragrafo) contiene le stringhe
# giustificate (i.e. linee) separate da terminatori di stringa
ht[:testo_giustificato] = []
ht[:testo].each do |paragrafo|
parole = paragrafo.split " "
paragrafo_giustificato = ""
linea = ""
# fin tanto che non ho giustificato tutte le parole...
while parole.size > 0
# togli la parola dall'array 'parole' e mettila in 'p'
p = parole.shift
# devo aggiungere la parola alla linea solo se a valle di questa operazione
# la conta dei caratteri non eccede ht[:larghezza_testo]
linea_giustificata = linea + " " + p
l = linea_giustificata.size
if l < ht[:larghezza_testo]
linea = linea_giustificata
# se la linea e` abbastanza corta e ho finito le parole nel paragrafo,
# allora appendi la linea al paragrafo cosi` com'e`
if parole.size == 0
paragrafo_giustificato << linea << "\n"
# reinizializza la linea
linea = ""
end
else
linea = riempi_stringa(linea, ht[:larghezza_testo])
# aggiungo la linea al paragrafo
paragrafo_giustificato << linea
# reinizializza la linea con la parola che avanza dalla linea precedente
linea = p
# se 'p' e` l'ultima parola del paragrafo, mandala accapo
paragrafo_giustificato << p << "\n" if parole.empty?
end # if
end # while parole
paragrafo_giustificato << "\n"
ht[:testo_giustificato] << paragrafo_giustificato
end # .each
puts "="*40
ht[:testo_giustificato].each{|par| puts par}
#__________________________________________________________________________
# 3. Salvare il testo giustificato in un nuovo file
#__________________________________________________________________________
File.open("testo_giustificato.txt", 'w') do |file|
ht[:testo_giustificato].each{|par| file.puts par}
end
Possibile soluzione (versione completa)
File 5.4_giustificazione_testo_completo.rb
File: 5.4_giustificazione_testo_completo.rb:
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#__________________________________________________________________________
# 1. Leggere il file 'testo.txt', salvare ogni paragrafo in una hash
# e farsi stampare sul terminale ogni riga.
# Durante questa operazione fare in modo di trascurare le righe
# corrispondenti all'autore, data, e titolo del documento
#__________________________________________________________________________
file = 'testo.txt'
# verifico se il file esiste
esiste = File.exists? file
raise ArgumentError, "Il file #{file} non esiste" unless esiste
ht = {:testo => []}
n_linee_vuote = 0
IO.foreach(file) do |line|
# stampo la linea
puts line
# pulisco la linea dai terminatori di stringa
line.chomp!
# salvo il testo in un array
ht[:testo] << line if n_linee_vuote >= 2
# conto il numero delle linee vuote
n_linee_vuote += 1 if line.empty?
end
#__________________________________________________________________________
# 2. Contare e farsi stampare il numero di paragrafi, parole e di caratteri
# (inclusi spazi bianchi) nel file.
#__________________________________________________________________________
ht[:n_paragrafi] = ht[:testo].size
ht[:n_parole] = 0
ht[:n_caratteri] = 0
ht[:testo].each do |paragrafo|
# numero di caratteri
ht[:n_caratteri] += paragrafo.size
ht[:n_parole] += paragrafo.split(" ").size
end
puts "_"*40
puts "Il testo contiene:\n\t#{ht[:n_paragrafi]} paragrafi\n\t#{ht[:n_parole]} parole\n\t#{ht[:n_caratteri]} caratteri"
puts "_"*40
#__________________________________________________________________________
# 3. Giustificare il testo con una larghezza della pagina pari a
#__________________________________________________________________________
ht[:larghezza_testo] = 100 # numero di caratteri in una linea
# quando non posso aggiungere caratteri per completare la mia linea,
# aggiungo spazi bianchi in corrispondenza delle parole piu` lunghe
def riempi_stringa(str, lunghezza)
raise ArgumentError, "Il primo argomento deve essere una stringa" unless str.is_a? String
raise ArgumentError, "Il secondo argomento deve essere un intero" unless lunghezza.is_a? Integer
l = str.size
nsb = lunghezza-l # numero di spazi bianchi da aggiungere
return str if nsb == 0
par = str.chomp.split " "
# ordino le parole dalla piu` lunga alla piu` corta
par_ord = par.sort{|x,y| y.size <=> x.size}
while nsb > 0
# trova la posizione della parola piu` lunga nella frase
i = par.index par_ord.shift
# non aggiungere spazi bianchi prima della prima parola nella linea
next if i == 0
# preponi uno spazio bianco alla parola piu` lunga
par[i].insert(0, " ")
nsb -= 1
end
nuova_linea = par.join " "
l = nuova_linea.size
# se le parole nella linea sono meno degli spazi bianchi,
# aggiungo spazi bianchi dopo l'ultima parola
nsb = lunghezza-l # numero di spazi bianchi da aggiungere
nuova_linea << " "*nsb
l = nuova_linea.size
begin
msg = "La lunghezza della linea #{nuova_linea.inspect} di #{l} non e` compatibile con #{lunghezza}"
raise RuntimeError, msg unless l == lunghezza
rescue
binding.pry
end
nuova_linea << "\n" # la linea deve andare accapo
return nuova_linea
end # def
# Separo ogni parola in ogni paragrafo nel testo
testo_separato = []
ht[:testo].each{|par| testo_separato << par.split(" ") }
# Giustifico il testo. Ogni array (i.e. paragrafo) contiene
# le stringhe giustificate (i.e. linee) separate da terminatori di stringa
ht[:testo_giustificato] = []
ht[:testo].each do |paragrafo|
parole = paragrafo.split " "
paragrafo_giustificato = ""
linea = ""
# fin tanto che non ho giustificato tutte le parole...
while parole.size > 0
# togli la parola dall'array 'parole' e mettila in 'p'
p = parole.shift
# devo aggiungere la parola alla linea solo se a valle di questa
# operazione la conta dei caratteri non eccede ht[:larghezza_testo]
linea_giustificata = linea + " " + p
l = linea_giustificata.size
if l < ht[:larghezza_testo]
linea = linea_giustificata
# se la linea e` abbastanza corta e ho finito le parole nel paragrafo,
# allora appendi la linea al paragrafo cosi` com'e`
if parole.size == 0
paragrafo_giustificato << linea << "\n"
# reinizializza la linea
linea = ""
end
else
linea = riempi_stringa(linea, ht[:larghezza_testo])
# aggiungo la linea al paragrafo
paragrafo_giustificato << linea
# reinizializza la linea con la parola che avanza dalla linea precedente
linea = p
# se 'p' e` l'ultima parola del paragrafo, mandala accapo
paragrafo_giustificato << p << "\n" if parole.empty?
end # if
end # while parole
paragrafo_giustificato << "\n"
ht[:testo_giustificato] << paragrafo_giustificato
end # .each
puts "="*40
ht[:testo_giustificato].each{|par| puts par}
#__________________________________________________________________________
# 3. Salvare il testo giustificato in un nuovo file
#__________________________________________________________________________
File.open("testo_giustificato.txt", 'w') do |file|
ht[:testo_giustificato].each{|par| file.puts par}
end
File testo
Lezione del 28/4/2014
File testo
Introduzione alle classi
File 6.1_intro_classi.rb
File: 6.1_intro_classi.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
=begin
In questa lezione vediamo una introduzione alla programmazione ad oggetti,
punto di forza dei moderni linguaggi di programmazione, come C++, Python,
Java, e Ruby.
UN OGGETTO E' UNA ISTANZA DI UNA CLASSE.
Vediamo quindi brevemente cos'e' una classe, e cosa vuol dire istanziare una
classe per creare un oggetto.
=end
=begin
CLASSI:
una classe e' un tipo di dato, definito da:
- attributi: variabili/costanti che definiscono le proprieta' degli oggetti
- metodi: funzioni interne, che posso essere applicate agli attributi, ma
anche a variabili esterne alla classe
Nelle lezioni successive vedremo che classi diverse possono essere messe in
relazione attraverso la relazione di EREDITARIETA'. Ereditare una classe
significa creare nuove classi partendo da classi pre-esistenti ed
estendendole con caratteristiche aggiuntive.
N.B.: IN RUBY quasi TUTTO E' UN OGGETTO. Ogni valore booleano, intero, float,
stringa, array, hash, struct, e classe sono FIGLI (i.e. ereditano) da altre
classi, che a loro volta ereditano dalla classe 'Class'. Posso verificare
cio' invocando il metodo 'class':
=end
s = 'ciao'
puts "s e' una classe #{s.class}"
puts "#{s.class} e' una classe #{s.class.class}"
puts "\n"*3
=begin
OGGETTI:
abbiamo detto che un oggetto e' una istanza di una classe. Istanziare
significa allocare della memoria per l'oggetto, e inizializzare la classe.
Per inizializzare una classe e' necessario invocare il suo metodo
costruttore, che in Ruby si chiama 'new'. Ad esempio, data una classe
'Cane', creero' l'oggetto 'fido' con il seguente comando:
fido = Cane.new
=end
=begin
ESEMPIO:
definiamo una classe e creiamo un oggetto istanziandola. Suppongo di
voler creare un Juke Box con le informazioni delle mie canzoni preferite.
Ogni canzone sara' una classe
Nota: ' buona norma dare i nomi alle classi con la prima lettera maiuscola.
Se il nome della mia classe e' composto da piu' parole adottero' la 'CamelCase'
notation (e.g. 'ClasseDiProva')
=end
class Canzone
# 1) 'initialize' e' in nome del metodo COSTRUTTORE, che verra' invocato quando
# istanzio la classe. In questo caso il costruttore ha tre argomenti:
# nome (Stringa) della canzone
# artista (Stringa) nome del cantante
# durata (Float) durata –in secondi– del brano
def initialize(nome, artista, durata)
# Le variabili che iniziano con la chiocciolina @ e sono definite dentro
# alla classe sono chiamate VARIABILI DI ISTANZA. Queste rappresentano gli
# ATTRIBUTI della mia classe, e sono definite (i.e. hanno un valore diverso
# da 'nil') solo allorquando la classe sia stata istanziata.
# Lo SCOPE degli attributi e' tutto a classe.
### Per inizializzare la mia classe canzone faro':
### c1 = Song.new('Arabella', 'Arctic Monkeys', 207)
@nome = nome
@artista = artista
@durata = durata
end
end
# Per inizializzare la mia classe canzone faro':
c1 = Canzone.new('Arabella', 'Arctic Monkeys', 207)
puts c1.inspect
class Canzone
# 2) Al momento la mia classe ha un costruttore che gli ho definito io, ma
# anche tutte le funzioni della classe da cui eredita. Abbiamo detto che
# in Ruby ogni classe eredita dalla classe 'Class', infatti:
# c1.class.class -> Class
# Ho quindi ereditato tutti i metodi di 'Class', che elenco con:
# puts Class.methods.sort
#
# Ad esempio vedo che ho il metodo 'inspect', che mi da una descrizione
# della mia istanza. Tuttavia l'output del metodo non e' molto leggibile,
# quindi posso sovrascrivere questo metodo.
def inspect
# Nota: per interpolare variabili di istanza in una stringa posso scrivere:
# "#{@nome}" oppure "#@nome"
return "Canzone: #@nome -- #@artista : #@durata"
end
end
puts "> Nuovo inspect:"
puts c1.inspect
# 3) Accessori: come posso fare a leggere il nome della mia canzone? Potrei
# pensare di scrivere:
# puts c1.nome
# ma Ruby mi dira' che in metodo 'nome' non e' stato definito per la mia classe
# c1. Devo quindi definire dei metodi che mi permettano di leggere, ed in caso
# scrivere, gli attributi (i.e. le variabili di istanza) del mio oggetto.
# Questo lo posso fare con due metodi:
class Canzone
# 3.1) definisco esplicitamente i metodi accessori...
# per leggere il nome:
# def nome
# return @nome
# end
# per scrivere il nome:
# def nome=(nuovo_nome)
# @nome = nuovo_nome
# end
# 3.2) oppure posso creare degli accessori attraverso delle scorciatoie:
# attr_reader :nome
# attr_writer :nome
# quando sono interessato sia all'accessore per la lettura che
# a quello per la scrittura posso scrivere direttamente:
attr_accessor :nome, :artista, :durata
end
puts c1.nome
c1.nome = "R U mine?"
puts c1.nome
leggi pixel, accendi e spegni pixel
File 6.2_ereditarieta.rb
File: 6.2_ereditarieta.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
=begin
Nell'esempio precedente abbiamo visto cos'e' una classe, un oggetto, ed abbiamo
parlato brevemente di cos'e' l'ereditarieta'. In questo esempio tratteremo
l'ereditarieta' in modo piu' completo
=end
# Definisco la classe Canzone con il metodo costruttore, inspect, e gli
# accessori
class Canzone
# accessori
attr_accessor :nome, :artista, :durata
# Costruttore
def initialize(nome, artista, durata)
@nome = nome
@artista = artista
@durata = durata
end
def inspect
return "Canzone: #@nome -- #@artista : #@durata"
end
end
# L'ereditarieta' mi permette di creare una classe che e' una specializzazione di
# un'altra classe. Ad esempio, creo una classe 'CanzoneKaraoke' e' deve essere
# come la classe 'Canzone', con l'unica differenza che deve avere anche
# informazioni sul testo della canzone.
# Devo quindi modificare soltanto il costruttore della classe
class CanzoneKaraoke < Canzone
attr_reader :testo
def initialize(nome, artista, durata, testo)
# il metodo 'super' messo qui richiama il costruttore di 'Canzone'
super(nome, artista, durata)
@testo = testo
end
end
# Proviamo ora la nostra classe 'CanzoneKaraoke'
# carico il testo della canzone da un file
testo = ""
IO.foreach('testi/cigarette_smoke.txt'){|line| testo << line}
k1 = CanzoneKaraoke.new('cigarette smoke', 'Arctic Monkeys', 176, testo)
# visualizziamo le informazioni sulla canzone:
puts k1.inspect
# mi restituisce: > Canzone: cigarette smoke -- Arctic Monkeys : 176
# che e' proprio l'output che avevo definito nella classe 'Canzone', ovviemente
# senza informazioni sul testo. Modifico quindi il metodo 'inspect' di
# 'CanzoneKaraoke'
class CanzoneKaraoke < Canzone
def inspect
# 'super' in questo caso dice a Ruby di invocare il metodo 'initialize' di
# 'Canzone'
descrizione = super
return descrizione + " [ #{@testo[0..20]} ... ]"
end
end
puts k1.inspect
File: 6.3_self_metodiClasse.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
=begin
Vedremo ora cos'e' in ruby la parola chiave 'self'. Quando usata all'interno
di una classe, la parola 'self' e' utilizzata per riferirsi all'oggetto (i.e.
istanza) corrente.
Vedremo inolte cosa sono i metodi e le variabili di classe
=end
class Item1
# metodo di istanza. E' creato solo dopo che ho instanziato la classe
def initialize(item_nome)
@item_nome = item_nome
end
# metodo di istanza
def show
# 'self' mi restituisce la rappresentazione dell'istanza dell'oggetto
puts "Metodo di istanza 'show' invocato per #{self}"
end
# se voglio una rappresentazione piu' leggibile
#def to_s
# "Item: #{@item_nome}"
#end
end
t = Item1.new('test')
t.show
############################################
#### METODI DI CLASSE ######################
############################################
puts "_"*40
class Item2
# aggiungendo un 'self' al nome del metodo creo un metodo di classe. Questo
# metodo esiste anche senza instanziare la classe
def self.show_class
puts "Invocato metodo di classe"
end
def show_instance
puts "Metodo di istanza"
#puts "La variabile di instanza vale #{@var_instance}"
end
end
Item2.show_class # ora uso il metodo 'show' senza istanziare la classe
#Item2.show_var_instance # da errore perche' la classe non e' stata inizializzata
# in alternativa avrei potuto scrivere
=begin
class Item2
class << self
def show
puts "Invocato metodo di classe"
end
end
end
=end
#====#====#====#====#====#====#====#====#====#====#====#====#====#====#====#
#N.B. I metodi di classe non hanno accesso ai metodi di istanza, o alle
# variabili di istanza. Al contrario, metodi di istanza possono accedere
# alle variabili ed ai metodi di classe. Verifichiamo la prima affermazione:
#====#====#====#====#====#====#====#====#====#====#====#====#====#====#====#
puts "_"*40
class Item3
# aggiungendo un 'self' al nome del metodo creo un metodo di classe. Questo
# metodo esiste anche senza instanziare la classe
def self.show_class
#show_instance # questo da errore
puts "@var_instanza = #{@var_instanza}" # questo da 'nil'
puts "Invocato metodo di classe"
end
def show_instance
@var_instanza = 3
puts "Metodo di istanza"
#puts "La variabile di instanza vale #{@var_instance}"
end
end
Item3.show_class
############################################
#### VARIABILI DI CLASSE ###################
############################################
puts "_"*40
class Pianeta
# le variabili di classe si definiscono con due '@'
@@numero_pianeti = 0
def initialize(name)
@name = name
@@numero_pianeti += 1
end
# definisco un metodo di classe che mi permette di accedere
# alla variabile di istanza numero_pianeti
def self.numero_pianeti
@@numero_pianeti
end
end
Pianeta.new("earth")
Pianeta.new("uranus")
puts "Il mio sistema planetario ha #{Pianeta.numero_pianeti} pianeti"
# le variabili di classe possono essere usate per salvare dati che appartengono
# a una classe, ma non ad una istanza.
############################################
#### VARIABILI DI ISTANZA DI CLASSE ########
############################################
class Foo
# N.B: una variabile nominata con un solo '@' e definita nel corpo della
# classe si chiama VARIABILE DI ISTANZA DI CLASSE
@contatore_inst_class = 0
@@contatore_class = 20
def aumenta_cont_inst_class # questo metodo dara' errore!
@contatore_inst_class += 1
end
def aumenta_cont_class
# questo metodo FUNZIONA perche' POSSO USARE VARIABILI (ma anche metodi)
# DI CLASSE NEI METODI di istanza
@@contatore_class += 1
end
def self.increment_counter
@contatore_inst_class += 1
end
def self.current_count_inst_class
@contatore_inst_class
end
def self.curret_count_cl
@@contatore_class
end
end
puts Foo.increment_counter # OK, funziona
f = Foo.new
#puts f.aumenta_cont_inst_class
puts "f.aumenta_cont_class #{f.aumenta_cont_class}"
# questo da errore perche' NON POSSO USARE VARIABILI DI
# ISTANZA DI CLASSE NEI METODI DI ISTANZA
# e che differenza c'e' tra '@@contatore_class' e '@contatore_inst_class'? Vediamolo...
class Bar < Foo
@contatore_inst_class = 100 # se non la definisco, vale 'nil', il suo valore non e' ereditato
@@foo_var_cl = 140 # questo NON VIENE SOVRASCRITTO!!!
end
puts "Variabile @contatore_inst_class in Foo #{Foo.current_count_inst_class}"
puts "Variabile @contatore_inst_class in Bar #{Bar.current_count_inst_class}"
puts "Variabile @@contatore_class in Foo #{Foo.curret_count_cl}"
puts "Variabile @@contatore_class in Bar #{Bar.curret_count_cl}"
=begin RIASSUMENDO
A) I metodi di classe non hanno accesso ai metodi di istanza,
o alle variabili di istanza. Al contrario, metodi di istanza
possono accedere alle variabili ed ai metodi di classe.
B) Le variabili di istanza sono disponibili solo per istanze di classi,
e si scrivono come '@foo'. Le variabili di classe invece sono disponibili
sia per i metodi di classe che per i metodi di istanza, e si scrivono
come '@@foo'.
C) Le variabili di istanza di classe si scrivono come le variabili di istanza
('@foo') ma vanno dichiarate nel corpo della classe e hanno proprieta' molto
diverse dalle variabili di istanza.
D) Le differenze tra VARIABILI DI CLASSE e VARIABILI DI ISTANZA DI CLASSE sono:
1) le variabili di istanza di classe NON PERMETTONO LA CONDIVISIONE DI DATI
ATTRAVERSO TUTTA LA CATENA DI EREDITARIETA`
(cosa che invece fanno le variabili di classe).
2) le variabili di istanza di classe possono essere
USATE SOLO IN METODI DI CLASSE
=end
Lezione del 30/4/2014
Classe plot ascii
File plot_ascii.rb
File: plot_ascii.rb:
PX_ON = '*'
PX_OFF = ' '
class PlotAscii
attr_reader :nrow, :ncol
# Inizializza il plot ascii, con spazi bianchi
def initialize(n_righe, n_colonne)
@nrow = n_righe
@ncol = n_colonne
@righe = Array.new(n_righe)
@righe.collect!{|r| PX_OFF*n_colonne}
end
# cancello schermo
def clean
@righe.collect! { PX_OFF*@ncol }
end
# accendere un pixel x = colonna, y = riga
def pixel_on(x, y)
@righe[y][x] = PX_ON if x >=0 and x < @ncol and y >= 0 and y < @nrow
end
def pixel_off(x,y)
@righe[y][x] = PX_OFF if x >=0 and x < @ncol and y >= 0 and y < @nrow
end
def pixel_reverse(x,y)
if x >=0 and x < @ncol and y >= 0 and y < @nrow then
@righe[y][x] = @righe[y][x] == PX_ON ? PX_OFF : PX_ON
end
end
def pixel?(x,y)
if x >=0 and x < @ncol and y >= 0 and y < @nrow then
return true if @righe[y][x] == PX_ON
end
return false
end
def print
puts "+"+("-"*@ncol)+"+"
@righe.reverse.each{|line| puts "|"+line+"|" }
puts "+"+("-"*@ncol)+"+"
end
def copy( scr )
for i in 0...@ncol do
for j in 0...@nrow do
if scr.pixel?(i,j) then
pixel_on(i,j)
else
pixel_off(i,j)
end
end
end
end
def reverse
for i in 0...@ncol do
for j in 0...@nrow do
pixel_reverse(i,j)
end
end
end
end
#pl = PlotAscii.new(24, 80)
#pl.pixel_on(10,30)
#pl.pixel_on(23,11)
#pl.print
Gioco vita di Convey
File vita.rb
File: vita.rb:
load 'plot_ascii.rb'
#
# inizializzo 2 istanze della classe PlotAscii
#
scr1 = PlotAscii.new( 24, 80 );
scr2 = PlotAscii.new( 24, 80 );
# inizializazione della popolazione iniziale
# con max 300 "abitanti"
(0..400).each do
j = Random.rand(24)
i = Random.rand(80)
scr1.pixel_on(i,j)
end
# loop
for k in 0..100 do
# stampa
puts "Popolazione N. #{k}"
scr1.print
# aggiorna schermo
for j in 0...scr1.nrow do
for i in 0...scr1.ncol do
# conto i primi vicini "vivi"
nlive = 0
nlive += 1 if scr1.pixel?(i+1,j-1)
nlive += 1 if scr1.pixel?(i+1,j)
nlive += 1 if scr1.pixel?(i+1,j+1)
nlive += 1 if scr1.pixel?(i,j-1)
nlive += 1 if scr1.pixel?(i,j+1)
nlive += 1 if scr1.pixel?(i-1,j-1)
nlive += 1 if scr1.pixel?(i-1,j)
nlive += 1 if scr1.pixel?(i-1,j+1)
# logica di Convey vivo/morto
if scr1.pixel?(i,j) then
if nlive == 2 or nlive == 3 then
scr2.pixel_off(i,j)
else
scr2.pixel_on(i,j)
end
else
if nlive == 3 then
scr2.pixel_on(i,j)
else
scr2.pixel_off(i,j)
end
end
end
end
# copio la schermata di scr2 in scr1
scr1.copy(scr2) ;
# aspetta un "return" da tastiera
gets
end
puts "FINE!"
Lezione del 12/5/2014
Classe polinomio:
File polynomial.rb
File: polynomial.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
# Classe polinomio
class Polynomial
attr_reader :dd
attr_reader :x
attr_reader :coeffs
attr_reader :omega
#
# inizializza il polinomio al polinomio vuoto
#
def initialize( cf = [] )
@dd = [] # differenze finite
@x = [] # ascisse di interpolazione
@omega = [] # coefficienti polinomio omega della interpolazione di Newton
@coeffs = cf # coefficienti polinomio interpolante o polinomio passato
end
#
# aggiunge un punto di interpolazione al polinomio
#
def add(x,y)
update_dd(x,y)
update_omega(x)
update_coeffs()
end
#
# somma di due polinomi
#
def +(other)
# calcolo ordine polinomio in uscita
a = self.coeffs.dup # per non modificare i @coeff di self
b = other.coeffs
n = [ a.size, b.size ].max
while a.size < n do a << 0 end
while b.size < n do b << 0 end
for i in 0...n do a[i] += b[i] end # meglio un collect per risparmare il dup
return Polynomial.new a
end
#
# converte il polinomio in una stringa "human readable"
#
def to_s
tmp = ""
@coeffs.each_with_index do |c,idx|
if idx == 0 then
tmp += c.to_s
elsif idx == 1 then
tmp += " + " + c.to_s + " * x"
else
tmp += " + " + c.to_s + " * x^" + idx.to_s
end
end
tmp = "0" if tmp.empty?
return tmp
end
private
#
# date le differenze divise dd[] che contiene
# f[x0], f[x0,x1], ...., f[x0,x1,...,xn]
# aggiunge in coda la differenza divisa f[x0,x1,...,xn,x[n+1]]
#
def update_dd(x,y)
n = @dd.size
if n == 0 then
@dd << y
else
d = y
for k in 0...n do # fino a n-1
d = (@dd[k]-d)/(@x[k]-x)
end
@dd << d # d contiene f[x0,x1,...,x[n+1]]
end
end
#
# dato omega[n](x) costruisco
# omega[n+1](x) = omega[n](x)*(x-x[n])
# dove x[n] = @lastx
def update_omega(x)
n = @omega.size
if n == 0 then
@omega << 1
else
# moltiplico @omega * (x-@x[n]) = @omega * x - @x[n] * @omega
@omega.insert(0,0) ;
for k in 0...n do
@omega[k] = @omega[k] - @omega[k+1]*@x[-1]
end
end
@x << x
end
#
# aggiunge al polinomio
# p(x) = f[x0]+f[x1]*(x-x0)+ .... +f[x0,x1,...,xn]*omega[n](x)
# il polinomio
# f[x0,x1,...,xn,x[n+1]]*omega[n+1](x)
# p(x) interpola anche l'ultimo punto inserito
def update_coeffs()
n = @coeffs.size
@coeffs << 0 ;
for k in 0..n do
@coeffs[k] += @omega[k] * @dd[-1]
end
end
end
if __FILE__ == $0
poly = Polynomial.new
puts "poly = "+poly.to_s
poly.add(1,5)
puts "poly = "+poly.to_s
poly.add(2,15)
puts "poly = "+poly.to_s
poly.add(3,31)
puts "poly = "+poly.to_s
poly1 = Polynomial.new [1,2,3]
poly2 = poly+poly1
puts "poly = "+poly.to_s
puts "poly1 = "+poly1.to_s
puts "poly+poly1 = "+poly2.to_s
end
Lezione del 12/5/2014
Uso dei blocchi in Ruby
File blocchi.rb
File: blocchi.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#ary = [11,22,33,44,55]
#ary.each do |el|
# puts el
#end
#
#ary.each{|el| puts el }
class Array
def ogni() # each
puts "2. Entrato nella funzione ogni"
for i in 0...self.size
puts "3. Inizio chiamata blocco"
yield(self[i])
yield(i)
puts "4. Fine chiamata blocco"
end
puts "5. Uscita dalla funzione ogni"
end
def ogni_con_indice() # each_with_index
for i in 0...self.size
yield(self[i], i)
end
end
end
module ValutaOperazioni
def self.sqrt(x)
return Math::sqrt(x)
end
def self.pow2(x)
return x*x
end
end
module StampaOperazioni
def self.sqrt(x)
puts Math::sqrt(x)
end
def self.pow2(x)
puts x*x
end
end
bary = ['11','22','33','44']
#puts "1. Definito array bary"
#bary.ogni do |el|
# puts el
#end
#puts "6. Uscita dal programma"
bary.ogni_con_indice do |el, indx|
res = StampaOperazioni::pow2( el.to_f )
puts "#{el} -> #{res.inspect}"
end
Integrazione col metodo dei trapezi (versione senza blocchi)
File trapezi_semplice.rb
File: trapezi_semplice.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Esempio di integrazione numerica,
# uso della formula dei trapezi per integrare
# x*sin(x) nell'intervallo [1,10]
#
def f(x)
return x*Math::sin(x)
end
#
# Metodo dei trapezi
# a = estremo sinistro intervallo di integrazione
# b = estremo destro intervallo di integrazione
# n = numero di intervalli
#
def trapezi( a, b, n )
h = (b.to_f-a.to_f)/n.to_f
res = (f(a)+f(b))/2
for i in 1...n do
xi = a+i*h # calcolo nodo di quadratura interno
res += f(xi) ;
end
return res*h
end
# integrale esatto calcolato "a mano"
esatto = Math::sin(10)-10*Math::cos(10)
a = 0
b = 10
n = 10
trap = trapezi(a,b,n)
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 20
trap = trapezi(a,b,n)
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 40
trap = trapezi(a,b,n)
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 80
trap = trapezi(a,b,n)
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 160
trap = trapezi(a,b,n)
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
Integrazione col metodo dei trapezi (versione CON i blocchi)
File: trapezi_con_blocchi.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
# Esempio di integrazione numerica,
# uso della formula dei trapezi per integrare
# x*sin(x) nell'intervallo [1,10]
#
def f(x)
return x*Math::sin(x)
end
#
# Metodo dei trapezi
# a = estremo sinistro intervallo di integrazione
# b = estremo destro intervallo di integrazione
# n = numero di intervalli
#
def trapezi( a, b, n ) # argomento nascosto: blocco
h = (b.to_f-a.to_f)/n.to_f
res = (f(a)+f(b))/2
for i in 1...n do
xi = a+i*h # calcolo nodo di quadratura interno
res += yield(xi) ;
end
return res*h
end
# integrale esatto calcolato "a mano"
esatto = Math::sin(10)-10*Math::cos(10)
a = 0
b = 10
n = 10
trap = trapezi(a,b,n){ |x| x*Math::sin(x) }
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 20
trap = trapezi(a,b,n){ |x| x*Math::sin(x) }
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 40
trap = trapezi(a,b,n){ |x| x*Math::sin(x) }
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 80
trap = trapezi(a,b,n){ |x| x*Math::sin(x) }
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
n = 160
trap = trapezi(a,b,n){ |x| x*Math::sin(x) }
puts "trapezi(#{a},#{b},#{n}), I = #{trap}, Errore = #{trap-esatto}"
Lezione del 19/5/2014
Approssimazione zeri di funzione (variabile singola):
File zeri.rb
File: zeri.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
#
class NthRooth
def initialize( a, n )
@a = a # numero del quale si vuole la radice quadrata
@n = n # ordine della radice da calcolare
end
def f(x)
return x**@n-@a
end
def df(x)
return @n*x**(@n-1)
end
end
class SqrtFun < NthRooth
def initialize( a )
super(a,2)
end
end
class ThirdRooth < NthRooth
def initialize( a )
super(a,3)
end
end
#class SqrtFun
# def initialize( a )
# @a = a # numero del quale si vuole la radice quadrata
# end
#
# def f(x)
# return x*x-@a
# end
#
# def df(x)
# return 2*x
# end
#end
def err_asymptotic( x, alpha )
for k in 2...x.size do
ek = (x[k-2]-alpha).abs
ekp1 = (x[k-1]-alpha).abs
ekp2 = (x[k] -alpha).abs
p = Math::log(ekp1/ekp2)/Math::log(ek/ekp1)
puts "k = #{k}, order p = #{p}"
end
end
def newton( x0, tol, iter_max )
x = [ x0.to_f ] # inizializza iterate
for k in 1..iter_max do
fdf = yield(x.last) # blocco calcola f(x) e df(x) e restituisce [f(x),df(x)]
h = -fdf[0]/fdf[1] # h = - f(x)/df(x)
break if h.abs < tol # interrompo ciclo se passo
# piu piccolo della tolleranza
x << x.last+h # x = x + h
end
return x
end
def secanti( x0, x1, tol, iter_max )
x = [ x0.to_f, x1.to_f ] # inizializza iterate
f0 = yield(x0)
f1 = yield(x1)
for k in 1..iter_max do
h = -f1/((f1-f0)/(x1-x0))
break if h.abs < tol # interrompo ciclo se passo
# piu piccolo della tolleranza
x << x.last+h # x = x + h
x0 = x1
x1 = x.last
f0 = f1
f1 = yield(x1)
end
return x
end
fun = SqrtFun.new 2
#x = newton( 2, 1e-10, 10 ){ |x| [fun.f(x),fun.df(x)] }
x = newton( 2, 1e-10, 10 ){ |x| [x*x-3,2*x] }
puts "x = #{x}"
err_asymptotic( x, Math::sqrt(3.0))
x = secanti( 2, 3, 1e-10, 10 ){ |x| x*x-3 }
puts "x = #{x}"
err_asymptotic( x, Math::sqrt(3.0))
Lezione del 23/5/2014
Costruzione grafo/albero dei divisori di un numero intero
File divisori.rb
File: divisori.rb:
#!/usr/bin/env ruby
#-------------------------------------------------------------------------#
# Esercitazioni in Laboratorio per il Corso di #
# Fondamenti di Informatica e Calcolo Numerico, AA 2013/2014 #
# #
# Autori: Enrico Bertolazzi e Carlos Maximiliano Giorgio Bort #
# Dipartimento di Ingeneria Industriale, Universita` di Trento #
# Sito web: http://www.ing.unitn.it/~bertolaz/ #
# #
# Contatti: enrico.bertolazzi@unitn.it, cm.giorgiobort@unitn.it #
# #
# Copyright (c) 2014 E.Bertolazzi e C.M. Giorgio Bort #
#-------------------------------------------------------------------------#
require 'pp'
#
# Programma che legge un numero da terminale e costruisce una struttura
# ad albero dei divisori.
# Una volta costruita la stuttura scrive l'albero risultante in un file .dot
# per visualizzarlo graficamente.
#
#
# La struttura data è una combinazione di Hash e Array fatta in questo modo
#
# Un modo dell'albero è una hash con 2 campi:
# :number --> un intero
# :divisors --> un Array di Hash con i divisori
#
# La funzione divisori costruisce ricorsivamente la struttura dati
#
def divisiori( n )
root = { :number => n, :divisors => [] }
#
# la ricorsione o meglio root è srruttura completa se `n` è un numero primo
# cioè non ha divisori. La prima cosa fare è calcolare i divisori
for i in 2..n/2
if n % i == 0 then
# se arrivo qui, i è un divisore del numero n
root[:divisors] << divisiori( i ) ; # divisori(i) restituisce la Hash del
# "sottoalbero" del divisore i
end
end
return root ;
end
#
# to_dot e' una funzione che data la struttura dati dell' albero dei
# divisori stampa una descrizione nel liguaggio "dot" di graphviz
# dell'albero corrispondente
#
def to_dot( albero )
from = albero[:number] ; # numero di partenza del rampo dell'albero
albero[:divisors].each { |d|
to = d[:number] ;
# stanpo il ramo from --> to
puts "#{from} -> #{to};"
to_dot( d ) ;
}
end
#
# input come linea di comando.
# se il comando è
# ruby divisori.rb 100
# ARGV[1] contiene 100
albero = divisiori( ARGV[0].to_i ) ;
puts "digraph G {"
to_dot(albero)
puts "}"
#pp albero
P.h.D. Course of Scientific Programming in C++ (AA 2013/2014)
- Introduction
- Timetable
- Lesson 1
- Lesson 2
- Lesson 3
- Lesson 4
- Lesson 5
- Lesson 6
- Lesson 7
- Lesson 8
- Lesson 9
- Lesson 10
- Lesson 11
This course will introduce the student to the efficient implementation of (some) algorithm of numerical analysis. As an example of possible arguments:
- Sort and searching.
- LU factorization.
- Interpolation with divided difference.
- Conversion of number from digits to letters.
- Runge Kutta methods.
- Zeros of polynomials and Sturm sequence.
- Adaptive quadrature.
All the examples are developed in C/C++ and an overview of Object Oriented programming is part of the course. Based on the needs of the audience, changes in the presented arguments and schedule can be performed.
Exam
The final evaluation will be carried out based on individual project on arguments proposed in the course.
Useful link
Lesson Timetable
DAY | TIME | ROOM |
---|---|---|
Wednesday | 8:30 - 11:30 | 221 |
Thursday | 8.30 - 10.30 | 221 |
Friday | 10.30 - 13.30 | 204 |
Thursday 10 July | 10 - 13 | Seminar Room |
Monday, 14 July | 10 - 13 | cancelled” |
Tuesday, 15 July | 10 - 13 | B104 |
Wednesday, 16 July | 10 - 13 | B104 |
Thursday, 17 July | 10 - 13 | B104 |
Friday, 18 July | 10 - 13 | B104 |
Monday, 21 July | 10 - 13 | B104 |
Tuesday, 22 July | 10 - 13 | B104 |
Wednesday, 23 July | 10 - 13 | B104 |
Thursday, 24 July | 10 - 13 | B103 |
Wednesday, 30 July | 14 - 17 | B105 |
Thursday, 31 July | 10 - 13 | B105 |
Lesson N.1 of July 10, 2014
Some simple C/C++ programs
File: example1.cc:
// I am a single line comment line
/*
I am a multiline comment
bla bla
bla bla
*/
int // int is the name of the type integer and
// is the return type of the function main
main( /* no argument for the moment */ ) { // { open the body block
return 0 ; // return 0 to the OS
} // close the body block
File: example2.cc:
// I am a single line comment line
/*
I am a multiline comment
bla bla
bla bla
*/
#include <stdio.h>
int
main( /* no argument for the moment */ ) {
int a, b, c ; // declare and instance a,b,c as integer variable
printf("I am a string\n") ;
// now assign the variable a, b, c to some value
a = 1 ;
b = 234 ;
c = -123 ;
printf("Write a formatted integer a = %i\n",a) ;
printf("Write a formatted integer a = %10i, b=%5i\n",a,b) ;
printf("Write a formatted integer a = %-10i, b=%5i, c=%6i\n",a,b,c) ;
float aa = 1.234 ; // declare, instance and initialize aa as floating point variable
printf("Write aa formatted aa = %f\n",aa) ;
printf("Write aa formatted aa = %10f\n",aa) ;
printf("Write aa formatted aa = %10.5f\n",aa) ;
printf("Write aa formatted aa = %e\n",aa) ;
printf("Write aa formatted aa = %10g\n",aa) ;
return 0 ; // return 0 to the OS
}
File: example3.cc:
// I am a single line comment line
/*
I am a multiline comment
bla bla
bla bla
*/
#include <iostream>
using namespace std ; // for the moment magic ``keyword''
/*
cout is a object for the output, means character out
*/
int
main( /* no argument for the moment */ ) {
double a, b, c ; // declare and instance a,b,c as double precision floating point variable
cout << "I am a string\n"
<< "I am another string\n" ;
cout << "I am a string\n" ;
cout << "I am another string\n" ;
// now assign the variable a, b, c to some value
a = 1 ;
b = 234 ;
c = -123 ;
cout << "a = " << a << "\n" ;
cout << "a = " << a << " b = " << b << "\n" ;
cout << "a = " << a << " b = " << b << " c = " << c << "\n" ;
float aa = 1.234 ; // declare, instance and initialize aa as floating point variable
cout << "aa = " << aa << "\n" ;
return 0 ; // return 0 to the OS
}
File: example4.cc:
/*
A simple program that solve
a*x^2 + b*x + c = 0
*/
#include <iostream>
#include <cmath>
using namespace std ; // for the moment magic ``keyword''
int
main( /* no argument for the moment */ ) {
double a, b, c ; // declare and instance a,b,c as double variable
cout << "Enter a = " ;
cin >> a ;
cout << "Enter b = " ;
cin >> b ;
cout << "Enter c = " ;
cin >> c ;
cout << "You entered " << a << "*x^2 + " << b << "*x + " << c << '\n' ;
// check if is a true quadratic
if ( a == 0 ) {
// the quadratic is "linear"
if ( b == 0 ) {
cerr << "the quadratic is degeneted\n" ; // use error I/O object
} else {
cout << "Linear case, one solution x = " << -c/b << '\n' ;
}
} else {
// regular case
// evaluate the discriminant of the quadratic
double delta = b*b - 4*a*c ;
if ( delta > 0 ) {
// case 2 distinct real roots
delta = sqrt(delta) ;
double x1 = (-b+delta)/(2*a) ;
double x2 = (-b-delta)/(2*a) ;
cout << "Two real roots x1 = " << x1 << " x2 = " << x2 << '\n' ;
} else if ( delta < 0 ) {
// case 2 complex conjugate roots
// case 2 distinct real roots
delta = sqrt(-delta) ;
double re = -b/(2*a) ;
double im = delta/(2*a) ;
cout << "Two complex conjugate roots:\n"
<< " x1 = (" << re << ", " << im << ")\n"
<< " x1 = (" << re << ", " << -im << ")\n" ;
} else {
// double root
cout << "Doble root x1 = x2 = " << -b/(2*a) << '\n' ;
}
}
return 0 ; // return 0 to the OS
}
File: example5.cc:
/*
A simple program that
implement newton iterative scheme
*/
#include <iostream>
#include <cmath>
using namespace std ; // for the moment magic ``keyword''
double
f( double x) {
return x*x-2 ;
}
double
df( double x) {
return 2*x ;
}
// user function implementing newton scheme
int
newton( double & x, // initial guess and returned value
double tolerance, // tolerance for stopping criteria
int max_iter ) { // maximum iterations allowed
// cout.precision(10) ;
for ( int i=0 ; i < max_iter ; ++i ) {
double h = f(x)/df(x) ;
x -= h ; // x = x - h
// cout << "x[" << i << "] = " << x << " h = " << h << '\n' ;
if ( abs(h) < tolerance ) return 0 ; // found solution
}
return 1 ; // failed to converge
}
int
main( /* no argument for the moment */ ) {
double x, tol = 1e-8 ;
cout << "Initial guess x0 = " ;
cin >> x ;
int ok = newton( x, tol, 100 ) ;
if ( ok == 0 ) {
cout << "Newton converged with value = " << x << "\n" ;
} else {
cout << "Newton do not converge\n" ;
}
return 0 ; // return 0 to the OS
}
All files in a zip file
Lesson N.2 of July 15, 2014
File: example6.cc:
/*
Few example using template (preliminari part)
*/
#include <iostream>
#include <cmath>
using namespace std ; // for the moment magic ``keyword''
//static // local function
unsigned // return the index of the minimum
findMinimum( int a[], unsigned size ) {
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( a[i] < a[imin] ) imin = i ;
return imin ;
}
//static // local function
unsigned // return the index of the minimum
findMinimum( long int a[], unsigned size ) {
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( a[i] < a[imin] ) imin = i ;
return imin ;
}
int
main( /* no argument for the moment */ ) {
int a[] = {2,-3,1,2,-9,8} ; ;
unsigned ipos = findMinimum( a, sizeof(a)/sizeof(a[0]) ) ;
cout << "minimum is " << a[ipos] << " at position " << ipos << '\n' ;
return 0 ; // return 0 to the OS
}
File: example7.cc:
/*
Few example using template (preliminari part)
*/
#include <iostream>
#include <cmath>
#include <complex>
using namespace std ; // for the moment magic ``keyword''
template <typename T>
unsigned // return the index of the minimum
findMinimum( T a[], unsigned size ) ;
// specialize the code for complex number
template <typename T>
unsigned // return the index of the minimum
findMinimum( complex<T> a[], unsigned size ) ;
// specialize the code for complex number
template <>
unsigned // return the index of the minimum
findMinimum( complex<double> a[], unsigned size ) ;
// specialize the code for complex number
unsigned // return the index of the minimum
findMinimum( complex<double> a[], unsigned size ) ;
/*
{
cout << "Calling version 4\n" ;
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( std::abs(a[i]) < std::abs(a[imin]) ) imin = i ;
return imin ;
}
*/
int
main( /* no argument for the moment */ ) {
double a[] = {2,-3,1,2,-9,8} ; ;
unsigned ipos = findMinimum( a, sizeof(a)/sizeof(a[0]) ) ;
cout << "minimum is " << a[ipos] << " at position " << ipos << '\n' ;
complex<double> b[] = { complex<double>(1,3),
complex<double>(0,1),
complex<double>(-2,0),
complex<double>(1,3),
complex<double>(1.2,0) } ;
ipos = findMinimum( b, sizeof(b)/sizeof(b[0]) ) ;
cout << "minimum is " << b[ipos] << " at position " << ipos << '\n' ;
return 0 ; // return 0 to the OS
}
File: example7b.cc:
/*
Few example using template (preliminari part)
*/
#include <iostream>
#include <cmath>
#include <complex>
using namespace std ; // for the moment magic ``keyword''
using namespace std ; // for the moment magic ``keyword''
template <typename T>
unsigned // return the index of the minimum
findMinimum( T a[], unsigned size ) {
cout << "Calling version 1\n" ;
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( a[i] < a[imin] ) imin = i ;
return imin ;
}
// specialize the code for complex number
template <typename T>
unsigned // return the index of the minimum
findMinimum( complex<T> a[], unsigned size ) {
cout << "Calling version 2\n" ;
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( std::abs(a[i]) < std::abs(a[imin]) ) imin = i ;
return imin ;
}
// specialize the code for complex number
template <>
unsigned // return the index of the minimum
findMinimum( complex<double> a[], unsigned size ) {
cout << "Calling version 3\n" ;
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( std::abs(a[i]) < std::abs(a[imin]) ) imin = i ;
return imin ;
}
// specialize the code for complex number
unsigned // return the index of the minimum
findMinimum( complex<double> a[], unsigned size )
{
cout << "Calling version 4\n" ;
unsigned imin = 0 ;
for ( unsigned i = 1 ; i < size ; ++i )
if ( std::abs(a[i]) < std::abs(a[imin]) ) imin = i ;
return imin ;
}
// explicit instantiation
template unsigned findMinimum( complex<double> a[], unsigned size ) ;
template unsigned findMinimum( double a[], unsigned size ) ;
template unsigned findMinimum( int a[], unsigned size ) ;
template unsigned findMinimum( float a[], unsigned size ) ;
template unsigned findMinimum( short a[], unsigned size ) ;
Matrix matrix multiplication
File: mm/mm.hh:
/*
* Matrix Matrix multiplication routine
*/
#ifndef MM_HH
#define MM_HH
//
// int : integer (normally of 4 bytes) signed int
// unsigned : integer with no sign (normally of 4 bytes) unsigned int
// long : integer (normally of 8 bytes) long int
// unsigned long : nteger with no sign (normally of 8 bytes)
// short : integer (normally of 2 bytes) signed short
// unsigned short : integer with no sign (normally of 2 bytes)
//
void
mm_print( double const A[], // `vector` pointing to the matrix A
unsigned ldA, // number of row of the allocated matrix A
unsigned n_row, // number of rows
unsigned n_col ) ; // number of columns ;
void
mm_standard( double const A[], // `vector` pointing to the matrix A
unsigned ldA, // number of row of the allocated matrix A
double const B[], // `vector` pointing to the matrix B
unsigned ldB, // number of row of the allocated matrix B
double C[], // `vector` pointing to the matrix C
unsigned ldC, // number of row of the allocated matrix C
unsigned n, // number of the rows of A
unsigned p, // number of the columns of A and rows of B
unsigned m // number of the columns of B
// the results is a matrix C of n rows and m columns
) ;
#endif
File: mm/mm_utils.cc:
/*
* Matrix Matrix multiplication routine
*/
#include <iostream>
#include <iomanip>
#include "mm.hh"
#define A(I,J) A[(I)+(J)*ldA]
using namespace std ;
void
mm_print( double const A[],
unsigned ldA,
unsigned n_row,
unsigned n_col ) {
for ( unsigned i = 0 ; i < n_row ; ++i ) {
cout << A(i,0) ;
for ( unsigned j = 1 ; j < n_col ; ++j )
cout << " " << setw(10) << A(i,j) ; // setw reserve 10 space for the next output
cout << '\n' ;
}
}
File: mm/mm_standard.cc:
/*
Matrix Matrix multiplication routine
g++ -O3 -funroll-loops -sse2 -sse3 -sse3 -ssse3 -sse4.1 mm_check.cc mm_standard.cc TimeMeter.cc
5 x 5 average time 0.01
10 x 10 average time 0.004
20 x 20 average time 0.014
40 x 40 average time 0.099
80 x 80 average time 0.789
160 x 160 average time 8.526
320 x 320 average time 70.61
640 x 640 average time 981.838
1280 x 1280 average time 10938.1
2560 x 2560 average time 624531
Time Ratio [ 10/5] = 0.4
Time Ratio [ 20/10] = 3.5
Time Ratio [ 40/20] = 7.07143
Time Ratio [ 80/40] = 7.9697
Time Ratio [ 160/80] = 10.8061
Time Ratio [ 320/160] = 8.28173
Time Ratio [ 640/320] = 13.9051
Time Ratio [ 1280/640] = 11.1404
Time Ratio [ 2560/1280] = 57.0969
*/
#include "mm.hh"
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
void
mm_standard( double const A[],
unsigned ldA,
double const B[],
unsigned ldB,
double C[],
unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j ) {
C(i,j) = 0 ; // C[i+j*ldC] ;
for ( unsigned k = 0 ; k < p ; ++k )
C(i,j) += A(i,k) * B(k,j) ;
}
}
File: mm/mm_check.cc:
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include "mm.hh"
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
using namespace std ;
int
main() {
double A[9] = { 1,2,3, // first column
4,5,6, // second column
7,8,9 } ; // third column
double B[] = { 1,2,0, // first column
0,0,1, // second column
1,2,1} ; // third column
double C[100] ;
cout << "Matrix A\n" ;
mm_print( A, 3, 3, 3 ) ;
cout << "Matrix B\n" ;
mm_print( B, 3, 3, 3 ) ;
mm_standard( A, 3,
B, 3,
C, 3,
3, 3, 3 ) ;
cout << "Matrix C = A*B\n" ;
mm_print( C, 3, 3, 3 ) ;
}
File: mm/TimeMeter.hh:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2014 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Indutriale |
| Universita` degli Studi di Trento |
| Via Sommarive 9, I-38123, Povo, Trento |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 |
| |
\*--------------------------------------------------------------------------*/
// to avoid double inclusion
#ifndef TIME_METER_HH
#define TIME_METER_HH
// prototype of the function
bool
getTime( long & sec, long & usec ) ; // return seconds and microseconds from January 1, 1970
void
timeDifference( long from_sec, long from_usec,
long to_sec, long to_usec,
long & sec, long & usec ) ;
#endif
File: mm/TimeMeter.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2014 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Indutriale |
| Universita` degli Studi di Trento |
| Via Sommarive 9, I-38123, Povo, Trento |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 |
| |
\*--------------------------------------------------------------------------*/
#include "TimeMeter.hh"
/*
// _ _____ _
// __ _ ___| ||_ _(_)_ __ ___ ___
// / _` |/ _ \ __|| | | | '_ ` _ \ / _ \
// | (_| | __/ |_ | | | | | | | | | __/
// \__, |\___|\__||_| |_|_| |_| |_|\___|
// |___/
*/
#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
bool
getTime( long & sec, long & usec ) {
FILETIME ft ;
GetSystemTimeAsFileTime( &ft ) ;
// FILETIME To UNIX Time
unsigned __int64 u_sec = ft . dwHighDateTime ;
u_sec <<= 32 ;
u_sec |= ft . dwLowDateTime ;
u_sec -= 116444736000000000ULL ;
u_sec /= 10ULL ;
sec = long( u_sec / 1000000L ) ;
usec = long( u_sec % 1000000L ) ;
return true ;
}
#else
#include <sys/time.h>
bool
getTime( long & sec, long & usec ) {
struct timeval now ;
bool ok = gettimeofday(&now, NULL) == 0 ;
if ( ok ) {
sec = now . tv_sec;
usec = now . tv_usec;
} else {
sec = usec = 0 ;
}
return ok ;
}
#endif
void
timeDifference( long from_sec, long from_usec,
long to_sec, long to_usec,
long & sec, long & usec ) {
sec = to_sec - from_sec ;
usec = to_usec - from_usec ;
while ( usec < 0 ) { --sec ; usec += 1000000L ; }
while ( usec > 1000000L ) { ++sec ; usec -= 1000000L ; }
}
// EOF TimeMeter.cc
File: mm/mm_check_time.cc:
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include "mm.hh"
#include "TimeMeter.hh"
using namespace std ;
//
// Fill with random value matric A (n x m)
//
static // routine visible only in "this file"
void
fillRandom( double A[], unsigned ldA, unsigned n, unsigned m ) {
#define A(I,J) A[(I)+(J)*ldA]
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j )
A(i,j) = rand()-rand() ; // IS NOT 0!
#undef A
}
#define NREPEAT 2
#define n 640
int
main() {
// for timing
long from_sec, from_usec ;
long to_sec, to_usec ;
long sec, usec ;
// declare and allocate matrices A, B and C
static double A[n*n] ;
static double B[n*n] ;
static double C[n*n] ;
// fill matrices A, B with random numbers
fillRandom( A, n, n, n ) ;
fillRandom( B, n, n, n ) ;
getTime( from_sec, from_usec ) ;
for ( int kk = 0 ; kk < NREPEAT ; ++kk ) {
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
mm_standard( A, n, B, n, C, n, n, n, n ) ;
}
getTime( to_sec, to_usec ) ;
timeDifference( from_sec, from_usec, to_sec, to_usec, sec, usec ) ;
double elapsed = sec+1E-6*usec ;
cout << "Elapsed time = " << elapsed/NREPEAT/10 << " seconds\n" ;
return 0 ;
}
All files in a zip file
Lesson N.3 of July 16, 2014
Pointers
File: example8.cc:
/*
Some examples with pointers
*/
#include <iostream>
#include <iomanip>
using namespace std ;
int
main() {
short int vec[] = {1,2,3,4,5,6} ;
cout << "Print the vector:\n" ;
for ( int i = 0 ; i < 6 ; ++i )
cout << "vec[" << i << "] = " << vec[i] << '\n' ;
short int * pvec ; // pointer to an integer
pvec = & vec[3] ; // pvec now "point" to the 4th element of the vector
cout << "vec[3] = " << vec[3] << '\n' ;
cout << "*pvec = " << *pvec << '\n' ;
cout << "modify *pvec = 123\n" ;
*pvec = 123 ;
cout << "Print the vector:\n" ;
for ( int i = 0 ; i < 6 ; ++i )
cout << "vec[" << i << "] = " << vec[i] << '\n' ;
cout << "Loop using pointer pvec...\n" ;
int i ;
for ( i = 0, pvec = vec ; i < 6 ; ++i, ++pvec )
*pvec = 2 ;
cout << "Print the vector:\n" ;
for ( int i = 0 ; i < 6 ; ++i )
cout << "vec[" << i << "] = " << vec[i] << '\n' ;
cout << "Better Loop using pointer pvec...\n" ;
for ( pvec = vec ; pvec < vec+6 ; ++pvec )
{ cout << "Modify at address: " << pvec
<< " the value " << *pvec << '\n' ;
*pvec = 3 ; }
cout << "Print the vector:\n" ;
for ( int i = 0 ; i < 6 ; ++i )
cout << "vec[" << i << "] = " << vec[i] << '\n' ;
return 0 ;
}
Unsane C-like vector
File: mvlib/mv.hh:
/*
Simple C-like dynamic vectors/matrices
use doble, no typedef no template
*/
#include <cstddef>
// if C++ < C++11 define nullptr
#if __cplusplus <= 199711L
#include <cstdlib>
#ifndef nullptr
#include <cstddef>
#define nullptr NULL
#endif
#endif
// define a vector as a struct with the size of the vector
// and a pointer to its values
struct Vec {
int size ;
double * values ;
} ;
void Initialize( struct Vec & vec ) ;
void Allocate( struct Vec & vec, int size ) ;
void Free( struct Vec & vec ) ;
File: mvlib/mv.cc:
#include "mv.hh"
// initialize structure to a vector of size 0
void
Initialize( struct Vec & vec ) {
vec.size = 0 ;
vec.values = nullptr ;
}
// alocate a vector to teh size: size
void
Allocate( struct Vec & vec, int size ) {
vec.size = size ;
// check if alreay allocated
if ( vec.values != nullptr ) delete [] vec.values ;
vec.values = new double[size] ;
}
void
Free( struct Vec & vec ) {
// check if alreay de-allocated
if ( vec.values != nullptr ) delete [] vec.values ;
vec.size = 0 ;
}
File: mvlib/mv_test.cc:
#include "mv.hh"
int
main() {
struct Vec a, b, c ;
double pippo = 1234 ;
c.values = &pippo ; // force error....
Initialize(a) ;
Initialize(b) ;
Allocate( a, 100 ) ;
Allocate( b, 100 ) ;
Allocate( c, 100 ) ;
Free( a ) ;
Free( b ) ;
Free( c ) ;
}
Unsane C-like vector/matrix functions
File: mvlib2/mv.hh:
/*
Simple C-like dynamic vectors/matrices
use doble, no typedef no template
*/
#include <cstddef>
// if C++ < C++11 define nullptr
#if __cplusplus <= 199711L
#include <cstdlib>
#ifndef nullptr
#include <cstddef>
#define nullptr NULL
#endif
#endif
// define a vector as a struct with the size of the vector
// and a pointer to its values
struct Vec {
int size ;
double * values ;
} ;
struct Mat {
int nrow, ncol ;
double * memory_block ; // allocated memory for the matrix
double ** values ; // pointer to the rows of the matrix
} ;
void Initialize( struct Vec & vec ) ;
void Allocate( struct Vec & vec, int size ) ;
void Fill( struct Vec & mat, double val ) ;
void Free( struct Vec & vec ) ;
void Initialize( struct Mat & mat ) ;
void Allocate( struct Mat & mat, int nrow, int ncol ) ;
void AllocateAndInitializeRandom( struct Mat & mat, int nrow, int ncol ) ;
void Fill( struct Mat & mat, double val ) ;
void Free( struct Mat & mat ) ;
void
Mat_x_Vec( struct Mat const & mat, // ensure the compiler that mat is not modified inside...
struct Vec const & vec,
struct Vec & res ) ;
void
Mat_x_Mat_123( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_132( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_213( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_231( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_312( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_321( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) ;
void
Mat_x_Mat_with_tiling( struct Mat const & A,
struct Mat const & B,
struct Mat & C,
int tsize ) ;
File: mvlib2/mv_vec.cc:
#include "mv.hh"
// initialize structure to a vector of size 0
void
Initialize( struct Vec & vec ) {
vec.size = 0 ;
vec.values = nullptr ;
}
// alocate a vector to teh size: size
void
Allocate( struct Vec & vec, int size ) {
vec.size = size ;
// check if alreay allocated
if ( vec.values != nullptr ) delete [] vec.values ;
vec.values = new double[size] ;
}
void
Fill( struct Vec & vec, double val ) {
for ( int i = 0 ; i < vec.size ; ++i )
vec.values[i] = val ;
}
void
Free( struct Vec & vec ) {
// check if alreay de-allocated
if ( vec.values != nullptr ) delete [] vec.values ;
vec.size = 0 ;
}
File: mvlib2/mv_mat.cc:
#include "mv.hh"
#include <iostream>
#include <stdlib.h> // for rand() function
using namespace std ;
// initialize structure to a matrix of size 0 x 0
void
Initialize( struct Mat & mat ) {
mat.nrow = 0 ;
mat.ncol = 0 ;
mat.memory_block = nullptr ;
mat.values = nullptr ;
}
// alocate a matrix to the size: nrow x ncol
void
Allocate( struct Mat & mat, int nrow, int ncol ) {
if ( mat.nrow == nrow && mat.ncol == ncol ) return ; // nothing to do!
mat.nrow = nrow ;
mat.ncol = ncol ;
if ( mat.memory_block != nullptr ) delete [] mat.memory_block ;
mat.memory_block = new double [nrow*ncol] ;
if ( mat.values != nullptr ) delete [] mat.values ;
mat.values = new double* [nrow] ;
// initialize the pointer of pointer
for ( int i = 0 ; i < nrow ; ++i )
mat.values[i] = mat.memory_block + i * ncol ;
}
void
AllocateAndInitializeRandom( struct Mat & mat, int nrow, int ncol ) {
Allocate( mat, nrow, ncol ) ;
for ( int i = 0 ; i < mat.nrow ; ++i )
for ( int j = 0 ; j < mat.ncol ; ++j )
mat.values[i][j] = rand() - rand() ;
}
void
Fill( struct Mat & mat, double val ) {
for ( int i = 0 ; i < mat.nrow ; ++i )
for ( int j = 0 ; j < mat.ncol ; ++j )
mat.values[i][j] = val ;
}
void
Mat_x_Vec( struct Mat const & mat, // ensure the compiler that mat is not modified inside...
struct Vec const & vec,
struct Vec & res ) {
// check matrix vector compatibility
if ( mat.ncol != vec.size ) {
cerr << "Mat_x_Vec, incompatible dimensions\n" ;
exit(0) ;
}
if ( res.size != mat.nrow ) Allocate( res, mat.nrow ) ;
for ( int i = 0 ; i < mat.nrow ; ++i ) {
res.values[i] = 0 ;
for ( int j = 0 ; j < mat.ncol ; ++i )
res.values[i] += mat.values[i][j]*vec.values[j] ;
}
}
void
Mat_x_Mat_123( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_123, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_132( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_132, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_213( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_213, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_231( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_231, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_312( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_312, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_321( struct Mat const & A,
struct Mat const & B,
struct Mat & C ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_321, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int k = 0 ; k < A.ncol ; ++k ) // 3
for ( int j = 0 ; j < B.ncol ; ++j ) // 2
for ( int i = 0 ; i < A.nrow ; ++i ) // 1
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
void
Mat_x_Mat_with_tiling( struct Mat const & A,
struct Mat const & B,
struct Mat & C,
int tsize ) {
// check compatibility
if ( A.ncol != B.nrow ) {
cerr << "Mat_x_Mat_321, incompatible dimensions\n" ;
exit(0) ;
}
// initialize matrix C
Allocate( C, A.nrow, B.ncol ) ;
// set to 0
Fill( C, 0 ) ; // 0 int --> convertex 0 double
for ( int ii = 0 ; ii < A.nrow ; ii += tsize ) { // 1
int ii_max = std::min(ii + tsize, A.nrow) ;
for ( int kk = 0 ; kk < A.ncol ; kk += tsize ) { // 3
int kk_max = std::min(kk + tsize, A.ncol) ;
for ( int jj = 0 ; jj < B.ncol ; jj += tsize ) { // 2
int jj_max = std::min(jj + tsize, B.ncol) ;
for ( int i = ii ; i < ii_max ; ++i ) // 1
for ( int k = kk ; k < kk_max ; ++k ) // 3
for ( int j = jj ; j < jj_max ; ++j ) // 2
C.values[i][j] += A.values[i][k]*B.values[k][j] ;
}
}
}
}
void
Free( struct Mat & mat ) {
// check if alreay de-allocated
if ( mat.memory_block != nullptr ) delete [] mat.memory_block ;
if ( mat.values != nullptr ) delete [] mat.values ;
mat.nrow = 0 ;
mat.ncol = 0 ;
}
File: mvlib2/mv_test.cc:
#include "mv.hh"
#include "TimeMeter.hh"
#include <iostream>
using namespace std ;
#define TEST(MM) \
timeStart() ; \
for ( int i = 0 ; i < NLOOP ; ++i ) { \
MM( A, B, C ) ; \
MM( C, B, A ) ; \
MM( A, B, C ) ; \
MM( C, B, A ) ; \
MM( A, B, C ) ; \
MM( C, B, A ) ; \
MM( A, B, C ) ; \
MM( C, B, A ) ; \
MM( A, B, C ) ; \
MM( C, B, A ) ; \
} \
elapsed = timeStop() ; \
cout << #MM << " time = " << elapsed/(10*NLOOP) << '\n'
#define TESTT(TS) \
timeStart() ; \
for ( int i = 0 ; i < NLOOP ; ++i ) { \
Mat_x_Mat_with_tiling( A, B, C, TS ) ; \
Mat_x_Mat_with_tiling( C, B, A, TS ) ; \
Mat_x_Mat_with_tiling( A, B, C, TS ) ; \
Mat_x_Mat_with_tiling( C, B, A, TS ) ; \
Mat_x_Mat_with_tiling( A, B, C, TS ) ; \
Mat_x_Mat_with_tiling( C, B, A, TS ) ; \
Mat_x_Mat_with_tiling( A, B, C, TS ) ; \
Mat_x_Mat_with_tiling( C, B, A, TS ) ; \
Mat_x_Mat_with_tiling( A, B, C, TS ) ; \
Mat_x_Mat_with_tiling( C, B, A, TS ) ; \
} \
elapsed = timeStop() ; \
cout << "Mat_x_Mat_with_tiling(" << TS << ") time = " << elapsed/(10*NLOOP) << '\n'
int
main() {
struct Vec a, b, c ;
struct Mat A, B, C ;
Initialize(a) ;
Initialize(b) ;
Initialize(c) ;
Initialize(A) ;
Initialize(B) ;
Initialize(C) ;
Allocate( a, 100 ) ;
Allocate( b, 100 ) ;
Allocate( c, 100 ) ;
int N = 500 ;
AllocateAndInitializeRandom( A, N, N ) ;
AllocateAndInitializeRandom( B, N, N ) ;
Allocate( C, N, N ) ;
int NLOOP = 2 ;
timeStart() ;
for ( int i = 0 ; i < NLOOP ; ++i ) {
Mat_x_Mat_123( A, B, C ) ;
Mat_x_Mat_123( C, B, A ) ;
Mat_x_Mat_123( A, B, C ) ;
Mat_x_Mat_123( C, B, A ) ;
Mat_x_Mat_123( A, B, C ) ;
Mat_x_Mat_123( C, B, A ) ;
Mat_x_Mat_123( A, B, C ) ;
Mat_x_Mat_123( C, B, A ) ;
Mat_x_Mat_123( A, B, C ) ;
Mat_x_Mat_123( C, B, A ) ;
}
double elapsed = timeStop() ;
cout << "Mat_x_Mat_123 time = " << elapsed/(10*NLOOP) << '\n' ;
TEST(Mat_x_Mat_132) ;
TEST(Mat_x_Mat_213) ;
TEST(Mat_x_Mat_231) ;
TEST(Mat_x_Mat_312) ;
TEST(Mat_x_Mat_321) ;
TESTT( 10 ) ;
TESTT( 20 ) ;
TESTT( 40 ) ;
TESTT( 80 ) ;
TESTT( 120 ) ;
TESTT( 160 ) ;
Free( a ) ;
Free( b ) ;
Free( c ) ;
Free( A ) ;
Free( B ) ;
Free( C ) ;
}
File: mvlib2/TimeMeter.hh:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2014 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Indutriale |
| Universita` degli Studi di Trento |
| Via Sommarive 9, I-38123, Povo, Trento |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 |
| |
\*--------------------------------------------------------------------------*/
// to avoid double inclusion
#ifndef TIME_METER_HH
#define TIME_METER_HH
// prototype of the function
bool
getTime( long & sec, long & usec ) ; // return seconds and microseconds from January 1, 1970
void
timeDifference( long from_sec, long from_usec,
long to_sec, long to_usec,
long & sec, long & usec ) ;
static long from_sec, from_usec ;
inline
bool
timeStart() {
return getTime( from_sec, from_usec ) ;
}
inline
double
timeStop() {
long to_sec, to_usec, sec, usec;
getTime( to_sec, to_usec ) ;
timeDifference( from_sec, from_usec, to_sec, to_usec, sec, usec ) ;
return sec+1E-6*usec ;
}
#endif
File: mvlib2/TimeMeter.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2014 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Indutriale |
| Universita` degli Studi di Trento |
| Via Sommarive 9, I-38123, Povo, Trento |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 |
| |
\*--------------------------------------------------------------------------*/
#include "TimeMeter.hh"
/*
// _ _____ _
// __ _ ___| ||_ _(_)_ __ ___ ___
// / _` |/ _ \ __|| | | | '_ ` _ \ / _ \
// | (_| | __/ |_ | | | | | | | | | __/
// \__, |\___|\__||_| |_|_| |_| |_|\___|
// |___/
*/
#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
bool
getTime( long & sec, long & usec ) {
FILETIME ft ;
GetSystemTimeAsFileTime( &ft ) ;
// FILETIME To UNIX Time
unsigned __int64 u_sec = ft . dwHighDateTime ;
u_sec <<= 32 ;
u_sec |= ft . dwLowDateTime ;
u_sec -= 116444736000000000ULL ;
u_sec /= 10ULL ;
sec = long( u_sec / 1000000L ) ;
usec = long( u_sec % 1000000L ) ;
return true ;
}
#else
#include <sys/time.h>
bool
getTime( long & sec, long & usec ) {
struct timeval now ;
bool ok = gettimeofday(&now, NULL) == 0 ;
if ( ok ) {
sec = now . tv_sec;
usec = now . tv_usec;
} else {
sec = usec = 0 ;
}
return ok ;
}
#endif
void
timeDifference( long from_sec, long from_usec,
long to_sec, long to_usec,
long & sec, long & usec ) {
sec = to_sec - from_sec ;
usec = to_usec - from_usec ;
while ( usec < 0 ) { --sec ; usec += 1000000L ; }
while ( usec > 1000000L ) { ++sec ; usec -= 1000000L ; }
}
// EOF TimeMeter.cc
All files in a zip file
Lesson N.4 of July 17, 2014
Matrix Vector example with methods
Matrix Vector example, adding some operators
Matrix Vector example, add data protection
Matrix Vector example, introduced classes with constructors and destructors
Lesson N.5 of July 18, 2014
Added constructors, TimeMeter now is a class
Added stream
Copy contructor and operator, some external operators
Lesson N.6 of July 21, 2014
Added templates
Example of use STL vector class
File: example10.cc:
/*
Some example of use of STL vector.
*/
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std ;
typedef long int value_type ;
int
main() {
vector<value_type> a, b(2) ;
cout << "Size a = " << a.size() << '\n' ;
cout << "Size b = " << b.size() << '\n' ;
a.reserve(100) ;
for ( int i = 0 ; i < 10 ; ++i ) a.push_back(i*i) ;
for ( int i = 0 ; i < 10 ; ++i )
cout << "a[ " << i << "] = " << a[i] << '\n';
// access the element by iterators
//vector<int>::value_type ; // the type of the element of a vector<int>
//vector<int>::iterator ; // the type of a "pointer" of an element of a vector
for ( vector<value_type>::iterator it = a.begin() ; it != a.end() ; ++it )
cout << "a[ " << it-a.begin() << "] = " << *it << '\n';
a.clear() ;
a.push_back(23) ;
a.push_back(3) ;
a.push_back(-33) ;
a.push_back(2) ;
a.push_back(5) ;
a.push_back(-53) ;
a.push_back(21) ;
cout << "Size of a = " << a.size() << '\n' ;
cout << "Capacity of a = " << a.capacity() << '\n' ;
cout << "a = " ;
for ( vector<value_type>::iterator it = a.begin() ; it != a.end() ; ++it )
cout << *it << ' ' ;
cout << '\n' ;
sort(a.begin(),a.end()) ;
cout << "a (sorted) = " ;
for ( vector<value_type>::iterator it = a.begin() ; it != a.end() ; ++it )
cout << *it << ' ' ;
cout << '\n' ;
reverse(a.begin(),a.end()) ;
cout << "a (reversed) = " ;
for ( vector<value_type>::iterator it = a.begin() ; it != a.end() ; ++it )
cout << *it << ' ' ;
cout << '\n' ;
return 0 ;
}
Lesson N.7 of July 22, 2014
A simple polynomial class
File: poly.hh:
/*
Simple polynomial class
*/
#include <cstddef>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
// if C++ < C++11 define nullptr
#if __cplusplus <= 199711L
#include <cstdlib>
#ifndef nullptr
#include <cstddef>
#define nullptr NULL
#endif
#endif
namespace Polynomial {
using namespace std ;
template <typename T>
inline
void
prettyPrint( ostream & stream, vector<T> const & a ) {
bool first = true ;
for ( int n = 0 ; n < a.size() ; ++n ) {
T an = a[n] ;
if ( abs(an) > 0 ) {
if ( !first ) stream << " + " ;
if ( n == 0 ) {
stream << an ;
} else {
if ( abs(an) != 1 ) stream << an << " * " ;
if ( n > 1 ) stream << "x^" << n ;
else stream << "x" ;
}
first = false ;
}
}
if ( first ) stream << "0" ;
}
// eliminates unused zeros
template <typename T>
inline
void
true_degree( vector<T> & coeffs_res ) {
// lower the degree if necessary
while ( coeffs_res.size() > 0 && coeffs_res.back() == 0 ) coeffs_res.pop_back() ;
}
// res = a
template <typename T>
inline
void
negate( vector<T> & coeffs ) {
for ( int i = 0 ; i < coeffs.size() ; ++i ) coeffs[i] = -coeffs[i] ;
}
// res = a
template <typename T>
inline
void
copy( vector<T> const & coeffs_a,
vector<T> & coeffs_res ) {
coeffs_res.resize(coeffs_a.size()) ;
copy( coeffs_a.begin(), coeffs_a.end(), coeffs_res.begin() ) ;
}
// res += a
template <typename T>
inline
void
add_to( vector<T> const & coeffs_a,
vector<T> & coeffs_res ) {
// if necessary add element initialized to 0
if ( coeffs_res.size() < coeffs_a.size() ) coeffs_res.resize(coeffs_a.size(),0) ;
for ( int i = 0 ; i < coeffs_a.size() ; ++i ) coeffs_res[i] += coeffs_a[i] ;
// lower the degree if necessary
true_degree( coeffs_res ) ;
}
// res -= a
template <typename T>
inline
void
sub_to( vector<T> const & coeffs_a,
vector<T> & coeffs_res ) {
// if necessary add element initialized to 0
if ( coeffs_res.size() < coeffs_a.size() ) coeffs_res.resize(coeffs_a.size(),0) ;
for ( int i = 0 ; i < coeffs_a.size() ; ++i ) coeffs_res[i] -= coeffs_a[i] ;
// lower the degree if necessary
true_degree( coeffs_res ) ;
}
// res *= scalar
template <typename T>
inline
void
mul_to( T scalar, vector<T> & coeffs_res ) {
for ( int i = 0 ; i < coeffs_res.size() ; ++i ) coeffs_res[i] *= scalar ;
// lower the degree if necessary
true_degree( coeffs_res ) ;
}
// res /= scalar
template <typename T>
inline
void
div_to( T scalar, vector<T> & coeffs_res ) {
// add check if scalar is 0
for ( int i = 0 ; i < coeffs_res.size() ; ++i ) coeffs_res[i] /= scalar ;
}
// res *= a --> res = res * a
template <typename T>
inline
void
mul_to( vector<T> const & coeffs_a, vector<T> & coeffs_res ) {
int res_degre = coeffs_res.size() ;
int a_degre = coeffs_a.size() ;
coeffs_res.resize( res_degre + a_degre, 0 ) ;
for ( int i = res_degre ; i >= 0 ; --i ) {
T tmp = coeffs_res[i] ;
coeffs_res[i] = 0 ;
for ( int j = 0 ; j <= a_degre ; ++j ) coeffs_res[i+j] += tmp * coeffs_a[j] ;
}
// lower the degree if necessary
true_degree( coeffs_res ) ;
}
// s ~ a/b --> a = b * s + r
template <typename T>
inline
void
div( vector<T> const & coeffs_a,
vector<T> const & coeffs_b,
vector<T> & coeffs_s,
vector<T> & coeffs_r ) {
int degreea = coeffs_a.size()-1 ;
int degreeb = coeffs_b.size()-1 ;
if ( degreeb > degreea) {
// a = b * 0 + a
coeffs_s.resize(1,0) ; // s = 0
coeffs_r.resize(coeffs_a.size()) ;
copy( coeffs_a.begin(), coeffs_a.end(), coeffs_r.begin() ) ;
} else {
coeffs_s.resize( coeffs_a.size() - coeffs_b.size() + 1 ) ;
coeffs_r.resize( coeffs_a.size() ) ;
copy( coeffs_a.begin(), coeffs_a.end(), coeffs_r.begin() ) ; // r = 0
for ( int i = degreea ; i >= degreeb ; --i ) {
// eliminate a[i]*x^i to polinomial a
// by subtracting b*x^(i-degreeb)*(a[i]/b[degreeb]) ;
T tmp = coeffs_r[i]/coeffs_b[degreeb] ;
for ( int j = 0 ; j <= degreeb ; ++j )
coeffs_r[j+i-degreeb] -= tmp * coeffs_b[j] ;
coeffs_s[i-degreeb] = tmp ;
}
coeffs_r.resize(degreeb) ;
// lower the degree if necessary
true_degree( coeffs_r ) ;
}
}
// s ~ a/b --> a = b * s + r
template <typename T>
inline
void
derivative( vector<T> const & coeffs_a,
vector<T> & coeffs_res ) {
coeffs_res.resize( coeffs_a.size() - 1 ) ;
for ( int i = coeffs_a.size()-1 ; i > 0 ; --i )
coeffs_res[i-1] = coeffs_a[i]*i ;
}
// s ~ a/b --> a = b * s + r
template <typename T>
inline
T
evaluate( T x, vector<T> const & coeffs_a ) {
int degree_a = coeffs_a.size()-1 ;
T res = 0 ;
for ( int i = degree_a ; i >= 0 ; --i )
res = res * x + coeffs_a[i] ;
}
template <typename T>
class Poly {
vector<T> coeffs ;
public:
Poly() {}
~Poly() {}
void clear() { coeffs.clear() ; }
// degree of polynomial
int degree() const { return coeffs.size() -1 ; }
void
setup( T const cf[], int degree ) {
coeffs.resize( degree+1 ) ;
// for ( int i = 0 ; i <= degree ; ++i ) coeffs[i] = cf[i] ;
// cf = pointer (iterator) to first element cf
// cf + degree + 1 = pointer (iterator) to past to the last element of cf
// coeffs.begin() = iterator pointing to the begin of the vector coeffs
copy( cf, cf + degree + 1, coeffs.begin() ) ;
}
void
setup( vector<T> const & cf ) {
coeffs.resize( cf.size() ) ;
copy( cf.begin(), cf.end(), coeffs.begin() ) ;
}
Poly<T> const & operator = ( Poly<T> const & a )
{ copy( a.coeffs, coeffs ) ; return *this ; }
Poly<T> const & operator += ( Poly<T> const & a )
{ add_to( a.coeffs, coeffs ) ; return *this ; }
Poly<T> const & operator -= ( Poly<T> const & a )
{ sub_to( a.coeffs, coeffs ) ; return *this ; }
Poly<T> const & operator *= ( Poly<T> const & a )
{ mul_to( a.coeffs, coeffs ) ; return *this ; }
Poly<T> const & operator *= ( T a )
{ mul_to( a, coeffs ) ; return *this ; }
Poly<T> const & operator /= ( T a )
{ div_to( a, coeffs ) ; return *this ; }
T operator [] ( int index ) const { return coeffs[index] ; }
void
remainder( Poly<T> const & b, Poly<T> & s, Poly<T> & r ) const {
// perform division of *this by b
// i.e. *this = b * s + r ;
div( this->coeffs, b.coeffs, s.coeffs, r.coeffs ) ;
}
Poly<T>
derivative() const {
Poly<T> res ;
Polynomial::derivative(coeffs,res.coeffs) ;
return res ;
}
Poly<T> const &
negate() {
Polynomial::negate(coeffs) ;
return *this ;
}
vector<T> const & get_coeffs() const { return coeffs ; }
// insert elements on polynomial
Poly<T> & operator << ( T value ) { coeffs.push_back(value) ; return *this ; }
} ;
/*
// __
// _ __/\__ / /
// _| |_\ /_____ / /
// |_ _/_ _\_____/ /
// |_| \/ /_/
*/
template <typename T>
inline
Poly<T>
operator + ( Poly<T> const & a, Poly<T> const & b ) {
Poly<T> tmp ;
tmp = a ;
tmp += b ;
return tmp ;
}
template <typename T>
inline
Poly<T>
operator - ( Poly<T> const & a, Poly<T> const & b ) {
Poly<T> tmp ;
tmp = a ;
tmp -= b ;
return tmp ;
}
template <typename T>
inline
Poly<T>
operator * ( Poly<T> const & a, Poly<T> const & b ) {
Poly<T> tmp ;
tmp = a ;
tmp *= b ;
return tmp ;
}
template <typename T>
inline
Poly<T>
operator * ( T a, Poly<T> const & b ) {
Poly<T> tmp ;
tmp = b ;
tmp *= a ;
return tmp ;
}
template <typename T>
inline
Poly<T>
operator * ( Poly<T> const & b, T a ) {
Poly<T> tmp ;
tmp = b ;
tmp *= a ;
return tmp ;
}
/*
// ___ _____
// |_ _| / / _ \
// | | / / | | |
// | | / /| |_| |
// |___/_/ \___/
*/
template <typename T>
inline
ostream &
operator << ( ostream & stream, Poly<T> const & a ) {
prettyPrint( stream, a.get_coeffs() ) ;
return stream ;
}
/*
// ____ _
// / ___|| |_ _ _ _ __ _ __ ___
// \___ \| __| | | | '__| '_ ` _ \
// ___) | |_| |_| | | | | | | | |
// |____/ \__|\__,_|_| |_| |_| |_|
*/
template <typename T>
inline
void
sturm( Poly<T> const & a, Poly<T> const & b, vector<Poly<T> > & seq ) {
seq.clear() ;
if ( a.degree() > b.degree() ) {
seq.push_back(a) ;
seq.push_back(b) ;
} else {
seq.push_back(b) ;
seq.push_back(a) ;
}
Poly<T> s, r ;
while ( seq.back().degree() > 0 ) {
Poly<T> & a = seq[seq.size()-2] ;
Poly<T> & b = seq.back() ;
a.remainder( b, s, r ) ;
//cout << " r = " << r << " degree = " << r.degree() << '\n' ;
seq.push_back(r.negate()) ;
}
// check the last residual, if is = 0 the true
// sturm sequence must be divided by the penultimate
// computed residual.
if ( std::abs(r[0]) < 1e-10 ) {
// multiple roots, remove it
seq.pop_back() ; // remove last residual
r = seq.back() ;
for ( typename vector<Poly<T> >::iterator it = seq.begin() ;
it != seq.end() ; ++it ) {
cout << "poly = " << *it << '\n' ;
Poly<T> tmp1, tmp2 ;
// *it / r --> *it ;
//(*it).remainder( b, s, r ) ;
it -> remainder( r, tmp1, tmp2 ) ;
*it = tmp1 ;
}
}
}
}
File: poly_test.cc:
#include "poly.hh"
#include "TimeMeter.hh"
#include <iostream>
using namespace std ;
typedef float valueType ; // alias of double to valueType
int
main() {
Polynomial::Poly<valueType> a, b, c ;
valueType const a_coeffs[] = { 1, 0, 2 } ; // 1+ 2*x^2
valueType const b_coeffs[] = { 1,1,1,1,1 } ; //1+x+x^2+x^3+x^4 ;
valueType const c_coeffs[] = { 1 } ; // 1
a.setup( a_coeffs, 2 ) ;
b.setup( b_coeffs, 4 ) ;
c.setup( c_coeffs, 0 ) ;
cout << " a= " << a << '\n' ;
cout << " b= " << b << '\n' ;
cout << " c= " << c << '\n' ;
cout << " a*b = " << a*b << '\n' ;
Polynomial::Poly<valueType> s, r ;
b.remainder( a, s, r ) ;
cout << " s = " << s << '\n' ;
cout << " r = " << r << '\n' ;
cout << " degree r = " << r.degree() << '\n' ;
a.clear() ;
//a << -1 << -1 << 0 << 1 << 1 ;
//a << 2 << -10 << -20 << 0 << 5 << 1 ;
a << 0 << 0 << -1 << -3 << 0 << 0 << 0 << 1 << 123;
b = a.derivative() ;
vector<Polynomial::Poly<valueType> > seq ;
Polynomial::sturm( a, b, seq ) ;
cout << "Sturm:\n" ;
for ( int i = 0 ; i < seq.size() ; ++i )
cout << i << " " << seq[i] << '\n' ;
}
Lesson N.8 of July 23, 2014
wrap a problem into a class
File: example11.cc:
/*
wrap a problem into a class
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
class Problem {
double a ;
public:
Problem( ) : a(0) { std::cout << "call constuctor 1\n" ; }
Problem( double _a ) : a(_a) { std::cout << "call constuctor 2\n" ; }
double f( double x ) const { return x*x-a ; }
double df( double x ) const { return 2*x ; }
} ;
// Newton--Raphson
bool
Newton( Problem & pb,
double & x, // x is the guess and at exit the approximate solution
int max_iter,
double tol ) {
for ( int i = 0 ; i < max_iter ; ++i ) {
double h = pb.f(x)/pb.df(x) ;
x -= h ;
if ( std::abs(h) < tol ) return true ;
}
return false ;
}
int
main() {
Problem pb1(2) ;
double x = 2 ;
bool ok = Newton( pb1, x, 10, 1E-10 ) ;
if ( ok ) {
std::cout << "Newton converged, x = " << x << '\n' ;
} else {
std::cout << "Newton failed, x = " << x << '\n' ;
}
return 0 ;
}
use template for the solver
File: example12.cc:
/*
Use template for the solver
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
class Problem1 {
double a ;
public:
Problem1( ) : a(0) { std::cout << "call constuctor 1\n" ; }
Problem1( double _a ) : a(_a) { std::cout << "call constuctor 2\n" ; }
double f( double x ) const { return x*x-a ; }
double df( double x ) const { return 2*x ; }
} ;
class Problem2 {
public:
Problem2( ) { std::cout << "call constuctor 1 (Problem2) \n" ; }
double f( double x ) const { return exp(x)-3 ; }
double df( double x ) const { return exp(x) ; }
} ;
// Newton--Raphson
template <typename PROBLEM>
inline
bool
Newton( PROBLEM & pb,
double & x, // x is the guess and at exit the approximate solution
int max_iter,
double tol ) {
for ( int i = 0 ; i < max_iter ; ++i ) {
double h = pb.f(x)/pb.df(x) ;
x -= h ;
if ( std::abs(h) < tol ) return true ;
}
return false ;
}
int
main() {
Problem1 pb1(2) ;
Problem2 pb2 ;
double x = 2 ;
bool ok = Newton( pb1, x, 10, 1E-10 ) ;
if ( ok ) {
std::cout << "Newton converged, x = " << x << '\n' ;
} else {
std::cout << "Newton failed, x = " << x << '\n' ;
}
x = 2 ;
ok = Newton( pb2, x, 10, 1E-10 ) ;
if ( ok ) {
std::cout << "Newton converged, x = " << x << '\n' ;
} else {
std::cout << "Newton failed, x = " << x << '\n' ;
}
return 0 ;
}
Use inheritance
File: example13.cc:
/*
Inheritance and usage of it
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
class Problem {
public:
Problem( ) { std::cout << "call constuctor Problem class\n" ; }
virtual double f( double x ) const = 0 ;
virtual double df( double x ) const = 0 ;
} ;
class Problem1 : public Problem {
double a ;
public:
Problem1( ) : a(0) { std::cout << "call constuctor Problem1\n" ; }
Problem1( double _a ) : a(_a) { std::cout << "call constuctor Problem1\n" ; }
virtual double f( double x ) const { return x*x-a ; }
virtual double df( double x ) const { return 2*x ; }
} ;
class Problem2 : public Problem {
public:
Problem2( ) { std::cout << "call constuctor 1 Problem2 \n" ; }
virtual double f( double x ) const { return exp(x)-3 ; }
virtual double df( double x ) const { return exp(x) ; }
} ;
// Newton--Raphson
bool
Newton( Problem * pb,
double & x, // x is the guess and at exit the approximate solution
int max_iter,
double tol ) {
for ( int i = 0 ; i < max_iter ; ++i ) {
double h = pb->f(x)/pb->df(x) ;
x -= h ;
if ( std::abs(h) < tol ) return true ;
}
return false ;
}
int
main() {
Problem1 pb1(2) ;
Problem2 pb2 ;
double x = 2 ;
bool ok = Newton( &pb1, x, 10, 1E-10 ) ;
if ( ok ) {
std::cout << "Newton converged, x = " << x << '\n' ;
} else {
std::cout << "Newton failed, x = " << x << '\n' ;
}
x = 2 ;
ok = Newton( &pb2, x, 10, 1E-10 ) ;
if ( ok ) {
std::cout << "Newton converged, x = " << x << '\n' ;
} else {
std::cout << "Newton failed, x = " << x << '\n' ;
}
return 0 ;
}
A BVP solver
File: bvp.hh:
#ifndef BVP_HH
#define BVP_HH
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
/*
*/
class BVP {
public:
typedef double value_type ;
private:
std::vector<value_type> x, y ;
public:
BVP( ) { std::cout << "call constuctor BVP class\n" ; }
virtual ~BVP( ) { std::cout << "call descructor BVP class\n" ; }
virtual value_type p( value_type x ) const = 0 ;
virtual value_type q( value_type x ) const = 0 ;
virtual value_type r( value_type x ) const = 0 ;
void
solve( value_type a, value_type Ya,
value_type b, value_type Yb,
int N ) ;
std::vector<value_type> const & get_x() const { return x ; }
std::vector<value_type> const & get_y() const { return y ; }
} ;
#endif
File: bvp.cc:
#include "bvp.hh"
/*
*/
/*
Solve BVP
y''(x) + p(x) y'(x) + q(x) y(x) = r(x)
y(a) = Ya, y(b) = Yb
=================
y[k-1]-2*y[k]+y[k+1] y[k+1]-y[k-1]
-------------------- + p(x[k]) ------------- + q(x[k]) * y[k] = r(x[k])
h*h 2*h
y[0] = Ya
y[N] = Yb
=================
y[k-1] * ( 1 - h*p(x[k])/2 ) +
y[k] * ( -2 + (h*h)*q(x[k]) ) +
y[k+1] * ( 1 + h*p(x[k])/2 ) = (h*h)*r(x[k])
=================
alpha[k] * y[k-1] + beta[k] * y[k] + gamma[k] * y[k+1] = omega[k]
alpha[k] = 1 - h*p(x[k])/2 ;
beta[k] = -2 + (h*h)*q(x[k]) ;
gamma[k] = 1 + h*p(x[k])/2 ;
omega[k] = (h*h)*r(x[k]) ;
=================
*/
using namespace std ;
void
BVP::solve( value_type a, value_type Ya,
value_type b, value_type Yb,
int N ) {
vector<value_type> alpha(N+1), beta(N+1), gamma(N+1), omega(N+1) ;
value_type h = (b-a)/N ;
// equation of the first BC
alpha[0] = 0 ;
beta[0] = 1 ;
gamma[0] = 0 ;
omega[0] = Ya ;
// equation of the second BC
alpha[N] = 0 ;
beta[N] = 1 ;
gamma[N] = 0 ;
omega[N] = Yb ;
// fill the lienear system
value_type h2 = h*h ;
x.resize(N+1) ;
y.resize(N+1) ;
x[0] = a ;
x[N] = b ;
for ( int k = 1 ; k < N ; ++k ) {
value_type xk = a+h*k ;
value_type bf = h*p(xk)/2 ;
x[k] = xk ;
alpha[k] = 1 - bf ;
beta[k] = -2 + h2*q(xk) ;
gamma[k] = 1 + bf ;
omega[k] = h2*r(xk) ;
}
// solve linear system and compute y
// eliminate lower diagonal
for ( int k = 1 ; k <= N ; ++k ) {
value_type bf = alpha[k]/beta[k-1] ;
beta[k] -= bf*gamma[k-1] ;
omega[k] -= bf*omega[k-1] ;
}
// solve bidiagonal system
y[N] = omega[N] / beta[N] ;
for ( int k = N-1 ; k >= 0 ; --k ) y[k] = (omega[k] - gamma[k]*y[k+1]) / beta[k] ;
}
File: bvp_test.cc:
#include "bvp.hh"
#include <iomanip>
using namespace std ;
/*
y'' + y' - 3*y = 9*exp(3*x) -6
y(0) = 3
y(1) = exp(3)+2
// exact solution
y(x) = exp(3*x) + 2
*/
class my_BVP : public BVP {
public:
virtual value_type p( value_type x ) const { return 1 ; }
virtual value_type q( value_type x ) const { return -3 ; }
virtual value_type r( value_type x ) const { return 9*exp(3*x) - 6 ; }
value_type exact( value_type x ) const { return exp(3*x) + 2 ; }
void
solve( value_type a, value_type b, int N )
{ BVP::solve( a, exact(a), b, exact(b), N ) ; }
};
int
main() {
my_BVP bvp ;
bvp.solve( 0, 1, 100 ) ;
vector<BVP::value_type> const & x = bvp.get_x() ;
vector<BVP::value_type> const & y = bvp.get_y() ;
cout << setw(4) << "index"
<< " " << setw(12) << "x"
<< " " << setw(12) << "y"
<< " " << setw(12) << "esatta"
<< '\n' ;
for ( int i = 0 ; i <= 100 ; ++i )
cout << setw(4) << i
<< " " << setw(12) << x[i]
<< " " << setw(12) << y[i]
<< " " << setw(12) << bvp.exact(x[i])
<< '\n' ;
return 0 ;
}
All the files in one zip file
Lesson N.9 of July 24, 2014
C and C++ string
File: example14.cc:
/*
Inheritance and usage of it
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string.h> // for strlen
#include <string> // C++ string
using namespace std ;
/*
print character inserted by number
*/
int
main() {
cout << "Digit 0\n" ;
cout << "Digit \x30\n" ;
cout << "Letter ~\n" ;
cout << "Letter \x7E\n" ;
char const * a_C_string = "I am a string" ; // pointer to a constant piece of memory
for ( int i = 0 ; i <= strlen(a_C_string) ; ++i )
cout << i << "-th character is: "
<< a_C_string[i]
<< " hex: " << hex << int(a_C_string[i]) << dec // reset to decimal
<< '\n' ;
string a_Cpp_string = "I am a string" ;
cout << "C++ string: " << a_Cpp_string << '\n' ;
cout << "length: " << a_Cpp_string.length() << '\n' ;
sort( a_Cpp_string.begin(), a_Cpp_string.end()) ;
cout << "Sorted: " << a_Cpp_string << '\n' ;
reverse( a_Cpp_string.begin(), a_Cpp_string.end()) ;
cout << "Reversed: " << a_Cpp_string << '\n' ;
string str1 = "I am string1" ;
string str2 = "I am string2" ;
string str = str1 + str2 ;
cout << "Concatenated: " << str << '\n' ;
cout << "str[1] " << str[1] << '\n' ;
cout << "str[5] " << str[5] << '\n' ;
cout << "str[3] " << str[3] << '\n' ;
return 0 ;
}
Divisors of a number
File: example15.cc:
/*
Build a tree with the divisors of a number
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
using namespace std ;
class Node {
int number ;
vector<Node*> childs ;
void free() ;
public:
Node() : number(1) {
cout << "Enter to the contructor of Node\n" ;
}
Node( int n ) : number(1) {
cout << "Enter to the contructor of Node(" << n << ")\n" ;
build( n ) ;
}
~Node() ;
void build( int n ) ;
void print( ostream &, int level = 0 ) ;
void to_dag( ostream &, int level = 0 ) ;
void to_tree( ostream &, int level = 0 ) ;
} ;
void
Node::free() {
cout << "Enter to the destructor of Node (" << number << ")\n" ;
for ( vector<Node*>::iterator it = childs.begin() ; it != childs.end() ; ++it )
delete *it ; // *it is a pointer to the corresponding child Node
// call the destroyer for the Node *it
childs.clear() ;
}
Node::~Node() {
free() ;
}
void
Node::build( int n ) {
//cout << "Enter build for number " << n << "\n" ;
if ( number != 1 ) free() ;
number = n ;
// search for the divisors
for ( int i = 2 ; i < n ; ++i ) {
if ( (n % i) == 0 ) { // found a divisor
//cout << "found divisor: " << i << " for number " << number << '\n' ;
Node * pChild = new Node(i) ; // allocate the new divisor `i`
//pChild->build(i) ; // compute the divisor of i
childs.push_back(pChild) ; // add to the list of child od `number`
}
}
//cout << "Exit build for number " << n << "\n" ;
}
void
Node::print( ostream & stream, int level ) {
stream << std::string(level*4, ' ') ;
stream << number << '\n' ;
for ( int i = 0 ; i < childs.size() ; ++i )
childs[i]->print( stream, level + 1 ) ;
}
void
Node::to_dag( ostream & stream, int level ) {
if ( level == 0 ) stream << "digraph divisor_of_" << number << " {\n" ;
for ( int i = 0 ; i < childs.size() ; ++i ) {
stream << " " << number << " -> " << childs[i]->number << ";\n" ;
childs[i]->to_dag( stream, level + 1 ) ;
}
if ( level == 0 ) stream << "}\n" ;
}
int
main() {
Node n(12) ;
n.to_dag(cout) ;
//n.build(234) ;
//n.to_dag(cout) ;
return 0 ;
}
Convert integer to letters
File: num_to_string.hh:
#ifndef NUM_TO_STRING_HH
#define NUM_TO_STRING_HH
#include <string> // C++ string
#include <vector> // C++ string
class NumToString {
std::vector<std::string> first20 ;
std::vector<std::string> tens ;
std::string to_string_less_than_1000( int ) const ;
public:
NumToString() ;
~NumToString() ;
std::string to_string( int ) const ;
} ;
#endif
File: num_to_string.cc:
#include "num_to_string.hh"
using namespace std ;
NumToString::NumToString() {
first20.clear() ;
first20.reserve(20) ;
first20.push_back("") ;
first20.push_back("one") ;
first20.push_back("two") ;
first20.push_back("three") ;
first20.push_back("four") ;
first20.push_back("five") ;
first20.push_back("six") ;
first20.push_back("seven") ;
first20.push_back("eight") ;
first20.push_back("nine") ;
first20.push_back("ten") ;
first20.push_back("eleven") ;
first20.push_back("twelve") ;
first20.push_back("thirteen") ;
first20.push_back("fourteen") ;
first20.push_back("fifteen") ;
first20.push_back("sixteen") ;
first20.push_back("seventeen") ;
first20.push_back("eighteen") ;
first20.push_back("nineteen") ;
tens.clear() ;
tens.reserve(10) ;
tens.push_back("zero") ;
tens.push_back("ten") ;
tens.push_back("twenty") ;
tens.push_back("thirty") ;
tens.push_back("forty") ;
tens.push_back("fifty") ;
tens.push_back("sixty") ;
tens.push_back("seventy") ;
tens.push_back("eighty") ;
tens.push_back("ninety") ;
}
NumToString::~NumToString() {
}
string
NumToString::to_string_less_than_1000( int num ) const {
string res = "" ;
// convert the first two digit
int tmp = num%100 ;
if ( tmp < 20 ) {
res = first20[tmp] ;
} else {
res = tens[tmp/10] ;
if ( (tmp%10) != 0 ) res += "-" + first20[tmp%10] ;
}
// convert hundreds
num /= 100 ;
tmp = num%10 ;
if ( tmp > 0 ) {
if ( res.length() > 0 ) res = first20[tmp]+"-hundred-"+res ;
else res = first20[tmp]+"-hundred" ;
}
return res ;
}
string
NumToString::to_string( int num ) const {
string res = to_string_less_than_1000( num ) ;
// convert thousand
string res1 = to_string_less_than_1000( num/1000 ) ;
if ( res1.length() > 0 ) {
if ( res.length() > 0 ) res = res1+"-thousand-"+res ;
else res = res1+"-thousand" ;
}
// convert millions
res1 = to_string_less_than_1000( num/1000000 ) ;
if ( res1.length() > 0 ) {
if ( res.length() > 0 ) res = res1+"-million-"+res ;
else res = res1+"-million" ;
}
// convert billion
res1 = to_string_less_than_1000( num/1000000000 ) ;
if ( res1.length() > 0 ) {
if ( res.length() > 0 ) res = res1+"-billion-"+res ;
else res = res1+"-billion" ;
}
return res ;
}
File: test_num_to_string.cc:
#include "num_to_string.hh"
#include <iostream>
using namespace std ;
int
main() {
NumToString nts ;
for ( int i = 1000000 ; i < 1000000+333 ; ++i )
cout << i << " --> " << nts.to_string(i) << '\n' ;
}
All the files in one zip file
Lesson N.10 of July 30, 2014
Using exception
File: example16.cc:
/*
example of use exception
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
#include <exception> // std::exception
using namespace std ;
void
throw_an_exception_level_1() {
cout << "Before the exception\n" ;
//throw "SOMETHING GO WRONG" ;
//throw 1234 ;
throw runtime_error("runtime_error used") ;
cout << "After the exception\n" ;
}
void
throw_an_exception() {
cout << "Before throw_an_exception_level_1\n" ;
throw_an_exception_level_1() ;
cout << "After throw_an_exception_level_1\n" ;
}
int
main() {
try {
// ....
cout << "Before the call of throw_an_exception()\n" ;
throw_an_exception() ;
cout << "After the call of throw_an_exception()\n" ;
// ....
}
catch ( char const error[] ) {
cerr << "Exception found: " << error << "\n" ;
}
catch ( int error ) {
cerr << "Exception number " << error << "\n" ;
}
catch ( exception const & error ) {
cerr << "Exception number " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
Using class as function
File: newton.cc:
/*
example of use exception
*/
#include "newton.hh"
#include "myfunction.hh"
#include "ncfunction.hh"
#include <iostream>
using namespace std ;
int
main() {
try {
//MyFunction<double> fun(2) ;
NC_Function<double> fun ;
double x = newton( fun, 400.0, 100, 1e-12 ) ;
cout << "x = " << x << '\n' ;
}
catch ( exception const & error ) {
cerr << "Exception: " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
File: newton.hh:
#ifndef NEWTON_HH
#define NEWTON_HH
#include "funclass.hh"
#include <cmath>
#include <stdexcept> // std::exception
template <typename FUNC, typename T, typename INT >
T // return the value of the approximated root
newton( FUNC const & f, // instance of object function class
T const & x0, // initial guess
INT maxIter, // maximum number of iteration
T const & tolerance // tolereance used to stop iterations
) {
T x = x0 ;
for ( INT i = 0 ; i < maxIter ; ++i ) {
T fun = f(x) ;
T Dfun = f.D(x) ;
if ( std::abs(Dfun) < 1E-10*std::abs(fun) )
throw std::runtime_error("newton, divide by (near) 0") ;
T h = fun/Dfun ;
x -= h ;
if ( std::abs(h) < tolerance ) return x ; // all ok!
if ( std::abs(x-x0) > 1E10 )
throw std::runtime_error("newton is diverging") ;
}
throw std::runtime_error("newton not converged within iteration limits") ;
} ;
#endif
File: funclass.hh:
#ifndef FUNCLASS_HH
#define FUNCLASS_HH
template <typename T>
class FunClass {
public:
typedef T valueType ; // valueType is an alias for T
private:
FunClass( FunClass const & ) ; // block the copy constructor
FunClass const & operator = ( FunClass const & ) ; // block the copy operator
public:
FunClass() {}
virtual T operator () ( T const & val ) const = 0 ;
virtual T D( T const & val ) const = 0 ; // make class pure virtual
} ;
#endif
File: ncfunction.hh:
#ifndef NC_FUNCTION_HH
#define NC_FUNCTION_HH
#include "funclass.hh"
template <typename T>
class NC_Function : FunClass<T> {
public:
NC_Function() : FunClass<T>() {}
NC_Function( T const & a ) : FunClass<T>() {}
virtual T operator () ( T const & x ) const {
return atan(x) ;
}
virtual T D( T const & x ) const {
return 1/(1+x*x);
}
} ;
#endif
File: myfunction.hh:
#ifndef MYFUNCTION_HH
#define MYFUNCTION_HH
#include "funclass.hh"
template <typename T>
class MyFunction : FunClass<T> {
T avalue ;
public:
MyFunction() : FunClass<T>(), avalue(2) {}
MyFunction( T const & a ) : FunClass<T>(), avalue(a) {}
virtual T operator () ( T const & x ) const {
return x*x-avalue ;
}
virtual T D( T const & x ) const {
return 2*x ;
}
} ;
#endif
All the files in one zip file
Lesson N.11 of July 31, 2014
Some experiments using Eigen3
File: example17.cc:
/*
Some experiments using Eigen3
-I/usr/local/include/eigen3 to add search of headers for eigen3 library
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
#include <exception> // std::exception
// include headers for the Dense linear algebra of Eigen library
#include <Eigen/Dense>
using namespace std ;
//using namespace Eigen ;
int
main() {
try {
// define a matrix od double (d) of size 2x2
// Matrix2d = Matrix<double,2,2>
Eigen::Matrix2d a ;
a << 1, 2,
3, 4 ;
// MatrixXd = Matrix<double,Dynamic,Dynamic>
Eigen::MatrixXd b(2,2) ;
b << 2, 3,
1, 4;
cout << "a + b =\n" << a + b << '\n' ;
cout << "a - b =\n" << a - b << '\n' ;
cout << "Doing a += b;" << '\n' ;
a += b;
cout << "Now a =\n" << a << '\n' ;
// Vector3d = Matrix<double,3,1>
Eigen::Vector3d v(1,2,3); // v << 1 << 2 << 3 ;
Eigen::Vector3d w(1,0,0); // v << 1 << 0 << 0 ;
cout << "-v + w - v =\n" << -v + w - v << '\n' ;
}
catch ( exception const & error ) {
cerr << "Exception number " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
File: example18.cc:
/*
Some experiments using Eigen3
-I/usr/local/include/eigen3 to add search of headers for eigen3 library
Linear regression, bad way and good way
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
#include <exception> // std::exception
// include headers for the Dense linear algebra of Eigen library
#include <Eigen/Dense>
using namespace std ;
//using namespace Eigen ;
template <typename T>
T
func( T x )
{ return 10*x-3 ; }
template <typename T>
void
generate_table( vector<T> & x,
vector<T> & y,
int N ) {
x.clear() ;
y.clear() ;
x.reserve(N) ;
y.reserve(N) ;
for ( int i = 0 ; i < N ; ++i ) {
T xx = ((rand() % 10000)-5000) * 0.001 ;
T yy = func(xx) ;
yy += ((rand() % 10000)-5000) * 0.0001 ;
x.push_back(xx) ;
y.push_back(yy) ;
}
}
typedef double valueType ;
int
main() {
try {
int N = 1000000 ;
vector<valueType> x, y ;
generate_table( x, y, N ) ;
// define a matrix od double (d) of size 2x2
// Matrix2d = Matrix<double,2,2>
Eigen::Matrix2d A ;
Eigen::Vector2d b, sol ;
// sum xi*xi
valueType bf = 0 ;
for ( int i = 0 ; i < N ; ++i ) bf += x[i]*x[i] ;
A(0,0) = bf ;
// sum xi
bf = 0 ;
for ( int i = 0 ; i < N ; ++i ) bf += x[i] ;
A(1,0) = A(0,1) = bf ;
A(1,1) = N ;
// sum xi*yi
bf = 0 ;
for ( int i = 0 ; i < N ; ++i ) bf += x[i]*y[i] ;
b(0) = bf ;
// sum yi
bf = 0 ;
for ( int i = 0 ; i < N ; ++i ) bf += y[i] ;
b(1) = bf ;
// use Cholewsky decomposition
Eigen::LLT<Eigen::Matrix2d> lltOfA(A) ;
sol = lltOfA.solve(b) ;
cout << "Solution = " << sol << '\n' ;
// solve the problem using least squares
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> Mat(N,2) ;
Eigen::Matrix<double,Eigen::Dynamic,1> Rhs(N) ;
for ( int i = 0 ; i < N ; ++i ) {
Mat(i,0) = x[i] ;
Mat(i,1) = 1 ;
Rhs(i) = y[i] ;
}
cout << "Mat^T * Mat =\n" << Mat.transpose() * Mat << '\n' ;
cout << "A =\n" << A << '\n' ;
sol = Mat.colPivHouseholderQr().solve(Rhs) ;
cout << "Solution (LS) = " << sol << '\n' ;
}
catch ( exception const & error ) {
cerr << "Exception number " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
File: example19.cc:
/*
Some experiments using Eigen3
-I/usr/local/include/eigen3 to add search of headers for eigen3 library
Linear regression, bad way and good way.
Using more Eigen3
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
#include <exception> // std::exception
// include headers for the Dense linear algebra of Eigen library
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std ;
//using namespace Eigen ;
template <typename T>
T
func( T x )
{ return 10*x-3 ; }
template <typename T>
void
generate_table( Eigen::Matrix<T,Eigen::Dynamic,1> & x,
Eigen::Matrix<T,Eigen::Dynamic,1> & y,
int N ) {
x.resize(N) ;
y.resize(N) ;
for ( int i = 0 ; i < N ; ++i ) {
T xx = ((rand() % 10000)-5000) * 0.001 ;
T yy = func(xx) ;
yy += ((rand() % 10000)-5000) * 0.0001 ;
x(i) = xx ;
y(i) = yy ;
}
}
typedef double valueType ;
int
main() {
try {
int N = 1000000 ;
Eigen::Matrix<double,Eigen::Dynamic,1> x, y ;
generate_table( x, y, N ) ;
// define a matrix od double (d) of size 2x2
// Matrix2d = Matrix<double,2,2>
Eigen::Matrix2d A ;
Eigen::Vector2d b, sol ;
// sum xi*xi
A(0,0) = x.dot(x) ;
// sum xi
A(1,0) = A(0,1) = x.sum() ;
A(1,1) = N ;
// sum xi*yi
b(0) = x.dot(y) ;
// sum yi
b(1) = y.sum() ;
// use Cholewsky decomposition
Eigen::LLT<Eigen::Matrix2d> lltOfA(A) ;
sol = lltOfA.solve(b) ;
cout << "Solution = " << sol << '\n' ;
// solve the problem using least squares
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> Mat(N,2) ;
Eigen::Matrix<double,Eigen::Dynamic,1> Rhs(N) ;
Mat.col(0) = x ;
Mat.col(1).fill(1) ; // fill column with one's
Rhs = y ;
cout << "Mat^T * Mat =\n" << Mat.transpose() * Mat << '\n' ;
cout << "A =\n" << A << '\n' ;
sol = Mat.colPivHouseholderQr().solve(Rhs) ;
cout << "Solution (LS) = " << sol << '\n' ;
}
catch ( exception const & error ) {
cerr << "Exception number " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
File: example20.cc:
/*
Some experiments using Eigen3
-I/usr/local/include/eigen3 to add search of headers for eigen3 library
Linear regression, bad way and good way.
Using more Eigen3
*/
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string> // C++ string
#include <exception> // std::exception
// include headers for the Dense linear algebra of Eigen library
#include <Eigen/Dense>
using namespace std ;
//using namespace Eigen ;
template <typename T>
T
func( T x )
{ return 10*x-3 ; }
template <typename T>
void
generate_table( Eigen::Matrix<T,Eigen::Dynamic,1> & x,
Eigen::Matrix<T,Eigen::Dynamic,1> & y,
int N ) {
x.resize(N) ;
y.resize(N) ;
for ( int i = 0 ; i < N ; ++i ) {
T xx = ((rand() % 10000)-5000) * 0.001 ;
T yy = func(xx) ;
yy += ((rand() % 10000)-5000) * 0.0001 ;
x(i) = xx ;
y(i) = yy ;
}
}
typedef double valueType ;
int
main() {
try {
int N = 1000000 ;
Eigen::Matrix<double,Eigen::Dynamic,1> x, y ;
generate_table( x, y, N ) ;
// define a matrix od double (d) of size 2x2
// Matrix2d = Matrix<double,2,2>
Eigen::Matrix2d A ;
Eigen::Vector2d b, sol ;
valueType tmp = x.sum() ;
A << x.dot(x), tmp,
tmp, N ;
b << x.dot(y), y.sum() ;
// use Cholewsky decomposition
Eigen::LLT<Eigen::Matrix2d> lltOfA(A) ;
sol = lltOfA.solve(b) ;
cout << "Solution = " << sol << '\n' ;
// solve the problem using least squares
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> Mat(N,2) ;
Mat.col(0) = x ;
Mat.col(1).fill(1) ; // fill column by ones!
sol = Mat.colPivHouseholderQr().solve(y) ;
cout << "Solution (LS) = " << sol << '\n' ;
}
catch ( exception const & error ) {
cerr << "Exception number " << error.what() << "\n" ;
}
catch ( ... ) {
cerr << "Exception found: Unknown error\n" ;
}
cout << "END OF PROGRAM\n" ;
return 0 ;
}
All the files in one zip file
Corso di Calcolo Numerico (AA 2012/2013)
Orario delle lezioni
GIORNO | ORARIO | AULA |
---|---|---|
Lunedì | 11:30 - 12:30 | A204 |
Martedì | 16.30 - 18.30 | A104 |
Giuovedì | 11.30 - 13.30 | A104 |
Mini riassunto comandi MATLAB
Esempi dalla lezione del 21 marzo 2013
Foglio Maple: lezione-2013-03-21-iterativi.mw.zip
File formato PDF: lezione-2013-03-21-iterativi.mw.pdf
Esempi dalla lezione del 25 marzo 2013
Foglio Maple: lezione-2013-03-25-poly-newton.mw.zip
File formato PDF: lezione-2013-03-25-poly-newton.mw.pdf
Esempi dalla lezione del 8 aprile 2013
Foglio Maple: lezione-2013-04-08-interp.mw.zip
File formato PDF: lezione-2013-04-08-interp.mw.pdf
Foglio Maple: lezione-2013-04-08-runge.mw.zip
File formato PDF: lezione-2013-04-08-runge.mw.pdf
Esempi dalla lezione del 15 aprile 2013
Foglio Maple: lezione-2013-04-15-integrazione.mw.zip
File formato PDF: lezione-2013-04-15-integrazione.mw.pdf
Esempi dalla lezione del 22 aprile 2013
Foglio Maple: lezione-2013-04-22-simpson.mw.zip
File formato PDF: lezione-2013-04-22-simpson.mw.pdf
Foglio Maple: lezione-2013-04-22-tre-ottavi.mw.zip
File formato PDF: lezione-2013-04-22-tre-ottavi.mw.pdf
Esempi dalla lezione del 16 maggio 2013
Foglio Maple: lezione-2013-05-16-eulero.mw.zip
File formato PDF: lezione-2013-05-16-eulero.mw.pdf
Esempi dalla lezione del 21 maggio 2013
Foglio Maple: lezione-2013-05-21-taylor.mw.zip
File formato PDF: lezione-2013-05-21-taylor.mw.pdf
Esempi dalla lezione del 30 maggio 2013
Foglio Maple: lezione-2013-05-30-AB.mw.zip
File formato PDF: lezione-2013-05-30-AB.mw.pdf
Foglio Maple: lezione-2013-05-30-AM.mw.zip
File formato PDF: lezione-2013-05-30-AM.mw.pdf
Foglio Maple: lezione-2013-05-30-MILNE.mw.zip
File formato PDF: lezione-2013-05-30-MILNE.mw.pdf
Esempi dalla lezione del 6 giugno 2013
Foglio Maple: lezione-2013-06-06-ASTABILITY.mw.zip
File formato PDF: lezione-2013-06-06-ASTABILITY.mw.pdf
Prova intermedia del 30 aprile 2013
- Testo della provetta prova-2013-04-30.pdf
Prova intermedia del 13 giugno 2013
- Testo della provetta prova-2013-06-13.pdf
Esame scritto del 8 luglio 2013
- Testo dell’esame cnum-2013-07-08.pdf
Esame scritto del 22 luglio 2013
- Testo dell’esame cnum-2013-07-22.pdf
Course of Numerical Methods for Dynamic Systems and Control [140155] (AA 2012/2013)
Lessons timetable
DAY | TIME | ROOM |
---|---|---|
Wednesday | 8:30 - 11:30 | 221 |
Thursday | 8.30 - 10.30 | 221 |
Friday | 10.30 - 13.30 | 204 |
Useful link
Numerical Solution of Differential Algebraic Equations Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Example from lesson of September 21, 2012
Maple sheet in a zip archive ex2012_09_21.mw.zip
Maple sheet in pdf ex2012_09_21.mw.pdf
Example from lesson of September 26, 2012
Maple sheet in a zip archive ex2012_09_26.mw.zip
Maple sheet in pdf ex2012_09_26.mw.pdf
Example from lesson of September 27, 2012
Maple sheet in a zip archive ex2012_09_27.mw.zip
Maple sheet in pdf ex2012_09_27.mw.pdf
Example from lesson of September 28, 2012
Maple sheet in a zip archive ex2012_09_28.mw.zip
Maple sheet in pdf ex2012_09_28.mw.pdf
Example from lesson of October 4, 2012
Maple sheet in a zip archive ex2012_10_04.mw.zip
Maple sheet in pdf ex2012_10_04.mw.pdf
Example from lesson of October 10, 2012
Maple sheet in a zip archive ex2012_10_10.mw.zip
Maple sheet in pdf ex2012_10_10.mw.pdf
Example from lesson of October 11, 2012
Maple sheet in a zip archive ex2012_10_11.mw.zip
Maple sheet in pdf ex2012_10_11.mw.pdf
Example from lesson of October 12, 2012
Maple sheet in a zip archive ex2012_10_12.mw.zip
Maple sheet in pdf ex2012_10_12.mw.pdf
Maple sheet in a zip archive ex2012_10_12b.mw.zip
Maple sheet in pdf ex2012_10_12b.mw.pdf
Example from lesson of October 17, 2012
Maple sheet in a zip archive ex2012_10_17.mw.zip
Maple sheet in pdf ex2012_10_17.mw.pdf
Example from lesson of October 19, 2012
Maple sheet in a zip archive ex2012_10_19.mw.zip
Maple sheet in pdf ex2012_10_19.mw.pdf
Maple sheet in a zip archive ex2012_10_19b.mw.zip
Maple sheet in pdf ex2012_10_19b.mw.pdf
Example from lesson of October 24, 2012
Maple sheet in a zip archive ex2012_10_24.mw.zip
Maple sheet in pdf ex2012_10_24.mw.pdf
Maple sheet in a zip archive ex2012_10_24b.mw.zip
Maple sheet in pdf ex2012_10_24b.mw.pdf
Example from lesson of October 25, 2012
Maple sheet in a zip archive ex2012_10_25.mw.zip
Maple sheet in pdf ex2012_10_25.mw.pdf
Maple sheet in a zip archive ex2012_10_25b.mw.zip
Maple sheet in pdf ex2012_10_25b.mw.pdf
Example from lesson of October 26, 2012
Maple sheet in a zip archive ex2012_10_26.mw.zip
Maple sheet in pdf ex2012_10_26.mw.pdf
Maple sheet in a zip archive ex2012_10_26a.mw.zip
Maple sheet in pdf ex2012_10_26a.mw.pdf
Example from lesson of November 7, 2012
Maple sheet in a zip archive ex2012_11_07a.mw.zip
Maple sheet in pdf ex2012_11_07a.mw.pdf
Maple sheet in a zip archive ex2012_11_07b.mw.zip
Maple sheet in pdf ex2012_11_07b.mw.pdf
Example from lesson of November 9, 2012
Maple sheet in a zip archive ex2012_11_09.mw.zip
Maple sheet in pdf ex2012_11_09.mw.pdf
Maple sheet in a zip archive ex2012_11_09b.mw.zip
Maple sheet in pdf ex2012_11_09b.mw.pdf
Example from lesson of November 14, 2012
Maple sheet in a zip archive ex2012_11_14.mw.zip
Maple sheet in pdf ex2012_11_14.mw.pdf
Example from lesson of November 15, 2012
Maple sheet in a zip archive ex2012_11_15.mw.zip
Maple sheet in pdf ex2012_11_15.mw.pdf
Maple sheet in a zip archive ex2012_11_15b.mw.zip
Maple sheet in pdf ex2012_11_15b.mw.pdf
Example from lesson of November 16, 2012
Maple sheet in a zip archive ex2012_11_15a.mw.zip
Maple sheet in pdf ex2012_11_15a.mw.pdf
Maple sheet in a zip archive ex2012_11_15b.mw.zip
Maple sheet in pdf ex2012_11_15b.mw.pdf
Maple sheet in a zip archive ex2012_11_15c.mw.zip
Maple sheet in pdf ex2012_11_15c.mw.pdf
Example from lesson of November 21, 2012
Maple sheet in a zip archive ex2012_11_21a.mw.zip
Maple sheet in pdf ex2012_11_21a.mw.pdf
Maple sheet in a zip archive ex2012_11_21b.mw.zip
Maple sheet in pdf ex2012_11_21b.mw.pdf
Example from lesson of November 29, 2012
Maple sheet in a zip archive ex2012_11_29.mw.zip
Maple sheet in pdf ex2012_11_29.mw.pdf
Example from lesson of December 6, 2012
Maple sheet in a zip archive ex2012_12_06.mw.zip
Maple sheet in pdf ex2012_12_06.mw.pdf
Tables and summary for the written exams
Exam of January 14, 2013
- Text in PDF format with solutions: nmdsc-2013-01-14.pdf
Exam of February 7, 2013
- Text in PDF format with solutions: nmdsc-2013-02-07.pdf
Comparison of Laplace and Z-transform
Connection between Bode plot and Laplace
Study with Fourier serie of three phase rectifier
Example of computation of exponential matrix
Computation of exponential matrix, many methods
Little tutorial on computing matrix exponential
Example of Index 1 DAE
Example of DAE: Pendulum in cartesian coordinate
Example of MATLAB solver with implicit Euler for the Pendulum in cartesian coordinate
The finite difference are generated using MAPLE, the files are here:
Example of Brachiostosdcrone problem with indirect method
Corso di Calcolo Numerico (AA 2011/2012)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11:30 - 12:30 | A204 |
Martedì | 16.30 - 18.30 | A104 |
Giovedì | 11.30 - 13.30 | A104 |
Prova intermedia del 24 aprile 2012
- Testo della provetta prova-2012-04-05.pdf
Prova intermedia del 11 giugno 2012
- Testo della provetta prova-2012-06-11.pdf
Prova scritta del 5 luglio 2012
- Testo dell’esame cnum-2012-07-05.pdf
Prova scritta del 23 luglio 2012
- Testo dell’esame cnum-2012-07-23.pdf
Prova scritta del 27 agosto 2012
- Testo dell’esame cnum-2012-08-27.pdf
Course of Numerical Methods for Dynamic Systems and Control [140155] (AA 2011/2012)
Lessons timetable
DAY | TIME | ROOM |
---|---|---|
Wednesday | 8:30 - 11:30 | 221 |
Thursday | 8.30 - 10.30 | 221 |
Friday | 10.30 - 13.30 | 212 |
Reception timetable
DAY | TIME | ROOM |
---|---|---|
Monday | 11 - 12 | 505 |
Tuesday | 11 - 12 | 505 |
Numerical Solution of Differential Algebraic Equations Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Example from lesson of September 21, 2011
Example from lesson of September 22, 2011
Examples from lesson of September 23, 2011
Examples from lesson of September 28, 2011
Exercises from lesson of September 29, 2011
Examples from lesson of September 30, 2011
Exercises from lesson of October 5, 2011
Examples from lesson of October 7, 2011
Exercises from lesson of October 13, 2011
Examples from lesson of October 14, 2011
Examples from lesson of October 19, 2011
Exercises from lesson of October 20, 2011
Examples from lesson of October 21, 2011
Examples from lesson of November 3, 2011
Examples from lesson of November 4, 2011
Examples from lesson of November 9, 2011
Examples from lesson of November 10, 2011
Exercises from lesson of November 11, 2011
Exercises from lesson of November 16, 2011
Examples from lesson of November 17 and 18, 2011
Exercises from lesson of November 24, 2011
Exercises from lesson of November 30, 2011
Examples from lesson of December 7, 2011
Exercises from lesson of December 14, 2011
Exercises from lesson of December 15, 2011
Examples from lesson of December 17, 2011
Examples from lesson of December 22, 2011
Examples from lesson of December 23, 2011
Italian slides on DAE
Student’s project
- The text of the assigned project is here
Exam of January 17, 2012
Text in PDF format: nmdsc-2012-01-17.pdf
Last exercise solution details: nmdsc-2012-01-17ex7.pdf
Exam of February 7, 2012
- Text in PDF format: nmdsc-2012-02-07.pdf
Exam of July 5, 2012
- Text in PDF format: nmdsc-2012-07-05.pdf
Exam of July 23, 2012
Text in PDF format: nmdsc-2012-07-23.pdf
solution of Z-transform: nmdsc-2012-07-23-solution-Z.pdf
Exam of August 27, 2012
Text in PDF format: nmdsc-2012-08-27.pdf
solution of Z-transform nmdsc-2012-08-27-solution-Z.pdf
Comparison of Laplace and Z-transform
Connection between Bode plot and Laplace
Study with Fourier serie of three phase rectifier
Example of computation of exponential matrix
Computation of exponential matrix, many methods
Little tutorial on computing matrix exponential
Example of Index 1 DAE
Example of DAE: Pendulum in cartesian coordinate
Example of MATLAB solver with implicit Euler for the Pendulum in cartesian coordinate
The finite difference are generated using MAPLE, the files are here:
Example of Brachiostosdcrone problem with indirect method
P.h.D. Course of Numerical Optimization (AA 2011/2012)
DAY | TIME | ROOM |
---|---|---|
Monday | 10:00 - 12:00 | A220 |
Monday | 13.00 - 15.00 | A220 |
Tuesday | 10:00 - 12:00 | Aula DIMS |
Thursday | 13.00 - 15.00 | A221 |
One Dimensional Non-Linear Problems
One-Dimensional Minimization
Unconstrained minimization
Conjugate Direction minimization
Non-linear problems in N variables
Quasi-Newton methods for minimization
Trust Region Method
Lesson of November 21, 2011
Lesson of November 22, 2011
Write a MATLAB code that implement Secant method, check numericallly the order of convergence.
Write a MATLAB code that implement Golden Section (univariate) minimization.
Write a MATLAB code that implement Fibonacci (univariate) minimization.
Teacher solution
Lesson of November 28, 2011
Lesson of November 29, 2011
Lesson of December 5, 2011
Lesson of December 6, 2011
Lesson of December 12, 2011
Lesson of December 13, 2011
Three categories
- Minimization
- Nonlinear systems
- Least Squares problems
Objective of the competition:
Solve the maximum number of problems
Minimize the cost of the solution
Competition timetable:
Competition begin at 9.00 on February 20, 2012
10 problems for each category are proposed to the competitors
Student must write a matlab function which solve each problem
Function must have signature like:
function x=MySolution(x0,fun)
wherex(:,i)
is the i-th iterate,x0
the starting point andfun
the function to be minimizeCompetition end at 21.00 on March 2, 2012
End of the competition is postponed at 24.00 on March 18, 2012
Competition ranking formation
Each competitor gets a point for each problem his program is able to solve
“undisclosed” problem (for each category) are use in rank formation
The winner is the competitor which maximize points (maximize number of problems solved)
In case of equal score with 2 or more competitor a computational cost index is used:
For each problem an additional point is attributed to competitor that minimizes the index:
nf + n * ng + n^2 * nh
wherenf
number of function evaluation,ng
number of gradient evaluation,nh
number of hessian evaluation.In case of nonlinear system the index is:
nF + n * nJ
wherenF
number of map evaluation,nJ
number of jacobian evaluation.
- In case equal score (very unlikely) additional and more difficult problems are considered until a winner is found
Computational limitation for each problem
n
is the number of unknownsA limit of
1000
iterationA limit of
n*n*1000
function evaluationsA limit of
n*1000
gradient evaluationsA limit of
1000
hessian evaluationsCompetition opened!
Corso di Calcolo Numerico (AA 2010/2011)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11:30 - 12:30 | A204 |
Martedì | 8.30 - 10.30 | A204 |
Giovedì | 11.30 - 13.30 | 104 |
Prova intermedia del 27 aprile 2011
- Testo della provetta prova-2011-04-27.pdf
Prova intermedia del 9 giugno 2011
- Testo della provetta prova-2011-06-09.pdf
Scritto del 5 luglio 2011
- Testo dello scritto prova-2011-07-05.pdf
Scritto del 22 agosto 2011
- Testo dello scritto prova-2011-08-22.pdf
Scritto del 17 gennaio 2012
- Testo dello scritto prova-2012-01-17.pdf
Scritto del 7 febbraio 2012
- Testo dello scritto prova-2012-02-07.pdf
Kinematic and Dynamic Simulation of Multibody Systems. The Real-Time Challenge, This book of Garcia de Jalon and Bayo can be downloaded at this link
Numerical Solution of Differential Algebraic Equations, Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Didactic material of prof. Andrea Calogero (Facoltà di Scienze Statistiche, Università di Milano Bicocca) The material can be found at this link
Course of Numerical Methods for Dynamic Systems and Control [140155] (AA 2010/2011)
Lessons timetable
DAY | TIME | ROOM |
---|---|---|
Wednesday | 8:30 - 11:30 | 221 |
Thursday | 8.30 - 10.30 | 221 |
Friday | 10.30 - 13.30 | 212 |
Reception timetable
DAY | TIME | ROOM |
---|---|---|
Monday | 11 - 12 | 505 |
Tuesday | 11 - 12 | 505 |
Numerical Solution of Differential Algebraic Equations Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Student’s project
- The text of the assigned project is here
Exam 17 January 2011
- Italian text in PDF format: nmdsc-2011-01-17.pdf
Exam 21 February 2011
- Italian text in PDF format: nmdsc-2011-02-21.pdf
Examination 5 July 2011
- Italian text in PDF format: nmdsc-2011-07-05.pdf
Examination 22 August 2011
- Italian text in PDF format: nmdsc-2011-08-22.pdf
Comparison of Laplace and Z-transform
Connection between Bode plot and Laplace
Study with Fourier serie of three phase rectifier
Example of computation of exponential matrix
Computation of exponential matrix, many methods
Little tutorial on computing matrix exponential
Example of Index 1 DAE
Example of DAE: Pendulum in cartesian coordinate
Example of MATLAB solver with implicit Euler for the Pendulum in cartesian coordinate
The finite difference are generated using MAPLE, the files are here:
Example of Brachiostosdcrone problem with indirect method
P.h.D. Course of Scientific Programming in C++ (AA 2010/2011)
- Lesson 1
- Lesson 2
- Lesson 3
- Lesson 4
- Lesson 5
- Lesson 6
- Lesson 7
- Lesson 8
- Lesson 9a
- Lesson 9b
- Lesson 10
- Lesson 11
- Lesson 12a
- Lesson 12b
- Assignments
- Useful
Lesson of 14 February 2011
Some simple C/C++ programs
A first example
File: example1.cc:
// to compile on unix/OSX use
// g++ example1.cc
// On windows with Visual Studio type
// cl.exe example1.cc
//
/*
I am a multiline comment!
*/
// I am a single line comment
// include header for C I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <stdio.h>
// include header for C++ I/O
// search iostream in standard C++ include directory e.g. /usr/include
#include <iostream>
#include <iomanip> // include objects for manipulators
using namespace std ; // "include" all the items of namespace std
typedef int myInteger ; // myInteger is an alias of int
typedef float myReal ; // myReal is an alias of float
int // this is the tye type of return value
main() {
printf("ciao sono io!\r\f") ;
// \n = new line character (go to the next line)
// \r = carriage return character (go to the begin of line)
// \f = form feed
// (float) i = cast operator, convert integer type to a float
// ++i is equivalent of i = i+1
for ( myInteger i = 0 ; i < 100 ; i=i+1 )
printf( "i = %lx (hex) %ld (dec) %50f (float)\n", i, i, (float)i ) ;
// cout = character out
for ( myReal i = 0 ; i < 100 ; ++i )
cout << "i = (hex) " << hex << i << " (dec) " << dec << i << '\n' ;
return 0 ; // return is a statement for returning value to the caller
}
A second example
File: example2.cc:
// to compile on unix/OSX use
// g++ example1.cc
// On windows with Visual Studio type
// cl.exe example1.cc
//
/*
A simple example: bubble sort
*/
// include header for C I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <stdio.h>
// include C standard lib for heapsort
#include <stdlib.h>
// include header for C++ I/O
// search iostream in standard C++ include directory e.g. /usr/include
#include <iostream>
#include <iomanip> // include objects for manipulators
using namespace std ; // "include" all the items of namespace std
typedef int myInteger ; // myInteger is an alias of int
typedef float myReal ; // myReal is an alias of float
void // nothing to return
sort( myInteger n, // first argument is an integer (the lenght of the vector)
myReal v[] ) { // vector of "unknown length"
for ( myInteger i = 0 ; i < n-1 ; ++i )
for ( myInteger j = i+1 ; j < n ; ++j )
if ( v[j] < v[i] ) {
myReal tmp = v[i] ; v[i] = v[j] ; v[j] = tmp ;
}
}
typedef bool (*PFUN)(myReal,myReal) ;
// Overloading permits to declare another sort routine with "different arguments"!
void // nothing to return
sort( myInteger n, // first argument is an integer (the lenght of the vector)
myReal v[], // vector of "unknown length"
bool (*less_than)(myReal,myReal) ) {
// you can use PFUN less_than instead of bool (*less_than)(myReal,myReal)
for ( myInteger i = 0 ; i < n-1 ; ++i )
for ( myInteger j = i+1 ; j < n ; ++j )
if ( less_than(v[j],v[i]) ) {
myReal tmp = v[i] ; v[i] = v[j] ; v[j] = tmp ;
}
}
bool
comparator( myReal a, myReal b )
{ return a > b ; }
int
C_comparator(const void * a, const void * b) {
myReal A = *((myReal*)a) ;
myReal B = *((myReal*)b) ;
if ( A < B ) return -1 ;
if ( A > B ) return +1 ;
return 0 ;
}
int // this is the tye type of return value
main() {
// declare v ad a vector, the size is deduced by the initialization with {}
myReal v[] = { 4, 1, -0.3, 8.4, 2.3, 88, 1231, 0.1212, -1000 } ;
myInteger vsize = sizeof(v)/sizeof(v[0]) ;
cout << "vsize = " << vsize << '\n' ;
cout << "sizeof(v) = " << sizeof(v) << '\n' ;
cout << "sizeof(v[0]) = " << sizeof(v[0]) << '\n' ;
cout << "sizeof(myReal) = " << sizeof(myReal) << '\n' ;
cout << "sizeof(double) = " << sizeof(double) << '\n' ;
cout << "sizeof(long int) = " << sizeof(long int) << '\n' ;
cout << "sizeof(short int) = " << sizeof(short int) << '\n' ;
// call the sort routine
//sort( vsize, v ) ;
// call the sort routine
sort( vsize, v, comparator ) ;
// call the C standard routine for ordering
int ok = heapsort(v, vsize, sizeof(v[0]), C_comparator );
// cout = character out
for ( myInteger i = 0 ; i < vsize ; ++i )
cout << "v[ " << i << "] = " << v[i] << '\n' ;
return 0 ; // return is a statement for returning value to the caller
}
Lesson of 15 February 2011
SWord count example
A first example
File: wc.cc:
// to compile on unix/OSX use
// g++ wc.cc
// On windows with Visual Studio type
// cl.exe example1.cc
//
// include header for C I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/*
// For example if you write "wc pippo"
// argc = 2
// argv[0] is a pointer to the begin of the string "wc"
// argv[1] is a pointer to the begin of the string "pippo"
*/
int
main( int argc, // number of words in the command line
char const * argv[] // vector of pointer to string
) {
// phase 0: checking aommand line arguments
if ( argc != 2 ) {
fprintf(stderr, "you must use as: %s filename\n", argv[0]) ;
exit(0) ; // exit from program and close all files cleanly
}
// phase 1: open the file
FILE * fd = fopen( argv[1], "r" ) ;
// phase 2: check opening error
if ( fd == NULL ) {
fprintf(stderr, "Error in opening file: %s\n", argv[1]) ;
exit(0) ;
}
// phase 3: scan/read the file and cont things
int nChar = 0 ; // count the number of characters
int nWord = 0 ; // count the number of words
int nLine = 0 ; // count the number of lines
int nSpace = 0 ; // count the number black character (space,tab,...)
char theLine[1024] ;
while ( fgets(theLine, 1023, fd) != NULL ) {
++nLine ; // a line is readed from the file
nChar += strlen(theLine) ; // compute the length of the readed line
// loop to characters of string theLine
//
// is equivalent to *pc != '\0'
// |
for ( char const * pc = theLine ; *pc ; ++pc )
if ( *pc == ' ' || *pc == '\t' ) ++nSpace ;
char const * sep = " \t\n" ;
char * brkt ;
// use strtok_r to separate word and count
for ( char * word = strtok_r(theLine, sep, &brkt);
word;
word = strtok_r(NULL, sep, &brkt))
++nWord ;
}
// phase 4: close file and check the error
int ierr = fclose( fd ) ;
if ( ierr ) perror( strerror( errno ) ) ;
// phase 5: out messages to the standard output
printf( "lines = %d\n", nLine ) ;
printf( "words = %d\n", nWord ) ;
printf( "characters = %d\n", nChar ) ;
printf( "spaces/tabs = %d\n", nSpace ) ;
return 0 ; // return is a statement for returning value to the caller
}
A second example
File: wcc.cc:
// to compile on unix/OSX use
// g++ wc.cc
// On windows with Visual Studio type
// cl.exe example1.cc
//
// include header for C++ I/O
#include <iostream>
#include <fstream>
#include <string> // for string and getline
using namespace std ;
/*
// For example if you write "wc pippo"
// argc = 2
// argv[0] is a pointer to the begin of the string "wc"
// argv[1] is a pointer to the begin of the string "pippo"
*/
int
main( int argc, // number of words in the command line
char const * argv[] // vector of pointer to string
) {
// phase 0: checking aommand line arguments
if ( argc != 2 ) {
fprintf(stderr, "you must use as: %s filename\n", argv[0]) ;
exit(0) ; // exit from program and close all files cleanly
}
// phase 1: open the file
ifstream file ;
file . open( argv[1] ) ;
// phase 2: check opening error
if ( file . fail() ) {
cerr << "Error in opening file: " << argv[1] << '\n' ;
exit(0) ;
}
// phase 3: scan/read the file and cont things
int nChar = 0 ; // count the number of characters
int nWord = 0 ; // count the number of words
int nLine = 0 ; // count the number of lines
int nSpace = 0 ; // count the number black character (space,tab,...)
string theLine ;
while ( getline( file, theLine) ) {
++nLine ; // a line is readed from the file
nChar += theLine . length()+1 ; // compute the length of the readed line
// end of line is not copied to the string so that
// must be counted extra
// loop to characters of string theLine
bool prev_is_sep = true ;
for ( string::const_iterator pc = theLine . begin() ; pc != theLine . end() ; ++pc ) {
bool is_sep = *pc == ' ' || *pc == '\t' ; // check if is a separator
if ( is_sep ) {
++nSpace ; // if a separator increment space counts
} else {
if ( prev_is_sep ) ++nWord ; // is previus was a separator start a new word
}
prev_is_sep = is_sep ;
}
}
// phase 4: close file and check the error
file . close() ;
// phase 5: out messages to the standard output
cout << "lines = " << nLine << '\n'
<< "words = " << nWord << '\n'
<< "characters = " << nChar << '\n'
<< "spaces/tabs = " << nSpace << '\n';
return 0 ; // return is a statement for returning value to the caller
}
Lesson of 16 February 2011
Sorting example
File: sortC++.cc:
// to compile on unix/OSX use
// g++ -I. sortC++.cc TimeMeter.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
// include header for STL vector and algorithm
#include <vector>
#include <algorithm>
// if in windows use a portable version of stdint.h
#ifdef _WIN32
#include "pstdint.h" // for uint64_t
#else
#include <stdint.h> // for uint64_t
#endif
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include "TimeMeter.hh" // class computing elapsed time
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return rand() ; }
// specialization for uint32_t (32 bit integer)
template <>
inline
uint32_t random<uint32_t>() {
return uint32_t(rand()) ^ (uint32_t(rand())<<16) ;
}
// specialization for uint64_t (64 bit integer)
template <>
inline
uint64_t random<uint64_t>() {
return uint64_t(rand()) ^
(uint64_t(rand())<<16) ^
(uint64_t(rand())<<32) ^
(uint64_t(rand())<<48) ;
}
template <typename T>
static
void
bubbleSort( vector<T> & v ) {
// passed by reference, any modifation of v is also on the caller
for ( unsigned i = 0 ; i < v.size()-1 ; ++i )
for ( unsigned j = i+1 ; j < v.size() ; ++j )
if ( v[i] > v[j] )
swap( v[i], v[j] ) ;
}
typedef uint64_t INTEGER ; // make an alias for uint64_t
int
main() {
vector<double> elapsed ; // define a vector containing saved elapsed time
vector<double> elapsed1 ; // define a vector containing saved elapsed time
vector<unsigned> sizevec ; // define a vector containing saved sizes
vector<INTEGER> A ; // a working vector with number to be oredered
TimeMeter tm ; // tm is an instance of a class TimeMeter for timing
elapsed . clear() ;
sizevec . clear() ; // vector are emptied and reduced of size 0
for ( unsigned sz = 100 ; sz <= 10000 ; sz *= 2 ) {
A . clear() ; // empty the vector, size is 0
A . reserve( sz ) ; // reserve memory for sz elements
for ( unsigned j = 0 ; j < sz ; ++j )
A . push_back( random<INTEGER>() ) ;
// setw(6) reserve 6 character for the next output
// flush : write immediately to the standard output (empty the buffer)
cout << "sorting (STL) " << setw(6) << sz << " numbers..." << flush ;
tm . start() ; // start time computation
sort( A . begin(), A . end() ) ; // STL ruotine to sort a vector
double e = tm . milliseconds() ;
elapsed . push_back( e ) ;
sizevec . push_back( sz ) ;
cout << "done in " << setprecision(4) << e << "ms\n" ;
A . clear() ; // empty the vector, size is 0
for ( unsigned j = 0 ; j < sz ; ++j )
A . push_back( random<INTEGER>() ) ;
cout << "sorting (BUBBLE) " << setw(6) << sz << " numbers..." << flush ;
tm . start() ; // start time computation
bubbleSort( A ) ; // Simple routine to sort a vector
e = tm . milliseconds() ;
elapsed1 . push_back( e ) ;
cout << "done in " << setprecision(4) << e << "ms\n" ;
}
cout << "\n\n\n" ;
for ( unsigned i = 0 ; i < sizevec . size() ; ++i ) {
double e = elapsed[i] ;
double e1 = elapsed1[i] ;
unsigned sz = sizevec[i] ;
cout << "n = " << setw(6) << sz
<< " elapsed " << setw(8) << setprecision(4) << e << "ms"
<< " elapsed/(n*log(n)) = " << setw(10) << 100000*e/(sz*log(sz))
<< " elapsed1 " << setw(8) << setprecision(4) << e1 << "ms"
<< " elapsed1/(n^2) = " << setw(10) << 100000*e1/(sz*sz)
<< " elapsed1/elapsed = " << setw(10) << e1/e
<< '\n' ;
}
return 0 ; // return is a statement for returning value to the caller
}
A cross-platform, free implementation of stdint.h
from Paul Hsieh
File: pstdint.h:
/* A portable stdint.h
****************************************************************************
* BSD License:
****************************************************************************
*
* Copyright (c) 2005-2007 Paul Hsieh
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************
*
* Version 0.1.11
*
* The ANSI C standard committee, for the C99 standard, specified the
* inclusion of a new standard include file called stdint.h. This is
* a very useful and long desired include file which contains several
* very precise definitions for integer scalar types that is
* critically important for making portable several classes of
* applications including cryptography, hashing, variable length
* integer libraries and so on. But for most developers its likely
* useful just for programming sanity.
*
* The problem is that most compiler vendors have decided not to
* implement the C99 standard, and the next C++ language standard
* (which has a lot more mindshare these days) will be a long time in
* coming and its unknown whether or not it will include stdint.h or
* how much adoption it will have. Either way, it will be a long time
* before all compilers come with a stdint.h and it also does nothing
* for the extremely large number of compilers available today which
* do not include this file, or anything comparable to it.
*
* So that's what this file is all about. Its an attempt to build a
* single universal include file that works on as many platforms as
* possible to deliver what stdint.h is supposed to. A few things
* that should be noted about this file:
*
* 1) It is not guaranteed to be portable and/or present an identical
* interface on all platforms. The extreme variability of the
* ANSI C standard makes this an impossibility right from the
* very get go. Its really only meant to be useful for the vast
* majority of platforms that possess the capability of
* implementing usefully and precisely defined, standard sized
* integer scalars. Systems which are not intrinsically 2s
* complement may produce invalid constants.
*
* 2) There is an unavoidable use of non-reserved symbols.
*
* 3) Other standard include files are invoked.
*
* 4) This file may come in conflict with future platforms that do
* include stdint.h. The hope is that one or the other can be
* used with no real difference.
*
* 5) In the current verison, if your platform can't represent
* int32_t, int16_t and int8_t, it just dumps out with a compiler
* error.
*
* 6) 64 bit integers may or may not be defined. Test for their
* presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
* Note that this is different from the C99 specification which
* requires the existence of 64 bit support in the compiler. If
* this is not defined for your platform, yet it is capable of
* dealing with 64 bits then it is because this file has not yet
* been extended to cover all of your system's capabilities.
*
* 7) (u)intptr_t may or may not be defined. Test for its presence
* with the test: #ifdef PTRDIFF_MAX. If this is not defined
* for your platform, then it is because this file has not yet
* been extended to cover all of your system's capabilities, not
* because its optional.
*
* 8) The following might not been defined even if your platform is
* capable of defining it:
*
* WCHAR_MIN
* WCHAR_MAX
* (u)int64_t
* PTRDIFF_MIN
* PTRDIFF_MAX
* (u)intptr_t
*
* 9) The following have not been defined:
*
* WINT_MIN
* WINT_MAX
*
* 10) The criteria for defining (u)int_least(*)_t isn't clear,
* except for systems which don't have a type that precisely
* defined 8, 16, or 32 bit types (which this include file does
* not support anyways). Default definitions have been given.
*
* 11) The criteria for defining (u)int_fast(*)_t isn't something I
* would trust to any particular compiler vendor or the ANSI C
* committee. It is well known that "compatible systems" are
* commonly created that have very different performance
* characteristics from the systems they are compatible with,
* especially those whose vendors make both the compiler and the
* system. Default definitions have been given, but its strongly
* recommended that users never use these definitions for any
* reason (they do *NOT* deliver any serious guarantee of
* improved performance -- not in this file, nor any vendor's
* stdint.h).
*
* 12) The following macros:
*
* PRINTF_INTMAX_MODIFIER
* PRINTF_INT64_MODIFIER
* PRINTF_INT32_MODIFIER
* PRINTF_INT16_MODIFIER
* PRINTF_LEAST64_MODIFIER
* PRINTF_LEAST32_MODIFIER
* PRINTF_LEAST16_MODIFIER
* PRINTF_INTPTR_MODIFIER
*
* are strings which have been defined as the modifiers required
* for the "d", "u" and "x" printf formats to correctly output
* (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
* (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
* PRINTF_INTPTR_MODIFIER is not defined for some systems which
* provide their own stdint.h. PRINTF_INT64_MODIFIER is not
* defined if INT64_MAX is not defined. These are an extension
* beyond what C99 specifies must be in stdint.h.
*
* In addition, the following macros are defined:
*
* PRINTF_INTMAX_HEX_WIDTH
* PRINTF_INT64_HEX_WIDTH
* PRINTF_INT32_HEX_WIDTH
* PRINTF_INT16_HEX_WIDTH
* PRINTF_INT8_HEX_WIDTH
* PRINTF_INTMAX_DEC_WIDTH
* PRINTF_INT64_DEC_WIDTH
* PRINTF_INT32_DEC_WIDTH
* PRINTF_INT16_DEC_WIDTH
* PRINTF_INT8_DEC_WIDTH
*
* Which specifies the maximum number of characters required to
* print the number of that type in either hexadecimal or decimal.
* These are an extension beyond what C99 specifies must be in
* stdint.h.
*
* Compilers tested (all with 0 warnings at their highest respective
* settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
* bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
* .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
*
* This file should be considered a work in progress. Suggestions for
* improvements, especially those which increase coverage are strongly
* encouraged.
*
* Acknowledgements
*
* The following people have made significant contributions to the
* development and testing of this file:
*
* Chris Howie
* John Steele Scott
* Dave Thorup
*
*/
#include <stddef.h>
#include <limits.h>
#include <signal.h>
/*
* For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
* do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
*/
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED)
#include <stdint.h>
#define _PSTDINT_H_INCLUDED
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
# endif
# ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# endif
/*
* Something really weird is going on with Open Watcom. Just pull some of
* these duplicated definitions from Open Watcom's stdint.h file for now.
*/
# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
# if !defined (INT64_C)
# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
# endif
# if !defined (UINT64_C)
# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
# endif
# if !defined (INT32_C)
# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
# endif
# if !defined (UINT32_C)
# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
# endif
# if !defined (INT16_C)
# define INT16_C(x) (x)
# endif
# if !defined (UINT16_C)
# define UINT16_C(x) (x)
# endif
# if !defined (INT8_C)
# define INT8_C(x) (x)
# endif
# if !defined (UINT8_C)
# define UINT8_C(x) (x)
# endif
# if !defined (UINT64_MAX)
# define UINT64_MAX 18446744073709551615ULL
# endif
# if !defined (INT64_MAX)
# define INT64_MAX 9223372036854775807LL
# endif
# if !defined (UINT32_MAX)
# define UINT32_MAX 4294967295UL
# endif
# if !defined (INT32_MAX)
# define INT32_MAX 2147483647L
# endif
# if !defined (INTMAX_MAX)
# define INTMAX_MAX INT64_MAX
# endif
# if !defined (INTMAX_MIN)
# define INTMAX_MIN INT64_MIN
# endif
# endif
#endif
#ifndef _PSTDINT_H_INCLUDED
#define _PSTDINT_H_INCLUDED
#ifndef SIZE_MAX
# define SIZE_MAX (~(size_t)0)
#endif
/*
* Deduce the type assignments from limits.h under the assumption that
* integer sizes in bits are powers of 2, and follow the ANSI
* definitions.
*/
#ifndef UINT8_MAX
# define UINT8_MAX 0xff
#endif
#ifndef uint8_t
# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
typedef unsigned char uint8_t;
# define UINT8_C(v) ((uint8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef INT8_MAX
# define INT8_MAX 0x7f
#endif
#ifndef INT8_MIN
# define INT8_MIN INT8_C(0x80)
#endif
#ifndef int8_t
# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
typedef signed char int8_t;
# define INT8_C(v) ((int8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef UINT16_MAX
# define UINT16_MAX 0xffff
#endif
#ifndef uint16_t
#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
typedef unsigned int uint16_t;
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
# define UINT16_C(v) ((uint16_t) (v))
#elif (USHRT_MAX == UINT16_MAX)
typedef unsigned short uint16_t;
# define UINT16_C(v) ((uint16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT16_MAX
# define INT16_MAX 0x7fff
#endif
#ifndef INT16_MIN
# define INT16_MIN INT16_C(0x8000)
#endif
#ifndef int16_t
#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
typedef signed int int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
#elif (SHRT_MAX == INT16_MAX)
typedef signed short int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef UINT32_MAX
# define UINT32_MAX (0xffffffffUL)
#endif
#ifndef uint32_t
#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
typedef unsigned long uint32_t;
# define UINT32_C(v) v ## UL
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (UINT_MAX == UINT32_MAX)
typedef unsigned int uint32_t;
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
# define UINT32_C(v) v ## U
#elif (USHRT_MAX == UINT32_MAX)
typedef unsigned short uint32_t;
# define UINT32_C(v) ((unsigned short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT32_MAX
# define INT32_MAX (0x7fffffffL)
#endif
#ifndef INT32_MIN
# define INT32_MIN INT32_C(0x80000000)
#endif
#ifndef int32_t
#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
typedef signed long int32_t;
# define INT32_C(v) v ## L
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (INT_MAX == INT32_MAX)
typedef signed int int32_t;
# define INT32_C(v) v
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#elif (SHRT_MAX == INT32_MAX)
typedef signed short int32_t;
# define INT32_C(v) ((short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
/*
* The macro stdint_int64_defined is temporarily used to record
* whether or not 64 integer support is available. It must be
* defined for any 64 integer extensions for new platforms that are
* added.
*/
#undef stdint_int64_defined
#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# endif
#endif
#if !defined (stdint_int64_defined)
# if defined(__GNUC__)
# define stdint_int64_defined
__extension__ typedef long long int64_t;
__extension__ typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
# define stdint_int64_defined
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
# define UINT64_C(v) v ## UI64
# define INT64_C(v) v ## I64
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "I64"
# endif
# endif
#endif
#if !defined (LONG_LONG_MAX) && defined (INT64_C)
# define LONG_LONG_MAX INT64_C (9223372036854775807)
#endif
#ifndef ULONG_LONG_MAX
# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
#endif
#if !defined (INT64_MAX) && defined (INT64_C)
# define INT64_MAX INT64_C (9223372036854775807)
#endif
#if !defined (INT64_MIN) && defined (INT64_C)
# define INT64_MIN INT64_C (-9223372036854775808)
#endif
#if !defined (UINT64_MAX) && defined (INT64_C)
# define UINT64_MAX UINT64_C (18446744073709551615)
#endif
/*
* Width of hexadecimal for number field.
*/
#ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
#endif
#ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
#endif
#ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
#endif
#ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
#endif
#ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
#endif
#ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
#endif
#ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
#endif
#ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
#endif
/*
* Ok, lets not worry about 128 bit integers for now. Moore's law says
* we don't need to worry about that until about 2040 at which point
* we'll have bigger things to worry about.
*/
#ifdef stdint_int64_defined
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
# define INTMAX_MAX INT64_MAX
# define INTMAX_MIN INT64_MIN
# define UINTMAX_MAX UINT64_MAX
# define UINTMAX_C(v) UINT64_C(v)
# define INTMAX_C(v) INT64_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# endif
#else
typedef int32_t intmax_t;
typedef uint32_t uintmax_t;
# define INTMAX_MAX INT32_MAX
# define UINTMAX_MAX UINT32_MAX
# define UINTMAX_C(v) UINT32_C(v)
# define INTMAX_C(v) INT32_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
# endif
#endif
/*
* Because this file currently only supports platforms which have
* precise powers of 2 as bit sizes for the default integers, the
* least definitions are all trivial. Its possible that a future
* version of this file could have different definitions.
*/
#ifndef stdint_least_defined
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
typedef int32_t int_least32_t;
typedef uint32_t uint_least32_t;
# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
# define UINT_LEAST8_MAX UINT8_MAX
# define INT_LEAST8_MAX INT8_MAX
# define UINT_LEAST16_MAX UINT16_MAX
# define INT_LEAST16_MAX INT16_MAX
# define UINT_LEAST32_MAX UINT32_MAX
# define INT_LEAST32_MAX INT32_MAX
# define INT_LEAST8_MIN INT8_MIN
# define INT_LEAST16_MIN INT16_MIN
# define INT_LEAST32_MIN INT32_MIN
# ifdef stdint_int64_defined
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
# define UINT_LEAST64_MAX UINT64_MAX
# define INT_LEAST64_MAX INT64_MAX
# define INT_LEAST64_MIN INT64_MIN
# endif
#endif
#undef stdint_least_defined
/*
* The ANSI C committee pretending to know or specify anything about
* performance is the epitome of misguided arrogance. The mandate of
* this file is to *ONLY* ever support that absolute minimum
* definition of the fast integer types, for compatibility purposes.
* No extensions, and no attempt to suggest what may or may not be a
* faster integer type will ever be made in this file. Developers are
* warned to stay away from these types when using this or any other
* stdint.h.
*/
typedef int_least8_t int_fast8_t;
typedef uint_least8_t uint_fast8_t;
typedef int_least16_t int_fast16_t;
typedef uint_least16_t uint_fast16_t;
typedef int_least32_t int_fast32_t;
typedef uint_least32_t uint_fast32_t;
#define UINT_FAST8_MAX UINT_LEAST8_MAX
#define INT_FAST8_MAX INT_LEAST8_MAX
#define UINT_FAST16_MAX UINT_LEAST16_MAX
#define INT_FAST16_MAX INT_LEAST16_MAX
#define UINT_FAST32_MAX UINT_LEAST32_MAX
#define INT_FAST32_MAX INT_LEAST32_MAX
#define INT_FAST8_MIN INT_LEAST8_MIN
#define INT_FAST16_MIN INT_LEAST16_MIN
#define INT_FAST32_MIN INT_LEAST32_MIN
#ifdef stdint_int64_defined
typedef int_least64_t int_fast64_t;
typedef uint_least64_t uint_fast64_t;
# define UINT_FAST64_MAX UINT_LEAST64_MAX
# define INT_FAST64_MAX INT_LEAST64_MAX
# define INT_FAST64_MIN INT_LEAST64_MIN
#endif
#undef stdint_int64_defined
/*
* Whatever piecemeal, per compiler thing we can do about the wchar_t
* type limits.
*/
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
# include <wchar.h>
# ifndef WCHAR_MIN
# define WCHAR_MIN 0
# endif
# ifndef WCHAR_MAX
# define WCHAR_MAX ((wchar_t)-1)
# endif
#endif
/*
* Whatever piecemeal, per compiler/platform thing we can do about the
* (u)intptr_t types and limits.
*/
#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
# define STDINT_H_UINTPTR_T_DEFINED
#endif
#ifndef STDINT_H_UINTPTR_T_DEFINED
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
# define stdint_intptr_bits 64
# elif defined (__WATCOMC__) || defined (__TURBOC__)
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
# define stdint_intptr_bits 16
# else
# define stdint_intptr_bits 32
# endif
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
# define stdint_intptr_bits 32
# elif defined (__INTEL_COMPILER)
/* TODO -- what will Intel do about x86-64? */
# endif
# ifdef stdint_intptr_bits
# define stdint_intptr_glue3_i(a,b,c) a##b##c
# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
# ifndef PRINTF_INTPTR_MODIFIER
# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
# endif
# ifndef PTRDIFF_MAX
# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef PTRDIFF_MIN
# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef UINTPTR_MAX
# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MAX
# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MIN
# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef INTPTR_C
# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
# endif
# ifndef UINTPTR_C
# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
# endif
typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
# else
/* TODO -- This following is likely wrong for some platforms, and does
nothing for the definition of uintptr_t. */
typedef ptrdiff_t intptr_t;
# endif
# define STDINT_H_UINTPTR_T_DEFINED
#endif
/*
* Assumes sig_atomic_t is signed and we have a 2s complement machine.
*/
#ifndef SIG_ATOMIC_MAX
# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
#endif
#endif
#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
/*
* Please compile with the maximum warning settings to make sure macros are not
* defined more than once.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define glue3_aux(x,y,z) x ## y ## z
#define glue3(x,y,z) glue3_aux(x,y,z)
#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0);
#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0);
#define DECL(us,bits) glue3(DECL,us,) (bits)
#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits)
int main () {
DECL(I,8)
DECL(U,8)
DECL(I,16)
DECL(U,16)
DECL(I,32)
DECL(U,32)
#ifdef INT64_MAX
DECL(I,64)
DECL(U,64)
#endif
intmax_t imax = INTMAX_C(0);
uintmax_t umax = UINTMAX_C(0);
char str0[256], str1[256];
sprintf (str0, "%d %x\n", 0, ~0);
sprintf (str1, "%d %x\n", i8, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1);
sprintf (str1, "%u %x\n", u8, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1);
sprintf (str1, "%d %x\n", i16, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1);
sprintf (str1, "%u %x\n", u16, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1);
sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1);
sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1);
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1);
#endif
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1);
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1);
TESTUMAX(8);
TESTUMAX(16);
TESTUMAX(32);
#ifdef INT64_MAX
TESTUMAX(64);
#endif
return EXIT_SUCCESS;
}
#endif
Compare STL sort with C qsort
File: sortCompare.cc:
// to compile on unix/OSX use
// g++ -I. sortCompare.cc TimeMeter.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
// include header for STL vector and algorithm
#include <vector>
#include <algorithm>
// if in windows use a portable version of stdint.h
#ifdef _WIN32
#include "pstdint.h" // for uint64_t
#else
#include <stdint.h> // for uint64_t
#endif
#include <stdlib.h> // for qsort
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include "TimeMeter.hh" // class computing elapsed time
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return rand() ; }
// specialization for uint32_t (32 bit integer)
template <>
inline
uint32_t random<uint32_t>() {
return uint32_t(rand()) ^ (uint32_t(rand())<<16) ;
}
// specialization for uint64_t (64 bit integer)
template <>
inline
uint64_t random<uint64_t>() {
return uint64_t(rand()) ^
(uint64_t(rand())<<16) ^
(uint64_t(rand())<<32) ^
(uint64_t(rand())<<48) ;
}
typedef uint64_t INTEGER ; // make an alias for uint64_t
int
C_comparator( void const * a, void const * b ) {
INTEGER const & A = *(static_cast<INTEGER const *>(a)) ;
INTEGER const & B = *(static_cast<INTEGER const *>(b)) ;
if ( A < B ) return -1 ;
if ( A > B ) return +1 ;
return 0 ;
}
int
main() {
vector<double> elapsed ; // define a vector containing saved elapsed time
vector<double> elapsed1 ; // define a vector containing saved elapsed time
vector<unsigned> sizevec ; // define a vector containing saved sizes
vector<INTEGER> A, B ; // a working vector with number to be oredered
TimeMeter tm ; // tm is an instance of a class TimeMeter for timing
elapsed . clear() ;
sizevec . clear() ; // vector are emptied and reduced of size 0
for ( unsigned sz = 1000 ; sz <= 1000000 ; sz *= 2 ) {
A . clear() ; // empty the vector, size is 0
A . reserve( sz ) ; // reserve memory for sz elements
for ( unsigned j = 0 ; j < sz ; ++j ) A . push_back( random<INTEGER>() ) ;
// make a copy of vector A
B . resize(A . size()) ;
copy( A.begin(), A.end(), B.begin() ) ;
cout << "sorting " << setw(6) << sz << flush ;
// setw(6) reserve 6 character for the next output
// flush : write immediately to the standard output (empty the buffer)
tm . start() ; // start time computation
sort( A . begin(), A . end() ) ; // STL ruotine to sort a vector
double e = tm . milliseconds() ;
elapsed . push_back( e ) ;
sizevec . push_back( sz ) ;
cout << " STL: " << setprecision(4) << setw(6) << e << "ms " ;
// using qsort
tm . start() ; // start time computation
qsort( &B.front(), B.size(), sizeof(B[0]), C_comparator ) ;
e = tm . milliseconds() ;
elapsed1 . push_back( e ) ;
cout << " qsort: " << setprecision(4) << setw(6) << e << "ms\n" ;
}
cout << "\n\n\n" ;
for ( unsigned i = 0 ; i < sizevec . size() ; ++i ) {
double e = elapsed[i] ;
double e1 = elapsed1[i] ;
unsigned sz = sizevec[i] ;
cout << "n = " << setw(6) << sz
<< " elapsed " << setw(8) << setprecision(4) << e << "ms"
<< " elapsed/(n*log(n)) = " << setw(10) << 100000*e/(sz*log(sz))
<< " elapsed1 " << setw(8) << setprecision(4) << e1 << "ms"
<< " elapsed1/(n*log(n)) = " << setw(10) << 100000*e1/(sz*log(sz))
<< " elapsed1/elapsed = " << setw(10) << e1/e
<< '\n' ;
}
return 0 ; // return is a statement for returning value to the caller
}
/*
Results with various optimization options
g++ -O0 -I. sortCompare.cc TimeMeter.cc
sorting 1000 STL: 0.194ms qsort: 0.132ms
sorting 2000 STL: 0.448ms qsort: 0.276ms
sorting 4000 STL: 0.943ms qsort: 0.679ms
sorting 8000 STL: 2.022ms qsort: 1.288ms
sorting 16000 STL: 4.66ms qsort: 2.761ms
sorting 32000 STL: 13.11ms qsort: 6.587ms
sorting 64000 STL: 18.91ms qsort: 13.21ms
sorting 128000 STL: 45.3ms qsort: 26.46ms
sorting 256000 STL: 90.34ms qsort: 57.22ms
sorting 512000 STL: 187.6ms qsort: 126.4ms
g++ -O1 -I. sortCompare.cc TimeMeter.cc
sorting 1000 STL: 0.044ms qsort: 0.097ms
sorting 2000 STL: 0.093ms qsort: 0.221ms
sorting 4000 STL: 0.2ms qsort: 0.497ms
sorting 8000 STL: 0.49ms qsort: 0.922ms
sorting 16000 STL: 1.237ms qsort: 2.168ms
sorting 32000 STL: 1.999ms qsort: 4.228ms
sorting 64000 STL: 5.265ms qsort: 10.21ms
sorting 128000 STL: 8.86ms qsort: 19.68ms
sorting 256000 STL: 18.47ms qsort: 44.15ms
sorting 512000 STL: 45.12ms qsort: 88.37ms
g++ -O2 -I. sortCompare.cc TimeMeter.cc
sorting 1000 STL: 0.042ms qsort: 0.096ms
sorting 2000 STL: 0.09ms qsort: 0.2ms
sorting 4000 STL: 0.192ms qsort: 0.427ms
sorting 8000 STL: 0.408ms qsort: 0.93ms
sorting 16000 STL: 0.997ms qsort: 2.145ms
sorting 32000 STL: 1.864ms qsort: 4.203ms
sorting 64000 STL: 4.076ms qsort: 14.47ms
sorting 128000 STL: 8.562ms qsort: 20.16ms
sorting 256000 STL: 18.13ms qsort: 41.41ms
sorting 512000 STL: 42.95ms qsort: 85.43ms
g++ -O3 -I. sortCompare.cc TimeMeter.cc
sorting 1000 STL: 0.042ms qsort: 0.096ms
sorting 2000 STL: 0.087ms qsort: 0.209ms
sorting 4000 STL: 0.256ms qsort: 0.429ms
sorting 8000 STL: 0.406ms qsort: 0.912ms
sorting 16000 STL: 0.872ms qsort: 1.962ms
sorting 32000 STL: 1.89ms qsort: 5.299ms
sorting 64000 STL: 4.61ms qsort: 9.939ms
sorting 128000 STL: 8.526ms qsort: 19.9ms
sorting 256000 STL: 19.01ms qsort: 43.14ms
sorting 512000 STL: 40.74ms qsort: 84.79ms
*/
Lesson of 17 February 2011
Union and big/little endian
File: biglittle.cc:
// to compile on unix/OSX use
// g++ -I. biglittle.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
// include header for STL vector and algorithm
#include <vector>
#include <algorithm>
#include "pstdint.h" // for uint64_t
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
using namespace std ;
int
main() {
// declare a struct called pluto
struct pluto {
float x, y ;
} ;
// declare a struct called pluto
typedef struct { float x, y ; } typeStructWithXYField ;
// declare a struct called pippo
struct pippo {
double a ;
double b ;
double c ;
int d ;
struct { // no name struct
float x, y ;
} ABC ;
} ;
union checkBigEndian {
uint64_t a_number ;
uint8_t a_list[8] ;
} ;
// define X of type struct pippo
struct pippo X ;
typeStructWithXYField Z ;
X . ABC . x = 1 ;
union checkBigEndian check ;
check . a_number = 0x0102030405060708 ;
cout << hex
<< "a[0] = " << (int)check . a_list[0] << '\n'
<< "a[1] = " << (int)check . a_list[1] << '\n'
<< "a[2] = " << (int)check . a_list[2] << '\n'
<< "a[3] = " << (int)check . a_list[3] << '\n'
<< "a[4] = " << (int)check . a_list[4] << '\n'
<< "a[5] = " << (int)check . a_list[5] << '\n'
<< "a[6] = " << (int)check . a_list[6] << '\n'
<< "a[7] = " << (int)check . a_list[7] << '\n' ;
uint64_t a_value = 0x0102030405060708 ;
//uint8_t * a_pointer = (uint8_t*)(&a_value) ;
uint8_t * a_pointer = reinterpret_cast<uint8_t*>(&a_value) ;
cout << hex
<< "a[0] = " << (int)a_pointer[0] << '\n'
<< "a[1] = " << (int)a_pointer[1] << '\n'
<< "a[2] = " << (int)a_pointer[2] << '\n'
<< "a[3] = " << (int)a_pointer[3] << '\n'
<< "a[4] = " << (int)a_pointer[4] << '\n'
<< "a[5] = " << (int)a_pointer[5] << '\n'
<< "a[6] = " << (int)a_pointer[6] << '\n'
<< "a[7] = " << (int)a_pointer[7] << '\n' ;
return 0 ;
}
Dynamic allocation on the stack
File: Dallocation.cc:
// to compile on unix/OSX use
// g++ -I. Dallocation.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
using namespace std ;
#ifdef USE_ALLOCA
// alloca use stack for allocation
#include <alloca.h>
#endif
int
main( int argc, char const * argv []) {
int dim ;
sscanf( argv[1], "%d", &dim ) ;
{
#ifdef USE_ALLOCA
unsigned * A = (unsigned*)alloca(dim*sizeof(unsigned)) ;
#else
unsigned A[dim] ;
#endif
cout << "A size = " << sizeof( A ) << endl ;
for ( unsigned i = 0 ; i < sizeof(A)/sizeof(A[0]) ; ++i )
A[i] = i ;
}
{
#ifdef USE_ALLOCA
unsigned * B = (unsigned*)alloca(dim*sizeof(unsigned)) ;
#else
unsigned B[dim] ;
#endif
cout << "B size = " << sizeof( B ) << endl ;
for ( unsigned i = 0 ; i < sizeof(B)/sizeof(B[0]) ; ++i )
B[i] = i ;
{
#ifdef USE_ALLOCA
unsigned * C = (unsigned*)alloca(dim*sizeof(unsigned)) ;
#else
unsigned C[dim] ;
#endif
cout << "C size = " << sizeof( C ) << endl ;
for ( unsigned i = 0 ; i < sizeof(C)/sizeof(C[0]) ; ++i )
C[i] = i ;
}
}
return 0 ;
}
The C way of dynamic allocation
File: Dallocation2.cc:
// to compile on unix/OSX use
// g++ -I. Dallocation.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
using namespace std ;
// use dynamic allocation of C
int
main( int argc, char const * argv []) {
int dim ;
sscanf( argv[1], "%d", &dim ) ;
{
unsigned * A = (unsigned*)malloc( dim*sizeof(unsigned) ) ;
if ( A == NULL ) {
cerr << "Memory allocation failed\n" ;
exit(0) ;
}
cout << "A size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
A[i] = i ;
free( A ) ; A = NULL ; // free used memory
free( A ) ; // free used memory
}
{
unsigned * B = (unsigned*)malloc( dim*sizeof(unsigned) ) ;
if ( B == NULL ) {
cerr << "Memory allocation failed\n" ;
exit(0) ;
}
cout << "B size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
B[i] = i ;
free( B ) ; // free used memory
{
unsigned * C = (unsigned*)malloc( dim*sizeof(unsigned) ) ;
if ( C == NULL ) {
cerr << "Memory allocation failed\n" ;
exit(0) ;
}
cout << "C size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
C[i] = i ;
}
}
return 0 ;
}
The C++ way of dynamic allocation
File: Dallocation3.cc:
// to compile on unix/OSX use
// g++ -I. Dallocation.cc
//
// include header for C++ I/O
// search stdio.h in standard C/C++ include directory e.g. /usr/include
#include <iostream> // for the definition of cin, cout, ...
#include <iomanip> // for manipulator setw, setprecision ...
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
using namespace std ;
// use dynamic allocation of C++
int
main( int argc, char const * argv []) {
if ( argc != 2 ) {
cerr << " expect an argument!\n" ;
exit(1) ;
}
int dim ;
sscanf( argv[1], "%d", &dim ) ;
{
unsigned * A = new unsigned[ dim ] ;
cout << "A size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
A[i] = i ;
delete [] A ;
}
{
unsigned * B = new unsigned[ dim ] ;
cout << "B size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
B[i] = i ;
delete [] B ; // free used memory
{
unsigned * C = new unsigned[ dim ] ;
cout << "C size = " << dim*sizeof(unsigned) << endl ;
for ( unsigned i = 0 ; i < dim ; ++i )
C[i] = i ;
delete [] C ; // free used memory
}
}
return 0 ;
}
Lesson of 18 February 2011
Example of linking with foreign language (and decoration)
A Fortran routine making simple addition
File: add.f:
subroutine add( a, b, c )
real*8 a(*), b(*), c(*)
do i=1,3
c(i) = a(i) + b(i)
end do
return
end
A simple C++ code with use external routine
File: testDecoration.cc:
// to compile on unix/OSX use
// g++ -c testDecoration.cc (for generation of testDecoration.o)
// g95 -c add.f (for generation of test.o a fortran routine)
// g++ testDecoration.o add.o -o test
// ./test (to run)
//
#include <iostream>
using namespace std ;
typedef struct {
double x, y, z ;
} Point3D ;
// routine 1
void
add( Point3D const * const a, // pointer to a structure, pointer non modificable
Point3D const * const b,
Point3D * const c ) {
c -> x = a -> x + b -> x ;
c -> y = a -> y + b -> y ;
c -> z = a -> z + b -> z ;
}
// routine 2
void
add( Point3D const & a,
Point3D const & b,
Point3D & c ) {
c.x = a.x + b.x ;
c.y = a.y + b.y ;
c.z = a.z + b.z ;
}
#define F77NAME(A) A##_
// routine 3
// make a prototype of the external routine
extern "C" void F77NAME(add)( double * a, double * b, double * c ) ;
int
main( int argc, char const * argv []) {
double a[3] = {1,2,3} ;
double b[3] = {3,4,5} ;
double c[3] ;
F77NAME(add)( a, b, c ) ; // only routine 3 match the prototype
cout << "c = [ " << c[0] << ", " << c[1] << ", " << c[2] << " ]\n" ;
return 0 ;
}
The C decoration A simple code which use an external printOnTerminal
C routine
File: testDecoration2.cc:
// to compile on unix/OSX use
// g++ -c testDecoration2.cc testDecoration2b.c -o test (for generation of testDecoration.o)
// ./test (to run)
//
#include <iostream>
using namespace std ;
// declare a prototype for a C++ routine
void printOnTerminal( char const msg[] ) ;
int
main( int argc, char const * argv []) {
char theMessage[] = "Ciao Mamma!\n" ;
printOnTerminal( theMessage ) ;
return 0 ;
}
A C code which define _Z15printOnTerminalPKc
. The code link (on GNU compiler) because the name fit the decoration of C++:
File: testDecoration2b.c:
// to compile on unix/OSX use
// g++ -c testDecoration2.cc
// gcc -c testDecoration2b.c
// g++ testDecoration2.o testDecoration2b.o -o test (for generation of testDecoration.o)
// ./test (to run)
//
#include <stdio.h>
void
_Z15printOnTerminalPKc( char const msg[] ) {
printf(msg) ;
}
Another example of Fortran linking A simple code which use an external print
Fortran routine
File: testFortranLink.cc:
// to compile on unix/OSX use
// g++ -c testDecoration.cc (for generation of testDecoration.o)
// g95 -c test.f (for generation of test.o a fortran routine)
// g++ testDecoration.o test.o -o test
// ./test (to run)
//
#include <cstdlib>
#include <cstring>
using namespace std ;
#define F77NAME(A) A##_
// make a prototype of the external routine
extern "C" void F77NAME(print)( char const * msg, int * value, unsigned long msgLen ) ;
int
main( int argc, char const * argv []) {
char msg[] = "I am a C message!" ;
int value = 199 ;
F77NAME(print)( msg, &value, strlen(msg) ) ;
return 0 ;
}
The fortran routine for which a parameter is a variable length string:
File: print.f:
subroutine print( msg, value )
integer value
character*(*) msg
print *,msg,value
return
end
Lesson of 21 February 2011
Example of heapsort ordering
The header file
File: heapsort.hh:
/*
//
// Heap Sort
//
//
//
*/
void
heapsort( double v[], unsigned size ) ;
Implementation
File: heapsort.cc:
// to compile on unix/OSX use
// g++ -c testDecoration.cc (for generation of testDecoration.o)
// g95 -c add.f (for generation of test.o a fortran routine)
// g++ testDecoration.o add.o -o test
// ./test (to run)
//
// include STL for swap
#include <algorithm>
static
inline
unsigned
father( unsigned son )
{ return (son-1)>>1 ; }
static
inline
unsigned
left_son( unsigned father )
{ return (father<<1)|1 ; } // equivalent to 2*father+1
static
inline
unsigned
right_son( unsigned father )
{ return (father<<1)+2 ; } // equivalent to 2*father+2
/*
//
// Build incrementally a heap.
// Each element is inserted to the heap starting from 1 to size-1.
*/
static
void
make_heap( double v[], unsigned size ) {
for ( unsigned i = 1 ; i < size ; ++i ) {
// insert v[i] to the heap
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
}
}
/*
// Given an heap of k+1 element drop root and store to the element a[k].
*/
static
void
drop( double v[], unsigned k ) {
double root = v[0] ; // maximum element
unsigned winner, i = 0 ;
while ( (winner=left_son(i)) <= k ) { // check if winner is inside the heap
unsigned rs = right_son(i) ;
if ( rs <= k && v[winner] < v[rs] ) winner = rs ;
// move winner to the father
v[i] = v[winner] ;
i = winner ;
}
// i is the insertion position for v[k] the last element of the heap.
// Now insert v[k] at position i
v[i] = v[k] ;
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
// copy root to v[k]
v[k] = root ;
}
void
heapsort( double v[], unsigned size ) {
// build the heap
make_heap( v, size ) ;
// drop maximimum from the heap
while ( --size > 0 ) drop( v, size ) ;
}
// file heapsort.cc
Testing the sort
File: test.cc:
// to compile on unix/OSX use
// g++ test.cc heapsort.cc -o test
// ./test (to run)
//
#include <iostream>
#include "heapsort.hh"
#define GET_SIZE(A) (sizeof(A)/sizeof(A[0]))
int
main() {
double a[] = {1, 2, 5, 32, -19, 2, 3, 9, 2, 2, 2, -3 } ;
unsigned const N = GET_SIZE(a) ;
heapsort( a, N ) ;
for ( unsigned i = 0 ; i < N ; ++i )
std::cout << "a[ " << i << " ] = " << a[i] << '\n' ;
return 0 ;
}
Example of heapsort with template
The templated algorithm
File: heapsortTemplate.hh:
// to compile on unix/OSX use
// g++ -c testDecoration.cc (for generation of testDecoration.o)
// g95 -c add.f (for generation of test.o a fortran routine)
// g++ testDecoration.o add.o -o test
// ./test (to run)
//
// include STL for swap
#include <algorithm>
static
inline
unsigned
father( unsigned son )
{ return (son-1)>>1 ; }
static
inline
unsigned
left_son( unsigned father )
{ return (father<<1)|1 ; } // equivalent to 2*father+1
static
inline
unsigned
right_son( unsigned father )
{ return (father<<1)+2 ; } // equivalent to 2*father+2
/*
//
// Build incrementally a heap.
// Each element is inserted to the heap starting from 1 to size-1.
*/
template <typename T>
void
make_heap( T v[], unsigned size ) {
for ( unsigned i = 1 ; i < size ; ++i ) {
// insert v[i] to the heap
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
}
}
/*
// Given an heap of k+1 element drop root and store to the element a[k].
*/
template <typename T>
void
drop( T v[], unsigned k ) {
T root = v[0] ; // maximum element
unsigned winner, i = 0 ;
while ( (winner=left_son(i)) <= k ) { // check if winner is inside the heap
unsigned rs = right_son(i) ;
if ( rs <= k && v[winner] < v[rs] ) winner = rs ;
// move winner to the father
v[i] = v[winner] ;
i = winner ;
}
// i is the insertion position for v[k] the last element of the heap.
// Now insert v[k] at position i
v[i] = v[k] ;
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
// copy root to v[k]
v[k] = root ;
}
template <typename T>
void
heapsort( T v[], unsigned size ) {
// build the heap
make_heap( v, size ) ;
// drop maximimum from the heap
while ( --size > 0 ) drop( v, size ) ;
}
// file heapsort.cc
Testing the sort
File: test1.cc:
// to compile on unix/OSX use
// g++ test1.cc heapsort.cc -o test
// ./test (to run)
//
#include <iostream>
#include "heapsortTemplate.hh"
#define GET_SIZE(A) (sizeof(A)/sizeof(A[0]))
int
main() {
double a[] = {1, 2, 5, 32, -19, 2, 3, 9, 2, 2, 2, -3 } ;
int b[] = {1, 2, 5, 32, -19, 2, 3, 9, 2, 2, 2, -3 } ;
unsigned const Na = GET_SIZE(a) ;
unsigned const Nb = GET_SIZE(b) ;
heapsort<double>( a, Na ) ;
heapsort<int>( b, Nb ) ;
for ( unsigned i = 0 ; i < Na ; ++i )
std::cout << "a[ " << i << " ] = " << a[i] << '\n' ;
return 0 ;
}
Example of heapsort with template instantiation
The templated algorithm
File: heapsort2.hxx:
//
// heapsort implementation
//
//
#include <algorithm>
#include "heapsort2.hh"
static
inline
unsigned
father( unsigned son )
{ return (son-1)>>1 ; }
static
inline
unsigned
left_son( unsigned father )
{ return (father<<1)|1 ; } // equivalent to 2*father+1
static
inline
unsigned
right_son( unsigned father )
{ return (father<<1)+2 ; } // equivalent to 2*father+2
/*
//
// Build incrementally a heap.
// Each element is inserted to the heap starting from 1 to size-1.
*/
template <typename T>
void
HeapSort<T>::make_heap( T v[], unsigned size ) {
for ( unsigned i = 1 ; i < size ; ++i ) {
// insert v[i] to the heap
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
}
}
/*
// Given an heap of k+1 element drop root and store to the element a[k].
*/
template <typename T>
void
HeapSort<T>::drop( T v[], unsigned k ) {
T root = v[0] ; // maximum element
unsigned winner, i = 0 ;
while ( (winner=left_son(i)) <= k ) { // check if winner is inside the heap
unsigned rs = right_son(i) ;
if ( rs <= k && v[winner] < v[rs] ) winner = rs ;
// move winner to the father
v[i] = v[winner] ;
i = winner ;
}
// i is the insertion position for v[k] the last element of the heap.
// Now insert v[k] at position i
v[i] = v[k] ;
for ( unsigned j = i ; j > 0 ; j = father(j) )
if ( v[j] > v[father(j)] ) std::swap( v[j], v[father(j)] ) ;
else break ;
// copy root to v[k]
v[k] = root ;
}
template <typename T>
void
HeapSort<T>::sort( T v[], unsigned size ) {
// build the heap
make_heap( v, size ) ;
// drop maximimum from the heap
while ( --size > 0 ) drop( v, size ) ;
}
// file heapsort.cc
The header file
File: heapsort2.hh:
//
// heapsort implementation
//
//
#ifndef HEAPSORT2_HH
#define HEAPSORT2_HH
// put elements in a struct for explicit specialization
template <typename T>
class HeapSort {
static void make_heap( T v[], unsigned size ) ;
static void drop( T v[], unsigned k ) ;
public:
static void sort( T v[], unsigned size ) ;
} ;
#endif
The explicit instantiation
File: heapsort2.cc:
#include "heapsort2.hh"
#include "heapsort2.hxx"
// intantiate class HeapSort for double and int specialization
template class HeapSort<double> ;
template class HeapSort<int> ;
Testing the sort
File: test2.cc:
// to compile on unix/OSX use
// g++ test.cc heapsort.cc -o test
// ./test (to run)
//
#include <iostream>
#include "heapsort2.hh"
#define GET_SIZE(A) (sizeof(A)/sizeof(A[0]))
int
main() {
double a[] = {1, 2, 5, 32, -19, 2, 3, 9, 2, 2, 2, -3 } ;
int b[] = {1, 2, 5, 32, -19, 2, 3, 9, 2, 2, 2, -3 } ;
unsigned const Na = GET_SIZE(a) ;
unsigned const Nb = GET_SIZE(b) ;
HeapSort<double>::sort( a, Na ) ;
HeapSort<int>::sort( b, Nb ) ;
for ( unsigned i = 0 ; i < Na ; ++i )
std::cout << "a[ " << i << " ] = " << a[i] << '\n' ;
return 0 ;
}
Lesson of 22 February 2011
Example of struct
with methods
File: example1.cc:
// to compile on unix/OSX use
// g++ example1.cc (for generation of testDecoration.o)
// ./a.out (to run)
//
#include <iostream>
#include <algorithm>
/*
A stupid example of variable size vector
*/
typedef struct variableVector {
int size ;
double * values ;
// define a constructor
variableVector() {
std::cout << "create a variableVector\n" ;
size = 0 ;
values = NULL ;
}
// define a constructor
variableVector( int sz ) {
std::cout << "create a variableVector of size " << sz << "\n" ;
size = sz ;
values = new double[sz] ;
}
// define a destructor
~variableVector() {
std::cout << "destroy a variableVector\n" ;
if ( values != NULL ) delete [] values ;
}
// ri-define default assignment operator
variableVector const &
operator = ( variableVector const & a ) {
std::cout << "use variableVector const & operator =\n" ;
size = a . size ;
if ( values != NULL ) delete [] values ;
values = new double[ size ] ;
for ( int i = 0 ; i < size ; ++i ) values[i] = a . values[i] ;
}
// declaration of a method which will add a to the struct
void addTo( struct variableVector const & a ) ;
} variableVector ;
// instance of addTo struct variableVector b, a ; b . addTo( a ) ;
void
variableVector::addTo( variableVector const & a ) {
int minSize = std::min( size, a . size ) ;
for ( int i = 0 ; i < minSize ; ++i ) values[i] += a . values[i] ;
}
// prototype (declaration) of a C like function to add vector a to vector b
void
addTo( variableVector const & a,
variableVector & res ) {
int minSize = std::min( res . size, a . size ) ;
for ( int i = 0 ; i < minSize ; ++i ) res . values[i] += a . values[i] ;
}
// prototype (declaration) of a C like
void
allocate( variableVector & res, int size ) {
res . size = size ;
if ( res . values != NULL ) delete [] res . values ;
res . values = new double[ size ] ;
}
// allocate resource for res
void
deallocate( variableVector & res ) {
res . size = 0;
delete [] res . values ;
res . values = NULL ;
}
// initialize vector res
void
initialize( variableVector & res ) {
res . size = 0;
res . values = NULL ;
}
// perform deep copy of a to res
void
deepCopy( variableVector const & a, variableVector & res ) {
allocate( res, a.size ) ;
for ( int i = 0 ; i < a.size ; ++i ) res . values[i] = a . values[i] ;
}
void
copy( variableVector const & a, variableVector & res ) {
res . size = a . size ;
res . values = a . values ; // loss pointer res . values
}
int
main() {
variableVector a, b(100), c(120) ;
initialize(a) ;
allocate( a, 100 ) ;
//copy( a, b ) ;
std::cout << "passa\n" ;
a = b ;
std::cout << "passa\n" ;
a . size = 0 ; // corrupt the "class" a
return 0 ;
}
A simple class
File: example2.cc:
// to compile on unix/OSX use
// g++ example2.cc (for generation of testDecoration.o)
// ./a.out (to run)
//
#include <iostream>
#include <algorithm>
/*
A stupid example of variable size vector
*/
class variableVector {
// private part of the class
int size ;
double * values ;
void allocate( int sz ) {
if ( values != NULL ) delete [] values ;
values = new double[ sz ] ;
}
void deallocate() {
if ( values != NULL ) delete [] values ;
values = NULL ;
}
public:
// define a constructor
variableVector() {
std::cout << "create a variableVector\n" ;
size = 0 ;
values = NULL ;
}
// define a constructor
variableVector( int sz ) {
std::cout << "create a variableVector of size " << sz << "\n" ;
allocate(sz) ;
}
int getSize() const { return size ; }
// destructor
~variableVector() {
std::cout << "destroy a variableVector\n" ;
deallocate() ;
}
variableVector const &
operator = ( variableVector const & a ) {
std::cout << "use variableVector const & operator =\n" ;
allocate( a.size ) ;
for ( int i = 0 ; i < size ; ++i ) values[i] = a . values[i] ;
}
// declaration of a method which will add a to the struct
void addTo( struct variableVector const & a ) ;
} ;
// instance of addTo struct variableVector b, a ; b . addTo( a ) ;
void
variableVector::addTo( variableVector const & a ) {
int minSize = std::min( size, a . size ) ;
for ( int i = 0 ; i < minSize ; ++i ) values[i] += a . values[i] ;
}
int
main() {
variableVector a, b(100), c(120) ;
//copy( a, b ) ;
a = b ;
a . getSize() ;
return 0 ;
}
A simple example of template metaprogramming
File: example3.cc:
// to compile on unix/OSX use
// g++ example3.cc (for generation of testDecoration.o)
// ./a.out (to run)
//
#include <iostream>
#include <algorithm>
/*
Example of template metaprogram
*/
template <unsigned N>
class Vector {
int values[N] ;
} ;
template <unsigned N>
class Factorial {
public:
static unsigned const RES = N*Factorial<N-1>::RES ;
} ;
template <>
class Factorial<1> {
public:
static unsigned const RES = 1 ;
} ;
int
main() {
Vector<10> a, b, c ;
Factorial<1> f1 ;
Factorial<2> f2 ;
Factorial<6> f6 ;
Factorial<10> f10 ;
std::cout << f1.RES << '\n' ; // access to class variable RES
std::cout << f2.RES << '\n' ; // access to class variable RES
std::cout << f6.RES << '\n' ; // access to class variable RES
std::cout << f10.RES << '\n' ; // access to class variable RES
return 0 ;
}
Lesson of 23 February 2011
Example of use of the reference in C++
File: example1.cc:
/*
Stupid example with reference
*/
#include <iostream>
#include <iomanip>
using namespace std ;
int
main() {
int aVeryLongAndStupidName = 1 ;
int & b = aVeryLongAndStupidName ;
int * pa = &aVeryLongAndStupidName ;
int * pb = &b ;
cout << "\npa = " << pa
<< "\npb = " << pb
<< "\n&b = " << &b
<< "\n&aVeryLongAndStupidName = " << &aVeryLongAndStupidName
<< '\n' ;
cout << " aVeryLongAndStupidName = " << aVeryLongAndStupidName
<< " b = " << b
<< '\n' ;
++aVeryLongAndStupidName ;
cout << " aVeryLongAndStupidName = " << aVeryLongAndStupidName
<< " b = " << b
<< '\n' ;
++b ;
cout << " aVeryLongAndStupidName = " << aVeryLongAndStupidName
<< " b = " << b
<< '\n' ;
long c = (long) &b ;
cout << "&b = " << &b
<< " c = " << hex << c
<< '\n' ;
cout << sizeof(int*) << '\n' ;
return 0 ;
}
Example of use of pointers in C++
File: example2.cc:
/*
Stupid example with pointer
*/
#include <iostream>
#include <iomanip>
using namespace std ;
int
main() {
int aStupidVector[] = { -123,1,2,3,4,5,6,7,8,9 } ;
int aStupidVectorSize = sizeof(aStupidVector)/sizeof(aStupidVector[0]) ;
int * pa = aStupidVector ;
cout << "*aStupidVector = " << *aStupidVector << '\n' ;
cout << "*pa = " << *pa << '\n' ;
++pa ;
cout << "*pa = " << *pa << '\n' ;
pa += 6 ; // pa = pa + 6
cout << "*pa = " << *pa << '\n' ;
pa -= 2 ; // pa = pa - 2
cout << "*pa = " << *pa << '\n' ;
int * pb = aStupidVector + 1 ;
unsigned long diff = pb - aStupidVector ;
cout << "diff = " << diff << '\n' ;
unsigned long diff1 = (long) pb - (long) aStupidVector ;
cout << "diff1 = " << diff1 << '\n' ;
pa = aStupidVector ;
pb = aStupidVector + aStupidVectorSize ;
for ( int * pp = pa ; pp < pb ; ++pp )
cout << "vec[ " << pp-pa << "] = " << *pp << '\n' ;
for ( int i = 0 ; i < aStupidVectorSize ; ++i )
cout << "vec[ " << i << "] = " << aStupidVector[i] << '\n' ;
int * pp = pa ;
while ( pp < pb ) cout << "vec[ " << pp-pa << "] = " << *pp++ << '\n' ;
return 0 ;
}
A simple class implementing polynomial algebra (incomplete)
File: poly.hh:
/*
An example of class implementing integer polynomial
*/
#include <vector>
#include <iostream>
class poly {
std::vector<int> coeffs ; // data are in the private part of the class
void reduce() ;
public:
// contructors
poly() ; // make a zero polinomial
poly( poly const & ) ; // copy constructor
poly( int coeffs[], int degree ) ; // make a polynomial from a C vector
poly( std::vector<int> const & coeffs ) ; // make a polynomial from a C vector
int degree() const { return coeffs.size()-1 ; }
// access to the coefficients
int const & operator [] ( int i ) const { return coeffs[i] ; }
int & operator [] ( int i ) { return coeffs[i] ; }
int get( int i ) const { return i < coeffs.size() ? coeffs[i] : 0 ; }
// internal operator
poly const & operator += ( poly const & a ) ;
poly const & operator -= ( poly const & a ) ;
poly const & operator *= ( poly const & a ) ;
poly const & operator /= ( poly const & a ) ;
poly const & operator %= ( poly const & a ) ;
// evaluation operator
int const & operator () ( int x ) const ;
void print( std::ostream & s ) const ;
} ;
// external operator
poly operator + ( poly const & a, poly const & b ) ;
poly operator - ( poly const & a, poly const & b ) ;
poly operator * ( poly const & a, poly const & b ) ;
poly operator / ( poly const & a, poly const & b ) ;
poly operator % ( poly const & a, poly const & b ) ;
inline
std::ostream & operator << ( std::ostream & s, poly const & a )
{ a . print(s) ; return s ; }
File: poly.cc:
#include "poly.hh"
#include <algorithm>
// contructors
poly::poly() {
std::cout << "call poly::poly()\n" ;
coeffs . clear() ;
}
poly::poly( poly const & a ) {
std::cout << "call poly::poly( poly const & )\n" ;
coeffs . resize( a . coeffs . size() ) ;
std::copy( a.coeffs.begin(), a.coeffs.end(), coeffs.begin() ) ;
}
poly::poly( int coeffs[], int degree ) {
std::cout << "call poly::poly( int coeffs[], int degree )\n" ;
this -> coeffs . resize( degree + 1 ) ;
std::copy( coeffs, coeffs + degree + 1, this -> coeffs . begin() ) ;
reduce() ;
}
poly::poly( std::vector<int> const & coeffs ) {
std::cout << "call poly::poly(std::vector<int> const & coeffs)\n" ;
this -> coeffs . resize( coeffs.size() ) ;
std::copy( coeffs . begin(), coeffs . end(), this -> coeffs . begin() ) ;
reduce() ;
}
void
poly::reduce() {
while ( (!coeffs.empty()) && coeffs.back() == 0 )
this -> coeffs . pop_back() ;
}
void
poly::print( std::ostream & s ) const {
if ( coeffs . size() == 0 ) {
s << "0" ;
} else if ( coeffs . size() == 1 ) {
s << coeffs[0] ;
} else {
if ( coeffs[0] != 0 ) s << coeffs[0] ;
if ( coeffs[1] != 0 ) {
if ( coeffs[0] != 0 ) s << " + " ;
if ( coeffs[1] == 1 ) s << "x" ;
else s << coeffs[1] << "*x" ;
}
for ( int i = 2 ; i < coeffs.size() ; ++i )
if ( coeffs[i] != 0 )
if ( coeffs[i] == 1 ) s << " + x^" << i ;
else s << " + " << coeffs[i] << "*x^" << i ;
}
}
poly const &
poly::operator += ( poly const & a ) {
if ( coeffs . size() < a . coeffs . size() )
coeffs . resize( a . coeffs . size() ) ;
for ( int i = 0 ; i <= a . degree() ; ++i )
coeffs[i] += a[i] ;
reduce() ;
return *this ;
}
poly const &
poly::operator -= ( poly const & a ) {
if ( coeffs . size() < a . coeffs . size() )
coeffs . resize( a . coeffs . size() ) ;
for ( int i = 0 ; i <= a . degree() ; ++i )
coeffs[i] -= a[i] ;
reduce() ;
return *this ;
}
poly operator + ( poly const & a, poly const & b ) {
int degree = std::max(a.degree(), b.degree()) ;
std::vector<int> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i )
coeffs[i] = a.get(i) + b.get(i) ;
return poly( coeffs ) ;
}
poly operator * ( poly const & a, poly const & b ) {
int degree = a . degree() + b . degree() ;
std::vector<int> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i ) {
coeffs[i] = 0 ;
for ( int k = 0 ; k <= i ; ++k )
coeffs[i] += a.get(k)*b.get(i-k) ;
}
return poly( coeffs ) ;
}
#if 0
// internal operator
poly const & operator += ( poly const & a ) ;
poly const & operator -= ( poly const & a ) ;
poly const & operator *= ( poly const & a ) ;
poly const & operator /= ( poly const & a ) ;
poly const & operator %= ( poly const & a ) ;
// evaluation operator
int const & operator () ( int x ) const ;
// external operator
poly operator + ( poly const & a, poly const & b ) ;
poly operator - ( poly const & a, poly const & b ) ;
poly operator * ( poly const & a, poly const & b ) ;
poly operator / ( poly const & a, poly const & b ) ;
poly operator % ( poly const & a, poly const & b ) ;
#endif
Testing the class
File: test.cc:
#include "poly.hh"
#include <iostream>
int
main() {
poly a, b, c, d ;
poly e(a) ;
int coeffs[] = { 1, 0, 2, 3, 4, 0 } ;
int degree = sizeof(coeffs)/sizeof(coeffs[0])-1 ;
poly f(coeffs,degree) ;
a = f+f ;
std::cout << "POLY f = " << f << '\n' ;
std::cout << "POLY a = " << a << '\n' ;
std::cout << "POLY a*f = " << a*f << '\n' ;
return 0 ;
}
Lesson of 24 February 2011 (part A)
Example of use of class and template
Basic polynomial class header
File: polyBasic.hh:
/*
* An example of class implementing integer polynomial
*/
#include <vector>
#include <iostream>
template <typename T>
class polyBasic {
/*
* Add public types to the class polyBasic
*/
public:
typedef T value_type ;
typedef std::vector<T> coeffs_type ;
private:
coeffs_type coeffs ; // data are in the private part of the class
void reduce() ;
public:
// contructors
polyBasic() ; // make a zero polinomial
polyBasic( polyBasic const & ) ; // copy constructor
polyBasic( value_type coeffs[], int degree ) ; // make a polynomial from a C vector
polyBasic( coeffs_type const & coeffs ) ; // make a polynomial from a C vector
int degree() const { return coeffs.size()-1 ; }
// access to the coefficients
value_type const & operator [] ( int i ) const { return coeffs[i] ; }
value_type & operator [] ( int i ) { return coeffs[i] ; }
value_type get( int i ) const { return i < coeffs.size() ? coeffs[i] : 0 ; }
// internal operator
polyBasic<T> const & operator = ( polyBasic<T> const & a ) ;
polyBasic<T> const & operator += ( polyBasic<T> const & a ) ;
polyBasic<T> const & operator -= ( polyBasic<T> const & a ) ;
// evaluation operator
T operator () ( T x ) const ;
void print( std::ostream & s ) const ;
} ;
// external operator
template <typename T> polyBasic<T> operator + ( polyBasic<T> const & a, polyBasic<T> const & b ) ;
template <typename T> polyBasic<T> operator - ( polyBasic<T> const & a, polyBasic<T> const & b ) ;
template <typename T>
inline
std::ostream & operator << ( std::ostream & s, polyBasic<T> const & a )
{ a . print(s) ; return s ; }
Body of the templated functions and methods
File: polyBasic.hxx:
// contructors
template <typename T>
polyBasic<T>::polyBasic() {
std::cout << "call polyBasic::polyBasic()\n" ;
coeffs . clear() ;
}
template <typename T>
polyBasic<T>::polyBasic( polyBasic<T> const & a ) {
std::cout << "call polyBasic::polyBasic( polyBasic const & )\n" ;
coeffs . resize( a . coeffs . size() ) ;
std::copy( a.coeffs.begin(), a.coeffs.end(), coeffs.begin() ) ;
}
template <typename T>
polyBasic<T>::polyBasic( T coeffs[], int degree ) {
std::cout << "call polyBasic::polyBasic( int coeffs[], int degree )\n" ;
this -> coeffs . resize( degree + 1 ) ;
std::copy( coeffs, coeffs + degree + 1, this -> coeffs . begin() ) ;
reduce() ;
}
template <typename T>
polyBasic<T>::polyBasic( std::vector<T> const & coeffs ) {
std::cout << "call polyBasic::polyBasic(std::vector<T> const & coeffs)\n" ;
this -> coeffs . resize( coeffs.size() ) ;
std::copy( coeffs . begin(), coeffs . end(), this -> coeffs . begin() ) ;
reduce() ;
}
template <typename T>
void
polyBasic<T>::reduce() {
while ( (!coeffs.empty()) && coeffs.back() == 0 )
this -> coeffs . pop_back() ;
}
template <typename T>
void
polyBasic<T>::print( std::ostream & s ) const {
if ( coeffs . size() == 0 ) {
s << "0" ;
} else if ( coeffs . size() == 1 ) {
s << coeffs[0] ;
} else {
if ( coeffs[0] != 0 ) s << coeffs[0] ;
if ( coeffs[1] != 0 ) {
if ( coeffs[0] != 0 ) s << " + " ;
if ( coeffs[1] == 1 ) s << "x" ;
else s << coeffs[1] << "*x" ;
}
for ( int i = 2 ; i < coeffs.size() ; ++i )
if ( coeffs[i] != 0 )
if ( coeffs[i] == 1 ) s << " + x^" << i ;
else s << " + " << coeffs[i] << "*x^" << i ;
}
}
// evaluation operator
template <typename T>
T
polyBasic<T>::operator () ( T x ) const {
T res = 0, xi = 1 ;
for ( int i = 0 ; i < coeffs . size() ; ++i, xi *= x )
res += coeffs[i] * xi ;
return res ;
}
template <typename T>
polyBasic<T> const &
polyBasic<T>::operator = ( polyBasic<T> const & a ) {
if ( coeffs . size() < a . coeffs . size() )
coeffs . resize( a . coeffs . size() ) ;
for ( int i = 0 ; i <= a . degree() ; ++i )
coeffs[i] = a[i] ;
reduce() ;
return *this ;
}
template <typename T>
polyBasic<T> const &
polyBasic<T>::operator += ( polyBasic<T> const & a ) {
if ( coeffs . size() < a . coeffs . size() )
coeffs . resize( a . coeffs . size() ) ;
for ( int i = 0 ; i <= a . degree() ; ++i )
coeffs[i] += a[i] ;
reduce() ;
return *this ;
}
template <typename T>
polyBasic<T> const &
polyBasic<T>::operator -= ( polyBasic<T> const & a ) {
if ( coeffs . size() < a . coeffs . size() )
coeffs . resize( a . coeffs . size() ) ;
for ( int i = 0 ; i <= a . degree() ; ++i )
coeffs[i] -= a[i] ;
reduce() ;
return *this ;
}
template <typename T>
polyBasic<T> operator + ( polyBasic<T> const & a, polyBasic<T> const & b ) {
int degree = std::max(a.degree(), b.degree()) ;
std::vector<T> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i )
coeffs[i] = a.get(i) + b.get(i) ;
return polyBasic<T>( coeffs ) ;
}
template <typename T>
polyBasic<T> operator - ( polyBasic<T> const & a, polyBasic<T> const & b ) {
int degree = std::max(a.degree(), b.degree()) ;
std::vector<T> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i )
coeffs[i] = a.get(i) - b.get(i) ;
return polyBasic<T>( coeffs ) ;
}
Explicit instantiation of the functions and methods
File: polyBasic.cc:
#include "polyBasic.hh" // include definition of class polyBasic
#include "polyBasic.hxx" // include declaration of template implementation
#define EXPLICIT_INSTANTIATION(TYPE) \
template class polyBasic<TYPE> ; \
template polyBasic<TYPE> operator + ( polyBasic<TYPE> const &, polyBasic<TYPE> const &) ; \
template polyBasic<TYPE> operator - ( polyBasic<TYPE> const &, polyBasic<TYPE> const &) ; \
// explicit instantiation polyBasic for int type
EXPLICIT_INSTANTIATION(int) ;
EXPLICIT_INSTANTIATION(long) ;
EXPLICIT_INSTANTIATION(unsigned) ;
EXPLICIT_INSTANTIATION(float) ;
EXPLICIT_INSTANTIATION(double) ;
Extend the class basic polynomial
Polinomial class header
File: poly.hh:
/*
* An example of class implementing integer polynomial
*/
#include "polyBasic.hh"
template <typename T>
class poly : public polyBasic<T> { // inherith all the definition and methods of polyBasic
double stupid[1000] ;
public:
// propagate type to the poly class
typedef typename polyBasic<T>::value_type value_type ;
typedef typename polyBasic<T>::coeffs_type coeffs_type ;
// contructors
poly()
: polyBasic<T>()
{
std::cout << "call poly::poly()\n" ;
} // make a zero polinomial
poly( poly const & a )
: polyBasic<T>(a)
{
std::cout << "call poly::poly( poly const & )\n" ;
} // copy constructor
poly( value_type coeffs[], int degree )
: polyBasic<T>( coeffs, degree )
{
std::cout << "call poly::poly( value_type [], int )\n" ;
} // make a polynomial from a C vector
poly( coeffs_type const & coeffs )
: polyBasic<T>( coeffs )
{
std::cout << "call poly::poly( coeffs_type const & )\n" ;
} // make a polynomial from a C vector
// internal operator
poly<T> const & operator *= ( poly<T> const & a ) ;
poly<T> const & operator /= ( poly<T> const & a ) ;
poly<T> const & operator %= ( poly<T> const & a ) ;
} ;
// external operator
template <typename T> poly<T> operator + ( poly<T> const & a, poly<T> const & b ) ;
template <typename T> poly<T> operator - ( poly<T> const & a, poly<T> const & b ) ;
template <typename T> poly<T> operator * ( poly<T> const & a, poly<T> const & b ) ;
template <typename T> poly<T> operator / ( poly<T> const & a, poly<T> const & b ) ;
template <typename T> poly<T> operator % ( poly<T> const & a, poly<T> const & b ) ;
Body of the templated functions and methods
File: poly.hxx:
// contructors
template <typename T>
poly<T> operator + ( poly<T> const & a, poly<T> const & b ) {
int degree = std::max(a.degree(), b.degree()) ;
std::vector<T> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i )
coeffs[i] = a.get(i) + b.get(i) ;
return poly<T>( coeffs ) ;
}
template <typename T>
poly<T> operator - ( poly<T> const & a, poly<T> const & b ) {
int degree = std::max(a.degree(), b.degree()) ;
std::vector<T> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i )
coeffs[i] = a.get(i) - b.get(i) ;
return poly<T>( coeffs ) ;
}
template <typename T>
poly<T> operator * ( poly<T> const & a, poly<T> const & b ) {
int degree = a . degree() + b . degree() ;
std::vector<T> coeffs(degree+1) ;
for ( int i = 0 ; i <= degree ; ++i ) {
coeffs[i] = 0 ;
for ( int k = 0 ; k <= i ; ++k )
coeffs[i] += a.get(k)*b.get(i-k) ;
}
return poly<T>( coeffs ) ;
}
Explicit instantiation of the functions and methods
File: poly.cc:
#include "poly.hh" // include definition of class polyBasic
#include "poly.hxx" // include declaration of template implementation
#define EXPLICIT_INSTANTIATION(TYPE) \
template class poly<TYPE> ; \
template poly<TYPE> operator + ( poly<TYPE> const &, poly<TYPE> const &) ; \
template poly<TYPE> operator - ( poly<TYPE> const &, poly<TYPE> const &) ; \
template poly<TYPE> operator * ( poly<TYPE> const &, poly<TYPE> const &) ; \
// explicit instantiation polyBasic for int type
EXPLICIT_INSTANTIATION(int) ;
EXPLICIT_INSTANTIATION(long) ;
EXPLICIT_INSTANTIATION(unsigned) ;
EXPLICIT_INSTANTIATION(float) ;
EXPLICIT_INSTANTIATION(double) ;
Testing the class
File: test.cc:
#include "poly.hh"
#include <iostream>
#include <cmath>
using std::abs ; // extract only abs fron std namespace
typedef float vtype ;
class polyMinimal {
public:
typedef int value_type ;
int coeffs[100] ;
int deg ;
// access to the coefficients
int const & operator [] ( int i ) const { return coeffs[i] ; }
int & operator [] ( int i ) { return coeffs[i] ; }
int degree() const { return deg ; }
} ;
/*
* Trivial way to define a (quite) generic routine
* for the sum of the abs of coeffs.
*/
template <typename T>
T
addAbsCoeffsOld( polyBasic<T> const & p ) {
T res = 0 ;
for ( int i = 0 ; i <= p.degree() ; ++i )
res += abs(p[i]) ;
return res ;
}
/*
* More general routine
*/
template <typename POLY>
typename POLY::value_type
addAbsCoeffs( POLY const & p ) {
typename POLY::value_type res = 0 ;
for ( int i = 0 ; i <= p.degree() ; ++i )
res += abs(p[i]) ;
return res ;
}
int
main() {
poly<vtype> a, b, c, d ;
poly<vtype> e(a) ;
vtype coeffs[] = { 1, 0, 2, 3, 4, 0 } ;
int degree = sizeof(coeffs)/sizeof(coeffs[0])-1 ;
poly<vtype> f(coeffs,degree) ;
a = f+f ;
std::cout << "POLY f = " << f << '\n' ;
std::cout << "POLY a = " << a << '\n' ;
std::cout << "POLY a*f = " << a*f << '\n' ;
std::cout << "|f| = " << addAbsCoeffs(f) << '\n' ;
polyMinimal pp ;
pp . deg = 1 ;
pp . coeffs[0] = pp . coeffs[1] = 2 ;
std::cout << "|pp| = " << addAbsCoeffs(pp) << '\n' ;
return 0 ;
}
Lesson of 24 February 2011 (part B)
Using exceptions
An example of using exceptions
File: exception1.cc:
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stdexcept>
using namespace std ;
/*
* A simple example of exception handling
*
*/
class my_throw {
public:
string where ;
my_throw( string const & file, unsigned line ) {
stringstream msg ;
msg << "Found an error in file: " << file << " at line: " << line ;
where = msg . str() ;
}
} ;
#define MY_THROW throw my_throw( __FILE__, __LINE__ )
// declare prototype
void a() ;
void b() ;
void c() ;
void
a() {
cout << "Enter in routine a\n" ;
b() ;
cout << "Exit from routine a\n" ;
} ;
void
b() {
cout << "Enter in routine b\n" ;
c() ;
cout << "Exit from routine b\n" ;
} ;
void
c() {
cout << "Enter in routine c\n" ;
// make an exception
throw logic_error("pluto") ;
throw runtime_error("pippo") ;
MY_THROW ;
throw "I am and excption string" ;
cout << "Exit from routine c\n" ;
} ;
int
main() {
try {
try {
a() ;
}
catch (...) {
cout << "nested exception\n" ;
throw ; // I rethrow the same exception to the upper block
}
a() ;
}
catch ( int e ) {
cout << "found an exception!\n" ;
cout << "value = " << e << "\n" ;
}
catch ( char const str [] ) {
cout << "found an exception!\n" ;
cout << "string = " << str << "\n" ;
}
catch ( my_throw const & e ) {
cout << e . where << '\n' ;
}
catch ( runtime_error const & e ) {
cout << "runtime_error: " << e . what() << '\n' ;
}
catch ( exception const & e ) {
cout << "exception: " << e . what() << '\n' ;
}
catch ( ... ) {
cout << "found an exception!\n" ;
}
return 0 ;
}
A second example
File: exception2.cc:
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stdexcept>
#include <memory>
using namespace std ;
/*
* A simple stupid class
*/
class stupid {
string my_name ;
public:
stupid( char const * n ) : my_name(n) {
cout << "contruct stupid(\"" << my_name << "\")\n" ;
}
~stupid() {
cout << "destroy stupid(\"" << my_name << "\")\n" ;
}
} ;
// declare prototype
void a() ;
void b() ;
void c() ;
long nw = 1ul<<30 ;
void
a() {
cout << "Enter in routine a\n" ;
stupid sa("sa") ;
auto_ptr<char> ptr(new char[nw]) ;
for ( long i = 0 ; i < nw ; i += 100 ) ptr.get()[i] = i % 234 ;
cout << "go ?" ; int a ; cin >> a ;
b() ;
cout << "Exit from routine a\n" ;
} ;
void
b() {
cout << "Enter in routine b\n" ;
stupid sb("sb") ;
auto_ptr<char> ptr(new char[nw]) ;
for ( long i = 0 ; i < nw ; i += 100 ) ptr.get()[i] = i % 234 ;
cout << "go ?" ; int a ; cin >> a ;
c() ;
cout << "Exit from routine b\n" ;
} ;
void
c() {
cout << "Enter in routine c\n" ;
stupid sc("sc") ;
auto_ptr<char> ptr(new char[nw]) ;
for ( long i = 0 ; i < nw ; i += 100 ) ptr.get()[i] = i % 234 ;
cout << "go ?" ; int a ; cin >> a ;
// make an exception
throw runtime_error("pippo") ;
cout << "Exit from routine c\n" ;
} ;
int
main() {
try {
a() ;
}
catch ( exception const & e ) {
cout << "exception: " << e . what() << '\n' ;
}
catch ( ... ) {
cout << "found an exception!\n" ;
}
cout << "finito ?" ;
int a ; cin >> a ;
return 0 ;
}
Lesson of 25 February 2011
Various matrix-matrix multiplication routine
The header file
File: mm.hh:
/*
Matrix Matrix multiplication routine
*/
template <typename Type>
void
mm_standard( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n, // number of the rows of A
unsigned p, // number of the columns of A and rows of B
unsigned m // number of the columns of B
// the results is a matrix C of n rows and m columns
) ;
template <typename Type>
void
mm_tiling( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n, // number of the rows of A
unsigned p, // number of the columns of A and rows of B
unsigned m, // number of the columns of B
// the results is a matrix C of n rows and m columns
unsigned BK // block size
) ;
template <typename Type>
void
mm_recurr( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n, // number of the rows of A
unsigned p, // number of the columns of A and rows of B
unsigned m ); // number of the columns of B
// the results is a matrix C of n rows and m columns
Standard routine
File: mm_standard.cc:
/*
Matrix Matrix multiplication routine
g++ -O3 -funroll-loops -sse2 -sse3 -sse3 -ssse3 -sse4.1 mm_check.cc mm_standard.cc TimeMeter.cc
5 x 5 average time 0.01
10 x 10 average time 0.004
20 x 20 average time 0.014
40 x 40 average time 0.099
80 x 80 average time 0.789
160 x 160 average time 8.526
320 x 320 average time 70.61
640 x 640 average time 981.838
1280 x 1280 average time 10938.1
2560 x 2560 average time 624531
Time Ratio [ 10/5] = 0.4
Time Ratio [ 20/10] = 3.5
Time Ratio [ 40/20] = 7.07143
Time Ratio [ 80/40] = 7.9697
Time Ratio [ 160/80] = 10.8061
Time Ratio [ 320/160] = 8.28173
Time Ratio [ 640/320] = 13.9051
Time Ratio [ 1280/640] = 11.1404
Time Ratio [ 2560/1280] = 57.0969
*/
#include "mm.hh"
#include "pstdint.h"
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
template <typename Type>
void
mm_standard( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j ) {
C(i,j) = 0 ;
for ( unsigned k = 0 ; k < p ; ++k )
C(i,j) += A(i,k) * B(k,j) ;
}
}
#define EXPLICIT_INSTANTIATE(T) \
template void mm_standard<T>( T const [], unsigned, \
T const [], unsigned, \
T [], unsigned, \
unsigned, unsigned, unsigned ) ;
EXPLICIT_INSTANTIATE(float) ;
EXPLICIT_INSTANTIATE(double) ;
EXPLICIT_INSTANTIATE(int32_t) ;
EXPLICIT_INSTANTIATE(int64_t) ;
Using tiling
File: mm_tiling.cc:
/*
Matrix Matrix multiplication routine
g++ -O3 mm_check.cc mm_standard.cc TimeMeter.cc
g++ -O3 -funroll-loops -sse2 -sse3 -sse3 -ssse3 -sse4.1 mm_check.cc mm_tiling.cc TimeMeter.cc
5 x 5 average time 0.01
10 x 10 average time 0.004
20 x 20 average time 0.014
40 x 40 average time 0.099
80 x 80 average time 0.789
160 x 160 average time 8.526
320 x 320 average time 70.61
640 x 640 average time 981.838
1280 x 1280 average time 10938.1
2560 x 2560 average time 624531
Time Ratio [ 10/5] = 0.4
Time Ratio [ 20/10] = 3.5
Time Ratio [ 40/20] = 7.07143
Time Ratio [ 80/40] = 7.9697
Time Ratio [ 160/80] = 10.8061
Time Ratio [ 320/160] = 8.28173
Time Ratio [ 640/320] = 13.9051
Time Ratio [ 1280/640] = 11.1404
Time Ratio [ 2560/1280] = 57.0969
*/
#include "mm.hh"
#include <algorithm>
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
template <typename Type>
inline
void
mm_tiling_addTo( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j ) {
Type tmp = 0 ;
for ( unsigned k = 0 ; k < p ; ++k ) tmp += A(i,k) * B(k,j) ;
C(i,j) += tmp ;
}
}
template <typename Type>
void
mm_tiling( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m,
unsigned BK ) {
/*
// BK
// +--+--+--+--+
// | | | | |
// +--+--+--+--+
// | | | | |
// +--+--+--+--+
// | | | | |
// +--+--+--+--+
// | | | | |
// +--+--+--+--+
// | | | | |
// +--+--+--+--+
*/
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
for ( unsigned jj = 0 ; jj < m ; jj += BK ) {
unsigned column = std::min(BK,m-jj) ;
for ( unsigned ii = 0 ; ii < n ; ii += BK ) {
unsigned row = std::min(BK,n-ii) ;
for ( unsigned kk = 0 ; kk < p ; kk += BK ) {
unsigned rc = std::min(BK,p-kk) ;
// multiply block A(ii,kk) * B(kk,jj)
mm_tiling_addTo( &A(ii,kk), ldA,
&B(kk,jj), ldB,
&C(ii,jj), ldC,
row, rc, column ) ;
}
}
}
}
#define EXPLICIT_INSTANTIATE(T) \
template void mm_tiling<T>( T const [], unsigned, \
T const [], unsigned, \
T [], unsigned, \
unsigned, unsigned, unsigned, unsigned ) ;
EXPLICIT_INSTANTIATE(float) ;
EXPLICIT_INSTANTIATE(double) ;
EXPLICIT_INSTANTIATE(int32_t) ;
EXPLICIT_INSTANTIATE(int64_t) ;
Using recurrence
File: mm_recurr.cc:
/*
Matrix Matrix multiplication routine
*/
#include "mm.hh"
#include <algorithm>
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
template <typename Type>
inline
void
mm_base_addto4x4( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC ) {
for ( unsigned i = 0 ; i < 4 ; ++i )
for ( unsigned j = 0 ; j < 4 ; ++j ) {
Type tmp = 0 ;
for ( unsigned k = 0 ; k < 4 ; ++k ) tmp += A(i,k) * B(k,j) ;
C(i,j) += tmp ;
}
}
template <typename Type>
inline
void
mm_base_addto8x8( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC ) {
for ( unsigned i = 0 ; i < 8 ; i += 4 )
for ( unsigned j = 0 ; j < 8 ; j += 4 )
for ( unsigned k = 0 ; k < 8 ; k += 4 )
mm_base_addto4x4( &A(i,k), ldA, &B(k,j), ldB, &C(i,j), ldC ) ;
}
template <typename Type>
inline
void
mm_base_addto16x16( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC ) {
for ( unsigned i = 0 ; i < 16 ; i += 8 )
for ( unsigned j = 0 ; j < 16 ; j += 8 )
for ( unsigned k = 0 ; k < 16 ; k += 8 )
mm_base_addto8x8( &A(i,k), ldA, &B(k,j), ldB, &C(i,j), ldC ) ;
}
template <typename Type>
inline
void
mm_classin_addto( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j ) {
Type tmp = 0 ;
for ( unsigned k = 0 ; k < p ; ++k ) tmp += A(i,k) * B(k,j) ;
C(i,j) += tmp ;
}
}
template <typename Type>
inline
void
mm_base_addto( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
unsigned const NB = 16 ;
for ( unsigned jj = 0 ; jj < m ; jj += NB ) {
unsigned column = std::min(NB,m-jj) ;
for ( unsigned ii = 0 ; ii < n ; ii += NB ) {
unsigned row = std::min(NB,n-ii) ;
for ( unsigned kk = 0 ; kk < p ; kk += NB ) {
unsigned rc = std::min(NB,p-kk) ;
if ( row == NB && rc == NB && column == NB )
mm_base_addto16x16( &A(ii,kk), ldA,
&B(kk,jj), ldB,
&C(ii,jj), ldC ) ;
else
mm_classin_addto( &A(ii,kk), ldA,
&B(kk,jj), ldB,
&C(ii,jj), ldC,
row, rc, column ) ;
}
}
}
}
//! C += A*B
template <typename Type>
void
mm_recurr_addto( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
unsigned const NB = 400 ;
if ( n <= NB && p <= NB && m <= NB ) {
mm_base_addto( A, ldA, B, ldB, C, ldC, n, p, m ) ;
return ;
}
/*
// splitting tipo 1A
// +-------+ +-------+ +-------+
// | | | | | |
// | C11 | | A11 | | B11 |
// | | | | | |
// +-------+ += +-------+ +-------+
// | | | |
// | C21 | | A21 |
// | | | |
// +-------+ +-------+
//
// splitting tipo 1B
// +-------+ +-------+-------+ +-------+
// | | | | | | |
// | C11 | | A11 | A12 | | B11 |
// | | | | | | |
// +-------+ += +-------+-------+ +-------+
// | | | | | | |
// | C21 | | A21 | A22 | | B21 |
// | | | | | | |
// +-------+ +-------+-------+ +-------+
//
// splitting tipo 2A
// +-------+-------+ +-------+ +-------+-------+
// | | | | | | | |
// | C11 | C12 | += | A11 | | B11 | B12 |
// | | | | | | | |
// +-------+-------+ +-------+ +-------+-------+
//
// splitting tipo 2B
// +-------+-------+ +-------+-------+ +-------+-------+
// | | | | | | | | |
// | C11 | C12 | += | A11 | A12 | | B11 | B12 |
// | | | | | | | | |
// +-------+-------+ +-------+-------+ +-------+-------+
// | | |
// | B21 | B22 |
// | | |
// +-------+-------+
//
// splitting tipo 3A
// +------+-------+ +-------+ +-------+-------+
// | | | | | | | |
// | C11 | C12 | | A11 | | B11 | B12 |
// | | | | | | | |
// +------+-------+ += +-------+ +-------+-------+
// | | | | |
// | C21 | C22 | | A21 |
// | | | | |
// +------+-------+ +-------+
//
// splitting tipo 3B
// +-------+-------+ +-------+-------+ +-------+-------+
// | | | | | | | | |
// | C11 | C12 | | A11 | A12 | | B11 | B12 |
// | | | | | | | | |
// +-------+-------+ += +-------+-------+ +-------+-------+
// | | | | | | | | |
// | C21 | C22 | | A21 | A22 | | B21 | B22 |
// | | | | | | | | |
// +-------+-------+ +-------+-------+ +-------+-------+
//
*/
unsigned n2 = n/2 ;
unsigned m2 = m/2 ;
unsigned p2 = p/2 ;
// n x p
Type const * A11 = A ;
Type const * A12 = A + ldA * p2 ;
Type const * A21 = A + n2 ;
Type const * A22 = A12 + n2 ;
// p x m
Type const * B11 = B ;
Type const * B12 = B + ldB * m2 ;
Type const * B21 = B + p2 ;
Type const * B22 = B12 + p2 ;
// n x m
Type * C11 = C ;
Type * C12 = C + ldC * m2 ;
Type * C21 = C + n2 ;
Type * C22 = C12 + n2 ;
// matrix C is n x m
if ( 2*n > 3*m ) { // matrix is tall
if ( 2*n > 3*p ) { // splitting of type 1A
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n2, p, m ) ;
mm_recurr_addto( A21, ldA, B11, ldB, C21, ldC, n-n2, p, m ) ;
} else { // splitting of type 1B
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n2, p2, m ) ;
mm_recurr_addto( A12, ldA, B21, ldB, C11, ldC, n2, p-p2, m ) ;
mm_recurr_addto( A21, ldA, B11, ldB, C21, ldC, n-n2, p2, m ) ;
mm_recurr_addto( A22, ldA, B21, ldB, C21, ldC, n-n2, p-p2, m ) ;
}
} else if ( 3*n < 2*m ) { // matrix is flat
if ( 2*p > 3*n ) { // splitting of type 2B
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n, p2, m2 ) ;
mm_recurr_addto( A12, ldA, B21, ldB, C11, ldC, n, p-p2, m2 ) ;
mm_recurr_addto( A11, ldA, B12, ldB, C12, ldC, n, p2, m-m2 ) ;
mm_recurr_addto( A12, ldA, B22, ldB, C12, ldC, n, p-p2, m-m2 ) ;
} else { // splitting of type 2A
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n, p, m2 ) ;
mm_recurr_addto( A11, ldA, B12, ldB, C12, ldC, n, p, m-m2 ) ;
}
} else {
if ( 2*n > 3*p ) { // splitting of type 3A
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n2, p, m2 ) ;
mm_recurr_addto( A11, ldA, B12, ldB, C12, ldC, n2, p, m-m2 ) ;
mm_recurr_addto( A21, ldA, B11, ldB, C21, ldC, n-n2, p, m2 ) ;
mm_recurr_addto( A21, ldA, B12, ldB, C22, ldC, n-n2, p, m-m2 ) ;
} else { // splitting of type 3B
mm_recurr_addto( A11, ldA, B11, ldB, C11, ldC, n2, p2, m2 ) ;
mm_recurr_addto( A12, ldA, B21, ldB, C11, ldC, n2, p-p2, m2 ) ;
mm_recurr_addto( A11, ldA, B12, ldB, C12, ldC, n2, p2, m-m2 ) ;
mm_recurr_addto( A12, ldA, B22, ldB, C12, ldC, n2, p-p2, m-m2 ) ;
mm_recurr_addto( A21, ldA, B11, ldB, C21, ldC, n-n2, p2, m2 ) ;
mm_recurr_addto( A22, ldA, B21, ldB, C21, ldC, n-n2, p-p2, m2 ) ;
mm_recurr_addto( A21, ldA, B12, ldB, C22, ldC, n-n2, p2, m-m2 ) ;
mm_recurr_addto( A22, ldA, B22, ldB, C22, ldC, n-n2, p-p2, m-m2 ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////
template <typename Type>
void
mm_recurr( Type const A[], unsigned ldA,
Type const B[], unsigned ldB,
Type C[], unsigned ldC,
unsigned n,
unsigned p,
unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
mm_recurr_addto( A, ldA, B, ldB, C, ldC, n, p, m ) ;
}
#define EXPLICIT_INSTANTIATE(T) \
template void mm_recurr<T>( T const [], unsigned, \
T const [], unsigned, \
T [], unsigned, \
unsigned, unsigned, unsigned ) ; \
template void mm_recurr_addto<T>( T const [], unsigned, \
T const [], unsigned, \
T [], unsigned, \
unsigned, unsigned, unsigned )
EXPLICIT_INSTANTIATE(float) ;
EXPLICIT_INSTANTIATE(double) ;
EXPLICIT_INSTANTIATE(int32_t) ;
EXPLICIT_INSTANTIATE(int64_t) ;
Check routine
File: mm_check.cc:
/*
Matrix Matrix multiplication routine
g++ -O3 -funroll-loops mm_check.cc mm_standard.cc mm_tiling.cc mm_recurr.cc TimeMeter.cc -lblas
g++ -O3 -funroll-loops -sse2 -sse3 -sse3 -ssse3 -sse4.1 mm_check.cc mm_standard.cc mm_tiling.cc mm_recurr.cc TimeMeter.cc -framework Accelerate
time using dgemm
5 x 5 average time 0.0076ms
10 x 10 average time 0.0012ms
20 x 20 average time 0.0046ms
40 x 40 average time 0.032ms
80 x 80 average time 0.303ms
160 x 160 average time 9.2734ms
320 x 320 average time 9.183ms
640 x 640 average time 66.8882ms
1280 x 1280 average time 458.291ms
2560 x 2560 average time 3958.36ms
Time Ratio [ 10/5] = 0.157895
Time Ratio [ 20/10] = 3.83333
Time Ratio [ 40/20] = 6.95652
Time Ratio [ 80/40] = 9.46875
Time Ratio [ 160/80] = 30.6053
Time Ratio [ 320/160] = 0.990252
Time Ratio [ 640/320] = 7.28392
Time Ratio [ 1280/640] = 6.8516
Time Ratio [ 2560/1280] = 8.63722
*/
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include <map>
#include "mm.hh"
#include "TimeMeter.hh"
#include "pstdint.h"
#define A(I,J) A[(I)+(J)*ldA]
#define B(I,J) B[(I)+(J)*ldB]
#define C(I,J) C[(I)+(J)*ldC]
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return (U)rand()-(U)rand() ; }
// store average time using map of STL
static map<unsigned,double> averageTime ;
//
// Fill with random value matric A (n x m)
//
template <typename Type>
static
void
fillRandom( Type A[], unsigned ldA, unsigned n, unsigned m ) {
for ( unsigned i = 0 ; i < n ; ++i )
for ( unsigned j = 0 ; j < m ; ++j )
A(i,j) = random() ;
}
typedef double valueType ;
//typedef int64_t valueType ;
#define F77NAME(A) A##_
extern "C" {
void
F77NAME(dgemm)( char const transA[],
char const transB[],
int const & M,
int const & N,
int const & K,
double const & ALPHA,
double const A[], int const & ldA,
double const B[], int const & ldB,
double const & beta,
double C[], int const & ldC ) ;
/* Purpose
* =======
*
* DGEMM performs one of the matrix-matrix operations
*
* C := alpha*op( A )*op( B ) + beta*C,
*
* where op( X ) is one of
*
* op( X ) = X or op( X ) = X',
*
* alpha and beta are scalars, and A, B and C are matrices, with op( A )
* an m by k matrix, op( B ) a k by n matrix and C an m by n matrix.
*/
};
int
main() {
TimeMeter tm ;
unsigned nruns = 5 ;
unsigned minsz = 5 ;
unsigned maxsz = 3000 ;
valueType * A = new valueType[ maxsz * maxsz ] ;
valueType * B = new valueType[ maxsz * maxsz ] ;
valueType * C = new valueType[ maxsz * maxsz ] ;
for ( unsigned sz = minsz ; sz < maxsz ; sz *= 2 ) {
unsigned ldA = sz ;
unsigned ldB = sz ;
unsigned ldC = sz ;
fillRandom( A, ldA, sz, sz ) ;
fillRandom( B, ldB, sz, sz ) ;
tm . start() ;
for ( unsigned k = 0 ; k < nruns ; ++k )
mm_recurr( A, ldA, B, ldB, C, ldC, sz, sz, sz ) ;
//mm_tiling( A, ldA, B, ldB, C, ldC, sz, sz, sz, 80 ) ;
//mm_standard( A, ldA, B, ldB, C, ldC, sz, sz, sz ) ;
//F77NAME(dgemm)( "N", "N", sz, sz, sz, 1, A, ldA, B, ldB, 0, C, ldC ) ;
double elapsed = tm . milliseconds() ;
averageTime[sz] = elapsed / nruns ;
cout << sz << " x " << sz << " average time " << averageTime[sz] << "ms\n" ;
}
for ( unsigned sz = 2*minsz ; sz < maxsz ; sz *= 2 )
cout << "Time Ratio [ " << sz << "/" << sz/2 << "] = "
<< averageTime[sz] / averageTime[sz/2] << '\n' ;
}
Lesson of 3 March 2011
Introduction to pthread
A first example
File: thread-esempio1.cc:
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
using namespace std ;
#define NUM_THREADS 5
pthread_mutex_t mutex_var = PTHREAD_MUTEX_INITIALIZER ;
typedef struct { int numThread ; } ParameterForThread ;
extern "C"
void *
PrintHello( void * thePars )
{
// thePars contains a pointer to the data passed in the
// call of pthread_create (last parameter)
ParameterForThread * pars = static_cast<ParameterForThread*>(thePars) ;
unsigned sn = (rand()%3)+1 ;
sleep(sn) ;
pthread_mutex_lock(&mutex_var) ; // block other thread until unlock
cerr << "\nThread n. " << pars -> numThread << " sleep = " << sn << " Hello World!\n" ;
pthread_mutex_unlock(&mutex_var) ;
pthread_exit(NULL) ; // exit and release resource for the thread
return NULL ;
}
int
main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS] ;
ParameterForThread pars[NUM_THREADS] ;
for ( int t = 0 ; t < NUM_THREADS ; ++t ) {
pars[t] . numThread = t ;
cout << "Creating thread N. " << t << endl ;
int rc = pthread_create(&threads[t], // storage for thread information
NULL,
PrintHello, // the called thread
static_cast<void*>(&pars[t]) ); // data passed to the thread
if ( rc ) {
cerr << "ERROR; return code from pthread_create() is " << rc << "\n" ;
exit(-1);
}
}
pthread_exit(NULL); /* aspetta che the thread abbiano finito */
return 0 ;
}
A second example
File: thread-esempio2.cc:
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
using namespace std ;
#define NUM_THREADS 5
pthread_mutex_t mutex_var = PTHREAD_MUTEX_INITIALIZER ;
typedef struct { int numThread ; } ParameterForThread ;
extern "C"
void *
PrintHello( void * thePars )
{
// thePars contains a pointer to the data passed in the
// call of pthread_create (last parameter)
ParameterForThread * pars = static_cast<ParameterForThread*>(thePars) ;
long sn = (rand()%3)+1 ;
sleep(sn) ;
pthread_mutex_lock(&mutex_var) ; // block other thread until unlock
cerr << "\nThread n. " << pars -> numThread << " sleep = " << sn << " Hello World!\n" ;
pthread_mutex_unlock(&mutex_var) ;
pthread_exit((void*)sn) ; // exit and release resource for the thread
return NULL ;
}
int
main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS] ;
ParameterForThread pars[NUM_THREADS] ;
for ( int t = 0 ; t < NUM_THREADS ; ++t ) {
pars[t] . numThread = t ;
cout << "Creating thread N. " << t << endl ;
int rc = pthread_create(&threads[t], // storage for thread information
NULL,
PrintHello, // the called thread
static_cast<void*>(&pars[t]) ); // data passed to the thread
if ( rc ) {
cerr << "ERROR; return code from pthread_create() is " << rc << "\n" ;
exit(-1);
}
}
// wait until all the thread has finisched
cout << "Wait!\n" ;
for ( int t = 0 ; t < NUM_THREADS ; ++t ) {
void * return_value ;
if ( pthread_join(threads[t], &return_value) ) {
cerr << "Error while waiting for thread N." << t << '\n' ;
exit(1) ;
}
pthread_mutex_lock(&mutex_var) ; // block other thread until unlock
cout << "Thread N. " << t << " returned " << (long) return_value << '\n' ;
pthread_mutex_unlock(&mutex_var) ; // block other thread until unlock
}
cout << "ALL DONE\n" ;
return 0 ;
}
A third example
File: thread-esempio3.cc:
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
#include <pthread.h>
using namespace std ;
#define NUM_THREADS 5
pthread_mutex_t mutex_var = PTHREAD_MUTEX_INITIALIZER ;
typedef struct { int numThread ; } ParameterForThread ;
// struct which contains the arguments passed to the thread
struct arguments {
vector<double> array ;
double sum ;
} ;
bool stop = true ;
// compute the sum of the element of the array
void * do_work( void *arg ) {
struct arguments * argument = (struct arguments*)arg ;
argument -> sum = 0 ;
while ( stop ) ;
for ( int i = 0 ; i < argument -> array . size() ; ++i ) {
argument -> sum += argument -> array[i] ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
void * return_value;
pthread_t worker_thread;
struct arguments arg ;
arg . array . reserve(100000) ;
for ( int i=0 ; i < 100000 ; ++i )
arg . array . push_back( (rand()%256) / 123.923) ;
if ( pthread_create(&worker_thread, NULL, do_work, (void *) &arg) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
sleep(1) ;
stop = false ;
int a = 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
cout << "Valore argomento " << arg . sum << '\n' ;
a = a + 1 ;
// wait the thread
if ( pthread_join(worker_thread, &return_value) ) {
cerr << "Error while waiting for thread\n" ;
exit(1);
}
cout << "Valore argomento dopo JOIN " << arg . sum << '\n' ;
pthread_exit(NULL) ;
return 0 ;
}
A NOT working solution of the Philosophes problem
A first example
File: thread-filosofi-1.cc:
/*
Versione NON funzionante del problema dei filosofi.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define N_FILOSOFI 5
pthread_mutex_t mutex_var ;
typedef enum { PENSO, MANGIO, DORMO } STATO_FILOSOFO ;
typedef enum { LIBERA, INUSO } STATO_FORCHETTE ;
static STATO_FILOSOFO stato_filosofo[N_FILOSOFI] ;
static STATO_FORCHETTE stato_forchetta[N_FILOSOFI] ;
void
prende_forchetta_destra( int const n ) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_destra = (n+1) % N_FILOSOFI ;
if ( stato_forchetta[f_destra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta destra\n",n) ;
while ( stato_forchetta[f_destra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_destra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta destra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
prende_forchetta_sinistra( int const n) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_sinistra = n ;
if ( stato_forchetta[f_sinistra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta sinistra\n",n) ;
while ( stato_forchetta[f_sinistra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_sinistra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta sinistra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
lascia_forchetta_destra( int const n ) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_destra = (n+1) % N_FILOSOFI ;
stato_forchetta[f_destra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta destra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
lascia_forchetta_sinistra( int const n) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_sinistra = n ;
stato_forchetta[f_sinistra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta sinistra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void *
filosofo(void *arg) {
long n = (long) arg ;
while ( 1 ) { /* ciclo infinito */
/* pensa */
stato_filosofo[n] = PENSO ;
printf("Il filosofo N.%ld PENSA\n", n) ;
prende_forchetta_destra( n ) ;
prende_forchetta_sinistra( n ) ;
/* mangia */
stato_filosofo[n] = MANGIO ;
printf("Il filosofo N.%ld MANGIA\n", n) ;
lascia_forchetta_destra( n ) ;
lascia_forchetta_sinistra( n ) ;
/* dorme */
stato_filosofo[n] = DORMO ;
printf("Il filosofo N.%ld DORME\n", n) ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
int i ;
while ( 1 ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
printf("\nFILOSOFI: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_filosofo[i] ) {
case PENSO: printf(" P") ; break ;
case MANGIO: printf(" M") ; break ;
case DORMO: printf(" D") ; break ;
}
}
printf("\nFORCHETTE: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_forchetta[i] ) {
case LIBERA: printf(" L") ; break ;
case INUSO: printf(" U") ; break ;
}
}
printf("\n") ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
pthread_t filosofo_thread[N_FILOSOFI], monitor_thread ;
if ( pthread_mutex_init(&mutex_var, NULL) ) {
/* inizializzo la variabile per il mutex */
printf("Error while creating mutex\n");
exit(1);
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
stato_filosofo[i] = DORMO ;
stato_forchetta[i] = LIBERA ;
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
printf("Creo il filosofo N.%d\n", i) ;
if ( pthread_create(&filosofo_thread[i], NULL, filosofo, (void *) i) ) {
printf("Error while creating thread\n");
exit(1);
}
}
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
printf("Error while creating thread\n");
exit(1);
}
pthread_exit(NULL) ;
return 0 ;
}
Lesson of 4 March 2011 (part a)
The philosophes problem
A NOT working example using pthread_cond_wait
File: thread-filosofi.cc:
/*
NOT Working version of 5 Philosopher
to compile: g++ thread-filosofi.cc
*/
#include <pthread.h>
#include <iostream>
#include <unistd.h> // for sleep
using namespace std ;
#define N_PHILOSOPHES 5
pthread_mutex_t mutex_var ;
pthread_cond_t cond_var ;
#define LEFT_FORK(N) (N)
#define RIGHT_FORK(N) (((N)+1) % N_PHILOSOPHES )
typedef enum { THINK, EAT, SLEEP } Philosopher_STATE ;
typedef enum { FREE, INUSE } Fork_STATE ;
static Philosopher_STATE philosopher_state[N_PHILOSOPHES] ;
static Fork_STATE fork_state[N_PHILOSOPHES] ;
void
get_right_fork( int const n ) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int right_fork = RIGHT_FORK(n) ;
if ( fork_state[right_fork] == INUSE ) {
cout << "Philosopher " << n << " waiting for the right fork!\n" ;
while ( fork_state[right_fork] == INUSE ) ; // stupid loop waiting resource
}
fork_state[right_fork] = INUSE ; /* si accaparra la forchetta */
cout << "Philosopher " << n << " acquired the right fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
get_left_fork( int const n) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int left_fork = LEFT_FORK(n) ;
if ( fork_state[left_fork] == INUSE ) {
cout << "Philosopher " << n << " waiting for the left fork!\n" ;
while ( fork_state[left_fork] == INUSE ) ; // stupid loop waiting resource
}
fork_state[left_fork] = INUSE ; /* si accaparra la forchetta */
cout << "Philosopher " << n << " acquired the left fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
drop_right_fork( int const n ) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int right_fork = RIGHT_FORK(n) ;
fork_state[right_fork] = FREE ;
cout << "Philosopher " << n << " drop the right fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
drop_left_fork( int const n) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int left_fork = LEFT_FORK(n) ;
fork_state[left_fork] = FREE ;
cout << "Philosopher " << n << " drop the left fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void *
philosopher( void *arg ) {
long n = (long) arg ;
// put a barrier for wait a go signal
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
cout << "Philosopher " << n << " is waiting to start\n" ;
pthread_cond_wait(&cond_var,&mutex_var);
cout << "Philosopher " << n << " is started\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
while ( true ) { // infinity loop
// thinking
philosopher_state[n] = THINK ;
cout << "Philosopher " << n << " is THINKING\n" ;
get_right_fork( n ) ;
get_left_fork( n ) ;
// eating
philosopher_state[n] = EAT ;
cout << "Philosopher " << n << " is EATING\n" ;
drop_right_fork( n ) ;
drop_left_fork( n ) ;
// sleeping
philosopher_state[n] = SLEEP ;
cout << "Philosopher " << n << " is SLEEPING\n" ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
while ( true ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
cout << "\nPhilosophes: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
switch ( philosopher_state[i] ) {
case THINK: printf(" T") ; break ;
case EAT: printf(" E") ; break ;
case SLEEP: printf(" S") ; break ;
}
}
cout << "\nForks: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
switch ( fork_state[i] ) {
case FREE: cout << " F" ; break ;
case INUSE: cout << " U" ; break ;
}
}
cout << endl ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
pthread_t philosopher_thread[N_PHILOSOPHES], monitor_thread ;
if ( pthread_mutex_init(&mutex_var, NULL) ) { // allocate resorce for mutex mutex_var
cerr << "Error while creating mutex\n" ;
exit(1);
}
if ( pthread_cond_init(&cond_var, NULL) ) { // allocate resorce for condition variable
cerr << "Error while creating condition\n" ;
exit(1);
}
// initialize the status of the philosophes
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
philosopher_state[i] = SLEEP ;
fork_state[i] = FREE ;
}
// create threads for philosophes
for ( long i = 0 ; i < N_PHILOSOPHES ; ++i ) {
cout << "Creo il filosofo " << i << "\n" ;
if ( pthread_create(&philosopher_thread[i], NULL, philosopher, (void *) i) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
sleep(1) ;
}
// create threads for monitor
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
// start philosopher
if ( pthread_cond_signal( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
sleep(5) ;
if ( pthread_cond_broadcast( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
// wait for thread termination
pthread_exit(NULL) ;
return 0 ;
}
A NOT working example with syncronized start of philosophes
File: thread-filosofi-2.cc:
/*
NOT Working version of 5 Philosopher
to compile: g++ thread-filosofi-2.cc
*/
#include <pthread.h>
#include <iostream>
#include <iomanip> // for setw
#include <unistd.h> // for sleep
using namespace std ;
#define N_PHILOSOPHES 5
#define LEFT_FORK(N) (N)
#define RIGHT_FORK(N) (((N)+1) % N_PHILOSOPHES )
pthread_mutex_t mutex_var ;
pthread_cond_t cond_var, cond_fork[N_PHILOSOPHES] ;
typedef enum { THINK, EAT, SLEEP } Philosopher_STATE ;
static Philosopher_STATE philosopher_state[N_PHILOSOPHES] ;
static int fork_state[N_PHILOSOPHES] ;
static int const FORK_FREE = -1 ; // -1 is free otherwise the philosopher using the fork
bool
get_right_fork( int const n ) {
int right_fork = RIGHT_FORK(n) ;
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
if ( fork_state[right_fork] != FORK_FREE ) {
cout << "Philosopher " << n << " waiting for the right fork!\n" ;
while ( fork_state[right_fork] != FORK_FREE )
pthread_cond_wait(&cond_fork[right_fork],&mutex_var) ; // intelligent loop waiting resource
}
fork_state[right_fork] = n ; // philosopher n acquire the fork
cout << "Philosopher " << n << " acquired the right fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
bool
get_left_fork( int const n) {
int left_fork = LEFT_FORK(n) ;
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
if ( fork_state[left_fork] != FORK_FREE ) {
cout << "Philosopher " << n << " waiting for the left fork!\n" ;
while ( fork_state[left_fork] != FORK_FREE )
pthread_cond_wait(&cond_fork[left_fork],&mutex_var) ; // intelligent loop waiting resource
}
fork_state[left_fork] = n ; // philosopher n acquire the fork
cout << "Philosopher " << n << " acquired the left fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
drop_right_fork( int const n ) {
int right_fork = RIGHT_FORK(n) ;
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
fork_state[right_fork] = FORK_FREE ;
cout << "Philosopher " << n << " drop the right fork!\n" ;
pthread_cond_signal( &cond_fork[right_fork] ) ; // signal that fork is fred
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
drop_left_fork( int const n) {
int left_fork = LEFT_FORK(n) ;
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
fork_state[left_fork] = FORK_FREE ;
cout << "Philosopher " << n << " drop the left fork!\n" ;
pthread_cond_signal( &cond_fork[left_fork] ) ; // signal that fork is fred
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void *
philosopher( void *arg ) {
long n = (long) arg ;
// put a barrier for wait a go signal
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
cout << "Philosopher " << n << " is waiting to start\n" ;
pthread_cond_wait(&cond_var,&mutex_var);
cout << "Philosopher " << n << " is started\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
while ( true ) { // infinity loop
// thinking
philosopher_state[n] = THINK ;
cout << "Philosopher " << n << " is THINKING\n" ;
get_right_fork( n ) ;
get_left_fork( n ) ;
// eating
philosopher_state[n] = EAT ;
cout << "Philosopher " << n << " is EATING\n" ;
drop_right_fork( n ) ;
drop_left_fork( n ) ;
// sleeping
philosopher_state[n] = SLEEP ;
cout << "Philosopher " << n << " is SLEEPING\n" ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
while ( true ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
cout << "\nPhilosophes: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
switch ( philosopher_state[i] ) {
case THINK: printf(" T") ; break ;
case EAT: printf(" E") ; break ;
case SLEEP: printf(" S") ; break ;
}
}
cout << "\nForks: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
if ( fork_state[i] == FORK_FREE ) cout << " F" ;
else cout << setw(2) << fork_state[i] ;
}
cout << endl ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
pthread_t philosopher_thread[N_PHILOSOPHES], monitor_thread ;
if ( pthread_mutex_init(&mutex_var, NULL) ) { // allocate resorce for mutex mutex_var
cerr << "Error while creating mutex\n" ;
exit(1);
}
if ( pthread_cond_init(&cond_var, NULL) ) { // allocate resorce for condition variable
cerr << "Error while creating condition\n" ;
exit(1);
}
// initialize the status of the philosophes
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
philosopher_state[i] = SLEEP ;
fork_state[i] = FORK_FREE ;
}
// create threads for philosophes
for ( long i = 0 ; i < N_PHILOSOPHES ; ++i ) {
cout << "Creo il filosofo " << i << "\n" ;
if ( pthread_create(&philosopher_thread[i], NULL, philosopher, (void *) i) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
sleep(1) ;
}
// create threads for monitor
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
// start philosopher
if ( pthread_cond_signal( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
sleep(1) ;
if ( pthread_cond_broadcast( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
// wait for thread termination
pthread_exit(NULL) ;
return 0 ;
}
A WORKING example of the the philosophes problem
File: thread-filosofi-3.cc:
/*
Working version of 5 Philosopher
to compile: g++ thread-filosofi-3.cc
*/
#include <pthread.h>
#include <iostream>
#include <iomanip> // for setw
#include <unistd.h> // for sleep
#include <sys/time.h> // for timeval
using namespace std ;
#define N_PHILOSOPHES 5
#define LEFT_FORK(N) (N)
#define RIGHT_FORK(N) (((N)+1) % N_PHILOSOPHES )
pthread_mutex_t mutex_var ;
pthread_cond_t cond_var, cond_fork[N_PHILOSOPHES] ;
typedef enum { THINK, EAT, SLEEP } Philosopher_STATE ;
static Philosopher_STATE philosopher_state[N_PHILOSOPHES] ;
static int fork_state[N_PHILOSOPHES] ;
static int const FORK_FREE = -1 ; // -1 is free otherwise the philosopher using the fork
static char const * left_right[] = { "left", "right" } ;
static int eat[N_PHILOSOPHES] ; // count number of eating!
void
drop_fork( int const np, /* the philosopher */
int const lr /* 0 = left fork, 1 == right fork */ ) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int nf = (np+lr) % N_PHILOSOPHES ;
if ( fork_state[nf] == FORK_FREE ) {
cerr << "Fatal error try to free fork " << nf << " already free!!!\n" ;
exit(1) ;
}
fork_state[nf] = FORK_FREE ;
cout << "Philosopher " << np << " drop the " << left_right[lr] << " fork!\n" ;
pthread_cond_signal( &cond_fork[nf] ) ; // signal that fork is fred
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
void
get_fork( int const np, /* the philosopher */
int const lr /* 0 = left fork, 1 == right fork */ ) {
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int nf = (np+lr) % N_PHILOSOPHES ;
while ( fork_state[nf] != FORK_FREE ) // fork not free, wait
pthread_cond_wait(&cond_fork[nf],&mutex_var) ; // intelligent loop waiting resource
// fork now is free, use it
fork_state[nf] = np ;
cout << "Philosopher " << np << " acquired " << left_right[lr] << " fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
}
bool
get_fork_with_timeout( int const np, /* the philosopher */
int const lr /* 0 = left fork, 1 == right fork */ ) {
// setup for the TIMEOUT
struct timeval now ;
struct timespec tout ;
if ( gettimeofday(&now, NULL) != 0 ) {
cerr << "failed gettimeofday\n" ;
exit(1) ;
}
tout . tv_sec = now . tv_sec + 5 ;
tout . tv_nsec = 0 ; // now . tv_usec * 1000 ;
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
int nf = (np+lr) % N_PHILOSOPHES ;
int ok = 0 ;
if ( fork_state[nf] != FORK_FREE )
ok = pthread_cond_timedwait(&cond_fork[nf],&mutex_var,&tout) ;
if ( fork_state[nf] == FORK_FREE ) { // fork aquired!
fork_state[nf] = np ;
cout << "Philosopher " << np << " acquired " << left_right[lr] << " fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
return true ;
} else { // fork not acquired
cout << "Philosopher " << np << " failed to acquire " << left_right[lr] << " fork!\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
return false ;
}
}
bool
get_right_fork( int const n ) {
return get_fork_with_timeout( n, 1 ) ;
//return get_fork( n, 1 ) ;
}
bool
get_left_fork( int const n) {
return get_fork_with_timeout( n, 0 ) ;
//return get_fork( n, 0 ) ;
}
void
drop_right_fork( int const n ) {
drop_fork( n, 1 ) ;
}
void
drop_left_fork( int const n) {
drop_fork( n, 0 ) ;
}
void *
philosopher( void *arg ) {
long n = (long) arg ;
// put a barrier for wait a go signal
pthread_mutex_lock(&mutex_var) ; // enter in the critical section
cout << "Philosopher " << n << " is waiting to start\n" ;
pthread_cond_wait(&cond_var,&mutex_var);
cout << "Philosopher " << n << " is started\n" ;
pthread_mutex_unlock(&mutex_var) ; // exit from the critical section
while ( true ) { // infinity loop
// thinking
philosopher_state[n] = THINK ;
cout << "Philosopher " << n << " is THINKING\n" ;
// try to change state
bool ok = false ;
while ( !ok ) {
ok = get_right_fork( n ) && get_left_fork( n ) ;
if ( !ok ) { // fork not FULLY acquired, drop it
if ( fork_state[LEFT_FORK(n)] == n ) drop_left_fork( n ) ;
if ( fork_state[RIGHT_FORK(n)] == n ) drop_right_fork( n ) ;
sleep(1) ;
}
}
// eating
++eat[n] ;
philosopher_state[n] = EAT ;
cout << "Philosopher " << n << " is EATING\n" ;
sleep(2) ;
drop_right_fork( n ) ;
drop_left_fork( n ) ;
// sleeping
philosopher_state[n] = SLEEP ;
cout << "Philosopher " << n << " is SLEEPING\n" ;
sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
while ( true ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
cout << "\nPhilosophes: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
switch ( philosopher_state[i] ) {
case THINK: printf(" T") ; break ;
case EAT: printf(" E") ; break ;
case SLEEP: printf(" S") ; break ;
}
}
cout << "\nForks: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
if ( fork_state[i] == FORK_FREE ) cout << " F" ;
else cout << setw(4) << fork_state[i] ;
}
cout << "\nEat Number: " ;
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) cout << setw(3) << " " << eat[i] ;
cout << endl ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
pthread_t philosopher_thread[N_PHILOSOPHES], monitor_thread ;
if ( pthread_mutex_init(&mutex_var, NULL) ) { // allocate resorce for mutex mutex_var
cerr << "Error while creating mutex\n" ;
exit(1);
}
if ( pthread_cond_init(&cond_var, NULL) ) { // allocate resorce for condition variable
cerr << "Error while creating condition\n" ;
exit(1);
}
// initialize the status of the philosophes
for ( int i = 0 ; i < N_PHILOSOPHES ; ++i ) {
philosopher_state[i] = SLEEP ;
fork_state[i] = FORK_FREE ;
eat[i] = 0 ;
if ( pthread_cond_init(&cond_fork[i], NULL) ) { // allocate resorce for condition variable
cerr << "Error while creating condition\n" ;
exit(1);
}
}
// create threads for philosophes
for ( long i = 0 ; i < N_PHILOSOPHES ; ++i ) {
cout << "Creo il filosofo " << i << "\n" ;
if ( pthread_create(&philosopher_thread[i], NULL, philosopher, (void *) i) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
sleep(1) ;
}
// create threads for monitor
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
// start philosopher
if ( pthread_cond_signal( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
sleep(1) ;
if ( pthread_cond_broadcast( &cond_var ) ) {
cerr << "Error while signaling a condition to a thread\n" ;
exit(1);
}
// wait for thread termination
pthread_exit(NULL) ;
return 0 ;
}
Lesson of 4 March 2011 (part b)
Bit matrix convolution
A simple bit-matrix convolution example
File: mask.cc:
// g++ -O3 -sse2 mask.cc TimeMeter.cc
// Elapsed 8:9 ms
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include <pthread.h>
#include "TimeMeter.hh"
//#include "pstdint.h"
#include <stdint.h>
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return (U)rand()-(U)rand() ; }
/*
//
// +-----------+
// | 1 | 2 | 3 |
// +-----------+
// | 4 | 5 | 6 | x mat
// +-----------+
// | 7 | 8 | 9 |
// +-----------+
//
//
//
*/
template <typename UNSIGNED>
void
applyMask( UNSIGNED * matrix, unsigned dimCol, unsigned Nrow, unsigned Ncol, UNSIGNED mask[3][3] ) {
UNSIGNED * r0 = (UNSIGNED *)alloca( 2 * Ncol * sizeof(UNSIGNED) ) ;
UNSIGNED * r1 = r0 + Nrow ;
//UNSIGNED r0[Ncol] ;
//UNSIGNED r1[Ncol] ;
// copy first column
std::copy( matrix, matrix + Nrow, r0 ) ;
// loop by column
for ( unsigned i = 1 ; i < Nrow-1 ; ++i ) {
UNSIGNED * ri = matrix + i*dimCol ;
UNSIGNED * ri1 = ri + dimCol ;
std::copy( ri, ri + Ncol, r1 ) ;
for ( unsigned j = 1 ; j < Ncol-1 ; ++j ) {
ri[j] = mask[0][0] * r0[j-1] + mask[0][1] * r1[j] + mask[0][2] * r1[j+1] +
mask[1][0] * r1[j-1] + mask[1][1] * r1[j] + mask[1][2] * r1[j+1] +
mask[2][0] * ri1[j-1] + mask[2][1] * ri1[j] + mask[2][2] * ri1[j+1] ;
}
std::copy( r1, r1 + Ncol, r0 ) ;
}
}
//typedef uint8_t BITS ;
//typedef uint16_t BITS ;
typedef uint32_t BITS ;
//typedef uint64_t BITS ;
int
main(int argc, char *argv) {
TimeMeter tm ;
unsigned const dimCol = 2000 ;
unsigned const Nrow = 1000 ;
unsigned const Ncol = 1000 ;
BITS * matrix = new BITS[dimCol*Nrow] ;
BITS mask[3][3] = { 1, 2, 4,
8, 16, 32,
64, 128, 256 } ;
for ( unsigned i = 0 ; i < dimCol*Nrow ; ++i ) matrix[i] = random<BITS>() ;
tm . start() ;
for ( unsigned i = 0 ; i < 10 ; ++i ) applyMask<BITS>( matrix, dimCol, Nrow, Ncol, mask ) ;
double elapsed = tm . milliseconds() ;
cout << "Elapsed " << elapsed/10 << "ms\n" ;
//pthread_exit(NULL) ;
return 0 ;
}
Fast bit-matrix convolution example, header file
File: imageConvolution.hh:
#ifndef IMAGE_CONVOLUTION_HH
#define IMAGE_CONVOLUTION_HH
template <typename UNSIGNED>
void
imageConvolution( UNSIGNED * matrix,
unsigned dimRowBlock,
unsigned numRowBlock,
unsigned numCols,
uint32_t const compressedTableConvolution[] ) ;
#endif
Fast bit-matrix convolution example, implementation
File: imageConvolution.cc:
#include <iostream>
#include <iomanip>
#include "pstdint.h"
//#include <stdint.h>
using namespace std ;
/*
//
// Given the bits
// A = x x x x x x x
// B = x x x x x x x
// C = x x x x x x x
//
// extract 3 x 3 bit mask and ...
*/
template <typename UNSIGNED>
inline
bool
useTable( uint32_t const compressedTableConvolution[], unsigned tn ) {
return (compressedTableConvolution[tn>>5]>>(tn&0x1F)) & 0x01 ;
}
template <typename UNSIGNED>
inline
UNSIGNED
convolution( bool do_left_special,
bool do_right_special,
UNSIGNED AL, UNSIGNED A, UNSIGNED AR,
UNSIGNED BL, UNSIGNED B, UNSIGNED BR,
UNSIGNED CL, UNSIGNED C, UNSIGNED CR,
uint32_t const compressedTableConvolution[] ) {
unsigned const numBits = sizeof(UNSIGNED) * CHAR_BIT ;
static UNSIGNED const mask3bit = 0x07 ;
static UNSIGNED const mask2bit = 0x03 ;
UNSIGNED RES = B ;
// special case first bit
unsigned tn ;
UNSIGNED bit = 0x01 ; // Starting bit
if ( do_left_special ) {
tn = ((A & mask2bit)<<1)|(AL>>(numBits-1)) |
((B & mask2bit)<<4)|((BL>>(numBits-4))&0x08) |
((C & mask2bit)<<7)|((CL>>(numBits-7))&0x20) ;
if ( useTable<UNSIGNED>(compressedTableConvolution,tn) ) RES |= bit ;
else RES &= ~bit ;
}
bit = 0x02 ;
for ( unsigned i = 1 ; i < numBits - 1 ; ++i ) {
tn = (A & mask3bit) | ((B & mask3bit)<<3) | ((C & mask3bit)<<6) ;
if ( useTable<UNSIGNED>(compressedTableConvolution,tn) ) RES |= bit ;
else RES &= ~bit ;
A >>= 1 ;
B >>= 1 ;
C >>= 1 ;
bit <<= 1 ;
}
// special case last bit
if ( do_right_special ) {
tn = ((A & mask2bit)<<1)|(AR&0x01) |
((B & mask2bit)<<4)|((BR<<3)&0x08) |
((C & mask2bit)<<7)|((CR<<7)&0x20) ;
if ( useTable<UNSIGNED>(compressedTableConvolution,tn) ) RES |= bit ;
else RES &= ~bit ;
}
}
/*
//
// Do convolution for 3 column (or rows)
//
*/
template <typename UNSIGNED>
inline
void
convolution( unsigned const N,
UNSIGNED const Avec[],
UNSIGNED Bvec[],
UNSIGNED const Cvec[],
uint32_t const compressedTableConvolution[] ) {
UNSIGNED Bsaved = Bvec[0] ;
Bvec[0] = convolution<UNSIGNED>( false, true,
0, Avec[0], Avec[1],
0, Bvec[0], Bvec[1],
0, Cvec[0], Cvec[1],
compressedTableConvolution ) ;
for ( unsigned i = 1 ; i < N-1 ; ++i ) {
UNSIGNED Bsaved1 = Bvec[i] ;
Bvec[i] = convolution<UNSIGNED>( true, true,
Avec[i-1], Avec[i], Avec[i+1],
Bsaved, Bvec[i], Bvec[i+1],
Cvec[i-1], Cvec[i], Cvec[i+1],
compressedTableConvolution ) ;
Bsaved = Bsaved1 ;
}
Bvec[N-1] = convolution<UNSIGNED>( true, false,
Avec[N-2], Avec[N-1], 0,
Bsaved, Bvec[N-1], 0,
Cvec[N-2], Cvec[N-1], 0,
compressedTableConvolution ) ;
}
template <typename UNSIGNED>
void
imageConvolution( UNSIGNED * matrix,
unsigned dimRowBlock,
unsigned numRowBlock,
unsigned numCols,
uint32_t const compressedTableConvolution[] ) {
UNSIGNED * csaved = (UNSIGNED *)alloca( 2 * numRowBlock * sizeof(UNSIGNED) ) ;
UNSIGNED * csaved1 = csaved + numRowBlock ;
// copy first column
std::copy( matrix + dimRowBlock, matrix + dimRowBlock + numRowBlock, csaved ) ;
// loop by column
for ( unsigned i = 1 ; i < numCols-1 ; ++i ) {
UNSIGNED * cim1 = matrix + (i-1)*dimRowBlock ;
UNSIGNED * ci = matrix + i*dimRowBlock ;
UNSIGNED * cip1 = matrix + (i+1)*dimRowBlock ;
// save row c1
std::copy( ci, ci + numRowBlock, csaved1 ) ;
convolution<UNSIGNED>( numRowBlock, csaved, ci, cip1, compressedTableConvolution ) ;
std::copy( csaved1, csaved1 + numRowBlock, csaved ) ;
}
}
template void imageConvolution<uint8_t> ( uint8_t *, unsigned, unsigned numRowBlock, unsigned numCols, uint32_t const [] ) ;
template void imageConvolution<uint16_t>( uint16_t *, unsigned, unsigned numRowBlock, unsigned numCols, uint32_t const [] ) ;
template void imageConvolution<uint32_t>( uint32_t *, unsigned, unsigned numRowBlock, unsigned numCols, uint32_t const [] ) ;
template void imageConvolution<uint64_t>( uint64_t *, unsigned, unsigned numRowBlock, unsigned numCols, uint32_t const [] ) ;
// eof imageConvolution.cc
Test without thread
File: maskBit.cc:
// g++ -O3 maskBit.cc imageConvolution.cc TimeMeter.cc
// g++ -O3 -sse2 -funroll-loops maskBit.cc imageConvolution.cc TimeMeter.cc
// 0.21 ms
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include <pthread.h>
#include "imageConvolution.hh"
#include "TimeMeter.hh"
#include "pstdint.h"
//#include <stdint.h>
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return (U)rand()-(U)rand() ; }
uint32_t compressedTableConvolution[16] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
} ;
//typedef uint8_t BITS ;
//typedef uint16_t BITS ;
//typedef uint32_t BITS ;
typedef uint64_t BITS ;
#define REPEAT 100000
int
main(int argc, char *argv) {
TimeMeter tm ;
unsigned const numBits = sizeof(BITS) * CHAR_BIT ;
unsigned const dimRowBlock = 4000/numBits ;
unsigned const numRowBlock = 2000/numBits ;
unsigned const numCols = 2000 ;
BITS * matrix = new BITS[dimRowBlock*numCols] ;
for ( unsigned i = 0 ; i < dimRowBlock*numCols ; ++i ) matrix[i] = random<BITS>() ;
tm . start() ;
for ( unsigned i = 0 ; i < REPEAT ; ++i )
imageConvolution<BITS>( matrix, dimRowBlock, numRowBlock, numCols, compressedTableConvolution ) ;
double elapsed = tm . milliseconds() ;
cout << "Elapsed " << elapsed/REPEAT << "ms\n" ;
//pthread_exit(NULL) ;
return 0 ;
}
Test with thread
File: maskBitThread.cc:
// g++ -O3 -funroll-loops maskBitThread.cc imageConvolution.cc TimeMeter.cc
// g++ -O3 -sse2 -funroll-loops maskBitThread.cc imageConvolution.cc TimeMeter.cc
// 0.1 ms
#include <iostream>
#include <iomanip>
#include <cstdlib> // near equivalent to <stdlib.h> for exit, rand, ...
#include <cmath> // near equivalent to <math.h> for sin, cos, log, ..
#include <pthread.h>
#include "imageConvolution.hh"
#include "TimeMeter.hh"
#include "pstdint.h"
//#include <stdint.h>
using namespace std ;
// general random numer generator
template <typename U>
inline
U random() { return (U)rand()-(U)rand() ; }
uint32_t compressedTableConvolution[16] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
} ;
//typedef uint8_t BITS ;
//typedef uint16_t BITS ;
//typedef uint32_t BITS ;
typedef uint64_t BITS ;
typedef struct {
BITS * matrix ;
unsigned dimRowBlock ;
unsigned numRowBlock ;
unsigned numCols ;
uint32_t const * compressedTableConvolution ;
} applyMask_data ;
extern "C"
void *
imageConvolution( void * args ) {
applyMask_data * data = static_cast<applyMask_data*>(args) ;
imageConvolution<BITS>( data -> matrix,
data -> dimRowBlock,
data -> numRowBlock,
data -> numCols,
data -> compressedTableConvolution ) ;
pthread_exit(NULL) ;
}
#define REPEAT 100000
int
main(int argc, char *argv) {
pthread_t thread[2] ;
TimeMeter tm ;
unsigned const numBits = sizeof(BITS) * CHAR_BIT ;
unsigned const dimRowBlock = 2000/numBits ;
unsigned const numRowBlock = 1000/numBits ;
unsigned const numCols = 1000 ;
BITS * matrix = new BITS[dimRowBlock*numCols] ;
for ( unsigned i = 0 ; i < dimRowBlock*numCols ; ++i ) matrix[i] = random<BITS>() ;
double elapsed1 = 0 ;
double elapsed2 = 0 ;
double elapsed3 = 0 ;
tm . start() ;
for ( unsigned i = 0 ; i < REPEAT ; ++i ) {
unsigned numCols2 = numCols/2 ;
applyMask_data data0 = { matrix, dimRowBlock, numRowBlock, numCols2, compressedTableConvolution } ;
applyMask_data data1 = { matrix + dimRowBlock * numCols2, dimRowBlock, numRowBlock, numCols-numCols2, compressedTableConvolution } ;
if ( pthread_create(&thread[0], NULL, imageConvolution, (void *) &data0) ||
pthread_create(&thread[1], NULL, imageConvolution, (void *) &data1) ) {
cerr << "Error while creating thread\n" ;
exit(1);
}
if ( pthread_join(thread[0], NULL) ) { cerr << "Error while joining thread\n" ; exit(1); }
if ( pthread_join(thread[1], NULL) ) { cerr << "Error while joining thread\n" ; exit(1); }
}
double elapsed = tm . milliseconds() ;
cout << "Elapsed " << elapsed/REPEAT << "ms\n" ;
//pthread_exit(NULL) ;
return 0 ;
}
The following problems are the assigment for the completion of the course (work in progess). The student must choose one, and produce a C/C++ code with a small report which describe the problem and the implementation. In alternative to the report DOXYGEN documentation is allowed.
Problem 1
Given two rectangular matrix \(\mathbf{A}\in\mathbb{R}^{n\times p}\) and \(\mathbf{B}\in\mathbb{R}^{p\times m}\) write a C or C++ code which compute the matrix \(\mathbf{C}=\mathbf{A}\mathbf{B}\in\mathbb{R}^{n\times m}\) using recursive splitting in such a way the splitted block fit in the computer cache.
Problem 2
Solve the problem 1 using thread
to parallelize recursion.
Problem 3
Given a matrix \(\mathbf{A}\in\{0,1,\ldots,255\}^{n\times p}\) of values in 0..255
store the matrix in a packed way in a matrix of integer. Using this packed representation write a C or C++ code which perform the following operation
\[ A_{i,j} \leftarrow A_{i,j} + \sum_{k=-1,0,1}\sum_{k=-1,0,1}A_{i+k,j+l} M_{k,l}, \quad \begin{cases} i=1,2,\ldots,n-2 \\ j=1,2,\ldots,p-2 \end{cases} \]
where
\[ \mathbf{M} = \begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{pmatrix} \]
Operation of sum and multiplication are performed modulo 256
i.e 13*34 = 186
and 255+1 = 0
.
Problem 4
Write a class Poly
which implement algebra of polinomial with values in \(\mathbb{R}\), in particular sum, multiplication and division with remainder must be in the class. Use the class to write a program which compute the the great common divisor of two polinomial, i.e. given \(p(x)\) and \(q(x)\) find \(m(x)\) such that \(m(x) \| p(x)\) and \(m(x) \| q(x)\) and if \(s(x)\) divide \(p(x)\) and \(q(x)\) then \(s(x)|m(x)\).
Problem 5
Solve the problem 4 with Galois field \(F_2=\mathbb{Z}/2\mathbb{Z}\)
Problem 6
Develop two class Vec2
and Mat2
which implement algebra of real vector and real square matrix of dimension 2. The operations for the vector class are element by element addition subtraction multiplication and division.
The operations for the matrix class are element by element addition subtraction and matrix-matrix multiplication.
Division is equivalent to left multiplication by inverse.
Write external operation which implement mixed operation of Matrix-Vector multiplication and vector-Matrix division which is the linear system solution, i.e. \(\mathbf{v}/\mathbf{A} \equiv \mathbf{A}^{-1}\mathbf{v}\).
Use this classes to solve some geometric problem in \(\mathbb{R}^2\), like
Find the tangent points between a circle and lines passing from a fixed points
Given two line in parametric form find the intersection point
Problem 7
Consider a lower triangular matrix \(\mathbf{L}\) an the partition
\[ \mathbf{L} = \begin{pmatrix} \mathbf{L}_{1,1} & \mathbf{0} \\ \mathbf{L}_{2,1} & \mathbf{L}_{2,2} \end{pmatrix} \]
The linear system \(\mathbf{L}\mathbf{x}=\mathbf{b}\) can be solved as follows
\[ \begin{pmatrix} \mathbf{L}_{1,1} & \mathbf{0} \\ \mathbf{L}_{2,1} & \mathbf{L}_{2,2} \end{pmatrix} \begin{pmatrix} \mathbf{x}_{1} \\ \mathbf{x}_{2} \end{pmatrix} = \begin{pmatrix} \mathbf{b}_{1} \\ \mathbf{b}_{2} \end{pmatrix}, \qquad \begin{cases} \mathbf{x}_{1} = \mathbf{L}_{1,1}^{-1} \mathbf{b}_{1} \\ \mathbf{x}_{2} = \mathbf{L}_{2,2}^{-1} (\mathbf{b}_{2}-\mathbf{x}_{1}) \\ \end{cases} \]
Use recursively this pattern to write a C or C++ routine which solve a lower triangular linear system.
Problem 8
Write a class GF3
which implement algebra of the Galois field \(F_3=\mathbb{Z}/3\mathbb{Z}\)
TimeMeter A portable class for time measuring
File: TimeMeter.hh:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#ifndef TIME_METER_HH
#define TIME_METER_HH
bool getTime( long & sec, long & usec ) ;
class TimeMeter {
long sec, usec ;
TimeMeter( TimeMeter const & ) ;
TimeMeter const & operator = ( TimeMeter const & ) const ;
public:
TimeMeter() { start() ; }
~TimeMeter() {} ;
void start() ;
double seconds() ;
double milliseconds() ;
} ;
#endif
File: TimeMeter.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#include "TimeMeter.hh"
using namespace std ;
/*
// _ _____ _
// __ _ ___| ||_ _(_)_ __ ___ ___
// / _` |/ _ \ __|| | | | '_ ` _ \ / _ \
// | (_| | __/ |_ | | | | | | | | | __/
// \__, |\___|\__||_| |_|_| |_| |_|\___|
// |___/
*/
#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
bool
getTime( long & sec, long & usec ) {
FILETIME ft ;
GetSystemTimeAsFileTime( &ft ) ;
// FILETIME To UNIX Time
unsigned __int64 u_sec = ft . dwHighDateTime ;
u_sec <<= 32 ;
u_sec |= ft . dwLowDateTime ;
u_sec -= 116444736000000000ULL ;
u_sec /= 10ULL ;
sec = long( u_sec / 1000000L ) ;
usec = long( u_sec % 1000000L ) ;
return true ;
}
#else
#include <sys/time.h>
bool
getTime( long & sec, long & usec ) {
struct timeval now ;
bool ok = gettimeofday(&now, NULL) == 0 ;
if ( ok ) {
sec = now . tv_sec;
usec = now . tv_usec;
} else {
sec = usec = 0 ;
}
return ok ;
}
#endif
void
TimeMeter::start() {
getTime( sec, usec ) ;
}
double
TimeMeter::seconds() {
long new_sec, new_usec ;
getTime( new_sec, new_usec ) ;
return (new_sec-sec)+(new_usec-usec)*1E-6 ;
}
double
TimeMeter::milliseconds() {
long new_sec, new_usec ;
getTime( new_sec, new_usec ) ;
return (new_sec-sec)*1E3+(new_usec-usec)*1E-3 ;
}
// EOF TimeMeter.cc
Useful link
Course of Numerical Methods for Dynamic Systems and Control [140155] (AA 2009/2010)
Lessons timetable
DAY | TIME | ROOM |
---|---|---|
Monday | 15:30 - 17:30 | 108 |
Tuesday | 8.30 - 11.30 | R4 |
Wednesday | 9.30 - 12.30 | R4 |
Reception timetable
DAY | TIME | ROOM |
---|---|---|
Monday | 11 - 12 | 505 |
Tuesday | 11.30 - 12.30 | 505 |
Numerical Solution of Differential Algebraic Equations Editors: Claus Bendtsen and Per Grove Thomsen. IMM Technical report, download at this link
Numerical Solution of Differential Algebraic Equations and Applications Editor: Per Grove Thomsen. IMM Technical report, download at this link
An interesting paper of Linda Petzold on DAE DAE are not ODE: download at this link free copy at researchgate: link
An Introduction to Mathematical Optimal Control Theory By Lawrence C. Evans of Department of Mathematics, University of California, Berkeley: download at this link
An optimal control course at EPFL The course of Dr. Gregory FRANCOIS and Dr. Benoit CHACHUAT can be found at this link
Student’s project
- The text of the assigned project is here
Examination 8 January 2010
- Italian text in PDF format: pdf
Examination 16 February 2010
- Italian text in PDF format: pdf
Examination 16 June 2010
- Italian text in PDF format: pdf
Examination 13 July 2010
- Italian text in PDF format: pdf
Examination 8 September 2010
- Italian text in PDF format: pdf
Comparison of Laplace and Z-transform
Connection between Bode plot and Laplace
Study with Fourier serie of three phase rectifier
Example of computation of exponential matrix
Computation of exponential matrix, many methods
Little tutorial on computing matrix exponential
Example of Index 1 DAE
Example of DAE: Pendulum in cartesian coordinate
Example of MATLAB solver with implicit Euler for the Pendulum in cartesian coordinate
The finite difference are generated using MAPLE, the files are here:
Example of Brachiostosdcrone problem with indirect method
P.h.D. Course of Numerical Linear Algebra with C++ (AA 2009/2010)
Some useful links
Some useful references
- The QR algorithm: 50 years later its genesis by John Francis and Vera Kublanovskaya and subsequent developments IMA Journal of Numerical Analysis 2009 29(3):467-485;
Lesson of 15 February 2010
Some simple C/C++ programs
A minimal program
File: example1.cc:
/*
I am a comment
*/
// I am a single line comment
/*
A C/C++ program is a "function" called "main()"
which return an integer.
Return 0 means all ok!.
Return != from 0 signal an error to the OS
*/
// standard I/O of C (libc)
#include <stdio.h>
// standard I/O of C++ (libstdc++)
#include <iostream>
using std::cout ; // use object cout of namespace std
using namespace std ; // use all the functions and object of namespace std
int // the type of return value
main() { // brackets contains the bosy of the program
// standard C way of I/O
printf("I am a string\n") ; // \n = new line character
// \r = return character
// \t = tabulation
// cout = character out object
cout << "I am a string output by cout\n" ;
return 0 ; // return 0 to the OS
}
Built in types
File: example2.cc:
// standard I/O of C (libc)
#include <stdio.h>
// standard I/O of C++ (libstdc++)
#include <iostream>
using namespace std ; // use all the functions and object of namespace std
int // the type of return value
main() { // brackets contains the bosy of the program
// the standard type of C/C++
int a, b, c ; // declare and define a, b, c as integer variable
c = 1 ;
a = 1 ; // assign a to the value 1
a = b / c ; // integer division
a = b % c ; // remainder of the division of b by c
/*
other integer like type
short int (smaller integer normally 2 byte)
long int (larger integer normlly 8 byte)
unsigned int (int without sign)
unsigned short int (short int without sign) [ short == short int]
unsigned long int (long int without sign) [ long == long int]
*/
float d, e, f ; // declare and define d, e,f as single precision floating point variables
d = 1.0 ;
e = 2.0 ;
e += d ; // ==> e = e + d
// in general "a OP= b" is equivalent to " a = a OP b "
double g, h, i ; // declare and define d, e,f as double precision floating point variables
return 0 ; // return 0 to the OS
}
Conditional and loops
File: example3.cc:
// standard I/O of C (libc)
#include <stdio.h>
// standard I/O of C++ (libstdc++)
#include <iostream>
using namespace std ; // use all the functions and object of namespace std
int
main() {
int a, b, c, d ;
a = 1 ;
if ( a < 3 ) cout << " a < 3 " ;
else cout << " a >= 3 " ; // use {} or more than 1 instruction
/*
comparisoin operators
== Check equality
!= Check inequality
> greather then
< less then
>= greather or equal then
<= less or equal then
*/
if ( a<3 && b == 0 ) cout << "a<3 and b==0\n" ;
/*
logical operation
|| or
&& and
! not
*/
for ( int i=0 ; i < 10 ; ++i ) // ++i => i = i+1
cout << i << "\n" ;
/*
for ( A ; B ; C ) EXPR ;
A is executed ONCE at the beginning of the loop
B is execued EACH time at the beginning of the loop
EXPR is executed each time B is true
C is executed at the end of each loop
*/
int i = 10 ;
while ( --i > 0 ) cout << i << "\n" ;
/*
while ( A ) EXPR ;
EXPR is executed each time A is true
*/
i = 10 ;
do {
cout << i << "\n" ;
} while ( --i > 0 ) ;
/*
do { EXPR ; } while ( A ) ;
EXPR is executed, then check A
*/
return 0 ; // return 0 to the OS
}
Functions and recursion
File: example4.cc:
// standard I/O of C (libc)
#include <stdio.h>
// standard I/O of C++ (libstdc++)
#include <iostream>
using namespace std ; // use all the functions and object of namespace std
// define the function factorial
int
fact( int n ) {
int res = 1 ;
for ( int i = 2 ; i <= n ; ++i )
res *= i ;
return res ;
}
// define the function factorial recursively
int
factRec( int n ) {
if ( n <= 1 ) return 1 ;
return n* factRec(n-1) ;
}
int
main() {
int n = 4 ;
cout << "fact " << n << " = " << fact(n) << "\n" ;
cout << "factRec " << n << " = " << factRec(n) << "\n" ;
return 0 ; // return 0 to the OS
}
Splitting code in more files
File: example5.h:
// standard I/O of C (libc)
#include <stdio.h>
// standard I/O of C++ (libstdc++)
#include <iostream>
using namespace std ; // use all the functions and object of namespace std
// declaration the function factorial
extern int fact( int n ) ;
// define the function factorial recursively
extern int factRec( int n ) ;
File: example5.cc:
// standard I/O of C (libc)
#include "example5.h"
int
main() {
int n = 4 ;
cout << "fact " << n << " = " << fact(n) << "\n" ;
cout << "factRec " << n << " = " << factRec(n) << "\n" ;
return 0 ; // return 0 to the OS
}
File: example5b.cc:
// standard I/O of C (libc)
#include "example5.h"
// define the function factorial
int
fact( int n ) {
int res = 1 ;
for ( int i = 2 ; i <= n ; ++i )
res *= i ;
return res ;
}
// define the function factorial recursively
int
factRec( int n ) {
if ( n <= 1 ) return 1 ;
return n* factRec(n-1) ;
}
Lesson of 16 February 2010
Some simple C/C++ programs
Simple macro examples
File: example6.cc:
/*
I am a comment
*/
// I am a single line comment
/*
A C/C++ program is a "function" called "main()"
which return an integer.
Return 0 means all ok!.
Return != from 0 signal an error to the OS
*/
#define I_AM_AN_EMPY_MACRO
#define I_AM_A_MACRO 1234
#define I_AM_A_MACRO_WITH_ARGUMENT(A) (A)*2
int // the type of return value
main() { // brackets contains the bosy of the program
I_AM_AN_EMPY_MACRO
int a = I_AM_A_MACRO ;
int b = I_AM_A_MACRO_WITH_ARGUMENT(1+2) ;
#ifdef _WIN32
printf("WIN32 environment\n") ;
#else
cout << "UNIX environment\n" ;
#endif
return 0 ; // return 0 to the OS
}
Example of FORTRAN linkage
File: example7.cc:
/*
I am a comment
*/
// include the standard definition for I/O
#include <iostream>
// include the definition I/O manipulation command like setw, oct etc.
#include <iomanip>
// load the standard namespace
using namespace std ;
// define the fortran name as c name + underscore
#define F77NAME(A) A##_
typedef double valueType ;
/* prototype of BLAS dgemm routine (fortran linkage) */
extern "C" // telling the compiler that dgemm_ has C linkage convection
void
F77NAME(dgemm)( char const TRANSA[], // pass a string address
char const TRANSB[], // pass a string address
int const * M, // pass the address of the integer N
int const * N, // pass the address of the integer M
int const * K, // pass the address of the integer K
double const * ALPHA, // pass the address of the double ALPHA
double const A[], // pass the address of the vector/matrix A
int const * LDA, // pass the address of the row dimension of A
double const B[], // pass the address of the vector/matrix A
int const * LDB, // pass the address of the row dimension of B
double const * BETA, // pass the address of the double BETA
double C[], // pass the address of the row dimension of C
int const * LDC ) ; // pass the address of the vector/matrix A
extern "C" // telling the compiler that sgemm_ has C linkage convection
void
F77NAME(sgemm)( char const TRANSA[],
char const TRANSB[],
int const * M,
int const * N,
int const * K,
float const * ALPHA,
float const A[],
int const * LDA,
float const B[],
int const * LDB,
float const * BETA,
float C[],
int const * LDC ) ;
/*
FORTRAN do not support overloading.
We use inline + C++ overloading to simulate it.
In particular we define two routine "gemm" with
float and double argument respectively.
The use of inline results in a DIRECT call to the fortran
routine. No penalty in calling fotran routine!.
*/
inline
void
gemm( char const TRANSA[],
char const TRANSB[],
int const M,
int const N,
int const K,
float const ALPHA,
float const A[],
int const LDA,
float const B[],
int const LDB,
float const BETA,
float C[],
int const LDC ) {
F77NAME(sgemm)( TRANSA, TRANSB, &M, &N, &K, &ALPHA, A, &LDA, B, &LDB, &BETA, C, &LDC ) ;
}
inline
void
gemm( char const TRANSA[],
char const TRANSB[],
int const M,
int const N,
int const K,
double const ALPHA,
double const A[],
int const LDA,
double const B[],
int const LDB,
double const BETA,
double C[],
int const LDC ) {
F77NAME(dgemm)( TRANSA, TRANSB, &M, &N, &K, &ALPHA, A, &LDA, B, &LDB, &BETA, C, &LDC ) ;
}
int // the type of return value
main() { // brackets contains the bosy of the program
// define matrix A and initialize
valueType A[3][3] = { {1, 2, 3},
{4, 5, 6},
{7, 8, 9} } ;
// define matrix B and initialize
valueType B[3][2] = { {1, 2},
{3, 4},
{5, 6} } ;
// define matrix C and DO NOT initialize
valueType C[10][10] ;
/* Due to the fact that C matrix are store by ROW and not by COLUMN
they are "seen" as transposed by the fortran routine.
Moreover (AB)^T = B^T A^T so that the
product of AB in C row major order is the
product BA in column major order!. */
// alpha * A * B + beta * C --> C
gemm( "N",
"N",
2,
3,
3,
1,
(valueType*)B, 2, // perform casting of the pointer to make compiler happy
(valueType*)A, 3, // perform casting of the pointer to make compiler happy
0,
(valueType*)C, // perform casting of the pointer to make compiler happy
10 ) ;
// display the result
for ( int i = 0 ; i < 3 ; ++i ) {
for ( int j = 0 ; j < 2 ; ++j ) {
cout << setw(10) << C[i][j] << " " ;
}
cout << '\n' ;
}
return 0 ; // return 0 to the OS
}
/*
Example of the assembler of the generated dgemm call
icc -S -fsource-asm -fcode-asm
;;; gemm( "N",
;;; "N",
;;; 2,
;;; 3,
;;; 3,
;;; 1,
;;; (valueType*)B, 2, // perform casting of the pointer to make compiler happy
;;; (valueType*)A, 3, // perform casting of the pointer to make compiler happy
;;; 0,
;;; (valueType*)C, // perform casting of the pointer to make compiler happy
movl $2, %ecx #example7.cc:119.3
movl $3, %r8d #example7.cc:119.3
lea 928(%rsp), %r9 #example7.cc:125.21
movq %r11, 952(%rsp) #example7.cc:105.21
lea 1088(%rsp), %rax #example7.cc:119.3
lea 976(%rsp), %r10 #example7.cc:126.21
lea 1096(%rsp), %r11 #example7.cc:119.3
movq %rdi, 960(%rsp) #example7.cc:105.21
lea 1056(%rsp), %rdi #example7.cc:119.3
movq %rsi, 968(%rsp) #example7.cc:105.21
lea 128(%rsp), %rsi #example7.cc:128.21
movl %ecx, 1064(%rsp) #example7.cc:119.3
movl %r8d, 1072(%rsp) #example7.cc:119.3
movl %r8d, 1080(%rsp) #example7.cc:119.3
movq %rdx, 1048(%rsp) #example7.cc:119.3
lea 1104(%rsp), %rdx #example7.cc:119.3
movl %ecx, 1088(%rsp) #example7.cc:119.3
lea 1072(%rsp), %rcx #example7.cc:119.3
movl %r8d, 1096(%rsp) #example7.cc:119.3
lea 1080(%rsp), %r8 #example7.cc:119.3
movq $0, 1056(%rsp) #example7.cc:119.3
movl $10, 1104(%rsp) #example7.cc:119.3
movq %r9, (%rsp) #example7.cc:125.21
lea 1048(%rsp), %r9 #example7.cc:119.3
movq %rax, 8(%rsp) #example7.cc:119.3
movq %r10, 16(%rsp) #example7.cc:126.21
movq %r11, 24(%rsp) #example7.cc:119.3
movq %rdi, 32(%rsp) #example7.cc:119.3
lea L_2__STRING.0(%rip), %rdi #example7.cc:119.3
movq %rsi, 40(%rsp) #example7.cc:128.21
movq %rdi, %rsi #example7.cc:119.3
movq %rdx, 48(%rsp) #example7.cc:119.3
lea 1064(%rsp), %rdx #example7.cc:119.3
call _dgemm_ #example7.cc:119.3
*/
Some free numerical linear algebra library
Lesson of 17 February 2010
Lesson file in a zip file
Alglin interface with Lapack/Atlas
File: alglin.hh:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2008 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
///
/// file: alglin.hh
///
#ifndef ALGLIN_HH
#define ALGLIN_HH
#ifndef BLASNAME
#define BLASNAME(A) A##_
#endif
#ifndef LAPACKNAME
#define LAPACKNAME(A) A##_
#endif
#ifndef ATLASNAME
#define ATLASNAME(A) ATL_##A
#endif
#include <stdexcept>
#include <cmath>
namespace alglin {
using namespace std ;
typedef char character ;
typedef int integer ;
typedef float single_precision ;
typedef double double_precision ;
enum ATLAS_ORDER { AtlasRowMajor = 101, AtlasColMajor = 102 };
enum ATLAS_TRANS { AtlasNoTrans = 111, AtlasTrans = 112,
AtlasConjTrans = 113, AtlasConj = 114 };
enum ATLAS_UPLO { AtlasUpper = 121, AtlasLower = 122 };
enum ATLAS_DIAG { AtlasNonUnit = 131, AtlasUnit = 132 };
enum ATLAS_SIDE { AtlasLeft=141, AtlasRight=142 } ;
inline
ATLAS_TRANS
trans_atlas(character const TRANS ) {
switch ( TRANS ) {
case 'N': case 'n': return AtlasNoTrans ;
case 'T': case 't': return AtlasTrans ;
case 'C': case 'c': return AtlasConjTrans ;
default: throw runtime_error("bad traspose mode selection\n") ;
}
}
inline
ATLAS_UPLO
uplo_atlas(character const UPLO ) {
switch ( UPLO ) {
case 'U': case 'u': return AtlasUpper ;
case 'L': case 'l': return AtlasLower ;
default: throw runtime_error("bad UP/LOW mode selection\n") ;
}
}
inline
ATLAS_DIAG
diag_atlas(character const DIAG ) {
switch ( DIAG ) {
case 'U': case 'u': return AtlasUnit ;
case 'N': case 'n': return AtlasNonUnit ;
default: throw runtime_error("bad diagonal mode selection\n") ;
}
}
inline
ATLAS_SIDE
side_atlas(character const SIDE ) {
switch ( SIDE ) {
case 'L': case 'l': return AtlasLeft ;
case 'R': case 'r': return AtlasRight ;
default: throw runtime_error("bad side mode selection\n") ;
}
}
/*
// ___ ___ _ __ _ _
// / __/ _ \| '_ \| | | |
// | (_| (_) | |_) | |_| |
// \___\___/| .__/ \__, |
// |_| |___/
*/
extern "C" {
void
BLASNAME(scopy)( integer const * N,
single_precision const X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
BLASNAME(dcopy)( integer const * N,
double_precision const X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
ATLASNAME(scopy)( const int N,
const float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(dcopy)( const int N,
const double *X, const int incX,
double *Y, const int incY );
}
inline
void
copy( integer const N,
single_precision const X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(scopy)( N, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(scopy)( &N, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
copy( integer const N,
double_precision const X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dcopy)( N, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(dcopy)( &N, X, &INCX, Y, &INCY ) ; }
#endif
/*
// _____ ____ _ _ __
// / __\ \ /\ / / _` | '_ \
// \__ \\ V V / (_| | |_) |
// |___/ \_/\_/ \__,_| .__/
// |_|
*/
extern "C" {
void
BLASNAME(sswap)( integer const * N,
single_precision X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
BLASNAME(dswap)( integer const * N,
double_precision X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
ATLASNAME(sswap)( const int N,
float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(dswap)( const int N,
double *X, const int incX,
double *Y, const int incY );
void
BLASNAME(slaswp)( integer const * NCOL,
single_precision A[],
integer const * LDA,
integer const * K1,
integer const * K2,
integer const IPIV[],
integer const * INC ) ;
void
BLASNAME(dlaswp)( integer const * NCOL,
double_precision A[],
integer const * LDA,
integer const * K1,
integer const * K2,
integer const IPIV[],
integer const * INC ) ;
}
inline
void
swap( integer const N,
single_precision X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(sswap)( N, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(sswap)( &N, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
swap( integer const N,
double_precision X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dswap)( N, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(dswap)( &N, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
swaps( integer const NCOL,
single_precision A[],
integer const LDA,
integer const I1,
integer const I2,
integer const IPIV[],
integer const INC ) {
integer K1 = I1+1 ;
integer K2 = I2+1 ;
BLASNAME(slaswp)( &NCOL, A, &LDA, &K1, &K2, IPIV, &INC ) ;
}
inline
void
swaps( integer const NCOL,
double_precision A[],
integer const LDA,
integer const I1,
integer const I2,
integer const IPIV[],
integer const INC ) {
integer K1 = I1+1 ;
integer K2 = I2+1 ;
BLASNAME(dlaswp)( &NCOL, A, &LDA, &K1, &K2, IPIV, &INC ) ;
}
/*
// _
// ___ ___ __ _| |
// / __|/ __/ _` | |
// \__ \ (_| (_| | |
// |___/\___\__,_|_|
*/
extern "C" {
void
BLASNAME(sscal)( integer const * N,
single_precision const * S,
single_precision X[],
integer const * INCX ) ;
void
BLASNAME(dscal)( integer const * N,
double_precision const * S,
double_precision X[],
integer const * INCX ) ;
void
ATLASNAME(sscal)( const int N,
const float alpha,
float *X, const int incX );
void
ATLASNAME(dscal)( const int N,
const double alpha,
double *X, const int incX );
}
inline
void
scal( integer const N,
single_precision const S,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(sscal)(N, S, X, INCX) ; }
#else
{ BLASNAME(sscal)(&N, &S, X, &INCX) ; }
#endif
inline
void
scal( integer const N,
double_precision const S,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dscal)(N, S, X, INCX) ; }
#else
{ BLASNAME(dscal)(&N, &S, X, &INCX) ; }
#endif
/*
// __ ___ ___ __ _ _
// / _` \ \/ / '_ \| | | |
// | (_| |> <| |_) | |_| |
// \__,_/_/\_\ .__/ \__, |
// |_| |___/
*/
extern "C" {
void
BLASNAME(saxpy)( integer const * N,
single_precision const * A,
single_precision const X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
BLASNAME(daxpy)( integer const * N,
double_precision const * A,
double_precision const X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
ATLASNAME(saxpy)( const int N,
const float alpha,
const float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(daxpy)( const int N,
const double alpha,
const double *X, const int incX,
double *Y, const int incY );
}
inline
void
axpy( integer const N,
single_precision const A,
single_precision const X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(saxpy)( N, A, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(saxpy)( &N, &A, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
axpy( integer const N,
double_precision const A,
double_precision const X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(daxpy)( N, A, X, INCX, Y, INCY ) ; }
#else
{ BLASNAME(daxpy)( &N, &A, X, &INCX, Y, &INCY ) ; }
#endif
/*
// _______ _ __ ___
// |_ / _ \ '__/ _ \
// / / __/ | | (_) |
// /___\___|_| \___/
*/
extern "C" {
void
ATLASNAME(szero)( const int N, float *X, const int incX );
void
ATLASNAME(dzero)( const int N, double *X, const int incX );
}
inline
void
zero( integer const N,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(szero)( N, X, INCX ) ; }
#else
{ single_precision z = 0 ;
integer iz = 0 ;
BLASNAME(scopy)( &N, &z, &iz, X, &INCX ) ; }
#endif
inline
void
zero( integer const N,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dzero)( N, X, INCX ) ; }
#else
{ double_precision z = 0 ;
integer iz = 0 ;
BLASNAME(dcopy)( &N, &z, &iz, X, &INCX ) ; }
#endif
/*
// __ _ ___ _ __
// / _` |/ _ \ '__|
// | (_| | __/ |
// \__, |\___|_|
// |___/
*/
extern "C" {
void
BLASNAME(sger)( integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const X[],
integer const * INCX,
single_precision const Y[],
integer const * INCY,
single_precision A[],
integer const * LDA ) ;
void
BLASNAME(dger)( integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const X[],
integer const * INCX,
double_precision const Y[],
integer const * INCY,
double_precision A[],
integer const * LDA ) ;
void
ATLASNAME(sger)( const int M, const int N,
const float alpha,
const float *X, const int incX,
const float *Y, const int incY,
float *A, const int lda );
void
ATLASNAME(dger)( const int M, const int N,
const double alpha,
const double *X, const int incX,
const double *Y, const int incY,
double *A, const int lda );
}
inline
void
ger( integer const M,
integer const N,
single_precision const ALPHA,
single_precision const X[],
integer const INCX,
single_precision const Y[],
integer const INCY,
single_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(sger)( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) ; }
#else
{ BLASNAME(sger)( &M, &N, &ALPHA, X, &INCX, Y, &INCY, A, &LDA ) ; }
#endif
inline
void
ger( integer const M,
integer const N,
double_precision const ALPHA,
double_precision const X[],
integer const INCX,
double_precision const Y[],
integer const INCY,
double_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(dger)( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) ; }
#else
{ BLASNAME(dger)( &M, &N, &ALPHA, X, &INCX, Y, &INCY, A, &LDA ) ; }
#endif
/*
// __ _ ___ _ __ _____ __
// / _` |/ _ \ '_ ` _ \ \ / /
// | (_| | __/ | | | | \ V /
// \__, |\___|_| |_| |_|\_/
// |___/
*/
extern "C" {
void
BLASNAME(sgemv)( character const TRANS[],
integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const A[],
integer const * LDA,
single_precision const X[],
integer const * INCX,
single_precision const * BETA,
single_precision Y[],
integer const * INCY ) ;
void
BLASNAME(dgemv)( character const TRANS[],
integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const A[],
integer const * LDA,
double_precision const X[],
integer const * INCX,
double_precision const * BETA,
double_precision Y[],
integer const * INCY ) ;
void
ATLASNAME(sgemv)( const enum ATLAS_TRANS TransA,
const int M, const int N,
const float alpha,
const float *A, const int lda,
const float *X, const int incX,
const float beta,
float *Y, const int incY );
void
ATLASNAME(dgemv)( const enum ATLAS_TRANS TransA,
const int M, const int N,
const double alpha,
const double *A, const int lda,
const double *X, const int incX,
const double beta,
double *Y, const int incY );
}
inline
void
gemv( character const TRANS[],
integer const M,
integer const N,
single_precision const ALPHA,
single_precision const A[],
integer const LDA,
single_precision const X[],
integer const INCX,
single_precision const BETA,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(sgemv)( trans_atlas(TRANS[0]), M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) ; }
#else
{ BLASNAME(sgemv)( TRANS, &M, &N, &ALPHA, A, &LDA, X, &INCX, &BETA, Y, &INCY ) ; }
#endif
inline
void
gemv( character const TRANS[],
integer const M,
integer const N,
double_precision const ALPHA,
double_precision const A[],
integer const LDA,
double_precision const X[],
integer const INCX,
double_precision const BETA,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dgemv)( trans_atlas(TRANS[0]), M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) ; }
#else
{ BLASNAME(dgemv)( TRANS, &M, &N, &ALPHA, A, &LDA, X, &INCX, &BETA, Y, &INCY ) ; }
#endif
/*
// __ _ ___ _ __ ___ _ __ ___
// / _` |/ _ \ '_ ` _ \| '_ ` _ \
// | (_| | __/ | | | | | | | | | |
// \__, |\___|_| |_| |_|_| |_| |_|
// |___/
*/
extern "C" {
void
BLASNAME(sgemm)( character const TRANSA[],
character const TRANSB[],
integer const * M,
integer const * N,
integer const * K,
single_precision const * ALPHA,
single_precision const A[],
integer const * LDA,
single_precision const B[],
integer const * LDB,
single_precision const * BETA,
single_precision C[],
integer const * LDC ) ;
void
BLASNAME(dgemm)( character const TRANSA[],
character const TRANSB[],
integer const * M,
integer const * N,
integer const * K,
double_precision const * ALPHA,
double_precision const A[],
integer const * LDA,
double_precision const B[],
integer const * LDB,
double_precision const * BETA,
double_precision C[],
integer const * LDC ) ;
void
ATLASNAME(sgemm)( const enum ATLAS_TRANS TransA,
const enum ATLAS_TRANS TransB,
const int M, const int N, const int K,
const float alpha,
const float *A, const int lda,
const float *B, const int ldb,
const float beta,
float *C, const int ldc );
void
ATLASNAME(dgemm)( const enum ATLAS_TRANS TransA,
const enum ATLAS_TRANS TransB,
const int M, const int N, const int K,
const double alpha,
const double *A, const int lda,
const double *B, const int ldb,
const double beta,
double *C, const int ldc );
}
inline
void
gemm( character const TRANSA[],
character const TRANSB[],
integer const M,
integer const N,
integer const K,
single_precision const ALPHA,
single_precision const A[],
integer const LDA,
single_precision const B[],
integer const LDB,
single_precision const BETA,
single_precision C[],
integer const LDC )
#ifdef USE_ATLAS
{ ATLASNAME(sgemm)( trans_atlas(TRANSA[0]), trans_atlas(TRANSB[0]),
M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ; }
#else
{ BLASNAME(sgemm)( TRANSA, TRANSB,
&M, &N, &K,
&ALPHA, A, &LDA,
B, &LDB,
&BETA, C, &LDC ) ; }
#endif
inline
void
gemm( character const TRANSA[],
character const TRANSB[],
integer const M,
integer const N,
integer const K,
double_precision const ALPHA,
double_precision const A[],
integer const LDA,
double_precision const B[],
integer const LDB,
double_precision const BETA,
double_precision C[],
integer const LDC )
#ifdef USE_ATLAS
{ ATLASNAME(dgemm)( trans_atlas(TRANSA[0]), trans_atlas(TRANSB[0]),
M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ; }
#else
{ BLASNAME(dgemm)( TRANSA, TRANSB,
&M, &N, &K,
&ALPHA, A, &LDA,
B, &LDB,
&BETA, C, &LDC ) ; }
#endif
/*
// ____
// _ __ _ __ _ __ ___ |___ \
// | '_ \| '__| '_ ` _ \ __) |
// | | | | | | | | | | |/ __/
// |_| |_|_| |_| |_| |_|_____|
*/
extern "C" {
single_precision
BLASNAME(snrm2)( integer const * N, single_precision const X[], integer const * INCX ) ;
double_precision
BLASNAME(dnrm2)( integer const * N, double_precision const X[], integer const * INCX ) ;
float
ATLASNAME(snrm2)( const int N, const float *X, const int incX ) ;
double
ATLASNAME(dnrm2)( const int N, const double *X, const int incX ) ;
}
inline
single_precision
nrm2( integer const N,
single_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(snrm2)( N, X, INCX ) ; }
#else
{ return BLASNAME(snrm2)( &N, X, &INCX ) ; }
#endif
inline
double_precision
nrm2( integer const N,
double_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(dnrm2)( N, X, INCX ) ; }
#else
{ return BLASNAME(dnrm2)( &N, X, &INCX ) ; }
#endif
/*
// __ _ ___ _ _ _ __ ___
// / _` / __| | | | '_ ` _ \
// | (_| \__ \ |_| | | | | | |
// \__,_|___/\__,_|_| |_| |_|
*/
extern "C" {
single_precision
BLASNAME(sasum)( integer const * N, single_precision const X[], integer const * INCX ) ;
double_precision
BLASNAME(dasum)( integer const * N, double_precision const X[], integer const * INCX ) ;
float
ATLASNAME(sasum)( const int N, const float *X, const int incX );
double
ATLASNAME(dasum)( const int N, const double *X, const int incX );
}
inline
single_precision
asum(integer const N,
single_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return ATLASNAME(sasum)( N, X, INCX ) ; }
#else
{ return BLASNAME(sasum)( &N, X, &INCX ) ; }
#endif
inline
double_precision
asum(integer const N,
double_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return ATLASNAME(dasum)( N, X, INCX ) ; }
#else
{ return BLASNAME(dasum)( &N, X, &INCX ) ; }
#endif
/*
// __ _ _ __ ___ __ ___ __
// / _` | '_ ` _ \ / _` \ \/ /
// | (_| | | | | | | (_| |> <
// \__,_|_| |_| |_|\__,_/_/\_\
*/
extern "C" {
integer
BLASNAME(isamax)( integer const * N, single_precision const X[], integer const * INCX ) ;
integer
BLASNAME(idamax)( integer const * N, double_precision const X[], integer const * INCX ) ;
int
ATLASNAME(isamax)( const int N, const float *X, const int incX );
int
ATLASNAME(idamax)( const int N, const double *X, const int incX );
}
inline
integer
iamax( integer const N,
single_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(isamax)( N, X, INCX )-1 ; }
#else
{ return BLASNAME(isamax)( &N, X, &INCX )-1 ; }
#endif
inline
integer
iamax( integer const N,
double_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(idamax)( N, X, INCX )-1 ; }
#else
{ return BLASNAME(idamax)( &N, X, &INCX )-1 ; }
#endif
inline
single_precision
amax( integer const N,
single_precision const X[],
integer const INCX )
{ return abs(X[iamax(N,X,INCX)]) ; }
inline
double_precision
amax( integer const N,
double_precision const X[],
integer const INCX )
{ return abs(X[iamax(N,X,INCX)]) ; }
/*
// _ _
// __| | ___ | |_
// / _` |/ _ \| __|
// | (_| | (_) | |_
// \__,_|\___/ \__|
*/
extern "C" {
single_precision
BLASNAME(sdot)( integer const * N,
single_precision const SX[],
integer const * INCX,
single_precision const SY[],
integer const * INCY ) ;
double_precision
BLASNAME(ddot)( integer const * N,
double_precision const SX[],
integer const * INCX,
double_precision const SY[],
integer const * INCY ) ;
float
ATLASNAME(sdot)( const int N,
const float *X, const int incX,
const float *Y, const int incY );
double
ATLASNAME(ddot)( const int N,
const double *X, const int incX,
const double *Y, const int incY );
}
inline
single_precision
dot( integer const N,
single_precision const SX[],
integer const INCX,
single_precision const SY[],
integer const INCY )
#ifdef USE_ATLAS
{ return ATLASNAME(sdot)( N, SX, INCX, SY, INCY ) ; }
#else
{ return BLASNAME(sdot)( &N, SX, &INCX, SY, &INCY ) ; }
#endif
inline
double_precision
dot( integer const N,
double_precision const SX[],
integer const INCX,
double_precision const SY[],
integer const INCY )
#ifdef USE_ATLAS
{ return ATLASNAME(ddot)( N, SX, INCX, SY, INCY ) ; }
#else
{ return BLASNAME(ddot)( &N, SX, &INCX, SY, &INCY ) ; }
#endif
/*
// __ _ ___ ___ ___ _ __ _ _
// / _` |/ _ \/ __/ _ \| '_ \| | | |
// | (_| | __/ (_| (_) | |_) | |_| |
// \__, |\___|\___\___/| .__/ \__, |
// |___/ |_| |___/
*/
extern "C" {
void
LAPACKNAME(slacpy)( character const UPLO[],
integer const * M,
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision B[],
integer const * LDB ) ;
void
LAPACKNAME(dlacpy)( character const UPLO[],
integer const * M,
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision B[],
integer const * LDB ) ;
void
ATLASNAME(sgecopy)( const int M, const int N,
const float *A, const int lda,
float *C, const int ldc ) ;
void
ATLASNAME(dgecopy)( const int M, const int N,
const double *A, const int lda,
double *C, const int ldc ) ;
}
inline
void
gecopy( integer const M,
integer const N,
single_precision const A[],
integer const LDA,
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(sgecopy)( M, N, A, LDA, B, LDB ) ; }
#else
{ LAPACKNAME(slacpy)( "A", &M, &N, A, &LDA, B, &LDB ) ; }
#endif
inline
void
gecopy( integer const M,
integer const N,
double_precision const A[],
integer const LDA,
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dgecopy)( M, N, A, LDA, B, LDB ) ; }
#else
{ LAPACKNAME(dlacpy)( "A", &M, &N, A, &LDA, B, &LDB ) ; }
#endif
/*
// __ _ ___ _______ _ __ ___
// / _` |/ _ \_ / _ \ '__/ _ \
// | (_| | __// / __/ | | (_) |
// \__, |\___/___\___|_| \___/
// |___/
*/
extern "C" {
void
LAPACKNAME(slaset)( character const UPLO[],
integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const * BETA,
single_precision A[],
integer const * LDA ) ;
void
LAPACKNAME(dlaset)( character const UPLO[],
integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const * BETA,
double_precision A[],
integer const * LDA ) ;
void
ATLASNAME(sgezero)( const int M, const int N, float *C, const int ldc ) ;
void
ATLASNAME(dgezero)( const int M, const int N, double *C, const int ldc ) ;
}
inline
void
gezero( integer const M,
integer const N,
single_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(sgezero)( M, N, A, LDA ) ; }
#else
{ single_precision zero = 0 ;
LAPACKNAME(slaset)( "A", &M, &N, &zero, &zero, A, &LDA ) ; }
#endif
inline
void
gezero( integer const M,
integer const N,
double_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(dgezero)( M, N, A, LDA ) ; }
#else
{ double_precision zero = 0 ;
LAPACKNAME(dlaset)( "A", &M, &N, &zero, &zero, A, &LDA ) ; }
#endif
/*
// _ _
// __ _ ___ __ _ __| | __| |
// / _` |/ _ \/ _` |/ _` |/ _` |
// | (_| | __/ (_| | (_| | (_| |
// \__, |\___|\__,_|\__,_|\__,_|
// |___/
*/
extern "C" {
void
ATLASNAME(sgeadd)( const int M, const int N,
const float alpha, const float *A, const int lda,
const float beta, float *C, const int ldc ) ;
void
ATLASNAME(dgeadd)( const int M, const int N,
const double alpha, const double *A, const int lda,
const double beta, double *C, const int ldc ) ;
}
/*
* B <- alpha*A + beta*B
*/
inline
void
geadd( integer const M,
integer const N,
single_precision const alpha,
single_precision const A[],
integer const LDA,
single_precision const beta,
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(sgeadd)( M, N, alpha, A, LDA, beta, B, LDB ) ; }
#else
{ for ( integer j = 0 ; j < N ; ++j ) {
single_precision const * Aj = A + j * LDA ;
single_precision * Bj = B + j * LDB ;
alglin::scal( M, beta, Bj, 1 ) ;
alglin::axpy( M, alpha, Aj, 1, Bj, 1 ) ;
}
}
#endif
inline
void
geadd( integer const M,
integer const N,
double_precision const alpha,
double_precision const A[],
integer const LDA,
double_precision const beta,
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dgeadd)( M, N, alpha, A, LDA, beta, B, LDB ) ; }
#else
{ for ( integer j = 0 ; j < N ; ++j ) {
double_precision const * Aj = A + j * LDA ;
double_precision * Bj = B + j * LDB ;
alglin::scal( M, beta, Bj, 1 ) ;
alglin::axpy( M, alpha, Aj, 1, Bj, 1 ) ;
}
}
#endif
/*
// _ __
// __ _ ___| |_ _ __ / _|
// / _` |/ _ \ __| '__| |_
// | (_| | __/ |_| | | _|
// \__, |\___|\__|_| |_|
// |___/
*/
extern "C" {
void
LAPACKNAME(sgetrf)( integer const * N,
integer const * M,
single_precision A[],
integer const * LDA,
integer IPIV[],
integer * INFO ) ;
void
LAPACKNAME(dgetrf)( integer const * N,
integer const * M,
double_precision A[],
integer const * LDA,
integer IPIV[],
integer * INFO ) ;
int
ATLASNAME(sgetrf)( const enum ATLAS_ORDER Order,
const int M, const int N,
float *A, const int lda,
int *ipiv ) ;
int
ATLASNAME(dgetrf)( const enum ATLAS_ORDER Order,
const int M, const int N,
double *A, const int lda,
int *ipiv ) ;
}
inline
integer
getrf( integer const N,
integer const M,
single_precision A[],
integer const LDA,
integer IPIV[] )
#ifdef USE_ATLAS
{ return ATLASNAME(sgetrf)( AtlasColMajor, N, M, A, LDA, IPIV ) ; }
#else
{ integer INFO ;
LAPACKNAME(sgetrf)( &N, &M, A, &LDA, IPIV, &INFO ) ;
return INFO ; }
#endif
inline
integer
getrf( integer const N,
integer const M,
double_precision A[],
integer const LDA,
integer IPIV[] )
#ifdef USE_ATLAS
{ return ATLASNAME(dgetrf)( AtlasColMajor, N, M, A, LDA, IPIV ) ; }
#else
{ integer INFO ;
LAPACKNAME(dgetrf)( &N, &M, A, &LDA, IPIV, &INFO ) ;
return INFO ; }
#endif
/*
// _
// __ _ ___| |_ _ __ ___
// / _` |/ _ \ __| '__/ __|
// | (_| | __/ |_| | \__ \
// \__, |\___|\__|_| |___/
// |___/
*/
extern "C" {
void
LAPACKNAME(sgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
single_precision const A[],
integer const * LDA,
integer const IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
LAPACKNAME(dgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
double_precision const A[],
integer const * LDA,
integer const IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
void
ATLASNAME(sgetrs)( const enum ATLAS_ORDER Order,
const enum ATLAS_TRANS Trans,
const int N,
const int NRHS,
const float *A, const int lda,
const int *ipiv,
float *B, const int ldb );
void
ATLASNAME(dgetrs)( const enum ATLAS_ORDER Order,
const enum ATLAS_TRANS Trans,
const int N,
const int NRHS,
const double *A, const int lda,
const int *ipiv,
double *B, const int ldb );
}
inline
integer
getrs( character const TRANS[],
integer const N,
integer const NRHS,
single_precision const A[],
integer const LDA,
integer const IPIV[],
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(sgetrs)( AtlasColMajor, trans_atlas(TRANS[0]), N, NRHS, A, LDA, IPIV, B, LDB ) ;
return 0 ; }
#else
{ integer INFO ;
LAPACKNAME(sgetrs)( TRANS, &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
inline
integer
getrs( character const TRANS[],
integer const N,
integer const NRHS,
double_precision const A[],
integer const LDA,
integer const IPIV[],
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dgetrs)( AtlasColMajor, trans_atlas(TRANS[0]), N, NRHS, A, LDA, IPIV, B, LDB ) ;
return 0 ; }
#else
{ integer INFO ;
LAPACKNAME(dgetrs)( TRANS, &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
/*
// __ _ ___ _____ __
// / _` |/ _ \/ __\ \ / /
// | (_| | __/\__ \\ V /
// \__, |\___||___/ \_/
// |___/
*/
extern "C" {
void
LAPACKNAME(sgesv)( integer const * N,
integer const * NRHS,
single_precision A[],
integer const * LDA,
integer IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
LAPACKNAME(dgesv)( integer const * N,
integer const * NRHS,
double_precision A[],
integer const * LDA,
integer IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
}
inline
integer
gesv( integer const N,
integer const NRHS,
single_precision A[],
integer const LDA,
integer IPIV[],
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ integer INFO = ATLASNAME(sgetrf)(AtlasColMajor, N, N, A, LDA, IPIV);
if ( INFO == 0 ) ATLASNAME(sgetrs)(AtlasColMajor, AtlasNoTrans,
N, NRHS, A, LDA, IPIV, B, LDB) ;
return INFO ; }
#else
{ integer INFO ;
LAPACKNAME(sgesv)( &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
inline
integer
gesv( integer const N,
integer const NRHS,
double_precision A[],
integer const LDA,
integer IPIV[],
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ integer INFO = ATLASNAME(dgetrf)(AtlasColMajor, N, N, A, LDA, IPIV);
if ( INFO == 0 ) ATLASNAME(dgetrs)(AtlasColMajor, AtlasNoTrans,
N, NRHS, A, LDA, IPIV, B, LDB) ;
return INFO ; }
#else
{ integer INFO ;
LAPACKNAME(dgesv)( &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
/*
// _ _ __
// __ _| |_| |_ _ __ / _|
// / _` | __| __| '__| |_
// | (_| | |_| |_| | | _|
// \__, |\__|\__|_| |_|
// |___/
*/
extern "C" {
void
LAPACKNAME(sgttrf)( integer const * N,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision DU2[],
integer IPIV[],
integer * INFO ) ;
void
LAPACKNAME(dgttrf)( integer const * N,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision DU2[],
integer IPIV[],
integer * INFO ) ;
}
inline
integer
gttrf( integer const N,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision DU2[],
integer IPIV[] )
{ integer INFO ;
LAPACKNAME(sgttrf)( &N, DL, D, DU, DU2, IPIV, &INFO) ;
return INFO ; }
inline
integer
gttrf( integer const N,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision DU2[],
integer IPIV[] )
{ integer INFO ;
LAPACKNAME(dgttrf)( &N, DL, D, DU, DU2, IPIV, &INFO) ;
return INFO ; }
/*
// _ _
// __ _| |_| |_ _ __ ___
// / _` | __| __| '__/ __|
// | (_| | |_| |_| | \__ \
// \__, |\__|\__|_| |___/
// |___/
*/
extern "C" {
void
LAPACKNAME(sgttrs)( character TRANS[],
integer const * N,
integer const * NRHS,
single_precision const DL[],
single_precision const D[],
single_precision const DU[],
single_precision const DU2[],
integer const IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
LAPACKNAME(dgttrs)( character TRANS[],
integer const * N,
integer const * NRHS,
double_precision const DL[],
double_precision const D[],
double_precision const DU[],
double_precision const DU2[],
integer const IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
}
inline
integer
gttrs( character TRANS[],
integer const N,
integer const NRHS,
single_precision const DL[],
single_precision const D[],
single_precision const DU[],
single_precision const DU2[],
integer const IPIV[],
single_precision B[],
integer const LDB )
{ integer INFO ;
LAPACKNAME(sgttrs)( TRANS, &N, &NRHS, DL, D, DU, DU2, IPIV, B, &LDB, &INFO) ;
return INFO ; }
inline
integer
gttrs( character TRANS[],
integer const N,
integer const NRHS,
double_precision const DL[],
double_precision const D[],
double_precision const DU[],
double_precision const DU2[],
integer const IPIV[],
double_precision B[],
integer const LDB )
{ integer INFO ;
LAPACKNAME(dgttrs)( TRANS, &N, &NRHS, DL, D, DU, DU2, IPIV, B, &LDB, &INFO) ;
return INFO ; }
/*
// _
// __ _| |_ _____ __
// / _` | __/ __\ \ / /
// | (_| | |_\__ \\ V /
// \__, |\__|___/ \_/
// |___/
*/
extern "C" {
void
LAPACKNAME(sgtsv)( integer const * N,
integer const * NRHS,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
LAPACKNAME(dgtsv)( integer const * N,
integer const * NRHS,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
}
inline
integer
gtsv( integer const N,
integer const NRHS,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision B[],
integer const LDB )
{ integer INFO ;
LAPACKNAME(sgtsv)( &N, &NRHS, DL, D, DU, B, &LDB, &INFO ) ;
return INFO ; }
inline
integer
gtsv( integer const N,
integer const NRHS,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision B[],
integer const LDB )
{ integer INFO ;
LAPACKNAME(dgtsv)( &N, &NRHS, DL, D, DU, B, &LDB, &INFO ) ;
return INFO ; }
/*
// _
// _ __ ___ _ __ _ __ ___ / |
// | '_ \ / _ \| '__| '_ ` _ \| |
// | | | | (_) | | | | | | | | |
// |_| |_|\___/|_| |_| |_| |_|_|
*/
extern "C" {
// 'M' or 'm' maxabs
// '1', 'O' or 'o' norm1
// 'I' or 'i' normI
// 'F', 'f', 'E' or 'e' normF
double_precision
LAPACKNAME(dlange)( char const NORM[],
integer const * M,
integer const * N,
double_precision const * A,
integer const * LDA,
double_precision * WORK ) ;
single_precision
LAPACKNAME(slange)( char const NORM[],
integer const * M,
integer const * N,
single_precision const * A,
integer const * LDA,
single_precision * WORK ) ;
}
inline
single_precision
normI( integer const N,
integer const M,
single_precision const A[],
integer const LDA,
single_precision WORK[] )
{ return LAPACKNAME(slange)( "I", &N, &M, A, &LDA, WORK ) ; }
inline
double_precision
normI( integer const N,
integer const M,
double_precision const A[],
integer const LDA,
double_precision WORK[] )
{ return LAPACKNAME(dlange)( "I", &N, &M, A, &LDA, WORK ) ; }
///////////////////
inline
single_precision
norm1( integer const N,
integer const M,
single_precision const A[],
integer const LDA )
{ return LAPACKNAME(slange)( "1", &N, &M, A, &LDA, NULL ) ; }
inline
double_precision
norm1( integer const N,
integer const M,
double_precision const A[],
integer const LDA )
{ return LAPACKNAME(dlange)( "1", &N, &M, A, &LDA, NULL ) ; }
///////////////////
inline
single_precision
normF( integer const N,
integer const M,
single_precision const A[],
integer const LDA )
{ return LAPACKNAME(slange)( "F", &N, &M, A, &LDA, NULL ) ; }
inline
double_precision
normF( integer const N,
integer const M,
double_precision const A[],
integer const LDA )
{ return LAPACKNAME(dlange)( "F", &N, &M, A, &LDA, NULL ) ; }
///////////////////
inline
single_precision
maxabs( integer const N,
integer const M,
single_precision const A[],
integer const LDA )
{ return LAPACKNAME(slange)( "M", &N, &M, A, &LDA, NULL ) ; }
inline
double_precision
maxabs( integer const N,
integer const M,
double_precision const A[],
integer const LDA )
{ return LAPACKNAME(dlange)( "M", &N, &M, A, &LDA, NULL ) ; }
/*
// _
// | |_ _ __ _ __ _____ __
// | __| '__| '_ ` _ \ \ / /
// | |_| | | | | | | \ V /
// \__|_| |_| |_| |_|\_/
*/
extern "C" {
void
BLASNAME(strmv)( char const UPLO[],
char const TRANS[],
char const DIAG[],
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision X[],
integer const * INCX ) ;
void
BLASNAME(dtrmv)( char const UPLO[],
char const TRANS[],
char const DIAG[],
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision X[],
integer const * INCX ) ;
void
ATLASNAME(strmv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const float *A, const int lda,
float *X, const int incX ) ;
void
ATLASNAME(dtrmv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const double *A, const int lda,
double *X, const int incX ) ;
}
inline
void
trmv( char const UPLO[],
char const TRANS[],
char const DIAG[],
integer const N,
single_precision const A[],
integer const LDA,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(strmv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ BLASNAME(strmv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
inline
void
trmv( char const UPLO[],
char const TRANS[],
char const DIAG[],
integer const N,
double_precision const A[],
integer const LDA,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dtrmv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ BLASNAME(dtrmv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
/*
// _
// | |_ _ __ _____ __
// | __| '__/ __\ \ / /
// | |_| | \__ \\ V /
// \__|_| |___/ \_/
*/
extern "C" {
void
BLASNAME(strsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision X[],
integer const * INCX ) ;
void
BLASNAME(dtrsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision X[],
integer const * INCX ) ;
void
ATLASNAME(strsv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const float *A, const int lda,
float *X, const int incX ) ;
void
ATLASNAME(dtrsv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const double *A, const int lda,
double *X, const int incX );
}
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
single_precision const A[],
integer const LDA,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(strsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ BLASNAME(strsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
double_precision const A[],
integer const LDA,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dtrsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ BLASNAME(dtrsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
/*
// _
// | |_ _ __ _ __ ___ _ __ ___
// | __| '__| '_ ` _ \| '_ ` _ \
// | |_| | | | | | | | | | | | |
// \__|_| |_| |_| |_|_| |_| |_|
*/
extern "C" {
void
BLASNAME(strmm) ( char const SIDE[], // "L" or "R"
char const UPLO[], // "U" or "L"
char const TRANSA[], // "N", "T", "C"
char const DIAG[], // "N", "U"
integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const A[],
integer const * LDA,
single_precision B[],
integer const * LDB ) ;
void
BLASNAME(dtrmm) ( char const SIDE[], // "L" or "R"
char const UPLO[], // "U" or "L"
char const TRANSA[], // "N", "T", "C"
char const DIAG[], // "N", "U"
integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const A[],
integer const * LDA,
double_precision B[],
integer const * LDB ) ;
void
ATLASNAME(strmm)( const enum ATLAS_SIDE Side,
const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int M,
const int N,
const float alpha,
const float *A, const int lda,
float *B, const int ldb ) ;
void
ATLASNAME(dtrmm)( const enum ATLAS_SIDE Side,
const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int M,
const int N,
const double alpha,
const double *A, const int lda,
double *B, const int ldb ) ;
}
inline
void
trmm( character const SIDE[],
character const UPLO[],
character const TRANSA[],
character const DIAG[],
integer const M,
integer const N,
double_precision const alpha,
double_precision const A[],
integer const LDA,
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dtrmm)( side_atlas(SIDE[0]),
uplo_atlas(UPLO[0]),
trans_atlas(TRANSA[0]),
diag_atlas(DIAG[0]),
M, N, alpha, A, LDA, B, LDB ) ; }
#else
{ BLASNAME(dtrmm) ( SIDE, UPLO, TRANSA, DIAG, &M, &N, &alpha, A, &LDA, B, &LDB ) ; }
#endif
/*
// _
// | |_ _ __ ___ _ __ ___
// | __| '__/ __| '_ ` _ \
// | |_| | \__ \ | | | | |
// \__|_| |___/_| |_| |_|
*/
extern "C" {
void
BLASNAME(strsm)( character const SIDE[],
character const UPLO[],
character const TRANSA[],
character const DIAG[],
integer const * M,
integer const * N,
single_precision const * alpha,
single_precision const A[],
integer const * LDA,
single_precision B[],
integer const * LDB ) ;
void
BLASNAME(dtrsm)( character const SIDE[],
character const UPLO[],
character const TRANSA[],
character const DIAG[],
integer const * M,
integer const * N,
double_precision const * alpha,
double_precision const A[],
integer const * LDA,
double_precision B[],
integer const * LDB ) ;
void
ATLASNAME(strsm)( const enum ATLAS_SIDE Side,
const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int M,
const int N,
const float alpha,
const float *A, const int lda,
float *B, const int ldb ) ;
void
ATLASNAME(dtrsm)( const enum ATLAS_SIDE Side,
const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int M,
const int N,
const double alpha,
const double *A, const int lda,
double *B, const int ldb ) ;
}
inline
void
trsm( character const SIDE[],
character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const M,
integer const N,
single_precision const alpha,
single_precision const A[],
integer const LDA,
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(strsm)( side_atlas(SIDE[0]),
uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
M, N, alpha, A, LDA, B, LDB ) ; }
#else
{ BLASNAME(strsm)( SIDE, UPLO, TRANS, DIAG, &M, &N, &alpha, A, &LDA, B, &LDB ) ; }
#endif
inline
void
trsm( character const SIDE[],
character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const M,
integer const N,
double_precision const alpha,
double_precision const A[],
integer const LDA,
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dtrsm)( side_atlas(SIDE[0]),
uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
M, N, alpha, A, LDA, B, LDB ) ; }
#else
{ BLASNAME(dtrsm)( SIDE, UPLO, TRANS, DIAG, &M, &N, &alpha, A, &LDA, B, &LDB ) ; }
#endif
} // end namespace alglin
#endif
///
/// eof: alglin.hh
///
A timing class
File: timing.hh:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#ifndef TIMING_HH
#define TIMING_HH
class Timing {
long sec, usec ;
Timing( Timing const & ) ;
Timing const & operator = ( Timing const & ) const ;
public:
Timing() ;
~Timing() {} ;
void start() ;
double seconds() ;
double milliseconds() ;
} ;
#endif
// EOF timing.hh
File: timing.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#include "timing.hh"
using namespace std ;
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#else
#include <sys/time.h>
#endif
/*
// _ _____ _
// __ _ ___| ||_ _(_)_ __ ___ ___
// / _` |/ _ \ __|| | | | '_ ` _ \ / _ \
// | (_| | __/ |_ | | | | | | | | | __/
// \__, |\___|\__||_| |_|_| |_| |_|\___|
// |___/
*/
bool getTime( long & sec, long & usec ) ;
#ifdef _WIN32
bool
getTime( long & sec, long & usec ) {
FILETIME ft ;
GetSystemTimeAsFileTime( &ft ) ;
// FILETIME To UNIX Time
unsigned __int64 u_sec = ft . dwHighDateTime ;
u_sec <<= 32 ;
u_sec |= ft . dwLowDateTime ;
u_sec -= 116444736000000000ULL ;
u_sec /= 10ULL ;
sec = long( u_sec / 1000000L ) ;
usec = long( u_sec % 1000000L ) ;
return true ;
}
#else
bool
getTime( long & sec, long & usec ) {
struct timeval now ;
bool ok = gettimeofday(&now, NULL) == 0 ;
if ( ok ) {
sec = now . tv_sec;
usec = now . tv_usec;
} else {
sec = usec = 0 ;
}
return ok ;
}
#endif
Timing::Timing() {
start() ;
}
void
Timing::start() {
getTime( sec, usec ) ;
}
double
Timing::seconds() {
long new_sec, new_usec ;
getTime( new_sec, new_usec ) ;
return (new_sec-sec) + (new_usec-usec)*1E-6 ;
}
double
Timing::milliseconds() {
return seconds() * 1E3 ;
}
// EOF timing.cc
Matrix-matrix product
File: mm.hh:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
// To avoid double inclusion (old trick)
#ifndef MM_HH
#define MM_HH
#ifndef REAL_TYPE
#define REAL_TYPE double
#endif
#ifndef INTEGER_TYPE
#define INTEGER_TYPE int
#endif
typedef REAL_TYPE valueType ;
typedef INTEGER_TYPE indexType ;
//#define ROW_MAJOR
#ifdef ROW_MAJOR
#define ADDR(M,I,J) M[(I)*ld##M+(J)]
#define NEXT_COLUMN(M) ++p##M
#define NEXT_ROW(M) p##M += ld##M
#else
#define ADDR(M,I,J) M[(I)+(J)*ld##M]
#define NEXT_COLUMN(M) p##M += ld##M
#define NEXT_ROW(M) ++p##M
#endif
void
MM_normal( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_temp( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_unroll4( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_unroll8( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_unroll16( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_pointer( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_lam( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_tiling( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType step ) ;
void
MM_maeno( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType lparm ) ;
void
MM_warner( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType nb ) ;
void
MM_blas( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
void
MM_blocking( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType step ) ;
void
MM_strassen( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) ;
#endif
// EOF mm.hh
File: mm.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#include "mm.hh"
#include "alglin.hh"
#include "strassen.hh"
#include <algorithm>
using namespace std ;
/*
* matrix multiply tests -- C language, version 1.0, May 1993
*
* Contact Mark Smotherman (mark@cs.clemson.edu)
*/
#define A(I,J) ADDR(a,I,J)
#define B(I,J) ADDR(b,I,J)
#define C(I,J) ADDR(c,I,J)
///////////////////////////////////////////////////////
void
MM_normal( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < m ; ++j ) {
C(i,j) = 0 ;
for ( indexType k = 0 ; k < p ; ++k ) {
C(i,j) += A(i,k)*B(k,j) ;
}
}
}
}
///////////////////////////////////////////////////////
void
MM_temp( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < m ; ++j ) {
valueType temp = 0 ;
for ( indexType k = 0 ; k < p ; ++k ) {
temp += A(i,k)*B(k,j) ;
}
C(i,j) = temp ;
}
}
}
///////////////////////////////////////////////////////
void
MM_unroll4( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < m ; ++j ) {
indexType k = 0 ;
valueType temp = 0 ;
for ( ; k < (p-3) ; k += 4 ) {
temp += A(i,k+0) * B(k+0,j) ;
temp += A(i,k+1) * B(k+1,j) ;
temp += A(i,k+2) * B(k+2,j) ;
temp += A(i,k+3) * B(k+3,j) ;
}
for ( ; k < p ; ++k ) temp += A(i,k)*B(k,j) ;
C(i,j) = temp ;
}
}
}
///////////////////////////////////////////////////////
void
MM_unroll8( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < m ; ++j ) {
indexType k = 0 ;
valueType temp = 0 ;
for ( ; k < (p-7) ; k += 8 ) {
temp += A(i,k+0) * B(k+0,j) ;
temp += A(i,k+1) * B(k+1,j) ;
temp += A(i,k+2) * B(k+2,j) ;
temp += A(i,k+3) * B(k+3,j) ;
temp += A(i,k+4) * B(k+4,j) ;
temp += A(i,k+5) * B(k+5,j) ;
temp += A(i,k+6) * B(k+6,j) ;
temp += A(i,k+7) * B(k+7,j) ;
}
for ( ; k < p ; ++k ) temp += A(i,k)*B(k,j) ;
C(i,j) = temp ;
}
}
}
///////////////////////////////////////////////////////
void
MM_unroll16( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < m ; ++j ) {
indexType k = 0 ;
valueType temp = 0 ;
for ( ; k < (p-15) ; k += 16 ) {
temp += A(i,k+ 0) * B(k+ 0,j) ;
temp += A(i,k+ 1) * B(k+ 1,j) ;
temp += A(i,k+ 2) * B(k+ 2,j) ;
temp += A(i,k+ 3) * B(k+ 3,j) ;
temp += A(i,k+ 4) * B(k+ 4,j) ;
temp += A(i,k+ 5) * B(k+ 5,j) ;
temp += A(i,k+ 6) * B(k+ 6,j) ;
temp += A(i,k+ 7) * B(k+ 7,j) ;
temp += A(i,k+ 8) * B(k+ 8,j) ;
temp += A(i,k+ 9) * B(k+ 9,j) ;
temp += A(i,k+10) * B(k+10,j) ;
temp += A(i,k+11) * B(k+11,j) ;
temp += A(i,k+12) * B(k+12,j) ;
temp += A(i,k+13) * B(k+13,j) ;
temp += A(i,k+14) * B(k+14,j) ;
temp += A(i,k+15) * B(k+15,j) ;
}
for ( ; k < p ; ++k ) temp += A(i,k)*B(k,j) ;
C(i,j) = temp ;
}
}
}
///////////////////////////////////////////////////////
void
MM_pointer( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i ) {
valueType * pc = &C(i,0) ;
for ( indexType j = 0 ; j < m ; ++j ) {
valueType temp = 0 ;
valueType const * pa = &A(i,0) ;
valueType const * pb = &B(0,j) ;
for ( indexType k = 0 ; k < p ; ++k ) {
temp += (*pa) * (*pb) ;
NEXT_COLUMN(a) ;
NEXT_ROW(b) ;
}
*pc = temp ;
NEXT_COLUMN(c) ;
}
}
}
/* from Monica Lam ASPLOS-IV paper */
void
MM_lam( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType k = 0 ; k < p ; ++k ) {
valueType a_entry = A(i,k) ;
for ( indexType j = 0 ; j < m ; ++j )
C(i,j) += a_entry*B(k,j) ;
}
}
/* from Monica Lam ASPLOS-IV paper */
void
MM_tiling( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType step ) {
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
for( indexType kk = 0 ; kk < p ; kk += step )
for( indexType jj = 0 ; jj < m ; jj += step )
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType k = kk ; k < min(kk+step,p) ; ++k ) {
valueType a_entry = A(i,k) ;
for ( indexType j = jj ; j < min(jj+step,m) ; ++j )
C(i,j) += a_entry*B(k,j) ;
}
}
/* Matrix Multiply tuned for SS-10/30;
* Maeno Toshinori
* Tokyo Institute of Technology
*
* Using gcc-2.4.1 (-O2), this program ends in 12 seconds on SS-10/30.
*
* in original algorithm - sub-area for cache tiling
* #define L 20
* #define L2 20
* three 20x20 matrices reside in cache; two may be enough
*/
void
MM_maeno( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType lparm ) {
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
for ( indexType i2 = 0 ; i2 < n ; i2 += lparm )
for ( indexType kk = 0 ; kk < p ; kk += lparm ) {
indexType it = i2 + lparm ;
indexType kt = kk + lparm ;
for ( indexType j = 0 ; j < m ; j += 4 )
for( indexType i = i2 ; i < min(n,it) ; i += 2 ) {
valueType t0=0,
t1=0,
t2=0,
t3=0,
t4=0,
t5=0,
t6=0,
t7=0 ;
for( indexType k = kk ; k < min(p,kt) ; ++k ) {
valueType s = A(i,k) ;
t0 += s*B(k,j+0);
t1 += s*B(k,j+1);
t2 += s*B(k,j+2);
t3 += s*B(k,j+3);
s = A(i+1,k) ;
t4 += s*B(k,j+0);
t5 += s*B(k,j+1);
t6 += s*B(k,j+2);
t7 += s*B(k,j+3);
}
C(i+0,j+0) += t0 ;
C(i+0,j+1) += t1 ;
C(i+0,j+2) += t2 ;
C(i+0,j+3) += t3 ;
C(i+1,j+0) += t4 ;
C(i+1,j+1) += t5 ;
C(i+1,j+2) += t6 ;
C(i+1,j+3) += t7 ;
}
}
}
/*
* Matrix Multiply by Dan Warner, Dept. of Mathematics, Clemson University
*
* mmbu2.f multiplies matrices a and b
* a and b are n by n matrices
* nb is the blocking parameter.
* the tuning guide indicates nb = 50 is reasonable for the
* ibm model 530 hence 25 should be reasonable for the 320
* since the 320 has 32k rather than 64k of cache.
* Inner loops unrolled to depth of 2
* The loop functions without clean up code at the end only
* if the unrolling occurs to a depth k which divides into n
* in this case n must be divisible by 2.
* The blocking parameter nb must divide into n if the
* multiply is to succeed without clean up code at the end.
*
* converted to c by Mark Smotherman
* note that nb must also be divisible by 2 => cannot use 25, so use 20
*/
void
MM_warner( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType nb ) {
for( indexType ii = 0 ; ii < n ; ii += nb ) {
for( indexType jj = 0 ; jj < m ; jj += nb ) {
for( indexType i = ii ; i < min(n,ii + nb) ; ++i )
for( indexType j = jj ; j < min(m,jj + nb) ; ++j )
C(i,j) = 0.0;
for( indexType kk = 0 ; kk < p ; kk += nb ) {
for( indexType i = ii ; i < min(n-1,ii + nb) ; i += 2 ) {
for( indexType j = jj ; j < min(m-1,jj + nb) ; j += 2 ) {
valueType s00 = C(i+0,j+0) ;
valueType s01 = C(i+0,j+1) ;
valueType s10 = C(i+1,j+0) ;
valueType s11 = C(i+1,j+1) ;
for( indexType k = kk ; k < kk + nb ; ++k ){
s00 += A(i+0,k)*B(k,j+0) ;
s01 += A(i+0,k)*B(k,j+1) ;
s10 += A(i+1,k)*B(k,j+0) ;
s11 += A(i+1,k)*B(k,j+1) ;
}
C(i+0,j+0) = s00 ;
C(i+0,j+1) = s01 ;
C(i+1,j+0) = s10 ;
C(i+1,j+1) = s11 ;
}
}
}
}
}
}
///////////////////////////////////////////////////////
void
MM_blas( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
#ifdef ROW_MAJOR
alglin::gemm( "N", "N", n, m, p,
1.0, b, ldb,
a, lda,
0.0, c, ldc ) ;
#else
alglin::gemm( "N", "N", n, m, p,
1.0, a, lda,
b, ldb,
0.0, c, ldc ) ;
#endif
}
///////////////////////////////////////////////////////
void
MM_blocking( valueType const a[], indexType lda, // n x p
valueType const b[], indexType ldb, // p x m
valueType c[], indexType ldc,
indexType n,
indexType p,
indexType m,
indexType step ) {
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
C(i,j) = 0 ;
for( indexType jj = 0 ; jj < m ; jj += step )
for( indexType ii = 0 ; ii < n ; ii += step )
for( indexType kk = 0 ; kk < p ; kk += step )
for( indexType j = jj ; j < min(m,jj+step) ; ++j )
for( indexType i = ii ; i < min(n,ii+step) ; ++i ) {
valueType temp = C(i,j) ;
for( indexType k = kk ; k < min(p,kk+step) ; ++k )
temp += A(i,k)*B(k,j) ;
C(i,j) = temp ;
}
}
///////////////////////////////////////////////////////
#include <iostream>
static valueType * aux = NULL ;
static indexType naux = 5000*5000*10 ;
void
MM_strassen( valueType const A[], indexType lda, // n x p
valueType const B[], indexType ldb, // p x m
valueType C[], indexType ldc,
indexType n,
indexType p,
indexType m ) {
if ( aux == NULL ) aux = new valueType [ naux ] ;
#ifdef ROW_MAJOR
strassen::matrixMultiply( n, /* Rows of C and A */
m, /* Cols of B and C */
p, /* Cols of A and Rows of B */
B, /* Pointer to coefficients of A */
ldb, /* Leading dimension of A, Fortran style */
A, /* Pointer to coefficients of B */
lda, /* Leading dimension of B, Fortran style */
C, /* Pointer to coefficients of C */
ldc, /* Leading dimension of C, Fortran style */
aux, /* Pointer to auxillary storage or NULL */
naux ) ; /* Number of elements in aux or <= 0 */
#else
strassen::matrixMultiply( n, /* Rows of C and A */
m, /* Cols of B and C */
p, /* Cols of A and Rows of B */
A, /* Pointer to coefficients of A */
lda, /* Leading dimension of A, Fortran style */
B, /* Pointer to coefficients of B */
ldb, /* Leading dimension of B, Fortran style */
C, /* Pointer to coefficients of C */
ldc, /* Leading dimension of C, Fortran style */
aux, /* Pointer to auxillary storage or NULL */
naux ) ; /* Number of elements in aux or <= 0 */
#endif
}
// EOF mm.hh
Driver for testing
File: main.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#include "mm.hh"
#include "timing.hh"
//#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <limits>
using namespace std ;
#define A(I,J) ADDR(Amat,I,J)
#define B(I,J) ADDR(Bmat,I,J)
static
void
M_check( char const msg[],
valueType * Amat, indexType ldAmat,
valueType * Bmat, indexType ldBmat,
indexType n,
indexType m ) {
valueType res = 0 ;
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
res = std::max( res, abs( A(i,j)-B(i,j) ) ) ;
if ( res > numeric_limits<valueType>::epsilon()*1000 ) {
cout << "\n\n\nerror in matrix multiplication: " << msg << " = " << res << "\n\n\n" ;
exit(0) ;
}
}
int
main() {
Timing tm ;
valueType *A, *B, *C, *Cref, elapsed ;
A = new valueType[ 5000 * 5000 ] ;
B = new valueType[ 5000 * 5000 ] ;
C = new valueType[ 5000 * 5000 ] ;
Cref = new valueType[ 5000 * 5000 ] ;
cout << setw(6) << "Size" ;
cout << setw(12) << "normal" ; // 1
cout << setw(12) << "temp" ; // 2
#if 0
cout << setw(12) << "unroll4" ; // 3
cout << setw(12) << "unroll8" ; // 4
cout << setw(12) << "unroll16" ; // 5
#endif
cout << setw(12) << "pointer" ; // 6
cout << setw(12) << "lam" ; // 7
cout << setw(12) << "tiling4" ; // 8
cout << setw(12) << "tiling8" ; // 9
cout << setw(12) << "tiling16" ; // 10
#if 0
cout << setw(12) << "Maeno4" ; // 11
cout << setw(12) << "Maeno8" ; // 12
cout << setw(12) << "Maeno16" ; // 13
#endif
cout << setw(12) << "Warner4" ; // 14
cout << setw(12) << "Warner8" ; // 15
cout << setw(12) << "Warner16" ; // 16
cout << setw(12) << "Blas" ; // 17
#if 0
cout << setw(12) << "blocking16" ; // 18
#endif
cout << setw(12) << "strassen" ; // 19
cout << '\n' ;
for ( indexType N = 100 ; N <= 600 ; N += 100 ) {
cout << setw(6) << N ;
for ( indexType i = 0 ; i < N ; ++i )
for ( indexType j = 0 ; j < N ; ++j )
A[i*N+j] = (arc4random()%10000) / 22123.0 ;
for ( indexType i = 0 ; i < N ; ++i )
for ( indexType j = 0 ; j < N ; ++j )
B[i*N+j] = (arc4random()%11111) / 32455.0 ;
//cout << "Generated matrix\n" ;
tm . start() ;
MM_normal( A, N, B, N, Cref, N, N, N, N ) ; // 1
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
tm . start() ;
MM_temp( A, N, B, N, C, N, N, N, N ) ; // 2
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "temp", C, N, Cref, N, N, N ) ;
#if 0
tm . start() ;
MM_unroll4( A, N, B, N, C, N, N, N, N ) ; // 3
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "unroll4", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_unroll8( A, N, B, N, C, N, N, N, N ) ; // 4
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "unroll8", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_unroll16( A, N, B, N, C, N, N, N, N ) ; // 5
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "unroll16", C, N, Cref, N, N, N ) ;
#endif
tm . start() ;
MM_pointer( A, N, B, N, C, N, N, N, N ) ; // 6
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "pointer", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_lam( A, N, B, N, C, N, N, N, N ) ; // 7
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "lam", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_tiling( A, N, B, N, C, N, N, N, N, 4 ) ; // 8
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "tiling4", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_tiling( A, N, B, N, C, N, N, N, N, 8 ) ;
elapsed = tm . milliseconds() ; // 9
cout << setw(10) << elapsed << "ms" ;
M_check( "tiling8", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_tiling( A, N, B, N, C, N, N, N, N, 16 ) ; // 10
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "tiling16", C, N, Cref, N, N, N ) ;
#if 0
tm . start() ;
MM_maeno( A, N, B, N, C, N, N, N, N, 4 ) ; // 11
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "maeno4", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_maeno( A, N, B, N, C, N, N, N, N, 8 ) ; // 12
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "maeno8", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_maeno( A, N, B, N, C, N, N, N, N, 16 ) ; // 13
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "maeno16", C, N, Cref, N, N, N ) ;
#endif
tm . start() ;
MM_warner( A, N, B, N, C, N, N, N, N, 4 ) ; // 14
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "warner4", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_warner( A, N, B, N, C, N, N, N, N, 8 ) ; // 15
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "warner8", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_warner( A, N, B, N, C, N, N, N, N, 16 ) ; // 16
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "warner16", C, N, Cref, N, N, N ) ;
tm . start() ;
MM_blas( A, N, B, N, C, N, N, N, N ) ; // 17
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "blas", C, N, Cref, N, N, N ) ;
#if 0
tm . start() ;
MM_blocking( A, N, B, N, C, N, N, N, N, 16 ) ; // 18
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "blocking16", C, N, Cref, N, N, N ) ;
#endif
tm . start() ;
MM_strassen( A, N, B, N, C, N, N, N, N ) ; // 19
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "strassen", C, N, Cref, N, N, N ) ;
cout << '\n' ;
}
delete [] A ;
delete [] B ;
delete [] C ;
delete [] Cref ;
return 0 ;
}
// EOF main.cc
File: main2.cc:
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
| version: 0.1 04-01-2010 |
| |
\*--------------------------------------------------------------------------*/
#include "mm.hh"
#include "timing.hh"
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cmath>
using namespace std ;
#define A(I,J) ADDR(Amat,I,J)
#define B(I,J) ADDR(Bmat,I,J)
void
M_check( char const msg[],
valueType * Amat, indexType ldAmat,
valueType * Bmat, indexType ldBmat,
indexType n,
indexType m ) {
valueType res = 0 ;
for ( indexType i = 0 ; i < n ; ++i )
for ( indexType j = 0 ; j < m ; ++j )
res = std::max( res, abs( A(i,j)-B(i,j) ) ) ;
if ( res > 1E-6 ) {
cout << "\n\n\nerror in matrix multiplication: " << msg << " = " << res << "\n\n\n" ;
exit(0) ;
}
}
int
main() {
Timing tm ;
valueType *A, *B, *C, *Cref, elapsed ;
A = new valueType[ 6000 * 6000 ] ;
B = new valueType[ 6000 * 6000 ] ;
C = new valueType[ 6000 * 6000 ] ;
Cref = new valueType[ 6000 * 6000 ] ;
for ( indexType i = 0 ; i < 6000 * 6000 ; ++i ) A[i] = arc4random() * 1.02323E-8 ;
for ( indexType i = 0 ; i < 6000 * 6000 ; ++i ) B[i] = arc4random() * 2.323E-8 ;
cout << setw(6) << "Size" ;
cout << setw(12) << "Blas" ;
cout << setw(12) << "strassen" ;
cout << '\n' ;
for ( indexType N = 6000 ; N >= 1000 ; N *= 0.5 ) {
cout << setw(6) << N ;
indexType m = N-1 ;
indexType p = N-1 ;
indexType n = N-3 ;
tm . start() ;
MM_blas( A, N, B, N, Cref, N, m, p, n ) ;
//MM_strassen( A, N, B, N, Cref, N, m, p, n ) ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
tm . start() ;
MM_strassen( A, N, B, N, C, N, m, p, n ) ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
M_check( "strassen", C, N, Cref, N, m, n ) ;
cout << '\n' ;
}
delete [] A ;
delete [] B ;
delete [] C ;
delete [] Cref ;
return 0 ;
}
// EOF main.cc
Makefile for the compilation of the tests
File: Makefile:
SRCS = mm.cc strassen.cc timing.cc
OBJS = $(patsubst %.cc, %.o, $(notdir $(SRCS)))
# costruzione lista nomi file dipendenze
DEPS = $(patsubst %.o, %.d, $(OBJS) )
INC =
LIBS = -lblas -llapack
OPTC = -O3 -g0 -pthread -fexceptions -msse2
CXX = g++
# compilation
all: $(OBJS)
$(CXX) $(DEFINE) $(OPTC) $(INC) main.cc -o test1 $(OBJS) $(LIBS)
$(CXX) $(DEFINE) $(OPTC) $(INC) main2.cc -o test2 $(OBJS) $(LIBS)
# dependencies
depend: $(DEPS)
@echo "dependencies done"
%.d: %.cc
@echo "Build dependencies for: $<"
@$(SHELL) -ec '$(CXX) -MM $(DEFINE) $(INC) $< | sed "1,1 s/^/objs\//" > $@'
# compilation rules for C++
%.o: %.cc
@echo "compiling: $<"
@$(CXX) $(DEFINE) $(OPTC) $(INC) -c $< -o $@
clean:
rm -f *.o *.d test1 test2
-include $(DEPS)
Lesson of 18 February 2010
Lesson in a zip file
Lesson of 19 February 2010
Lesson in a zip file
The header of QR decomposition
File: qr.hh:
#ifndef QR_HH
#define QR_HH
namespace QR {
typedef double valueType ; // the type for real number
typedef unsigned indexType ; // the type for integer (unsigned)
indexType
factorize( indexType const n, /* Number of rows of matrix A */
indexType const m, /* Number of columns of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType ipiv[], /* Permutation vector */
valueType work[] ) ;
void
solve( indexType const n, /* Number of rows and columns of matrix A */
valueType const QR[], /* Pointer to coefficients of LU */
indexType const lda, /* Leading dimension of QR, Fortran style */
indexType const ipiv[], /* Permutation vector */
valueType const work[],
valueType b[], /* Pointer to coefficients of vector b */
indexType incB ) ;
void
applyReflections( indexType const n, /* Number of rows of matrix QR */
indexType const m, /* Number of columns of matrix QR */
valueType const QR[], /* Pointer to coefficients of QR */
indexType const lda, /* Leading dimension of QR, Fortran style */
indexType const ipiv[], /* Permutation vector */
valueType const work[],
valueType v[],
indexType incV ) ;
}
#endif
The code of QR decomposition
File: qr.cc:
#include "QR.hh"
#include "alglin.hh"
namespace QR {
// Purpose
// =======
// generates a real elementary reflector H of order n, such that
//
// H * ( x0 ) = ( beta ), H^T * H = I.
// ( v ) ( 0 )
//
// where alpha and beta are scalars, beta is non-negative, and x is
// an (n-1)-element real vector. H is represented in the form
//
// 2
// H = I - --------------- ( alpha ) * ( alpha v' ),
// alpha^2 + v^2 ( v )
//
// 2
// H * ( x0 ) = ( x0 ) - -------------- ( alpha ) * ( alpha v' ) ( x0 )
// ( v ) ( v ) alpha^2+v^2 ( v ) ( v )
//
// 2*(x0*alpha+v^2)
// = ( x0 ) - ------------------ ( alpha )
// ( v ) alpha^2+v^2 ( v )
//
// alpha = sign(x0) * (|x0| + || (x0,xv) ||)
//
// 2 alpha * ( alpha x0 + v^2)
// beta = x0 - ------------------------------
// alpha^2 + v^2
//
// H = I - gamma ( 1 ) * ( 1 v'/alpha ),
// ( v/alpha )
//
// gamma = 2*alpha^2/(alpha^2+v'*v)
//
valueType // The value tau.
buildReflection( indexType n, // The order of the elementary reflector.
valueType x[], // On entry, the vector x. On exit, it is overwritten with the vector v and beta
valueType xNorm ) { // The norm of vector x
// xNorm^2 = x0^2 + v^2
valueType x0 = x[0] ;
valueType xNorm2 = xNorm*xNorm ;
valueType vNorm2 = xNorm2-x0*x0 ;
valueType alpha = ( x0 > 0 ? x0 + xNorm : x0 - xNorm ) ;
valueType gamma = 2/(1+vNorm2/(alpha*alpha)) ;
x[0] -= gamma * ( x0 + vNorm2 / alpha ) ; // beta
alglin::scal( n-1, 1/alpha, x+1, 1 ) ;
return gamma ;
}
indexType
factorize( indexType const n, /* Number of rows of matrix A */
indexType const m, /* Number of columns of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType ipiv[], /* Permutation vector */
valueType work[] ) {
indexType nm = m < n ? m : n-1 ;
for ( indexType i = 0 ; i < nm ; ++i ) {
// evaluate column norm
for ( indexType j = i ; j < m ; ++j ) work[j] = alglin::nrm2( n-i, A+i+j*lda, 1 ) ;
// find the column with maximum norm
indexType ip = i+alglin::iamax( m-i, work+i, 1 ) ;
if ( work[ip] == 0 ) return i ; // no more column found
// swap columns
if ( i != ip ) alglin::swap( n, A + i*lda, 1, A + ip*lda, 1 ) ;
ipiv[i] = ip ; // store the pivot index to vector ipiv
// build householder reflection
valueType * Ai = A + i*(lda+1) ;
work[i] = buildReflection( n-i, Ai, work[ip] ) ;
// apply householder reflection to submatrix
valueType * w = work + i + 1 ;
// Ai = ( beta v )^T not (1 v^T)
valueType tmp = *Ai ;
*Ai = 1 ;
// gemv: w <- beta * w + alpha * A^T x
// row column alpha A x beta w
alglin::gemv( "Transpose", n-i, m-i-1, 1.0, Ai+lda, lda, Ai, 1, 0.0, w, 1 ) ;
// ger: A <- A + alpha u v^T
// row column alpha A u v
alglin::ger( n-i, m-i-1, -work[i], Ai, 1, w, 1, Ai+lda, lda ) ;
*Ai = tmp ;
}
return 0 ;
}
void
applyReflections( indexType const n, /* Number of rows of matrix QR */
indexType const m, /* Number of columns of matrix QR */
valueType const QR[], /* Pointer to coefficients of QR */
indexType const lda, /* Leading dimension of QR, Fortran style */
indexType const ipiv[], /* Permutation vector */
valueType const work[],
valueType v[],
indexType incV ) {
indexType nm = m < n ? m : n-1 ;
for ( indexType i = 0 ; i < nm ; ++i ) {
valueType * vi = v + i*incV ;
valueType const * Qi = QR + i*lda + i + 1 ;
valueType bf = work[i] * (*vi + alglin::dot( n-i-1, Qi, 1, vi + incV, incV )) ;
*vi -= bf ;
alglin::axpy( n-i-1, -bf, Qi, 1, vi + incV, 1 ) ;
}
}
void
solve( indexType const n, /* Number of rows and columns of matrix A */
valueType const QR[], /* Pointer to coefficients of LU */
indexType const lda, /* Leading dimension of LU, Fortran style */
indexType const ipiv[], /* Permutation vector */
valueType const work[],
valueType b[], /* Pointer to coefficients of vector b */
indexType incB ) {
applyReflections( n, n, QR, lda, ipiv, work, b, incB ) ;
alglin::trsv( "Upper", "No Transpose", "Non Unit", n, QR, lda, b, incB ) ;
for ( indexType i = 0 ; i < n-1 ; ++i ) {
indexType ip = ipiv[i] ;
if ( ip != i ) std::swap( b[i*incB], b[ip*incB] ) ;
}
}
}
Lesson of 24 February 2010
Lesson in a zip file
The header of Jacobi method for eigenvalues computation
File: jacobi.hh:
#ifndef JACOBI_HH
#define JACOBI_HH
namespace Jacobi {
typedef double valueType ; // the type for real number
typedef unsigned indexType ; // the type for integer (unsigned)
void
GivensLeft( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const row1, /* first row for Givens rotation */
indexType const row2, /* second row for Givens rotation */
valueType const theta ) ;
void
GivensRight( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const col1, /* first column for Givens rotation */
indexType const col2, /* second column for Givens rotation */
valueType const theta ) ;
valueType
evalAngle( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const row,
indexType const col ) ;
bool
Jacobi( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
valueType Q[], /* Pointer to coefficients of Q */
indexType const ldq, /* Leading dimension of Q, Fortran style */
valueType const epsi, /* tolerance for off diagonal elements */
indexType const maxIter ); /* maximum number of big iterations */
}
#endif
The code of Jacobi method
File: jacobi.cc:
#include "jacobi.hh"
#include "alglin.hh"
#include <cmath>
#include <iostream>
namespace Jacobi {
using namespace std ;
void
GivensLeft( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const row1, /* first row for Givens rotation */
indexType const row2, /* second row for Givens rotation */
valueType const theta ) {
//
// / \
// | cos(theta) sin(theta) |
// | |
// | -sin(theta) cos(theta) |
// \ /
//
// row1 <- cos(theta) * row1 + sin(theta) * row2
// row2 <- -sin(theta) * row1 + cos(theta) * row2
valueType cs = cos(theta) ;
valueType sn = sin(theta) ;
valueType * R1 = A + row1 ;
valueType * R2 = A + row2 ;
for ( indexType i=0 ; i < n ; ++i, R1 += lda, R2 += lda ) {
valueType tmp = cs*(*R1)+sn*(*R2) ;
*R2 = cs*(*R2)-sn*(*R1) ;
*R1 = tmp ;
}
}
void
GivensRight( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const col1, /* first column for Givens rotation */
indexType const col2, /* second column for Givens rotation */
valueType const theta ) {
//
// / \
// | cos(theta) -sin(theta) |
// | |
// | sin(theta) cos(theta) |
// \ /
//
// col1 <- cos(theta) * col1 + sin(theta) * col2
// row2 <- -sin(theta) * col1 + cos(theta) * col2
valueType cs = cos(theta) ;
valueType sn = sin(theta) ;
valueType * C1 = A + col1 * lda ;
valueType * C2 = A + col2 * lda ;
for ( indexType i=0 ; i < n ; ++i, ++C1, ++C2 ) {
valueType tmp = cs*(*C1)+sn*(*C2) ;
*C2 = cs*(*C2)-sn*(*C1) ;
*C1 = tmp ;
}
}
valueType
evalAngle( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
indexType const row, // row > col
indexType const col ) {
//
// col
// |
// . . . . .
// . Aii . Aij .
// . . . . .
// . . . . .
// . Aij . Ajj . <--- row
// . . . . .
valueType Aij = A[row + col * lda] ;
valueType Aii = A[col + col * lda] ;
//valueType Ajj = A[row + row * lda] ;
return -atan2( Aij, Aii ) ;
}
bool
Jacobi( indexType const n, /* Number of rows of matrix A */
valueType A[], /* Pointer to coefficients of A */
indexType const lda, /* Leading dimension of A, Fortran style */
valueType Q[], /* Pointer to coefficients of Q */
indexType const ldq, /* Leading dimension of Q, Fortran style */
valueType const epsi, /* tolerance for off diagonal elements */
indexType const maxIter ) { /* maximum number of big iterations */
// initialize Q to the identity matrix
valueType one = 1 ;
alglin::zero( n*ldq, Q, 1 ) ;
alglin::copy( n, &one, 0, Q, ldq+1 ) ;
for ( indexType k = 0 ; k < maxIter ; ++k ) {
// evaluate max norm of non diagonal elements
indexType iAbs = 0 ;
indexType jAbs = 0 ;
valueType maxAbs = 0 ;
for ( indexType i = 1 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < i ; ++j ) {
valueType absAij = abs( A[ i + lda * j] ) ;
if ( absAij > maxAbs ) {
iAbs = i ;
jAbs = j ;
maxAbs = absAij ;
}
}
}
if ( maxAbs < epsi ) return true ;
// loop for elements under diagonal
#if 1
// evaluate givens rotation
valueType theta = evalAngle( n, A, lda, iAbs, jAbs ) ;
// apply givens rotation
GivensLeft ( n, A, lda, iAbs, jAbs, theta ) ;
GivensRight( n, A, lda, iAbs, jAbs, theta ) ;
// apply givens rotation to Q
GivensRight( n, Q, ldq, iAbs, jAbs, theta ) ;
#else
for ( indexType i = 1 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < i ; ++j ) {
// evaluate givens rotation
valueType theta = evalAngle( n, A, lda, i, j ) ;
// apply givens rotation
GivensLeft ( n, A, lda, i, j, theta ) ;
GivensRight( n, A, lda, i, j, theta ) ;
// apply givens rotation to Q
GivensRight( n, Q, ldq, i, j, theta ) ;
}
}
#endif
}
return false ;
}
}
A driver code
File: test_jacobi.cc:
#include "Jacobi.hh"
#include "alglin.hh"
#include <iostream>
#include <iomanip>
using Jacobi::valueType ;
using Jacobi::indexType ;
using namespace std ;
#define NRow 4
#define LDA 4
#define LDQ 4
#define LDAQ 4
int
main() {
valueType Q[NRow*LDQ], AQ[NRow*LDAQ], Asaved[NRow*LDA] ;
valueType A[NRow*LDA] = {
4, 1, 1, 1,
1, 4, 1, 1,
1, 1, 4, 1,
1, 1, 1, 4
} ;
alglin::copy( NRow*LDA, A, 1, Asaved, 1) ;
bool ok = Jacobi::Jacobi( NRow, A, LDA, Q, LDQ, 10E-12, 100000 ) ;
cout << "\nDiagonalized matrix\n\n" ;
for ( indexType i = 0 ; i < NRow ; ++i ) {
for ( indexType j = 0 ; j < NRow ; ++j ) {
cout << setw(10) << A[ i + LDA * j ] << ' ' ;
}
cout << '\n' ;
}
cout << "\nEigenvectors\n" ;
cout << '\n' ;
for ( indexType i = 0 ; i < NRow ; ++i ) {
for ( indexType j = 0 ; j < NRow ; ++j ) {
cout << setw(10) << Q[ i + LDQ * j ] << ' ' ;
}
cout << '\n' ;
}
alglin::gemm( "No Transpose", "No Transpose", NRow, NRow, NRow,
1.0, Asaved, LDA,
Q, LDQ,
0.0, AQ, LDAQ ) ;
alglin::gemm( "No Transpose", "No Transpose", NRow, NRow, NRow,
1.0, Q, LDQ,
A, LDA,
-1.0, AQ, LDAQ ) ;
cout << "\nResidual AQ - Q Lambda\n" ;
cout << '\n' ;
for ( indexType i = 0 ; i < NRow ; ++i ) {
for ( indexType j = 0 ; j < NRow ; ++j ) {
cout << setw(10) << AQ[ i + LDQ * j ] << ' ' ;
}
cout << '\n' ;
}
return 0 ;
}
Lesson of 25 February 2010
Lesson in a zip file
The header of cyclic reduction for BABD linear system
File: AmodioLU.hh:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2003 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
/**
*
* @mainpage BLOCK LU
* @date May 30, 2006
* @version 1.0
* @note first release May 30, 2006
*
* @author Enrico Bertolazzi
*
* @par Affiliation:
* Department of Mechanics and Structures Engineering <br>
* University of Trento <br>
* via Mesiano 77, I -- 38050 Trento, Italy <br>
* enrico.bertolazzi@ing.unitn.it
*
* @par Preface
*
* @par Abstract
*
*/
#ifndef AMODIO_LU_HH
#define AMODIO_LU_HH
#include "Malloc.hh"
#ifndef CHAR_TYPE
#define CHAR_TYPE char
#endif
#ifndef REAL_TYPE
#define REAL_TYPE double
#endif
#ifndef INTEGER_TYPE
#define INTEGER_TYPE int
#endif
namespace AmodioLUDefine {
typedef REAL_TYPE valueType ;
typedef valueType* valuePointer ;
typedef const valueType* valueConstPointer ;
typedef valueType& valueReference ;
typedef const valueType& valueConstReference ;
typedef INTEGER_TYPE indexType ;
typedef indexType* indexPointer ;
typedef const indexType* indexConstPointer ;
typedef indexType& indexReference ;
typedef const indexType& indexConstReference ;
/*
// _ _ _ _ _ _
// / \ _ __ ___ ___ __| (_) ___ | | | | | |
// / _ \ | '_ ` _ \ / _ \ / _` | |/ _ \| | | | | |
// / ___ \| | | | | | (_) | (_| | | (_) | |__| |_| |
// /_/ \_\_| |_| |_|\___/ \__,_|_|\___/|_____\___/
*/
class AmodioLU {
private:
Malloc<valueType> baseValue ;
Malloc<indexType> baseIndex ;
AmodioLU(AmodioLU const &) ;
AmodioLU const & operator = (AmodioLU const &) ;
indexType nblock ; //!< total number of blocks
indexType n ; //!< size of square blocks
indexType m ; //!< number final rows (m>=n)
indexType nnz ; //!< total number of non zeros
/*
//
// Matrix structure
//
// n * nblock
// ________________^_________________
// / \
// n n n n q
// +-----+-----+-----+----.........-----+-----+-----+ \
// | Ad | Au | 0 | | 0 | 0 | n |
// +-----+-----+-----+ -----+-----+-----+ |
// | 0 | Ad | Au | 0 | 0 | 0 | n |
// +-----+-----+-----+-----+ -----+-----+-----+ |
// | 0 | 0 | Ad | Au | | 0 | 0 | n |
// +-----+-----+-----+-----+ -----+-----+-----+ |
// | : |
// : : > n * nblock
// : : |
// : : |
// : : |
// : +-----+-----+-----+ |
// : | Au | 0 | 0 | |
// : +-----+-----+-----+-----+ |
// : | 0 | Ad | Au | 0 | n |
// +-----+-----+---......---+-----+-----+=====+=====+ /
// | | | | | ! | !
// | H0 | 0 | | | 0 ! HN | Hq ! m
// | | | | | ! | !
// +-----+-----+---......---+-----+-----+=====+=====+
//
*/
valueConstPointer AdAu ;
valueConstPointer H0 ;
valueConstPointer HN ;
valueConstPointer Hq ;
///////////////////////////////////////////////////////
valuePointer SR_blk ;
valuePointer D_blk ;
valuePointer F_blk ;
indexPointer ipiv_work ;
indexPointer ipiv_blk ;
indexPointer perm_blk ;
valuePointer TMP_blk ;
public:
explicit
AmodioLU()
: baseValue("AmodioLU_value")
, baseIndex("AmodioLU_index")
{ }
~AmodioLU() {
baseValue . free() ;
baseIndex . free() ;
}
void load( indexType nblk,
indexType n,
indexType q,
valueConstPointer AdAu,
valueConstPointer H0,
valueConstPointer HN,
valueConstPointer Hq ) ;
void amxpy( valueType a, valuePointer x, valuePointer y ) const ;
indexType factorize() ;
void solve( valuePointer in_out ) ;
} ;
}
namespace AmodioLULoad {
using AmodioLUDefine::AmodioLU ;
}
#endif
The code of cyclic reduction
File: AmodioLU.cc:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2003 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita' degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
#include "AmodioLU.hh"
#include "alglin.hh"
#include <iostream>
using namespace std ;
namespace AmodioLUDefine {
using namespace std ;
static const valueType ONE = 1 ;
static const valueType M_ONE = -1 ;
/*
// _ _
// | | ___ __ _ __| |
// | |/ _ \ / _` |/ _` |
// | | (_) | (_| | (_| |
// |_|\___/ \__,_|\__,_|
*/
void
AmodioLU::load( indexType nblock,
indexType n,
indexType q,
valueConstPointer AdAu,
valueConstPointer H0,
valueConstPointer HN,
valueConstPointer Hq ) {
this -> AdAu = AdAu ;
this -> H0 = H0 ;
this -> HN = HN ;
this -> Hq = Hq ;
this -> nblock = nblock ;
this -> n = n ;
this -> m = n+q ;
indexType nnzF = nblock*n*n ;
indexType nnzSR = 2*nnzF ;
indexType nnzD = (n+m)*(n+m) ;
indexType nnzTMP = 2*n*n ;
indexType nv = nnzF + nnzSR + nnzD + nnzTMP ;
indexType ni = 2*n*nblock + 2*n+m ;
baseValue . allocate(nv) ;
baseIndex . allocate(ni) ;
SR_blk = baseValue( nnzSR ) ;
D_blk = baseValue( nnzD ) ;
F_blk = baseValue( nnzF ) ;
TMP_blk = baseValue( nnzTMP ) ;
perm_blk = baseIndex( 2*n*nblock ) ;
ipiv_blk = baseIndex( n+m ) ;
ipiv_work = baseIndex( n ) ;
alglin::copy( nnzSR, AdAu, 1, SR_blk, 1 ) ;
}
/* __ _ _ __ ___ __ ___ __ _ _
// / _` | '_ ` _ \\ \/ / '_ \| | | |
// | (_| | | | | | |> <| |_) | |_| |
// \__,_|_| |_| |_/_/\_\ .__/ \__, |
// |_| |___/
*/
void
AmodioLU::amxpy( valueType alpha, valuePointer x, valuePointer y ) const {
valueType * yk = y ;
valueType const * xk = x ;
for ( indexType k = 0 ; k < nblock ; ++k, xk += n, yk += n ) {
valueConstPointer Ad = AdAu + 2*k*n*n ;
valueConstPointer Au = Ad + n*n ;
alglin::gemv( "N", n, n, alpha, Ad, n, xk, 1, ONE, yk, 1 ) ;
alglin::gemv( "N", n, n, alpha, Au, n, xk+n, 1, ONE, yk, 1 ) ;
}
alglin::gemv( "No Transpose", m, n, alpha, H0, m, x, 1, ONE, yk, 1 ) ;
alglin::gemv( "No Transpose", m, n, alpha, HN, m, xk, 1, ONE, yk, 1 ) ;
alglin::gemv( "No Transpose", m, m-n, alpha, Hq, m, xk+n, 1, ONE, yk, 1 ) ;
}
/*
// __ _ _
// / _| __ _ ___| |_ ___ _ __(_)_______
// | |_ / _` |/ __| __/ _ \| '__| |_ / _ \
// | _| (_| | (__| || (_) | | | |/ / __/
// |_| \__,_|\___|\__\___/|_| |_/___\___|
*/
indexType
AmodioLU::factorize() {
/*\
| Based on the algorithm
| Pierluigi Amodio and Giuseppe Romanazzi
| Algorithm 859: BABDCR: a Fortran 90 package for the Solution of Bordered ABD Linear Systems
| ACM Transactions on Mathematical Software, 32, 4, 597—608 (2006)
\*/
// some constanst
indexType const nxn = n*n ;
indexType const nx2 = n*2 ;
// initialize indices
valuePointer F = F_blk ;
indexPointer perm = perm_blk ;
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// 0 * 2 * 4 * 6 * 8 * 10 * 12
// 0 - * - 4 - * - 8 - * - 12
// 0 - - - * - - - 8 - - - 12
// 0 - - - - - - - * - - - 12
// !!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! reduction phase !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!
for ( indexType jump = 1 ; jump < nblock ; jump *= 2 ) {
for ( indexType k = 1 ; k*jump < nblock ; k += 2 ) {
indexType jC = k*jump ;
indexType jL = jC-jump ;
indexType jR = min(jC + jump,nblock) ;
valuePointer S = SR_blk + 2*jL*nxn ;
valuePointer RS = SR_blk + (2*jC-1)*nxn ;
valuePointer R = SR_blk + (2*jR-1)*nxn ;
// reshape ( Rb Sb ) as ( Rb ) and save in ( , ) columns by columns
// ( Sb )
alglin::copy( 2*nxn, RS, 1, TMP_blk, 1 ) ;
alglin::gecopy( n, n, TMP_blk, n, RS, nx2 ) ;
alglin::gecopy( n, n, TMP_blk+nxn, n, RS+n, nx2 ) ;
/*\
| reduces a 2x3 block matrix / Sa Rb \ to a 1x2 block matrix ( Sa' Rc' )
| \ Sb Rc /
|
| by using the following algorithm:
|
| P * / Rb \ = / Rb' \ = / L \ (U) = / I \ (L*U) = / I \ (L*U)
| \ Sb / \ Sb' / \ Sb' U^(-1) / \ Sb' (L*U)^(-1) / \ G /
|
| where and G = Sb'*U^(-1)*L^(-1).
|
| / -G I \ * P * / Rb \ = / -G I \ / I \ (L*U) = / 0 \
| \ I 0 / \ Sb / \ I 0 / \ G / \ L*U /
|
| ------------------------------------------------------------
|
| / -G I \ * P * / Sa 0 \ = / -G I \ / Sa' Rc' \ = / Sa''' Rc''' \
| \ I 0 / \ 0 Rc / \ I 0 / \ Sa'' Rc'' / \ Sa' Rc' /
|
| where Sa''' = Sa'' - G*Sa', Rc''' = Rc'' - G*Rc' and thus
|
| / -G I \ * P * / Sa Rb \ = / Sa''' 0 Rc''' \
| \ I 0 / \ Sb Rc / \ Sa' L*U Rc' /
|
\*/
// factorize RS by means of the LU factorization
// P * / Rb \ = / L \ (U)
// \ Sb / \ Sb' U^(-1) /
indexType INFO = alglin::getrf( nx2, n, RS, nx2, ipiv_work ) ;
if ( INFO != 0 ) return INFO ;
// compute G = Sb' U^(-1) L^(-1)
// / L \ (U) = / I \ (L*U) = / I \ (L*U)
// \ Sb' U^(-1) / \ Sb' U^(-1) L^(-1) / \ G /
alglin::trsm( "Right", "Lower", "No Transpose", "Unit", n, n, ONE, RS, nx2, RS+n, nx2 ) ;
// determine the permutation vector
for ( indexType i = 0 ; i < nx2 ; ++i ) perm[i] = i ;
for ( indexType i = 0 ; i < n ; ++i ) {
indexType ip = ipiv_work[i]-1 ;
if ( ip != i ) std::swap( perm[i], perm[ip] ) ;
}
// P * / Sa 0 \ = / Sa' Rc' \
// \ 0 Rc / \ Sa'' Rc'' /
// S = Sa'' and R = Rc''
valuePointer Sa1 = TMP_blk ;
valuePointer Rc1 = TMP_blk + nxn ;
alglin::copy( nxn, S, 1, Sa1, 1 ) ; alglin::zero( nxn, S, 1 ) ;
alglin::copy( nxn, R, 1, Rc1, 1 ) ; alglin::zero( nxn, R, 1 ) ;
for ( indexType i = 0 ; i < n ; ++i ) {
indexType pi = perm[i+n] ;
if ( pi < n ) alglin::copy( n, Sa1+pi, n, S+i, n ) ;
else alglin::copy( n, Rc1+pi-n, n, R+i, n ) ;
}
// / -G I \ / Sa' Rc' \ = / Sa''' Rc''' \
// \ I 0 / \ Sa'' Rc'' / \ Sa' Rc' /
//
// where Sa''' = Sa'' - G*Sa', Rc''' = Rc'' - G*Rc'
// where the nonnull rows of Sa' and Rc' are saved in F
valuePointer Fi = F ;
valuePointer Gi = RS + n ; // i-th column of G
for ( indexType i = 0 ; i < n ; ++i, Fi += n, Gi += nx2 ) {
indexType pi = perm[i] ;
valuePointer R_or_S, Ra_or_Sc ;
if ( pi < n ) { // save nonnull row of Sa' in the column of F
Ra_or_Sc = Sa1 + pi ;
R_or_S = S ;
} else { // save nonnull row of Rc' in the column of F
Ra_or_Sc = Rc1 + pi - n ;
R_or_S = R ;
}
alglin::copy( n, Ra_or_Sc, n, Fi, 1 ) ;
alglin::ger( n, n, M_ONE, Gi, 1, Fi, 1, R_or_S, n ) ;
}
perm += nx2 ;
F += nxn ;
}
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! factorization of the last 2 by 2 matrix !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
valuePointer S = SR_blk ;
valuePointer R = SR_blk + (2*nblock-1)*nxn ;
indexType nm = n+m ;
alglin::gecopy( n, n, S, n, D_blk, nm ) ;
alglin::gecopy( n, n, R, n, D_blk+n*nm, nm ) ;
alglin::gecopy( m, n, H0, m, D_blk+n, nm ) ;
alglin::gecopy( m, n, HN, m, D_blk+n+n*nm, nm ) ;
if ( m > n ) {
alglin::gezero( n, m-n, D_blk+nx2*nm, nm ) ;
alglin::gecopy( m, m-n, Hq, m, D_blk+nx2*nm+n, nm ) ;
}
return alglin::getrf( nm, nm, D_blk, nm, ipiv_blk ) ;
}
/* _
// ___ ___ | |_ _____
// / __|/ _ \| \ \ / / _ \
// \__ \ (_) | |\ V / __/
// |___/\___/|_| \_/ \___|
*/
void
AmodioLU::solve( valuePointer y ) {
/*\
|
| Purpose
| =======
|
| BABDCR_SOLV solves a babd linear system whose coefficient matrix
| has been factorized by BABDCR_FACT. The algorithm consists of three
| phases: reduction (by using the subroutine REDUCE_RHS), solution of
| the 2 by 2 block system (by using the subroutine DGETRS) and
| back-substitution (by using the subroutine SOLVE_BLOCK).
|
| In input, BABDCR_SOLV requires the coefficient matrix factorized by
| the subroutine BABDCR_FACT (see details of this subroutine) and the
| right hand side which is stored in the block vector VECT_B in the
| following form
|
| VECT_B = [f(0), f(1), ...., f(NBLOKS)].
|
| The first block element f(0) corresponds to the first row of the
| coefficient matrix containing Ba and Bb.
|
| On exit, BABDCR_SOLV gives the solution of the babd linear system.
| The solution is stored in the block vector VECT_B.
|
\*/
// some constanst
indexType const nxn = n*n ;
indexType const nx2 = 2*n ;
// initialize indices
valuePointer F = F_blk ;
indexPointer perm = perm_blk ;
// !!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! reduction phase !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!
indexType jump = 1 ;
for ( ; jump < nblock ; jump *=2 ) {
for ( indexType k = 1 ; k*jump < nblock ; k += 2 ) {
indexType jC = k * jump ;
indexType jL = jC - jump ;
valuePointer RS = SR_blk + (2*jC-1)*nxn ;
valuePointer Va = y + jL*n ;
valuePointer Vb = y + jC*n ;
/*\
| P * / Va \ = / Vp \
| \ Vb / \ Vq /
\*/
alglin::copy( n, Va, 1, TMP_blk, 1 ) ;
alglin::copy( n, Vb, 1, TMP_blk+n, 1 ) ;
for ( indexType i = 0 ; i < n ; ++i ) {
Va[i] = TMP_blk[perm[i+n]] ;
Vb[i] = TMP_blk[perm[i]] ;
}
/*\
| / -G I \ / Vp \ = / Vq-G*Vp \
| \ I 0 / \ Vq / \ Vp /
\*/
alglin::gemv( "No Transpose", n, n, M_ONE, RS + n, nx2, Vb, 1, ONE, Va, 1 ) ;
perm += nx2 ;
F += nxn ;
}
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! 2 by 2 block linear system solution !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
indexType nm = n+m ;
// / S R 0 \ /x(0)\ = b(0)
// \ H0 HN Hq / \x(N)/ = b(N)
valuePointer ye = y + (nblock-1) * n ;
// Apply row interchanges to the right hand sides.
alglin::swap( n, y, 1, ye, 1 ) ;
alglin::swaps( 1, ye, nm, 0, nm-1, ipiv_blk, 1 ) ;
alglin::trsv( "Lower", "No transpose", "Unit", nm, D_blk, nm, ye, 1 ) ;
alglin::trsv( "Upper", "No transpose", "Non-Unit", nm, D_blk, nm, ye, 1 ) ;
alglin::swap( n, y, 1, ye, 1 ) ;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!! back-substitution phase !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for ( jump /= 2 ; jump > 0 ; jump /= 2 ) {
indexType k = (nblock-1)/jump ;
if ( (k & 0x01) == 0 ) --k ;
for ( ; k > 0 ; k -= 2 ) {
indexType jC = k*jump ;
indexType jL = jC-jump ;
indexType jR = min(jC + jump,nblock) ;
valuePointer Xm = y + jL*n ;
valuePointer Xs = y + jR*n ;
valuePointer V = y + jC*n ;
valuePointer RS = SR_blk + (2*jC-1)*nxn ;
perm -= nx2 ;
F -= nxn ;
/*\
| computes the solution Xn (of length n) of the linear system
|
| L*U Xn = Vp - Sp*Xm - Rp*Xs
|
| obtained from the subroutines reduceBlock and reduceRHS applied
| to the system (see the subroutine reduceBlock for further details)
|
| ( Sa Rb ) ( Xm ) ( Va ).
| ( Sb Rc ) ( Xn ) = ( Vb )
| ( Xs )
|
| ( I ) * P * ( Sa Rb ) ( Xm ) ( Sp L*U Rp ) ( Xm ) ( Vp )
| ( -G I ) ( Sb Rc ) ( Xn ) = ( Sa' 0 Rc' ) ( Xn ) = ( V' )
| ( Xs ) ( Xs )
\*/
// compute V = Vp - Sp*Xm - Rp*Xs
for ( indexType i = 0 ; i < n ; ++i )
V[i] -= alglin::dot( n, F + i*n, 1, perm[i] < n ? Xm : Xs, 1 ) ;
// solve the system L*U Xn = V
alglin::trsv( "Lower", "No transpose", "Unit", n, RS, nx2, V, 1 ) ;
alglin::trsv( "Upper", "No transpose", "Non Unit", n, RS, nx2, V, 1 ) ;
}
}
}
}
The header of LU decomposition for BABD linear system
File: BlockLU.hh:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2003 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
/**
*
* @mainpage BLOCK LU
* @date May 30, 2006
* @version 1.0
* @note first release May 30, 2006
*
* @author Enrico Bertolazzi
*
* @par Affiliation:
* Department of Mechanics and Structures Engineering <br>
* University of Trento <br>
* via Mesiano 77, I -- 38050 Trento, Italy <br>
* enrico.bertolazzi@ing.unitn.it
*
* @par Preface
*
* @par Abstract
*
*/
#ifndef BLOCK_LU_HH
#define BLOCK_LU_HH
#include "Malloc.hh"
#ifndef CHAR_TYPE
#define CHAR_TYPE char
#endif
#ifndef REAL_TYPE
#define REAL_TYPE double
#endif
#ifndef INTEGER_TYPE
#define INTEGER_TYPE int
#endif
namespace BlockLUDefine {
typedef CHAR_TYPE charType ;
typedef charType* charPointer ;
typedef const charType* charConstPointer ;
typedef charType& charReference ;
typedef const charType& charConstReference ;
typedef REAL_TYPE valueType ;
typedef valueType* valuePointer ;
typedef const valueType* valueConstPointer ;
typedef valueType& valueReference ;
typedef const valueType& valueConstReference ;
typedef INTEGER_TYPE indexType ;
typedef indexType* indexPointer ;
typedef const indexType* indexConstPointer ;
typedef indexType& indexReference ;
typedef const indexType& indexConstReference ;
/*
// ____ _ _ _ _ _
// | __ )| | ___ ___| | _| | | | | |
// | _ \| |/ _ \ / __| |/ / | | | | |
// | |_) | | (_) | (__| <| |__| |_| |
// |____/|_|\___/ \___|_|\_\_____\___/
//
*/
class BlockLU {
Malloc<valueType> baseValue ;
Malloc<indexType> baseIndex ;
BlockLU(BlockLU const &) ;
BlockLU const & operator = (BlockLU const &) ;
indexType nblock ; //!< total number of blocks
indexType n ; //!< size of square blocks
indexType m ; //!< number final rows (m>=n)
indexType N ; //!< n * (nblock+1) + q
indexType nnz ; //!< total number of non zeros
/*
//
// Matrix structure
//
// n * nblock
// ________________^_________________
// / \
// n n n n q
// +-----+-----+-----+----.........-----+-----+-----+ \
// | Ad | Au | 0 | | 0 | 0 | n |
// +-----+-----+-----+ -----+-----+-----+ |
// | 0 | Ad | Au | 0 | 0 | 0 | n |
// +-----+-----+-----+-----+ -----+-----+-----+ |
// | 0 | 0 | Ad | Au | | 0 | 0 | n |
// +-----+-----+-----+-----+ -----+-----+-----+ |
// | : |
// : : > n * nblock
// : : |
// : : |
// : : |
// : +-----+-----+-----+ |
// : | Au | 0 | 0 | |
// : +-----+-----+-----+-----+ |
// : | 0 | Ad | Au | 0 | n |
// +-----+-----+---......---+-----+-----+=====+=====+ /
// | | | | | ! | !
// | H0 | 0 | | | 0 ! HN | Hq ! m
// | | | | | ! | !
// +-----+-----+---......---+-----+-----+=====+=====+
//
*/
valueConstPointer AdAu ;
valueConstPointer H0 ;
valueConstPointer HN ;
valueConstPointer Hq ;
/*
//
// Working block AdH_blk [ size = nblock * ( n * (n+m) ) ]
//
// n * nblock
// ________________^_________________
// / \
// n n n
// +-----+-----+-----+----........+-----+
// | Ad | Ad | Ad | Ad | n
// +-----+-----+-----+ +-----+
// | | | | | !
// | H0 | 0 | | | 0 ! m
// | | | | | !
// +-----+-----+---......---+-----+-----+
//
*/
valuePointer AdH_blk ;
/*
//
// Working block Au_blk [ size = nblock * (n*n) ]
//
// n * nblock + q
// ________________^________________________
// / \
// n n n n q
// +-----+-----+-----+----.........-----+------+
// | Au | Au | Au | Au | fill | n
// +-----+-----+-----+----.........-----+------+
//
*/
valuePointer Au_blk ;
/*
//
// Working block DD_blk [ size = m * m ]
//
// n q (n+q=m)
// +=====+=====+
// ! | !
// ! HN | Hq ! m
// ! | !
// +=====+=====+
//
*/
valuePointer DD_blk ;
/*
//
// Working block FF_blk [ size = nblock * (n*m) ]
//
// n q (n+q=m)
// +-----+-----+ \
// |fill |fill | n |
// +-----+-----+ |
// |fill |fill | n |
// +-----+-----+ |
// |fill |fill | n |
// +-----+-----+ :
// | | : n * (nblock-1)
// : : :
// : : :
// : : :
// : : :
// : : :
// |fill |fill | n |
// +-----+-----+ /
//
*/
valuePointer FF_blk ;
// pivot vector
indexPointer ipiv_blk ;
void allocate( indexType nblk, indexType n, indexType q ) ;
public:
explicit BlockLU();
~BlockLU() ;
void load( indexType nblk,
indexType n,
indexType q,
valueConstPointer AdAu,
valueConstPointer H0,
valueConstPointer HN,
valueConstPointer Hq ) ;
void amxpy( valueType a, valuePointer x, valuePointer y ) const ;
indexType factorize() ;
void solve( valuePointer in_out ) ;
} ;
}
namespace BlockLULoad {
using BlockLUDefine::BlockLU ;
}
#endif
The code of LU decomposition
File: BlockLU.cc:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2003-2010 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
/**
*
* @mainpage BLOCK LU
* @date February 12, 2010
* @version 1.0
* @note first release May 30, 2006
*
* @author Enrico Bertolazzi
*
* @par Affiliation:
* Department of Mechanics and Structures Engineering <br>
* University of Trento <br>
* via Mesiano 77, I -- 38050 Trento, Italy <br>
* enrico.bertolazzi@ing.unitn.it
*
* @par Preface
*
* @par Abstract
*
*/
#include "BlockLU.hh"
#include "Alglin.hh"
#include <limits>
namespace BlockLUDefine {
using namespace std ;
static const valueType ONE = 1 ;
static const valueType M_ONE = -1 ;
/* ____ _ _ _ _ _
// | __ )| | ___ ___| | _| | | | | |
// | _ \| |/ _ \ / __| |/ / | | | | |
// | |_) | | (_) | (__| <| |__| |_| |
// |____/|_|\___/ \___|_|\_\_____\___/
*/
BlockLU::BlockLU()
: baseValue("BlockLU_value")
, baseIndex("BlockLU_index")
{ }
BlockLU::~BlockLU() {
baseValue . free() ;
baseIndex . free() ;
}
/* _ _ _
// __ _| | | ___ ___ __ _| |_ ___
// / _` | | |/ _ \ / __/ _` | __/ _ \
// | (_| | | | (_) | (_| (_| | || __/
// \__,_|_|_|\___/ \___\__,_|\__\___|
*/
void
BlockLU::allocate( indexType nblock, indexType n, indexType q ) {
this -> nblock = nblock ;
this -> n = n ;
this -> m = n+q ;
this -> N = nblock*n+m ;
indexType nnzAdH = nblock*(n*(n+m)) ; // blocchi AdH
indexType nnzAu = nblock*(n*n)+n*q ; // blocchi Au
indexType nnzFF = (nblock-1)*(n*m) ; // blocchi FF
indexType nnzDD = m*m ; ; // blocco DD
nnz = nnzAdH + nnzAu + nnzFF + nnzDD ;
baseValue . allocate( nnz ) ;
baseIndex . allocate( N ) ;
AdH_blk = baseValue( nnzAdH ) ;
Au_blk = baseValue( nnzAu ) ;
FF_blk = baseValue( nnzFF ) ;
DD_blk = baseValue( nnzDD ) ;
ipiv_blk = baseIndex( N ) ;
}
/* _ _
// | | ___ __ _ __| |
// | |/ _ \ / _` |/ _` |
// | | (_) | (_| | (_| |
// |_|\___/ \__,_|\__,_|
*/
void
BlockLU::load( indexType nblk,
indexType n,
indexType q,
valueConstPointer AdAu,
valueConstPointer H0,
valueConstPointer HN,
valueConstPointer Hq ) {
allocate( nblk, n, q ) ;
this -> AdAu = AdAu ;
this -> H0 = H0 ;
this -> HN = HN ;
this -> Hq = Hq ;
// Initialize structures
alglin::zero( nnz, AdH_blk, 1 ) ;
// fill matrix
indexType nm = n+m ;
for ( indexType k = 0 ; k < nblock ; ++k ) {
valueConstPointer Ad = AdAu + 2*k*n*n ;
valueConstPointer Au = Ad + n*n ;
alglin::gecopy( n, n, Ad, n, AdH_blk + k*nm*n, nm ) ;
alglin::gecopy( n, n, Au, n, Au_blk + k*n*n, n ) ;
}
alglin::gecopy( m, n, H0, m, AdH_blk + n, nm ) ;
alglin::gecopy( m, n, HN, m, DD_blk, m ) ;
alglin::gecopy( m, q, Hq, m, DD_blk + m*n, m ) ;
}
/* __ _ _ __ ___ __ ___ __ _ _
// / _` | '_ ` _ \\ \/ / '_ \| | | |
// | (_| | | | | | |> <| |_) | |_| |
// \__,_|_| |_| |_/_/\_\ .__/ \__, |
// |_| |___/
*/
void
BlockLU::amxpy( valueType alpha, valuePointer x, valuePointer y ) const {
valueType * yk = y ;
valueType const * xk = x ;
for ( indexType k = 0 ; k < nblock ; ++k, xk += n, yk += n ) {
valueConstPointer Ad = AdAu + 2*k*n*n ;
valueConstPointer Au = Ad + n*n ;
alglin::gemv( "N", n, n, alpha, Ad, n, xk, 1, ONE, yk, 1 ) ;
alglin::gemv( "N", n, n, alpha, Au, n, xk+n, 1, ONE, yk, 1 ) ;
}
alglin::gemv( "No Transpose", m, n, alpha, H0, m, x, 1, ONE, yk, 1 ) ;
alglin::gemv( "No Transpose", m, n, alpha, HN, m, xk, 1, ONE, yk, 1 ) ;
alglin::gemv( "No Transpose", m, m-n, alpha, Hq, m, xk+n, 1, ONE, yk, 1 ) ;
}
/* __ _ _
// / _| __ _ ___| |_ ___ _ __(_)_______
// | |_ / _` |/ __| __/ _ \| '__| |_ / _ \
// | _| (_| | (__| || (_) | | | |/ / __/
// |_| \__,_|\___|\__\___/|_| |_/___\___|
*/
indexType
BlockLU::factorize() {
indexType nm = n+m ;
indexType rowFF = (nblock-1)*n ;
indexType INFO ;
indexPointer ipivk = ipiv_blk ;
valuePointer AdH = AdH_blk ;
valuePointer Au = Au_blk ;
valuePointer FF = FF_blk ;
for ( indexType k = 0 ; k < nblock-1 ; ++k, ipivk += n, AdH += nm*n, Au += n*n, FF += n ) {
INFO = alglin::getrf( nm, n, AdH, nm, ipivk ) ; // LU factorization
if ( INFO != 0 ) return INFO + k*n ;
valuePointer H = AdH + n ;
valuePointer CC = AdH + nm*n + n ;
for ( indexType i = 0 ; i < n ; ++i ) {
indexType ip = ipivk[i]-1 ;
if ( ip != i ) { // detected row exchange
if ( ip < n ) { // exchange row
alglin::swap( n, Au + i, n, Au + ip, n ) ;
alglin::swap( m, FF + i, rowFF, FF + ip, rowFF ) ; // last column block
} else {
alglin::swap( n, Au + i, n, CC + (ip-n), nm ) ;
alglin::swap( m, FF + i, rowFF, DD_blk + (ip-n), m ) ; // last column block
}
}
}
//
// +---------+---------+ ........ +--------+
// | \ U | | | |
// | \ |L^(-1)Au | |L^(-1)FF|
// | L \ | | | |
// |=========|=========| +========+
// | | | | |
// | H | CC* | | DD* |
// | | | | |
// +---------+---------+ ........ +--------+
//
// CC* = CC - H (LU)^(-1) Au
// DD* = DD - H (LU)^(-1) FF
//
alglin::trsm( "Left", "Lower", "No Transpose", "Unit", n, n, ONE, AdH, nm, Au, n ) ;
alglin::trsm( "Left", "Lower", "No Transpose", "Unit", n, m, ONE, AdH, nm, FF, rowFF ) ;
alglin::gemm( "No Transpose", "No Transpose", m, n, n, M_ONE, H, nm, Au, n, ONE, CC, nm ) ;
alglin::gemm( "No Transpose", "No Transpose", m, m, n, M_ONE, H, nm, FF, rowFF, ONE, DD_blk, m ) ;
}
// factorize last two block
INFO = alglin::getrf( nm, n, AdH, nm, ipivk ) ; // LU factorization
if ( INFO != 0 ) return false ;
for ( indexType i = 0 ; i < n ; ++i ) {
indexType ip = ipivk[i]-1 ;
if ( ip != i ) { // detected row exchange
if ( ip < n ) { // exchange row
alglin::swap( m, Au + i, n, Au + ip, n ) ; // last column block
} else {
alglin::swap( m, Au + i, n, DD_blk + (ip-n), m ) ; // last column block
}
}
}
//
// +---------+---------+
// | \ U | |
// | \ |L^(-1)Au |
// | L \ | |
// |=========|=========|
// | | |
// | H | CC* |
// | | |
// +---------+---------+
//
// CC* = CC - H (LU)^(-1) Au
//
valuePointer H = AdH + n ;
alglin::trsm( "Left", "Lower", "No Transpose", "Unit", n, m, ONE, AdH, nm, Au, n ) ;
alglin::gemm( "No Transpose", "No Transpose", m, m, n, M_ONE, H, nm, Au, n, ONE, DD_blk, m ) ;
// factorize last block
ipivk += n ;
INFO = alglin::getrf( m, m, DD_blk, m, ipivk ) ; // LU factorization
return INFO == 0 ;
}
/* _
// ___ ___ | |_ _____
// / __|/ _ \| \ \ / / _ \
// \__ \ (_) | |\ V / __/
// |___/\___/|_| \_/ \___|
*/
void
BlockLU::solve( valuePointer y ) {
// solve L
indexType nm = n+m ;
indexType rowFF = (nblock-1) * n ;
valuePointer ye = y + nblock * n ;
for ( indexType k = 0 ; k < nblock ; ++k ) {
indexConstPointer ipivk = ipiv_blk + k * n ;
valueConstPointer AdH = AdH_blk + k * (nm*n) ;
valuePointer yk = y + k * n ;
// apply permutation
for ( indexType i = 0 ; i < n ; ++i ) {
indexType ip = ipivk[i]-1 ;
if ( ip != i ) { // detected row exchange
if ( ip < n ) std::swap( yk[i], yk[ip] ) ;
else std::swap( yk[i], ye[ip-n] ) ;
}
}
alglin::trsv( "Lower", "No Transpose", "Unit", n, AdH, nm, yk, 1 ) ;
alglin::gemv( "No Transpose", m, n, M_ONE, AdH + n, nm, yk, 1, ONE, ye, 1 ) ;
}
indexConstPointer ipive = ipiv_blk + nblock * n ;
indexType ok = alglin::getrs( "No Transpose", m, 1, DD_blk, m, ipive, ye, m ) ;
if ( rowFF > 0 ) alglin::gemv( "No Transpose", rowFF, m, M_ONE, FF_blk, rowFF, ye, 1, ONE, y, 1 ) ;
if ( m > n ) alglin::gemv( "No Transpose", n, m-n, M_ONE, Au_blk + nblock*n*n, n, ye+n, 1, ONE, ye-n, 1 ) ;
indexType k = nblock ;
do {
--k ;
valueConstPointer AdH = AdH_blk + k*nm*n ;
valueConstPointer Au = Au_blk + k*n*n ;
valuePointer yk = y + k*n ;
alglin::gemv( "No Transpose", n, n, M_ONE, Au, n, yk + n, 1, ONE, yk, 1 ) ;
alglin::trsv( "Upper", "No Transpose", "Non Unit", n, AdH, nm, yk, 1 ) ;
} while ( k > 0 ) ;
}
}
A driver code
File: main.cc:
#include "BlockLU.hh"
#include "AmodioLU.hh"
//#include "ArcecoLU.hh"
#include "Alglin.hh"
#include "timing.hh"
#include <cmath>
#include <iostream>
#include <iomanip>
using namespace std ;
/*
// + . +
// | n*n n*n . |
// | n*n n*n . |
// | n*n n*n . |
// | . |
// | . |
// | . . . . . |
// | n*n . n*n n*q | q = m-n
// | m*n . m*n 0 |
// + +
//
*/
using namespace BlockLULoad ;
using namespace AmodioLULoad ;
//using namespace ArcecoLULoad ;
typedef BlockLUDefine::valueType valueType ;
typedef BlockLUDefine::indexType indexType ;
int
main() {
Timing tm ;
BlockLU bm ;
AmodioLU am ;
//ArcecoLU bm ;
bool ok ;
valueType elapsed ;
indexType nblk = 1700 ;
indexType n = 16 ;
indexType q = 9 ;
indexType m = n+q ;
indexType nxn = n*n ;
indexType N = (nblk+1)*n+q ;
valueType * AdAu = new valueType[2*nblk*nxn] ;
valueType * Hi = new valueType[m*n] ;
valueType * Hf = new valueType[m*n] ;
valueType * Hmu = new valueType[m*q] ;
valueType * xb = new valueType[N] ;
valueType * xb1 = new valueType[N] ;
valueType * x = new valueType[N] ;
cout << setw(12) << "factor" ; // 1
cout << setw(12) << "solve" ; // 1
cout << setw(12) << "err" ; // 1
cout << setw(12) << "factor (Amo)" ; // 1
cout << setw(12) << "solve (Amo)" ; // 1
cout << setw(12) << "err" ; // 1
cout << '\n' ;
for ( indexType kkk = 0 ; kkk < 100 ; ++kkk ) {
// riempie la matrice
for ( indexType i = 0 ; i < n ; ++i ) {
for ( indexType j = 0 ; j < n ; ++j ) {
indexType iaddr = i+j*n ;
for ( indexType k = 0 ; k < nblk ; ++k ) {
valueType * Ad = AdAu + 2*k*nxn ;
valueType * Au = Ad + nxn ;
Ad[iaddr] = (rand()%1000) ;
Au[iaddr] = (rand()%2000) ;
}
}
}
// riempie la matrice
for ( indexType i = 0 ; i < m ; ++i ) {
for ( indexType j = 0 ; j < n ; ++j ) {
indexType iaddr = i+j*m ;
Hi[iaddr] = (rand()%1000) ;
Hf[iaddr] = (rand()%1000) ;
}
}
// riempie la matrice
for ( indexType i = 0 ; i < m ; ++i ) {
for ( indexType j = 0 ; j < q ; ++j ) {
indexType iaddr = i+j*m ;
Hmu[iaddr] = (rand()%1000) ;
}
}
//
for ( indexType i = 0 ; i < N ; ++i ) {
x[i] = i ; // (arc4random()%234) ;
xb[i] = 0 ;
xb1[i] = 0 ;
}
//////////////////////////////
bm . load( nblk, n, q, AdAu, Hi, Hf, Hmu ) ;
am . load( nblk, n, q, AdAu, Hi, Hf, Hmu ) ;
bm . amxpy( 1, x, xb ) ;
bm . amxpy( 1, x, xb1 ) ;
tm . start() ;
ok = bm . factorize() ; if ( !ok ) cout << "factorize error\n" ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
tm . start() ;
bm . solve( xb ) ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
alglin::axpy( N, -1.0, x, 1, xb, 1 ) ;
cout << " " << setw(10) << alglin::nrm2( N, xb, 1 ) ;
tm . start() ;
indexType ierr = am . factorize() ;
if ( ierr ) cout << "factorize error ierr = " << ierr << '\n' ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
tm . start() ;
am . solve( xb1 ) ;
elapsed = tm . milliseconds() ;
cout << setw(10) << elapsed << "ms" ;
alglin::axpy( N, -1.0, x, 1, xb1, 1 ) ;
cout << " " << setw(10) << alglin::nrm2( N, xb1, 1 ) ;
cout << '\n' ;
}
}
Lesson of 26 February 2010
Lesson in a zip file
The header of Greville algorithm for pseudoinverse
File: greville.hh:
#ifndef GREVILLE_HH
#define GREVILLE_HH
namespace Greville {
typedef double valueType ;
typedef unsigned indexType ;
void
pseudoinverse( indexType nRow, // number of rows of A
indexType nCol, // number of columns of A
valueType const A[], // the marix A
indexType ldA, // row dimension of A
valueType iA[], // computed pseudoinverse
indexType ldiA, // row dimension of A
valueType work[] ) ;
}
#endif
The code of Greville algorithm for pseudoinverse
File: greville.cc:
#include "greville.hh"
#include "alglin.hh"
namespace Greville {
void
pseudoinverse( indexType nRow, // number of rows of A
indexType nCol, // number of columns of A
valueType const A[], // the marix A
indexType ldA, // row dimension of A
valueType Aplus[], // computed pseudoinverse
indexType ldAplus, // row dimension of A
valueType work[] ) {
valueType epsi = 1E-10 ;
valueType *dk = work ;
valueType *ck = dk + nCol ;
// init recursion, evalute pseudo inverse first column
alglin::copy( nRow, A, 1, Aplus, ldAplus ) ; // copy first column of A to the first row of iA
valueType len = alglin::nrm2( nRow, A, 1 ) ; // norm of first column of A
alglin::scal( nRow, 1/len/len, Aplus, ldAplus ) ;
// Greville recursion
for ( indexType k = 1 ; k < nCol ; ++k ) {
valueType const *ak = A + k*ldA ; // k-th column of A
valueType *bk = Aplus + k ; // k-th row of A^+
// evaluate dk = A^+_{k-1} * ak
alglin::gemv( "No Transpose", k, nRow,
1.0, Aplus, ldAplus,
ak, 1,
0.0, dk, 1 ) ;
// evaluate ck = ak - A_{k-1} * dk
alglin::copy( nRow, ak, 1, ck, 1 );
alglin::gemv( "No Transpose", nRow, k,
-1.0, A, ldA,
dk, 1,
1.0, ck, 1 ) ;
valueType lenck = alglin::nrm2( nRow, ck, 1 ) ;
if ( lenck < epsi ) {
// bk = (A^+)^T dk / (1+dk^2)
valueType bf = alglin::nrm2( k, dk, 1 ) ;
alglin::gemv( "Transpose", k, nRow,
1.0/(1+bf*bf), Aplus, ldAplus, dk, 1,
0.0, bk, ldAplus ) ;
} else {
// bk = ck^+
alglin::copy( nRow, ck, 1, bk, ldAplus ) ;
alglin::scal( nRow, 1/lenck/lenck, bk, ldAplus ) ;
}
// A^+_{k-1} -= dk^T*bk
alglin::ger( k, nRow, -1.0, dk, 1, bk, ldAplus, Aplus, ldAplus ) ;
}
}
}
A driver code
File: testGreville.cc:
#include <cmath>
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include "greville.hh"
#include "alglin.hh"
using namespace std ;
using namespace Greville ;
#define NROW 3
#define NCOL 2
int
main() {
valueType iA[NROW*NCOL], work[NROW+NCOL], B[NROW*NROW+NCOL*NCOL] ;
valueType A[NROW*NCOL] = { 2, 1, 0, 1, 1, 1 } ;
pseudoinverse( NROW, NCOL, A, NROW, iA, NCOL, work ) ;
alglin::gemm( "No Transpose", "No Transpose", NROW, NROW, NCOL, 1.0, A, NROW, iA, NCOL, 0.0, B, NROW ) ;
for ( indexType i = 0 ; i < NROW ; ++i ) {
for ( indexType j = 0 ; j < NROW ; ++j )
cout << "(A*iA)(" << i << "," << j << ") = " << B[i+NROW*j] << '\n' ;
cout << '\n' ;
}
alglin::gemm( "No Transpose", "No Transpose", NCOL, NCOL, NROW, 1.0, iA, NCOL, A, NROW, 0.0, B, NCOL ) ;
for ( indexType i = 0 ; i < NCOL ; ++i ) {
for ( indexType j = 0 ; j < NCOL ; ++j )
cout << "(iA*A)(" << i << "," << j << ") = " << B[i+NCOL*j] << '\n' ;
cout << '\n' ;
}
}
Course of Numerical Analysis (AA 2008/2009)
MATLAB lessons N.1
- Essential MATLAB commands: TutorialMatlab.pdf
MATLAB lessons N.2
A simple function used to test ode45
:
File: f.m:
% A comment is a line beginned with the '%' character
%
% Define the function f(x,y) = x^2 - y to be integrated
% by a numerical solver of MATLAB
%
% A function is defined by the keyword function
% followed by the prototype of the functions itself
function res = f( x, y )
res = x^2 - y ;
end
A simple function whise solution lie on a circle:
File: f1.m:
%
% function for the definition of the ODE system
%
% y1'=y2
% y2'=-y1
% y1(0)=1
% y2(0)=0
%
function res = f1( x, Y )
res = [ Y(2) ; -Y(1) ] ; % return a matrix with 2 row and 1 column
end
Another example of ODE:
File: f3.m:
%
% ODE:
% y'=v
% y'=exp(x)-v-y
%
function res = f3( x, Y )
% y = Y(1)
% v = Y(2)
res = [ Y(2) ; exp(x) - Y(1) - Y(2) ] ;
end
An exact solution to test the code:
File: exact.m:
%
% Exact solution for problem
%
% y'''(t) = -t - y(t)
% y(0) = y'(0) = 0
% y''(0) = 1
%
function res = exact( t )
res = -t + (2/sqrt(3))*exp(t/2).*sin((sqrt(3)/2)*t) ;
end
MATLAB lessons N.3
A simple implementation of Euler scheme:
File: Euler.m:
%
% This routine approximate the solution of the IVP (Initial Value Problem)
%
% / y' = f(t,y)
% |
% | y(a) = y[0]
% \
%
% PARAMETERS:
% FUN = reference to user defined function
% t0 = Starting integration time
% y0 = Initial data of the IVP
% h = time step
% N = number of step to be performed
%
% OUTPUT
% T = vector containing the nodes where
% the approximate solution is computed
% t = t0, t0+h, t0+3*h,..... t0+N*h
% Y = vector containing the approximate solution at nodes T, i.e
% Y(1) ~ y(t0),
% Y(2) ~ y(t0+h),
% Y(3) ~ y(t0+2*h),
% .....
% Y(N+1) ~ y(t0+N*h)
%
function [T,Y] = Euler( FUN, t0, y0, h, N )
% pre allcation of the output vector T and Y
T = zeros(N+1,1) ;
Y = zeros(N+1,1) ;
% set T(1) and Y(1) with the initial condition
T(1) = t0 ;
Y(1) = y0 ;
% loop performing the Euler Steps
for k=1:N
T(k+1) = T(k) + h ;
Y(k+1) = Y(k) + h * feval( FUN, T(k), Y(k) ) ;
% feval( FUN, T(k), Y(k) ) == FUN( T(k), Y(k) )
end
end
A simple ODE to test the code:
File: problem1.m:
%
% function for the IVP
%
% y' = -t*y
%
function dy = problem1( t, y )
dy = -t*y ;
end
MATLAB lessons N.4
A simple implementation of Euler scheme (vector form):
File: Euler.m:
%
% This routine approximate the solution of the IVP (Initial Value Problem)
%
% / y' = f(t,y)
% |
% | y(a) = y[0]
% \
%
% PARAMETERS:
% FUN = reference to user defined function
% t0 = Starting integration time
% y0 = Initial data of the IVP
% h = time step
% N = number of step to be performed
%
% OUTPUT
% T = vector containing the nodes where
% the approximate solution is computed
% t = t0, t0+h, t0+3*h,..... t0+N*h
% Y = matrix whose columsn containing the approximate solution at nodes T, i.e
% Y(:,1) ~ y(t0),
% Y(:,2) ~ y(t0+h),
% Y(:,3) ~ y(t0+2*h),
% .....
% Y(:,N+1) ~ y(t0+N*h)
%
function [T,Y] = Euler( FUN, t0, y0, h, N )
% pre allcation of the output vector T and Y
T = zeros(N+1,1) ;
Y = zeros(size(y0,1),N+1) ; % size(y0,1) number of rows of y0
% set T(1) and Y(1) with the initial condition
T(1) = t0 ;
Y(:,1) = y0 ; % Y(:,1) access the first column of matrix Y
% loop performing the Euler Steps
for k=1:N
T(k+1) = T(k) + h ;
Y(:,k+1) = Y(:,k) + h * feval( FUN, T(k), Y(:,k) ) ;
% feval( FUN, T(k), Y(k) ) == FUN( T(k), Y(k) )
end
end
A simple ODE to test the code:
File: problem1.m:
%
% function for the IVP
%
% x'(t) = -y(t)
% y'(t) = x(t)
%
% x(0) = 1
% y(0) = 0
%
% / x \
% Z = | |
% \ y /
%
function f = problem1( t, Z )
f = zeros(2,1) ; % allocate for a 2 elements column vector
f(1) = -Z(2) ;
f(2) = Z(1) ;
end
A simple implementation of Heun scheme (vector form):
File: Heun.m:
%
% This routine approximate the solution of the IVP (Initial Value Problem)
%
% / y' = f(t,y)
% |
% | y(a) = y[0]
% \
%
% PARAMETERS:
% FUN = reference to user defined function
% t0 = Starting integration time
% y0 = Initial data of the IVP
% h = time step
% N = number of step to be performed
%
% OUTPUT
% T = vector containing the nodes where
% the approximate solution is computed
% t = t0, t0+h, t0+3*h,..... t0+N*h
% Y = matrix whose columsn containing the approximate solution at nodes T, i.e
% Y(:,1) ~ y(t0),
% Y(:,2) ~ y(t0+h),
% Y(:,3) ~ y(t0+2*h),
% .....
% Y(:,N+1) ~ y(t0+N*h)
%
function [T,Y] = Heun( FUN, t0, y0, h, N )
% pre allcation of the output vector T and Y
T = zeros(N+1,1) ;
Y = zeros(size(y0,1),N+1) ; % size(y0,1) number of rows of y0
% set T(1) and Y(1) with the initial condition
T(1) = t0 ;
Y(:,1) = y0 ; % Y(:,1) access the first column of matrix Y
% loop performing the Euler Steps
for k=1:N
T(k+1) = T(k) + h ;
K1 = feval( FUN, T(k), Y(:,k) ) ;
ETA = Y(:,k) + h * K1 ; % Euler step y(k+1) = y(k) + h * f(t(k),y(k))
K2 = feval( FUN, T(k+1), ETA ) ;
Y(:,k+1) = Y(:,k) + (h/2) * (K1+K2) ; % Heun correction step
% y(k+1) = y(k) + (h/2) * (f(t(k),y(k))+f(t(k+1),y(k+1)))
end
end
A simple implementation of Runge Kutta oder 4 (vector form):
File: RK4.m:
%
% This routine approximate the solution of the IVP (Initial Value Problem)
%
% / y' = f(t,y)
% |
% | y(a) = y[0]
% \
%
% PARAMETERS:
% FUN = reference to user defined function
% t0 = Starting integration time
% y0 = Initial data of the IVP
% h = time step
% N = number of step to be performed
%
% OUTPUT
% T = vector containing the nodes where
% the approximate solution is computed
% t = t0, t0+h, t0+3*h,..... t0+N*h
% Y = matrix whose columsn containing the approximate solution at nodes T, i.e
% Y(:,1) ~ y(t0),
% Y(:,2) ~ y(t0+h),
% Y(:,3) ~ y(t0+2*h),
% .....
% Y(:,N+1) ~ y(t0+N*h)
%
function [T,Y] = RK4( FUN, t0, y0, h, N )
% pre allcation of the output vector T and Y
T = zeros(N+1,1) ;
Y = zeros(size(y0,1),N+1) ; % size(y0,1) number of rows of y0
% set T(1) and Y(1) with the initial condition
T(1) = t0 ;
Y(:,1) = y0 ; % Y(:,1) access the first column of matrix Y
% loop performing the Euler Steps
for k=1:N
T(k+1) = T(k) + h ;
K1 = feval( FUN, T(k), Y(:,k) ) ;
K2 = feval( FUN, T(k)+h/2, Y(:,k)+(h/2)*K1 ) ;
K3 = feval( FUN, T(k)+h/2, Y(:,k)+(h/2)*K2 ) ;
K4 = feval( FUN, T(k)+h, Y(:,k)+h*K3 ) ;
Y(:,k+1) = Y(:,k) + (h/6) * (K1+2*(K2+K3)+K4) ;
end
end
Exact solution to check the order:
File: exact1.m:
%
% exact solution for the IVP
%
% x'(t) = -y(t)
% y'(t) = x(t)
%
% x(0) = 1
% y(0) = 0
%
% / x \
% Z = | |
% \ y /
%
% x(t) = cos(t)
% y(t) = sin(t)
%
function Z = exact1( t )
Z = zeros(2,size(t,1)) ; % allocate for a 2 elements column vector
Z(1,:) = cos(t) ;
Z(2,:) = sin(t) ;
end
A simple script to check the order:
File: checkError.m:
%
% Compute approximate solution with a numerical scheme "METHOD"
% and compute numerically the order
%
function checkError( METHOD )
%
h = 0.1 ;
N = 100 ;
% compute approximate solution
t0 = 0 ;
y0 = [1;0] ;
[T,Y] = feval ( METHOD, @problem1, t0, y0, h, N ) ;
Z = exact1( T ) ;
E1 = max(max(abs(Y-Z))) ;
% h <- h/2 N <- 2*N
h = h/2 ;
N = N*2 ;
[T,Y] = feval ( METHOD, @problem1, t0, y0, h, N ) ;
Z = exact1( T ) ;
E2 = max(max(abs(Y-Z))) ;
% h <- h/2 N <- 2*N
h = h/2 ;
N = N*2 ;
[T,Y] = feval ( METHOD, @problem1, t0, y0, h, N ) ;
Z = exact1( T ) ;
E3 = max(max(abs(Y-Z))) ;
fprintf( 1, 'log(E1/E2)/log(2) = %f\n', log(E1/E2)/log(2) ) ;
fprintf( 1, 'log(E2/E3)/log(2) = %f\n', log(E2/E3)/log(2) ) ;
end
MATLAB lessons N.5
A simple implementation of Euler scheme (vector form):
File: BVPsolver.m:
%
% Solve the BVP of the form
%
% y'' + p y' + q y = r
% y(a) = ya, y(b)=yb
%
% with N subinterval.
%
% h = (b-a)/N
% x(k) = a + h*k,
% y(k) ~ y(a+h*k),
%
% p : reference of a function of one argument p(x)
% q : reference of a function of one argument q(x)
% r : reference of a function of one argument r(x)
%
% BCa : vector of two element [ a , y(a) ] with left BC
% BCb : vector of two element [ b , y(b) ] with ight BC
%
% N : number of subdivision of interval [a,b]
%
function [x,y] = BVPsolver( p, q, r, BCa, BCb, N )
% extract the boundary conditions
a = BCa(1) ;
b = BCb(1) ;
ya = BCa(2) ;
yb = BCb(2) ;
% fill x
h = (b-a)/N ;
x = a + h*[0:N]' ;
% fill the 3 diagonal of the linear system and the RHS
alpha = zeros( N-1, 1 ) ;
beta = zeros( N-1, 1 ) ;
gamma = zeros( N-1, 1 ) ;
omega = zeros( N-1, 1 ) ;
alpha = -2/h^2 + feval( q, x(2:end-1) ) ;
beta = 1/h^2 - feval( p, x(2:end-1) ) ./(2*h) ;
gamma = 1/h^2 + feval( p, x(2:end-1) ) ./(2*h) ;
omega = feval( r, x(2:end-1) ) ;
omega(1) = omega(1) - beta(1)*ya ;
omega(N-1) = omega(N-1) - gamma(N-1)*yb ;
% this is equivalent to the following loop
% for k=1:N-1
% alpha(k) = -2/h^2 + feval( q, x(k+1) ) ;
% beta(k) = 1/h^2 - feval( p, x(k+1) ) /(2*h) ;
% gamma(k) = 1/h^2 + feval( q, x(k+1) ) /(2*h) ;
% omega(k) = feval( r, x(2:end-1) ) ;
% end
% omega(1) = omega(1) - beta(1)*ya ;
% omega(N-1) = omega(N-1) - gamma(N-1)*yb ;
% fill the tridiagonal system
A = zeros( N-1, N-1 ) ;
A = diag(alpha,0) + diag(gamma(1:N-2),1) + diag( beta(2:N-1),-1) ;
% this is equivalent to the following loop
% for k=1:N-1
% A(k,k) = alpha(k) ;
% end
% for k=1:N-2
% A(k+1,k) = beta(k+1) ; % fill the lower diagonal
% A(k,k+1) = gamma(k) ; % fill the upper diagonal
% end
% fill the RHS
b = zeros( N-1, 1 ) ;
b = omega ;
% solve the linear system
sol = A\b ;
% fill the y
y = [ ya; sol; yb] ;
end
A simple BVP defined by the functions p1
, q1
, r1
to test the code:
File: p1.m:
function res = p1( x )
res = -x ;
end
File: r1.m:
function res = r1(x)
%res = 1 ;
res = ones(size(x)) ;
end
File: q1.m:
function res = q1(x)
%res = -1 ;
res = -ones(size(x)) ;
end
Exact solution to check the order:
File: exact1.m:
function res = exact1(x)
t1 = exp(0.5);
t3 = sqrt(2);
t5 = erf(t3 / 2);
t10 = erf(x .* t3 / 2);
t11 = x .^ 2;
t13 = exp(t11 / 2 - 1 / 2);
t17 = exp(t11 / 2);
res = t13 .* t10 ./ t5 .* (3 - t1) + t17 - 1 ;
end
A simple script to check the order:
File: checkerror.m:
BCa = [0;0] ;
BCb = [1;2] ;
N = [ 10, 20, 40, 80, 160, 320 ] ;
for i=1:length(N)
[x,y] = BVPsolver( @p1, @q1, @r1, BCa, BCb, N(i) );
err(i) = norm( y - exact1( x ), inf ) ;
end
for i=2:length(N)
h1 = 1/N(i-1) ;
h = 1/N(i) ;
p = log( err(i-1)/err(i) ) / log( h1/h ) ;
disp(p) ;
end
MATLAB lessons N.6
A simple implementation of Euler scheme (vector form):
File: BVPshoot.m:
%
% Solve the BVP of the form
%
% y'' + p y' + q y = r
% y(a) = ya, y(b) = yb
%
% with N subinterval and the shooting method
%
% h = (b-a)/N
% x(k) = a + h*k,
% y(k) ~ y(a+h*k),
%
% p : reference of a function of one argument p(x)
% q : reference of a function of one argument q(x)
% r : reference of a function of one argument r(x)
%
% BCa : vector of two element [ a , ya ] with left BC
% BCb : vector of two element [ b , yb ] with ight BC
%
% N : number of subdivision of interval [a,b]
%
function [x,y] = BVPshoot( p, q, r, BCa, BCb, N )
global pFunction qFunction rFunction ; % store problem in global variables
pFunction = p ;
qFunction = q ;
rFunction = r ;
% extract the boundary conditions
a = BCa(1) ;
b = BCb(1) ;
ya = BCa(2) ;
yb = BCb(2) ;
% fill x
h = (b-a)/N ;
x = a + h*[0:N]' ;
% first problem y(a) = ya, y'(a) = 0
[x1,z] = ode45(@localOde1,x,[ya;0]) ;
% second problem y(a) = 0, y'(a) = 1 and with r=0
[x2,w] = ode45(@localOde2,x,[0;1]) ;
% lambda for the linear combination solution
lambda = (yb - z(end,1))/w(end,1) ;
% fill the y
y = z(:,1)+lambda*w(:,1) ;
end
%
% Transformation of the second oder ODE
%
% y''(x) + p(x) y'(x) + q(x) y(x) = r(x)
%
% To a first order ODE (system)
%
% y'(x) = v(x)
% v'(x) = r(x) - p(x) v(x) - q(x) y(x)
%
% / y(x) \
% The vector Z(x) = | |
% \ v(x) /
%
function dZ = localOde1( x, Z )
global pFunction qFunction rFunction ;
dZ = [ Z(2) ; ...
feval(rFunction,x) ...
- feval(pFunction,x) *Z(2) ...
- feval(qFunction,x) * Z(1) ] ;
end
%
% Transformation of the second oder ODE
%
% y''(x) + p(x) y'(x) + q(x) y(x) = 0
%
% To a first order ODE (system)
%
% y'(x) = v(x)
% v'(x) = - p(x) v(x) - q(x) y(x)
%
% / y(x) \
% The vector Z(x) = | |
% \ v(x) /
%
function dZ = localOde2( x, Z )
global pFunction qFunction rFunction ;
dZ = [ Z(2) ; ...
- feval(pFunction,x) *Z(2) ...
- feval(qFunction,x) * Z(1) ] ;
end
A simple BVP defined by the functions p1
, q1
, r1
to test the code:
File: p1.m:
function res = p1( x )
res = -x ;
end
File: q1.m:
function res = q1(x)
%res = -1 ;
res = -ones(size(x)) ;
end
File: r1.m:
function res = r1(x)
%res = 1 ;
res = ones(size(x)) ;
end
Exact solution to check the order:
File: exact1.m:
function res = exact1(x)
C1 = (3*exp(-0.5) - 1) / erf( 1/sqrt(2)) ;
res = -1 + ( 1 + C1 * erf( x ./ sqrt(2) ) ) .* exp( (x.^2) ./ 2 ) ;
end
A simple script to check the order:
File: checkError.m:
BCa = [0;0] ;
BCb = [1;2] ;
N = [ 10, 20, 40, 80, 160, 320, 640];%, 10000, 50000, 100000 ] ;
for i=1:length(N)
[x,y] = BVPshoot( @p1, @q1, @r1, BCa, BCb, N(i) );
err(i) = norm( y - exact1( x ), inf ) ;
disp( sprintf( 'error = %g\n', err(i) ) ) ;
end
MATLAB lessons N.7 and N.8
An implementation of ADER2 numerical flux:
File: ADER2Flux.m:
%
% Compute Ader Flux
%
function [F,S] = ADER2Flux( Q, ...
Xnodes, ...
DT, ...
Flux, ...
SlopeLimiter, ...
Leading0, ...
Leading1, ...
Source )
nr = size(Q,1) ;
DX = Xnodes(2)-Xnodes(1) ;
% Reconstruct phase
% construct limited slopes (given N+2 averages return N slopes)
DQ = feval( SlopeLimiter, Q ) ;
% extrapolate from the left
QL = Q(:,2:end-2) + DQ(:,1:end-1)./2 ;
% extrapolate from the right
QR = Q(:,3:end-1) - DQ(:,2:end)./2 ;
% compute slopes
DELTA = DQ ./ DX ;
% left slopes
DELTAL = DELTA(:,1:end-1) ;
% right slopes
DELTAR = DELTA(:,2:end) ;
% End of Reconstruct phase
% Compute leading term
D0 = Leading0( QL, QR ) ;
D1 = Leading1( DELTAL, DELTAR, D0 ) ;
% End Compute leading term
% Evaluate ADER2 state
D0L = D0 - D1 ./2 ;
D0R = D0 + D1 ./2 ;
%
% In order to eliminate the loop
%
%Qader = D0 ;
%for k=1:size(Qader,2)
% A0 = feval( JFlux, D0(:,k) ) ;
% Qader(:,k) = Qader(:,k) + (DT/2) * (feval(Source, D0(:,k)) - A0 * D1(:,k)) ;
%end
%
% The second order approxination A0 * D1 ~ Flux( D0+D1/2 ) - Flux(D0-D1/2)
%
Qader = D0 + (DT/2) * ( feval( Source, D0 ) - feval( Flux, D0R ) + feval( Flux, D0L ) ) ;
F = feval( Flux, Qader) ;
% End Evaluate numerical flux
% Evaluate source
Qs = Q(:,3:end-2) ; % consider only "true" cells
DD = DELTA(:,2:end-1) ./2 ; % consider only half of the slope of "true" cells
%
% In order to eliminate the loop
%
% for k=1:size(Qs,2)
% Qs(:,k) = Qs(:,k) + (DT/2) * ( feval( Source, Qs(:,k) ) - feval( JFlux, Qs(:,k) )*DELTA(:,k+1) ) ;
% end
%
% The second order approxination JFlux(Qs) DELTA = Flux( Qs+DELTA/2 ) - Flux(Qs-DELTA/2)
%
DL = Qs - DD ;
DR = Qs + DD ;
Qs = Qs + (DT/2) * ( feval( Source, Qs ) - feval( Flux, DR ) + feval( Flux, DL ) ) ;
S = feval( Source, Qs ) ;
% End Evaluate source
end
A generic advancing algorithm for hyperbolic problem:
File: Advancing.m:
% General Advancing procedure used to test numerical solver for hyperbolic equations
%
% Name of program: Advancing
%
% Developed by: Enrico Bertolazzi
% Department of Mechanical and Structural Engineering
% enrico.bertolazzi@ing.unitn.it
% http://www.ing.unitn.it/~bertolaz/
%
% Last revision: 2 June 2009
%
% INPUTS:
%
% Qinit = initial cell average values
% Xnodes = boundary of the cells
% InitialTime = starting simulation time
% FinalTime = end of simulation time
% StepTime = the time difference at which the solution is saved
% CFLratio = the Courant–Friedrichs–Lewy ratio at which the solver can advance
%
% maxSpeed = function with one vector argument which compute maximum speed signal for each cell.
% Usage: feval( maxSpeed, Q ).
%
% doStep = function which perform step of the numerical scheme
% Usage: feval( doStep, Time, DT, DX, XC, Q ).
% Time = Actual time
% DT = advancing time step
% DX = cells size
% XC = cells center
% Q = cells actual state
%
% OUTPUTS:
%
% Tframes = vector with the time values of saved frame
% Qframes = cell array with the solution frames computed
% Qframes{1} = contains the solution at time Tframes(1)
% Qframes{2} = contains the solution at time Tframes(2)
%
% ...
%
% Qframes{end} = contains the solution at time Tframes(end)
%
function [ Qframes, Tframes ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
maxSpeed, ...
doStep )
% Initial conditions are copied in the vector Q
Q = Qinit ;
% Compute cell size DX, the size of the cells are assumed all equals.
DX = Xnodes(2) - Xnodes(1) ;
% save initial frame
Qframes{1} = Q ;
Tframes(1) = InitialTime ;
kframe = 1 ; % number of saved framed
Time = InitialTime ; % initial time
NextTime = InitialTime + StepTime ; % Time to save next frame
% Time marching procedure, a maximum of 10000 steps are allowed
for NITER=1:10000
% Courant-Friedrichs-Lewy (CFL) condition imposed
DT = CFLratio * DX / max( feval( maxSpeed, Q ) ) ;
% reduce DT if necessary for the last step
if Time+DT >= FinalTime
DT = FinalTime - Time ;
% perform last step
Q = feval( doStep, Time, DT, Xnodes, Q ) ;
% save last frame
kframe = kframe+1 ;
Qframes{kframe} = Q ;
Tframes(kframe) = FinalTime ;
% exit loop
break ;
end
% adjust time step if necessary to match the time grid
DT1 = NextTime - Time ;
while DT >= DT1 % if DT contains a grid step perform smaller step
% perform step
Qnew = feval( doStep, Time, DT1, Xnodes, Q ) ;
% Solution frame is saved
kframe = kframe+1 ;
Qframes{kframe} = Qnew ;
Tframes(kframe) = NextTime ;
% check if we have reached the final mesh point
if FinalTime < NextTime
break ;
end ;
% update next time frame
NextTime = NextTime + StepTime ;
DT1 = NextTime - Time ;
end
% perform step
Q = feval( doStep, Time, DT, Xnodes, Q ) ;
% update time
Time = Time + DT ;
end
end
Utility routine for good plotting of average values:
File: buildXYForPlot.m:
% Name of program: buildXYForPlot
%
% Developed by: Enrico Bertolazzi
% Department of Mechanical and Structural Engineering
% enrico.bertolazzi@ing.unitn.it
% http://www.ing.unitn.it/~bertolaz/
%
% Last revision: 2 June 2009
%
% Given a vector CB of cells boundary edges and a vector Q of cell average values
% build the vectos x and y which can be used to plot the piecewise constant function
% which represents the solution
%
% INPUT
% Xnodes: cells boundary (row vector)
% Q: cell average value
%
% OUTPUT
% X: x-coordinate
% Y:
%
% +------+------+
% | | | +------+
% +------+ | | | |
% | | | +------+ |
% | Q(1) | Q(2) | Q(3) | Q(4) | |
% | | | | | |
% CB(1) CB(2) CB(3)
%
% Last revision: 2 June 2009
%
function [X,Y] = buildXYForPlot( Xnodes, Q )
% allocate memory
N = size(Q,2) ;
X = zeros( 1, 2*N ) ;
Y = zeros( size(Q,1), 2*N ) ;
X(1:2:2*N-1) = Xnodes(1:end-1) ;
X(2:2:2*N) = Xnodes(2:end) ;
Y(:,1:2:2*N-1) = Q ;
Y(:,2:2:2*N) = Q ;
end
An implementation of minmid slope limiter:
File: WENOSlopeLimiter.m:
% Given average states compute WENO limited slopes
%
% Name of program: WENOSlopeLimiter.m
%
% Developed by: Enrico Bertolazzi
% Department of Mechanical and Structural Engineering
% enrico.bertolazzi@ing.unitn.it
% http://www.ing.unitn.it/~bertolaz/
%
% This code is inspired on the library
% NUMERICA
% A Library of Source Codes for Teaching,
% Research and Applications,
% by E. F. Toro
% Published by NUMERITEK LTD,
% Website: www.numeritek.coM
%
% The algorithm are described in the book:
%
% E. F. Toro, "Riemann Solvers and Numerical Methods for Fluid Dynamics"
% Springer-Verlag, 1997, Second Edition, 1999
%
% Last revision: 27 May 2009
%
% The scheme can be visualized in the following way
%
% +===+ The cell where the average value Qi is "stored".
%
% +...+ Ghost cell. These cells are used to extrapolate values for the
% construction of the bounary conditions. Two ghost cell for boundary
% are enough for all the considered fluxes.
%
% +xxx+ Uncomputed values. These cells do not cotains valid values.
% Are used to avoid shifting of indices or complex indicization.
%
% Averages states
%
% +...+...+===+===+===+===+=== ===+===+...+...+
% Q1 Q2 Q3 QN+4
%
% Limited slopes, the slopes S1 and SN+4 are not computed (indeed it is not possible)
%
% +xxx+===+===+===+===+===+=== ===+===+===+xxx+
% S1 S2 S3 SN+1
%
% INPUTS:
%
% Q = average values
%
% OUTPUTS:
%
% SLOPE = limited slopes
%
% The slopes are built by finite difference of sucessive averages.
% In this way slopes associated to interfaces are used to copute cell slopes.
% The slopes associated to a cell is the minimum slope between the two interface slopes.
%
function DELTA = WENOSlopeLimiter( Q )
% compute interface slopes, SLOPE(k) is the slopes of interface between cell k and k+1
SLOPE = Q(:,2:end) - Q(:,1:end-1) ;
% left slopes
LSLOPE = SLOPE(:,1:end-1);
% right slopes
RSLOPE = SLOPE(:,2:end);
% find minimum slopes
DELTA = minmod( LSLOPE, RSLOPE ) ;
% is equivalent to the loop
%
% for k=1:lenght(SLOPE)
% if abs(LSLOPE(k)) < abs(RSLOPE(k))
% SLOPE(k) = LSLOPE(k);
% else
% SLOPE(k) = RSLOPE(k);
% end
% end
end
%
% given the vector (matrix) a and b return
% res(k) = sign(a)*min(abs(a(k)),abs(b(k))) if a(k)*b(k)>0
% res(k) = 0 otherwise
%
function res = minmod( a, b )
res = zeros( size(a) ) ;
I1 = find( a > 0 & b > 0 ) ;
I2 = find( a < 0 & b < 0 ) ;
I3 = find( a.*b <= 0 ) ;
res(I1) = min(a(I1),b(I1)) ;
res(I2) = max(a(I2),b(I2)) ;
res(I3) = 0 ;
end
Test Ader2 for linear transport equation:
File: TestAder2LinearTransport.m:
% Test Advancing routine by solving the problem
%
% Q(x,t) + Q(x,t) = 0 -1 <= x <= 1
% t x
%
% /
% | 0 if x < -1/2
% Q(x,0) = | 1 if x > -1/2 and x < 1/2
% | 0 if x > 1/2
% \
% +---+
% | |
% ---------+ +----------
%
% Cyclic boundary conditions
%
% Last revision: 28 May 2009
%
function TestAder2LinearTransport
N = 100 ; % number of cells
N4 = N/4 ;
% setup intial conditions
Qinit = [ zeros(1,N4) ones(1,N-2*N4) zeros(1,N4) ] ;
% setup the boundary of the cells
Xnodes = -1:2/N:1 ;
% initial time and time step
InitialTime = 0 ;
FinalTime = 20 ;
StepTime = 0.1 ;
CFLratio = 0.95 ;
[ Qframes, Tframes ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepADER2 ) ;
[ Qframes1, Tframes1 ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepGodunov ) ;
% plot the solution at final time step
[XX,YY] = buildXYForPlot( Xnodes, Qframes{end} ) ;
[X1,Y1] = buildXYForPlot( Xnodes, Qframes1{end} ) ;
plot( XX, YY, X1, Y1 ) ;
end
%
% Return a vector with the maximum speed of each cell
%
function SPEED = maxSpeed( Q )
SPEED = ones(size(Q)) ;
end
%
% Flux for linear transport
%
function F = Flux( Q )
F = Q ;
end
%
% Jacobians of the flux (vectorial form)
%
function A = JFlux( Q )
A = ones(size(Q)) ;
end
%
% Solve the Riemann problem for the linear transport equation exactly.
%
function USTAR = Riemann(UL, UR)
USTAR = UL ;
end
function S = Source( Q )
S = zeros(size(Q)) ;
end
function D0 = Leading0( QL, QR )
D0 = Riemann(QL,QR) ;
end
function D1 = Leading1( DL, DR, D0 )
D1 = Riemann(DL, DR) ;
end
%
% Advancing with ADER2 numerical scheme
%
function Qnew = doStepADER2( Time, DT, Xnodes, Q )
% extrapolation
Qe = [ Q(:,end-1) Q(:,end) Q Q(:,1) Q(:,2) ] ;
[F,S] = ADER2Flux( Qe, Xnodes, DT, @Flux, @WENOSlopeLimiter, @Leading0, @Leading1, @Source ) ;
DX = Xnodes(2)-Xnodes(1) ;
Qnew = Q - (DT/DX) .* ( F(:,2:end) - F(:,1:end-1) ) + DT * S ;
end
%
% Advancing with simple Godunov numerical scheme
%
function Qnew = doStepGodunov( Time, DT, Xnodes, Q )
% extrapolation (with only one ghost cell by side)
Qe = [ Q(:,end) Q Q(:,1) ] ;
% reconstruction no needed
% compute numerical flux
QL = Qe(:,1:end-1) ; % cell on the left
QR = Qe(:,2:end) ; % cell on the right
QSTAR = Riemann(QL, QR) ;
F = Flux(QSTAR) ;
S = Source(Q) ;
DX = Xnodes(2) - Xnodes(1) ; % cells are assumed all of equal size
Qnew = Q - (DT/DX) .* ( F(2:end) - F(1:end-1) ) + DT * S ;
end
Test Ader2 for Burger equation:
File: TestAder2Burger.m:
% Test Advancing routine by solving the problem
%
% Q (x,t) + Q(x,t) Q (x,t) = 0 -pi <= x <= pi
% t x
%
% Q(x,0) = 1+sin(x)
%
% Cyclic boundary conditions
%
% Last revision: 28 May 2009
%
function TestAder2Burger
N = 100 ; % number of cells
% setup the boundary of the cells
DX = 2*pi/N ;
Xnodes = [-pi:DX:pi] ;
% setup intial conditions
Xc = (Xnodes(1:end-1)+Xnodes(2:end))/2 ; % center of the cells
Qinit = 1+sin(Xc) ;
% initial time and time step
InitialTime = 0 ;
FinalTime = 10 ;
StepTime = 0.1 ;
CFLratio = 0.9 ;
[ Qframes, Tframes ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepADER2 ) ;
[ Qframes1, Tframes1 ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepGodunov ) ;
% plot the solution at final time step
[XX,YY] = buildXYForPlot( Xnodes, Qframes{end} ) ;
[X1,Y1] = buildXYForPlot( Xnodes, Qframes1{end} ) ;
plot( XX, YY, X1, Y1 ) ;
end
%
% Return a vector with the maximum speed of each cell
%
function SPEED = maxSpeed( Q )
SPEED = abs(Q) ;
end
function A = JFlux( Q )
A = Q ;
end
function F = Flux( Q )
F = (Q .* Q) ./ 2 ;
end
%
% Solve the Riemann problem for the inviscid Burgers equation exactly.
%
function USTAR = Riemann(UL, UR)
% UL Left data state
% UR Right data state
% S Shock speed
% USTAR Sampled state
ISW = find ( UL < UR ) ;
IRW = find ( UL >= UR ) ;
% Solution is a shock wave
% Compute shock speed S
S(ISW) = 0.5*(UL(ISW) + UR(ISW)) ;
% Sample the state along the t-axis
IGE = find( S(ISW) >= 0 ) ;
ILT = find( S(ISW) < 0 ) ;
USTAR(IGE) = UL(IGE) ;
USTAR(ILT) = UR(ILT) ;
% Solution is a rarefaction wave.
% There are 3 cases:
I1 = find( UL >= 0 ) ;
I2 = find( UR <= 0 ) ;
I3 = find( UL < 0 & UR > 0 ) ;
USTAR(I1) = UL(I1) ; % Right supersonic rarefaction
USTAR(I2) = UR(I2) ; % Left supersonic rarefaction
USTAR(I3) = 0 ; % Transonic rarefaction
end
function S = Source( Q )
S = zeros(size(Q)) ;
end
function D0 = Leading0( QL, QR )
D0 = Riemann(QL,QR) ;
end
function D1 = Leading1( QL, QR, D0 )
D1 = zeros(size(QL)) ;
I1 = find( D0 > 0 ) ;
I2 = find( D0 <= 0 ) ;
D1(I1) = QL(I1) ;
D1(I2) = QR(I2) ;
%for k=1:size(QL,2)
% D1(k) = LinearRiemannProblem( QL(k), QR(k), A(k) ) ;
%end
end
%
% Advancing with simple Godunov numerical scheme
%
function Qnew = doStepADER2( Time, DT, Xnodes, Q )
% extrapolation
Qe = [ Q(:,end-1) Q(:,end) Q Q(:,1) Q(:,2) ] ;
[F,S] = ADER2Flux( Qe, Xnodes, DT, @Flux, @WENOSlopeLimiter, @Leading0, @Leading1, @Source ) ;
DX = Xnodes(2)-Xnodes(1) ;
Qnew = Q - (DT/DX) .* ( F(:,2:end) - F(:,1:end-1) ) + DT * S ;
end
%
% Advancing with simple Godunov numerical scheme
%
function Qnew = doStepGodunov( Time, DT, Xnodes, Q )
% extrapolation (with only one ghost cell by side)
Qe = [ Q(end) Q Q(1) ] ;
% reconstruction no needed
% compute numerical flux
QL = Qe(1:end-1) ; % cell on the left
QR = Qe(2:end) ; % cell on the right
QSTAR = Riemann(QL, QR) ;
F = Flux( QSTAR ) ;
DX = Xnodes(2) - Xnodes(1) ; % cells are assumed all of equal size
Qnew = Q - (DT/DX) .* ( F(2:end) - F(1:end-1) ) ;
end
Test Ader2 for a 2D linear hyperbolic equation:
File: TestAder2.m:
% Test Advancing routine by solving the problem
%
% Q (x,t) + A Q (x,t) = 0 -1 <= x <= 1
% t x
%
% /
% | [0;0] if x < -1/2
% Q(x,0) = | [1;2] if x > -1/2 and x < 1/2
% | [0;0] if x > 1/2
% \
% +---+
% | |
% ---------+ +----------
%
% Cyclic boundary conditions
%
% Last revision: 28 May 2009
%
function TestAder2
global A_jacobian ;
A_jacobian = [ 0 1 ; 1 0 ] ;
N = 100 ; % number of cells
N4 = N/4 ;
% setup intial conditions
Qinit = [ zeros(2,N4) [1;2]*ones(1,N-2*N4) zeros(2,N4) ] ;
% setup the boundary of the cells
Xnodes = -1:2/N:1 ;
% initial time and time step
InitialTime = 0 ;
FinalTime = 6.3 ;
StepTime = 0.1 ;
CFLratio = 0.9 ;
[ Qframes, Tframes ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepADER2 ) ;
[ Qframes1, Tframes1 ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepGodunov ) ;
% plot the solution at final time step
[XX,YY] = buildXYForPlot( Xnodes, Qframes{end} ) ;
[X1,Y1] = buildXYForPlot( Xnodes, Qframes1{end} ) ;
plot( XX, YY, X1, Y1 ) ;
end
%
% Return a vector with the maximum speed of each cell
%
function SPEED = maxSpeed( Q )
SPEED = ones(1,size(Q,2)) ;
end
function F = Flux( Q )
F = JFlux( Q ) * Q ;
end
function A = JFlux( Q )
global A_jacobian ;
A = A_jacobian ;
end
function S = Source( Q )
S = zeros(size(Q)) ;
end
function D0 = Leading0( QL, QR )
global A_jacobian ;
D0 = LinearRiemannProblem( QL, QR, A_jacobian ) ;
end
function D1 = Leading1( QL, QR, D0 )
global A_jacobian ;
D1 = LinearRiemannProblem( QL, QR, A_jacobian ) ;
end
%
% Advancing with simple Godunov numerical scheme
%
function Qnew = doStepADER2( Time, DT, Xnodes, Q )
% extrapolation
Qe = [ Q(:,end-1) Q(:,end) Q Q(:,1) Q(:,2) ] ;
[F,S] = ADER2Flux( Qe, Xnodes, DT, @Flux, @WENOSlopeLimiter, @Leading0, @Leading1, @Source ) ;
DX = Xnodes(2)-Xnodes(1) ;
Qnew = Q - (DT/DX) .* ( F(:,2:end) - F(:,1:end-1) ) + DT * S ;
end
%
% Advancing with simple Godunov numerical scheme
%
function Qnew = doStepGodunov( Time, DT, Xnodes, Q )
% extrapolation (with only one ghost cell by side)
Qe = [ Q(:,end) Q Q(:,1) ] ;
% reconstruction no needed
% compute numerical flux
QL = Qe(:,1:end-1) ; % cell on the left
QR = Qe(:,2:end) ; % cell on the right
QSTAR = Leading0(QL, QR) ;
F = Flux( QSTAR ) ;
DX = Xnodes(2) - Xnodes(1) ; % cells are assumed all of equal size
Qnew = Q - (DT/DX) .* ( F(:,2:end) - F(:,1:end-1) ) ;
end
Check the second order of Ader2 numerical flux:
File: TestAder2Order.m:
% Test ADER2 by solving the problem
%
% Q(x,t) + Q(x,t) = 0 -1 <= x <= 1
% t x
%
% Q(x,0) = 1+sin(x)
%
% With Cyclic boundary conditions
%
% Last revision: 28 May 2009
%
function TestAder2Order
NN = [ 50 100 200 400 800 ] ;
for k=1:4
N = NN(k) ;% number of cells
% setup the boundary of the cells
DX = 2*pi/N ;
Xnodes = [-pi:DX:pi] ;
% setup intial conditions
Xc = (Xnodes(1:end-1)+Xnodes(2:end))/2 ; % center of the cells
Qinit = Q0(Xc) ;
% initial time and time step
InitialTime = 0 ;
FinalTime = 20 ;
StepTime = 1 ;
CFLratio = 0.95 ;
Qesatta = Q0(Xc - 20) ;
[ Qframes, Tframes ] = Advancing( Qinit, ...
Xnodes, ...
InitialTime, ...
FinalTime, ...
StepTime, ...
CFLratio, ...
@maxSpeed, ...
@doStepADER2 ) ;
% plot the solution at final time step
[XX,YY] = buildXYForPlot( Xnodes, Qframes{end} ) ;
[X1,Y1] = buildXYForPlot( Xnodes, Qesatta ) ;
plot( XX, YY, X1, Y1) ;
err(k) = max(abs(YY-Y1)) ;
disp( sprintf( 'Errore %g', err(k) ) ) ;
end
disp( sprintf( 'Order %g', log(err(1)/err(2))/log(2) ) ) ;
disp( sprintf( 'Order %g', log(err(2)/err(3))/log(2) ) ) ;
disp( sprintf( 'Order %g', log(err(3)/err(4))/log(2) ) ) ;
end
%
%
%
function Q = Q0( Xc )
Q = 1+sin(Xc) ;
end
%
% Return a vector with the maximum speed of each cell
%
function SPEED = maxSpeed( Q )
SPEED = ones(size(Q)) ;
end
%
% Flux for linear transport
%
function F = Flux( Q )
F = Q ;
end
%
% Jacobians of the flux (vectorial form)
%
function A = JFlux( Q )
A = ones(size(Q)) ;
end
%
% Solve the Riemann problem for the linear transport equation exactly.
%
function USTAR = Riemann(UL, UR)
USTAR = UL ;
end
function S = Source( Q )
S = zeros(size(Q)) ;
end
function D0 = Leading0( QL, QR )
D0 = Riemann(QL,QR) ;
end
function D1 = Leading1( DL, DR, D0 )
D1 = Riemann(DL, DR) ;
end
%
% Given average states compute unlimited slopes
%
% INPUTS:
%
% Q = average values
%
% OUTPUTS:
%
% DELTA = slopes
%
% The slopes are built by finite difference of sucessive averages.
% In this way slopes associated to interfaces are used to copute cell slopes.
% The slopes associated to a cell is the minimum slope between the two interface slopes.
%
function DELTA = SlopeNoLimiter( Q )
% compute interface slopes, SLOPE(k) is the slopes of interface between cell k and k+1
DELTA = (Q(:,3:end) - Q(:,1:end-2))./2 ;
end
%
% given the vector (matrix) a and b return
% res(k) = sign(a)*min(abs(a(k)),abs(b(k))) if a(k)*b(k)>0
% res(k) = 0 otherwise
%
function res = minmod( a, b )
res = zeros( size(a) ) ;
I1 = find( a > 0 & b > 0 ) ;
I2 = find( a < 0 & b < 0 ) ;
I3 = find( a.*b <= 0 ) ;
res(I1) = min(a(I1),b(I1)) ;
res(I2) = max(a(I2),b(I2)) ;
res(I3) = 0 ;
end
%
% Advancing with ADER2 numerical scheme
%
function Qnew = doStepADER2( Time, DT, Xnodes, Q )
% extrapolation
Qe = [ Q(:,end-1) Q(:,end) Q Q(:,1) Q(:,2) ] ;
[F,S] = ADER2Flux( Qe, Xnodes, DT, @Flux, @SlopeNoLimiter, @Leading0, @Leading1, @Source ) ;
DX = Xnodes(2)-Xnodes(1) ;
Qnew = Q - (DT/DX) .* ( F(:,2:end) - F(:,1:end-1) ) + DT * S ;
end
9th February 2009
Text of the exam lm-tel-feb09.pdf
11th January 2009
Text of the exam ls-tel-jan09.pdf
8th July 2008
Text of the exam ls-tel-july08.pdf
24th July 2008
Text of the exam ls-tel-july24-08.pdf
Part I: Ordinary Differential Equations: project1.pdf
Corso di Metodi Matematici e Calcolo per Ingegneria (AA 2008/2009)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 13:30 - 16:30 | T4 |
Giovedì | 8.30 - 10.30 | R1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11 - 12 | 505 |
Giovedì | 11 - 12 | 505 |
Dispense del corso
Prontuario
Prontuario per l’esame: download
Lucidi sulla trasformata di Laplace
La trasformata di Laplace
versione a schermo slides-laplace-1x1.pdf
versione stampabile 2 lucidi per foglio slides-laplace-1x2.pdf
versione stampabile 4 lucidi per foglio slides-laplace-2x2.pdf
Inversione della trasformata di Laplace
versione a schermo slides-invlaplace-1x1.pdf
versione stampabile 2 lucidi per foglio slides-invlaplace-1x2.pdf
versione stampabile 4 lucidi per foglio slides-invlaplace-2x2.pdf
Lucidi sulla trasformata Z
La trasformata Z
versione a schermo slides-Z-1x1.pdf
versione stampabile 2 lucidi per foglio slides-Z-1x2.pdf
versione stampabile 4 lucidi per foglio slides-Z-2x2.pdf
Problema degli indiani Natchez:
Testo natchez.pdf preso dalla homepage del prof. Lorenzo Farina url (nel 2005) risolto con MAPLE e la trasformata Z natchez.mw.zip
Problema del boundary layer risolto con MAPLE e la trasformata Z
Lucidi sulla serie di Fourier
La serie di Fourier
versione a schermo slides-Fourier-1x1.pdf
versione stampabile 2 lucidi per foglio slides-Fourier-1x2.pdf
versione stampabile 4 lucidi per foglio slides-Fourier-2x2.pdf
Lucidi sui minimi vincolati
Minimi vincolati
versione a schermo slides-Minimi-1x1.pdf
versione stampabile 2 lucidi per foglio slides-Minimi-1x2.pdf
versione stampabile 4 lucidi per foglio slides-Minimi-2x2.pdf
Problema della massima dissipazione su una resistenza risolto con MAPLE e condizioni KKT
Problema del minimo costo di un bidone risolto con MAPLE e condizioni KKT
Lucidi sulle DAE
Approssimazione Numerica delle DAE
versione a schermo slides-DAE-1x1.pdf
versione stampabile 2 lucidi per foglio slides-DAE-1x2.pdf
versione stampabile 4 lucidi per foglio slides-DAE-2x2.pdf
Minidispensa sui numeri complessi
Esami svolti
Appello 15 gennaio 2009
- Testo dell’appello (con soluzioni) mmci-2009-01-15.pdf
Appello 6 febbraio 2009
- Testo dell’appello (con soluzioni) mmci-2009-02-06.pdf
Appello 23 giugno 2009
- Testo dell’appello (con soluzioni) mmci-2009-06-23.pdf
Appello 27 luglio 2009
- Testo dell’appello (con soluzioni) mmci-2009-07-27.pdf
Appello 11 settembre 2009
- Testo dell’appello (con soluzioni) in formato PDF: mmci-2009-09-11.pdf
P.h.D. Course of Scientific Programming in C++ (AA 2008/2009)
Suggested lectures
Bruce Eckel’s Free Electronic Books:
C++ Annotations
Some useful links
A small tutorial on Sturm Theorem (in italian)
The tutorial sturm.pdf
Lesson of 7 July 2009
Some simple C programs
A minimal program
File: example1.cc:
/*
A multiline comment.
*/
// a single line comment
/*
A simple program that write "ciao mamma" to the console
*/
#include "myinclude.h"
#include <stdio.h>
int // the return type of the main function
main() { // main is the entry point of the executable
printf("ciao mamma\n") ; // \n is the new line character
return 0 ; // exit from the program, all thing go well
}
Example of types and keyrowds of C
File: example2.cc:
/*
Introduction to the type of C
*/
#include <stdio.h>
int // the return type of the main function
main() { // main is the entry point of the executable
int a, b, c ; // declare the variable a, b and c as of integer type (normally 4 byte)
short int a1, b1, c1 ; // declare the variable a1, b1 and c1 as of short integer type (normally 2 byte)
long int a2, b2, c2 ; // declare the variable a2, b2 and c2 as of long integer type (normally 4 or 8 byte)
float C ; // declare C as a single precision variable (4 byte normally)
double D ; // declare D as a double precision variable (8 byte normally)
char a3, a4 ; // declare a3 and a4 as charater (1 byte)
unsigned short int aa, bb, cc ; // declare the variable aa, bb and cc
// as of short integer type without sign (normally 2 byte)
// the prefix short and long can be used to define the size of integer
// the prefix signed, unsigned can be used for int and char
;;;;;; // ; is a separation characted ;; separate EMPTY instructions
printf("ciao mamma\n") ; // \n is the new line character
// some instruction for conditional execution
C = 1.0 ;
D = 1.3 ;
if ( C == D )
printf( "C and D are equal\n" );
else
printf( "C and D are NOT equal\n" );
if ( C = D ) printf( "C = D is true but it is really false!\n" ) ;
// some loop intruction
int i=10 ; // declare i as intger and initialize to 10
// while ( expr ) intruction ;
// when expr is different from 0 or true execute "intruction"
while ( --i ) printf( "%d\n", i ) ;
// --i means i = i-1 the operation is performed before the value of i is used
i = 10 ; // re-initialize i to 10
while ( i-- ) printf( "%d\n", i ) ;
// i-- means i = i-1 the operation is performed after the value of i is used
// for ( init ; expr ; incr ) instruction ;
// is equivalent to
// init ; // executed only one time at the beginning
// while ( expr ) { intruction ; incr }
//
// the
// while(expr) instr ;
// loop is equivalent to
// for ( ; expr ; ) instr ;
//
// infinite loop
// while (1) expr ;
// for (;;) expr ;
for ( int j = 1 ; j < 10 ; j *= 2 ) { // j *= 2 ==> j = j*2 ;
// in general res OP= expr ==> res = res OP expr
// where OP can be + - / * ~ | &
printf( "for loop, i = %10d\n", j) ;
}
// do { ... } while () is near the same of while loop
//
unsigned ii=10 ;
do {
printf( "do while loop i = %u\n", ii ) ;
} while ( --ii > 0 ) ;
// the last conditional instruction is switch
//
// switch ( integer expressin ) {
// case NUMBER:
// inst ;
// ....
// inst ;
// [ break ; ]
// case NUMBER:
// inst ;
// ....
// inst ;
// [ break ; ]
// ....
// [ default: ]
// inst ;
// ....
// inst ;
// [ break ; ]
// }
//
for ( i=0 ; i < 10 ; ++i ) {
switch ( i ) {
case 0: printf("pass 0, i=%d\n",i) ; break ;
default: printf("pass default, i=%d\n",i) ;
case 1: printf("pass 1, i=%d\n",i) ;
case 4: printf("pass 4, i=%d\n",i) ; break ;
case 5:
case 6:
case 7:
printf("pass 5,6,7, i=%d\n",i) ; break ;
}
}
return 0 ; // exit from the program, all thing go well
}
Print first N
numbers
File: myinclude.h:
int pippo() ; // declare a body of a function
Lesson of 13 July 2009
Some simple C programs
Fibonacci serie, recursive and non recursive implementation
File: fibonacci.cc:
/*
A simple implementation of the calculation of Fibonacci numbers.
F[0] = 0 ;
F[1] = 1 ;
F[k+1] = F[k] + F[k-1] ;
*/
#include <stdio.h> // use C stile I/O
// non recursive implementation
int // return an integer
fibonacci // name of the function
( // arguments of the function
int k // request of the k-th Fibonacci number
)
{ // begin of the body of the function
int fk ; // k-th Fibonacci number
int fkp1 ; // k+1 Fibonacci number
int fkm1 ; // k-1 Fibonacci number
switch ( k ) {
case 0:
// do not need return 1 here because there is return 1
// for case 1:
case 1:
return 1 ;
// break; is not necessary because return exit from switch
default:
// normal case, k>1. I can modify k because k is passed "by value".
// In FORTRAN arguments are passed "by reference".
// initialization, setup fk, fkp1 and fkm1 for k=1
fkm1 = 1 ;
fk = 1 ;
fkp1 = 2 ;
// update fk
while ( k-- > 1 ) { // while ( k-- > 2 ) can be interpreted
// as while ( k > 2 ) whith k decremented
// after the comparison
fkp1 = fk + fkm1 ; // new value ;
// shift new value
fkm1 = fk ;
fk = fkp1 ;
} ;
return fkp1 ;
}
} // end of the body of the function
// Recursive implementation
int
fibonacciR( int k ) {
printf("Entering Fibonacci %d\n",k) ;
switch ( k ) {
case 0:
case 1:
return 1 ;
default:
return fibonacciR(k-1)+fibonacciR(k-2) ;
}
printf("Exiting Fibonacci %d\n",k) ;
}
int
main() {
// check fibonacci function
int f10 = fibonacci( 10 ) ;
int f10R = fibonacciR( 10 ) ;
printf("fibonacci(10) = %d\n", f10 ) ;
printf("fibonacciR(10) = %d\n", f10R ) ;
}
QuickSort algorithm of O’Hara, recursive implementation on integer C vector
File: quicksort.cc:
/*
Algorithm quick sort
*/
#include <iostream> // use I/O of C++
using namespace std ; // load the functions in standard namespace
/*
Sort a verctor of integer by quick sort algorithm
(John O'Hara algorithm)
*/
void
quickSort (int a[], int lo, int hi, int level) {
// a[]: a is a pointer to the vector,
// to access the element use a[0] = the first element
// a[1] the second element, a[k] the k+1 element.
//
// lo is the lower index, hi is the upper index
// of the region of array a that is to be sorted
//
// level = level of recursion
for ( int kk = 0 ; kk < level ; ++kk ) cout << " " ;
cout << "[" << lo << ", " << hi << "]\n" ;
// sort only if we have at least 2 element
if ( hi <= lo ) return ;
int i = lo ; // i is set to the beginning of the region
int j = hi ; // j is set to the end of the region
int pivot = a[(lo+hi)/2] ; // (lo+hi)/2 the pivot is chosen
// in the middle of the vector
// but any index between lo and hi
// can be used.
// (lo+hi)/2 is truncated to
// the lower near integer
// partition
while ( j > i ) { // if i==j only one elemet: the region is sorted
// if i < j empty region, nothing to sort
while ( a[i] < pivot ) i++ ; // a[ii] for ii <= i are less than pivot
while ( a[j] > pivot ) j-- ; // a[jj] for jj >= j are greater than pivot
if ( i <= j ) { // check if the sub-regions are complete.
// if not, we need to exchange the elements outside the
// sub-regions
int h=a[i] ; a[i]=a[j]; a[j]=h ; // exchange a[i] with a[j
i++; j--; // a[i] and a[j] are in the correct region
// so that we do not need to check again
}
} ;
// recursion onfy if region is not empty
quickSort(a, lo, j, level+1);
quickSort(a, i, hi, level+1);
}
int
main() {
int vec[100] ; // declare and instance a vector of 100 elements
// initialize some elements
vec[0] = 9 ;
vec[1] = 1 ;
vec[2] = -1 ;
vec[3] = 2 ;
vec[4] = 2 ;
vec[5] = 6 ;
vec[6] = 5 ;
vec[7] = -23 ;
vec[8] = -2 ;
vec[9] = 1 ;
quickSort( vec, 0, 9, 0 ) ;
// cout = character out object
for ( int i = 0 ; i < 10 ; ++i )
cout << i << " " << vec[i] << '\n' ;
// define and initialize a vector
int b[] = { 1, 2, -3, 0, -45, -1, 0, 3, 67} ;
// evaluate the size of vector b.
// sizeof return the size in byte of the element in argument
// sizeof(b) return the number of bytes used by the whole vector
// sizeof(b[0]) return the number of bytes used by and element of the vector
int szb = sizeof(b)/sizeof(b[0]) ;
quickSort( b, 0, szb-1, 0 ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << b[i] << '\n' ;
return 0 ;
}
Lesson of 14 July 2009 (morning)
Improved QuickSort
File: quicksort.cc:
/*
Algorithm quick sort, generalization
by using C technique
*/
#include <iostream> // use I/O of C++
#include <string.h> // for memcpy
#include <alloca.h> // for the use of alloca
using namespace std ;
/*
Define the type Comparator as a pointer to
function used to compare two elements.
if return value is
0 : a is equal to b
>= 1 : a is greater than b
<= -1 : a is less than b
*/
typedef int (*Comparator)( void * a, void * b ) ;
/* function that calculate the addess of an element
of a generic vector given a pointer to the
begin of the vector at the size of each element */
void *
getAddress( void * beginOfVector,
int index,
int sizeOfElement ) {
return (char*) beginOfVector + index * sizeOfElement ;
}
/*
Sort a verctor of integer by quick sort algorithm
(John O'Hara algorithm)
*/
void
quickSort ( void * a, // pointer to the a memory location where the vector lies.
int lo, // lo is the lower index of the region to be sorted
int hi, // hi is the upper index of the region to be sorted
int sizeOfElement, // size of the single element
Comparator comp, // pointer to the comparator fuction
int level
) {
// level = level of recursion
for ( int kk = 0 ; kk < level ; ++kk ) cout << " " ;
cout << "[" << lo << ", " << hi << "]\n" ;
// sort only if we have at least 2 element
if ( hi <= lo ) return ;
// memory allocation to store the pivot.
// We need sizeOfElement bytes of allocation.
// You can use void * pivot = new char [sizeOfElement] ;
// but char cab be BAD aligned in memory.
// nelem is the minimum number of int that is larger of
// sizeOfElement bytes
int nelem = (sizeOfElement+sizeof(int)-1)/sizeof(int) ;
/*
// new allocate memory for nelem int and return a poiter
// to this memory
int * pivot = new int [nelem] ;
// buffer of memory for swap elements
int * buffer = new int [nelem] ;
*/
// use alloca instead of new
int * pivot = (int*)alloca(sizeOfElement) ;
int * buffer = (int*)alloca(sizeOfElement) ;
int i = lo ; // i is set to the beginning of the region
int j = hi ; // j is set to the end of the region
//
int ipivot = (lo+hi)/2 ; // (lo+hi)/2 the pivot is chosen
// calculate the address of ipivot element
// (char*) a is a "cast" to convert the void* pointer
// to a char* pointer which point to element of size 1-byte
//void * a_ipivot = (char*)a + ipivot * sizeOfElement ;
void * a_ipivot = getAddress( a, ipivot, sizeOfElement ) ;
// copy the pivot to the allocated memory
memcpy( pivot, a_ipivot, sizeOfElement ) ;
// partition
while ( j > i ) { // if i==j only one elemet: the region is sorted
// if i < j empty region, nothing to sort
// To compare a[i] with pivot use
// int res = (*comp) ( getAddress( a, i, sizeOfElement ), pivot )
// you can use the following sintactic glue
// int res = comp( getAddress( a, i, sizeOfElement ), pivot )
//
while ( comp( getAddress( a, i, sizeOfElement ), pivot ) < 0 ) i++ ; // a[ii] for ii <= i are less than pivot
while ( comp( getAddress( a, j, sizeOfElement ), pivot ) > 0 ) j-- ; // a[jj] for jj >= j are greater than pivot
if ( i <= j ) { // check if the sub-regions are complete.
// if not, we need to exchange the elements outside the
// sub-regions
void * ai = getAddress( a, i, sizeOfElement ) ;
void * aj = getAddress( a, j, sizeOfElement ) ;
// buffer = a[i] ;
memcpy( buffer, ai, sizeOfElement ) ;
// a[i] = a[j]
memcpy( ai, aj, sizeOfElement ) ;
// a[j] = buffer
memcpy( aj, buffer, sizeOfElement ) ;
i++; j--; // a[i] and a[j] are in the correct region
// so that we do not need to check again
}
} ;
// recursion onfy if region is not empty
quickSort(a, lo, j, sizeOfElement, comp, level+1);
quickSort(a, i, hi, sizeOfElement, comp, level+1);
// free the allocated memory
/*
using alloca no need to free memory
delete [] pivot ;
delete [] buffer ;
*/
}
/*
Function that compare the pointer of two integer
*/
int
comp_int( void * pa, void * pb ) {
// (int*)a tell to the compiler that a point to int type
// * ( ) read the memory (deferentiation)
int ia = * ((int*)pa) ; // copy the content at address pa to the variable ia
int ib = * ((int*)pb) ; // copy the content at address pb to the variable ib
if ( ia < ib ) return -1 ;
if ( ia > ib ) return +1 ;
return 0 ;
}
/*
Function that compare the pointer of two integer
*/
int
comp_double( void * pa, void * pb ) {
// (double*)a tell to the compiler that a point to int type
// * ( ) read the memory (deferentiation)
double da = * ((double*)pa) ; // copy the content at address pa to the variable ia
double db = * ((double*)pb) ; // copy the content at address pb to the variable ib
if ( da < db ) return -1 ;
if ( da > db ) return +1 ;
return 0 ;
}
int
main() {
int vec[100] ; // declare and instance a vector of 100 elements
// initialize some elements
vec[0] = 9 ;
vec[1] = 1 ;
vec[2] = -1 ;
vec[3] = 2 ;
vec[4] = 2 ;
vec[5] = 6 ;
vec[6] = 5 ;
vec[7] = -23 ;
vec[8] = -2 ;
vec[9] = 1 ;
quickSort( vec, 0, 9, sizeof(vec[0]), comp_int, 0 ) ;
// cout = character out object
for ( int i = 0 ; i < 10 ; ++i )
cout << i << " " << vec[i] << '\n' ;
// define and initialize a vector
int b[] = { 1, 2, -3, 0, -45, -1, 0, 3, 67} ;
// evaluate the size of vector b.
// sizeof return the size in byte of the element in argument
// sizeof(b) return the number of bytes used by the whole vector
// sizeof(b[0]) return the number of bytes used by and element of the vector
int szb = sizeof(b)/sizeof(b[0]) ;
quickSort( b, 0, szb-1, sizeof(vec[0]), comp_int, 0 ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << b[i] << '\n' ;
// allocate a vector of double
double * dvec = new double[ 10 ] ;
dvec[0] = 3 ;
dvec[1] = 1.2 ;
dvec[2] = 0.3 ;
dvec[3] = 1/4.;
dvec[4] = 2 ;
dvec[5] = -0.34 ;
dvec[6] = 0.000001 ;
dvec[7] = -0.000001 ;
dvec[8] = 1 ;
dvec[9] = 3 ;
quickSort( dvec, 0, 9, sizeof(double), comp_double, 0 ) ;
for ( int i = 0 ; i < 10 ; ++i )
cout << i << " " << dvec[i] << '\n' ;
// free the memory used to allocate the vector
delete [] dvec ;
return 0 ;
}
Infinite recursion
File: stack.cc:
// a simple infinite recursion to show stack overflow
void
overflow(int i) {
overflow(i+1) ;
overflow(i+2) ;
overflow(i+3) ;
overflow(i+4) ;
overflow(i+5) ;
overflow(i+6) ;
overflow(i+7) ;
overflow(i+8) ;
overflow(i+9) ;
}
int
main() {
overflow(1) ;
return 1 ;
}
Lesson of 14 July 2009 (afternoon)
QuickSort rewritten with an header and an implementation file
File: quicksort.hh:
/*
Parametrize the type for quickSort,
valueType is an alias for double
*/
typedef double valueType ;
/*
Algorithm quick sort
*/
extern // means that the routine here declared is defined somewhere
void
quickSort ( valueType a[], // vector to be sorted
int const n // number of element of the vector to be sorted
) ;
File: quicksort.cc:
/*
Algorithm quick sort
*/
#include "quicksort.hh"
#include <iostream> // use I/O of C++
#include <algorithm> // use STL algorithm
using namespace std ; // load the functions in standard namespace
// declare the prototype for the routine that perform the sort
static void quickSort ( valueType a[], int lo, int hi, int level ) ;
// implementation of quickSort
void
quickSort ( valueType a[], int const n ) {
// due to overloading quickSort is selected by
// the matching of its arguments
quickSort (a, 0, n-1, 0) ;
}
/*
Sort a verctor of integer by quick sort algorithm
(John O'Hara algorithm)
*/
static // static means the routine is visible only in "this file"
void
quickSort (valueType a[], int lo, int hi, int level) {
// a[]: a is a pointer to the vector,
// to access the element use a[0] = the first element
// a[1] the second element, a[k] the k+1 element.
//
// lo is the lower index, hi is the upper index
// of the region of array a that is to be sorted
//
// level = level of recursion
for ( int kk = 0 ; kk < level ; ++kk ) cout << " " ;
cout << "[" << lo << ", " << hi << "]\n" ;
// sort only if we have at least 2 element
if ( hi <= lo ) return ;
int i = lo ; // i is set to the beginning of the region
int j = hi ; // j is set to the end of the region
int pivot = a[(lo+hi)/2] ; // (lo+hi)/2 the pivot is chosen
// in the middle of the vector
// but any index between lo and hi
// can be used.
// (lo+hi)/2 is truncated to
// the lower near integer
// partition
while ( j > i ) { // if i==j only one element: the region is sorted
// if i < j empty region, nothing to sort
while ( a[i] < pivot ) i++ ; // a[ii] for ii <= i are less than pivot
while ( a[j] > pivot ) j-- ; // a[jj] for jj >= j are greater than pivot
if ( i <= j ) { // check if the sub-regions are complete.
// if not, we need to exchange the elements outside the
// sub-regions
swap( a[i], a[j] ) ;
i++; j--; // a[i] and a[j] are in the correct region
// so that we do not need to check again
}
} ;
// recursion onfy if region is not empty
quickSort(a, lo, j, level+1);
quickSort(a, i, hi, level+1);
}
File: prova.cc:
#include "quicksort.hh"
#include <iostream>
using namespace std ;
int
main() {
// define and initialize a vector
valueType b[] = { 1.2, 2.2, -0.3, 0, -45, -1, 0, 3, 67} ;
// evaluate the size of vector b.
// sizeof return the size in byte of the element in argument
// sizeof(b) return the number of bytes used by the whole vector
// sizeof(b[0]) return the number of bytes used by and element of the vector
int szb = sizeof(b)/sizeof(b[0]) ;
quickSort( b, szb ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << b[i] << '\n' ;
return 0 ;
}
Multiple version of QuickSort by using overloading an macros
File: macro/quicksort.hh:
/*
Algorithm quick sort
*/
#define VALUE int
#include "quicksort.hxx"
#undef VALUE
#define VALUE double
#include "quicksort.hxx"
#undef VALUE
#define VALUE float
#include "quicksort.hxx"
#undef VALUE
/*
extern void quickSort ( int a[], int const n ) ;
extern void quickSort ( double a[], int const n ) ;
*/
File: macro/quicksort.hxx:
/*
Algorithm quick sort
*/
extern // means that the routine here declared is defined somewhere
void
quickSort ( VALUE a[], // vector to be sorted
int const n // number of element of the vector to be sorted
) ;
File: macro/quicksort.cc:
#include "quicksort.hh"
#include <iostream> // use I/O of C++
#include <algorithm> // use STL algorithm
using namespace std ; // load the functions in standard namespace
#define VALUE int
#include "quicksort.cxx"
#undef VALUE
#define VALUE double
#include "quicksort.cxx"
#undef VALUE
#define VALUE float
#include "quicksort.cxx"
#undef VALUE
File: macro/quicksort.cxx:
/*
Algorithm quick sort
*/
// declare the prototype for the routine that perform the sort
static void quickSort ( VALUE a[], int lo, int hi, int level ) ;
// implementation of quickSort
void
quickSort ( VALUE a[], int const n ) {
// due to overloading quickSort is selected by
// the matching of its arguments
quickSort (a, 0, n-1, 0) ;
}
/*
Sort a verctor of integer by quick sort algorithm
(John O'Hara algorithm)
*/
static // static means the routine is visible only in "this file"
void
quickSort (VALUE a[], int lo, int hi, int level) {
// a[]: a is a pointer to the vector,
// to access the element use a[0] = the first element
// a[1] the second element, a[k] the k+1 element.
//
// lo is the lower index, hi is the upper index
// of the region of array a that is to be sorted
//
// level = level of recursion
for ( int kk = 0 ; kk < level ; ++kk ) cout << " " ;
cout << "[" << lo << ", " << hi << "]\n" ;
// sort only if we have at least 2 element
if ( hi <= lo ) return ;
int i = lo ; // i is set to the beginning of the region
int j = hi ; // j is set to the end of the region
VALUE pivot = a[(lo+hi)/2] ; // (lo+hi)/2 the pivot is chosen
// in the middle of the vector
// but any index between lo and hi
// can be used.
// (lo+hi)/2 is truncated to
// the lower near integer
// partition
while ( j > i ) { // if i==j only one elemet: the region is sorted
// if i < j empty region, nothing to sort
while ( a[i] < pivot ) i++ ; // a[ii] for ii <= i are less than pivot
while ( a[j] > pivot ) j-- ; // a[jj] for jj >= j are greater than pivot
if ( i <= j ) { // check if the sub-regions are complete.
// if not, we need to exchange the elements outside the
// sub-regions
swap( a[i], a[j] ) ;
i++; j--; // a[i] and a[j] are in the correct region
// so that we do not need to check again
}
} ;
// recursion onfy if region is not empty
quickSort(a, lo, j, level+1);
quickSort(a, i, hi, level+1);
}
File: macro/prova.cc:
#include "quicksort.hh"
#include <iostream>
using namespace std ;
int
main() {
// define and initialize a vector
double b[] = { 1.2, 2.2, -0.3, 0, -45, -1, 0, 3, 67} ;
// evaluate the size of vector b.
// sizeof return the size in byte of the element in argument
// sizeof(b) return the number of bytes used by the whole vector
// sizeof(b[0]) return the number of bytes used by and element of the vector
int szb = sizeof(b)/sizeof(b[0]) ;
quickSort( b, szb ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << b[i] << '\n' ;
return 0 ;
}
Multiple version of QuickSort by using templates
File: template/quicksort.hh:
#include <iostream>
/*
Algorithm quick sort
*/
template <typename VALUE>
void quickSort ( VALUE a[], int lo, int hi, int level ) ;
// VALUE can be any type
template <typename VALUE>
void quickSort ( VALUE a[], int const n ) ;
/*
Algorithm implementation
*/
// implementation of quickSort
template <typename VALUE>
void
quickSort ( VALUE a[], int const n ) {
quickSort (a, 0, n-1, 0) ;
}
template <typename VALUE>
void
quickSort (VALUE a[], int lo, int hi, int level) {
using namespace std ;
for ( int kk = 0 ; kk < level ; ++kk ) cout << " " ;
cout << "[" << lo << ", " << hi << "]\n" ;
// sort only if we have at least 2 element
if ( hi <= lo ) return ;
int i = lo ; // i is set to the beginning of the region
int j = hi ; // j is set to the end of the region
VALUE pivot = a[(lo+hi)/2] ; // (lo+hi)/2 the pivot is chosen
// in the middle of the vector
// but any index between lo and hi
// can be used.
// (lo+hi)/2 is truncated to
// the lower near integer
// partition
while ( j > i ) { // if i==j only one elemet: the region is sorted
// if i < j empty region, nothing to sort
while ( a[i] < pivot ) i++ ; // a[ii] for ii <= i are less than pivot
while ( a[j] > pivot ) j-- ; // a[jj] for jj >= j are greater than pivot
if ( i <= j ) { // check if the sub-regions are complete.
// if not, we need to exchange the elements outside the
// sub-regions
swap( a[i], a[j] ) ;
i++; j--; // a[i] and a[j] are in the correct region
// so that we do not need to check again
}
} ;
// recursion onfy if region is not empty
quickSort(a, lo, j, level+1);
quickSort(a, i, hi, level+1);
}
File: template/prova.cc:
#include "quicksort.hh"
#include <iostream>
#include <algorithm> // to include "sort"
using namespace std ;
int
main() {
// define and initialize a vector
//double b[] = { 1.2, 2.2, -0.3, 0, -45, -1, 0, 3, 67} ;
unsigned long b[] = { 1, 2, 3, 0, 45, 1, 0, 3, 67} ;
// evaluate the size of vector b.
// sizeof return the size in byte of the element in argument
// sizeof(b) return the number of bytes used by the whole vector
// sizeof(b[0]) return the number of bytes used by and element of the vector
unsigned szb = sizeof(b)/sizeof(b[0]) ;
quickSort( b, szb ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << b[i] << '\n' ;
// define and initialize a vector
//double b[] = { 1.2, 2.2, -0.3, 0, -45, -1, 0, 3, 67} ;
int bb[] = { 1, 2, 3, 0, 45, 1, 10, 3, 67} ;
// use STL to sort the vector
sort( bb, bb + 9 ) ;
//cout = character out object
for ( int i = 0 ; i < szb ; ++i )
cout << i << " " << bb[i] << '\n' ;
return 0 ;
}
Multiple version of Max by using templates
File: template/max.cc:
#include <iostream>
using namespace std ;
template <typename T>
T
massimo( T const & a, T const & b) {
if ( a > b ) return a ;
else return b ;
}
template <typename T1, typename T2>
T2
massimo1( T1 const & a, T2 const & b) {
if ( a > b ) return a ;
else return b ;
}
int
main() {
cout << massimo1( 2,3.2 ) << '\n' ;
cout << massimo1( 2.3,1) << '\n' ;
return 0 ;
}
STL Vector and Maps
File: template/vectorTest.cc:
#include <iostream>
#include <vector> // to include "vector"
#include <algorithm> // to include "sort"
using namespace std ;
int
main() {
vector<float> v ; // declare an empty vector of 0-size
vector<float> w(100) ; // declare an empty vector of size 100
// fill a vector incrementally
for ( int i = 0 ; i < 10 ; ++i ) {
cout << "Size of v = " << v . size() << '\n' ;
v . push_back( (i*23) % 5 ) ; // add an element to vector and increase by one its size
cout << "Size of v = " << v . size() << '\n' ;
}
// access to element directly
v[3] = 4.5 ;
for ( vector<float>::iterator iv = v . begin() ; // get iterator pointing
// to the first element
iv != v . end() ; // check if the iterator point to the (past) to
// the last element
++iv // move the iterator to "point" the next element
)
cout << *iv << '\n' ;
sort( v . begin() , v . end() ) ;
for ( vector<float>::iterator iv = v . begin() ; // get iterator pointing
// to the first element
iv != v . end() ; // check if the iterator point to the (past) to
// the last element
++iv // move the iterator to "point" the next element
)
cout << *iv << '\n' ;
int i = 0 ;
int i1 = i++ ;
int i2 = ++i ;
cout << i << " " << i1 << " " << i2 << '\n' ;
return 0 ;
}
File: template/mapTest.cc:
#include <iostream>
#include <map> // to include "map"
#include <algorithm> // to include "sort"
#include <string>
using namespace std ;
int
main() {
map<string,string> months ; // declare an empty map
months["january"] = "31";
months["february"] = "28";
months["march"] = "31";
months["april"] = "30";
months["may"] = "31";
months["june"] = "30";
months["july"] = "31";
months["august"] = "31";
months["september"] = "30";
months["october"] = "31";
months["november"] = "30";
months["december"] = "31";
for ( map<string,string>::iterator im = months . begin() ;
im != months . end() ;
++im ) {
cout << im -> first << " " << im -> second << '\n' ;
}
// (*im).first ;
map<int,double> sparsev ;
sparsev[1] = 1.23 ;
sparsev[1001] = 1.23 ;
sparsev[-2345233] = 1.23 ;
for ( map<int,double>::iterator im = sparsev . begin() ;
im != sparsev . end() ;
++im ) {
cout << im -> first << " " << im -> second << '\n' ;
}
return 0 ;
}
Lesson of 20 July 2009 (morning)
Skeleton of a Simple vector/matrix library for 3d vector and 3x3 matrix (C style)
File: lib3d.h:
/*
File: lib3d.h
Simple vector/matrix library for 3d vector and 3x3 matrix.
*/
/* first trick, avoid double inclusion using conditional compilation */
/* check if LIB3D_H is defined, if NOT the lines up to #endif are expanded */
#ifndef LIB3D_H
#define LIB3D_H // define an empty macro, only to define the symbol LIB3D_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* valueType is the "real number" type */
typedef double valueType ;
/* A vector is a struct with 3 field, x y z */
/*
struct _point3d {
valueType x ;
valueType y ;
valueType z ;
} ;
typedef struct _point3d point3d ;
*/
typedef struct {
valueType x ;
valueType y ;
valueType z ;
} point3d ;
/* matrix 3 by 3 type */
typedef valueType matrix3d[3][3] ;
/* prototype for addition of two vectors */
void l3d_print( FILE * fd, point3d const * v ) ;
void l3d_scal_by_vec( valueType, point3d const * v, point3d * pRes );
/* prototype for addition of two vectors */
void l3d_add( point3d const * v1,
point3d const * v2,
point3d * pRes ) ;
/* prototype for subtraction of two vectors */
void l3d_sub( point3d const * v1,
point3d const * v2,
point3d * pRes ) ;
/* prototype for vector product of two vectors */
void l3d_vec_product( point3d const * v1,
point3d const * v2,
point3d * pRes ) ;
/* prototype for dot product of two vectors */
valueType l3d_dot_product( point3d const * v1,
point3d const * v2 ) ;
/* initialize a matrix */
void l3d_zero_matrix( matrix3d m ) ;
void l3d_id_matrix( matrix3d m ) ;
void l3d_ones_matrix( matrix3d m ) ;
void l3d_addm( matrix3d const m1,
matrix3d const m2,
matrix3d res ) ;
/* prototype for subtraction of two vectors */
void l3d_subm( matrix3d const m1,
matrix3d const m2,
matrix3d res ) ;
void l3d_mv( matrix3d m,
point3d const * v,
point3d * pRes ) ;
void l3d_mm( matrix3d const m1,
matrix3d const m2,
matrix3d res ) ;
#ifdef __cplusplus
}
#endif
#endif /* close LIB3D_H */
File: lib3d.c:
/*
File: lib3d.c
Simple vector/matrix library for 3d vector and 3x3 matrix.
*/
#include "lib3d.h"
void
l3d_print( FILE * fd, point3d const * v ) {
fprintf( fd, "[ %lf %lf %lf]\n", v -> x, v -> y, v -> z ) ;
}
void
l3d_scal_by_vec( valueType s, point3d const * v, point3d * pRes ) {
pRes -> x = v -> x * s ;
pRes -> y = v -> y * s ;
pRes -> z = v -> z * s ;
}
void
l3d_add( point3d const * v1,
point3d const * v2,
point3d * pRes ) {
/*
(*pRes) . x = v1 . x + v2 . x ;
(*pRes) . y = v1 . y + v2 . y ;
(*pRes) . z = v1 . z + v2 . z ;
*/
pRes -> x = v1 -> x + v2 -> x ;
pRes -> y = v1 -> y + v2 -> y ;
pRes -> z = v1 -> z + v2 -> z ;
}
void
l3d_sub( point3d const * v1,
point3d const * v2,
point3d * pRes ) {
pRes -> x = v1 -> x - v2 -> x ;
pRes -> y = v1 -> y - v2 -> y ;
pRes -> z = v1 -> z - v2 -> z ;
}
void
l3d_vec_product( point3d const * v1,
point3d const * v2,
point3d * pRes ) {
pRes -> x = v1 -> y * v2 -> z - v1 -> z * v2 -> y ;
pRes -> y = v1 -> z * v2 -> x - v1 -> x * v2 -> z ;
pRes -> z = v1 -> x * v2 -> y - v1 -> y * v2 -> x ;
}
valueType
l3d_dot_product( point3d const * v1,
point3d const * v2 ) {
return v1 -> x * v2 -> x +
v1 -> y * v2 -> y +
v1 -> z * v2 -> z ;
}
void
l3d_zero_matrix( matrix3d m ) {
m[0][0] = m[0][1] = m[0][2] =
m[1][0] = m[1][1] = m[1][2] =
m[2][0] = m[2][1] = m[2][2] = 0 ;
}
void
l3d_id_matrix( matrix3d m ) {
m[0][1] = m[0][2] = m[1][0] =
m[1][2] = m[2][0] = m[2][1] = 0 ;
m[0][0] = m[1][1] = m[2][2] = 1 ;
}
void
l3d_ones_matrix( matrix3d m ) {
m[0][0] = m[0][1] = m[0][2] =
m[1][0] = m[1][1] = m[1][2] =
m[2][0] = m[2][1] = m[2][2] = 1 ;
}
void
l3d_mv( matrix3d m,
point3d const * v,
point3d * pRes ) {
valueType tmp1 = m[0][0] * v -> x + m[0][1] * v -> y + m[0][2] * v -> z ;
valueType tmp2 = m[1][0] * v -> x + m[1][1] * v -> y + m[1][2] * v -> z ;
pRes -> z = m[2][0] * v -> x + m[2][1] * v -> y + m[2][2] * v -> z ;
pRes -> y = tmp2 ;
pRes -> x = tmp1 ;
}
File: test.c:
#include "lib3d.h"
#include <stdio.h>
int
main() {
point3d v1, v2, v3, vbuff ;
matrix3d M ;
v1 . x = 1 ;
v1 . y = 0 ;
v1 . z = 0 ;
v2 . x = 0 ;
v2 . y = 1 ;
v2 . z = 0 ;
l3d_ones_matrix( M ) ;
/* M * (v1 + 3 * v2) */
l3d_scal_by_vec( 3, & v2, & vbuff ); /* 3 * v2 --> vbuff */
l3d_add( & v1, & vbuff, & vbuff ); /* v1 + vbuff --> vbuff */
l3d_mv( M, & vbuff, & vbuff ) ;
l3d_print( stdout, & vbuff ) ;
l3d_vec_product( & v1, & v2, & v3 );
l3d_print( stdout, & v3 ) ;
/*printf( " v3 . x = %lf\n", v3 . x ) ;
printf( " v3 . y = %lf\n", v3 . y ) ;
printf( " v3 . z = %lf\n", v3 . z ) ;
*/
return 0 ;
}
Lesson of 20 July 2009 (afternoon)
Skeleton of a Simple vector/matrix library for 3d vector and 3x3 matrix (C++ style)
File: lib3d.hh:
/*
File: lib3d.hh
Simple vector/matrix library for 3d vector and 3x3 matrix.
*/
/* first trick, avoid double inclusion using conditional compilation */
/* check if LIB3D_H is defined, if NOT the lines up to #endif are expanded */
#ifndef LIB3D_HH
#define LIB3D_HH // define an empty macro, only to define the symbol LIB3D_HH
#include <iostream>
// valueType is the "real number" type
typedef double valueType ;
// A vector is a CLASS with 3 field, x y z
class point3d {
private:
valueType x ;
valueType y ;
valueType z ;
public:
valueType *ptr ;
private:
private:
private:
public:
// constructor
point3d() {
std::cout << "pass to constructor 1\n" ;
x=y=z=0 ;
ptr = new valueType[100] ;
}
point3d( valueType x, valueType y, valueType z ) {
std::cout << "pass to constructor 2\n" ;
this -> x = x ;
this -> y = y ;
this -> z = z ;
ptr = new valueType[10] ;
}
~point3d() {
delete [] ptr ;
std::cout << "pass to destructor\n" ;
}
point3d const &
operator = ( point3d const & in ) ;
void
setup( valueType x, valueType y, valueType z ) ;
valueType getx() const { return x ; } // const means that the method
// do not modify the class
valueType gety() const { return y ; }
valueType getz() const { return z ; }
} ;
std::ostream & // return a reference (pointer) to the object
// ostream is into the namespace std
operator << ( std::ostream & s, // left argumenet of left << right
point3d const & v ) ; // right argumenet of left << right
point3d scal( valueType s, point3d const & v ) ;
point3d
add( point3d const & v1,
point3d const & v2 ) ;
point3d
sub( point3d const & v1,
point3d const & v2 ) ;
point3d
vector_product( point3d const & v1,
point3d const & v2 ) ;
valueType dot( point3d const & v1, point3d const & v2 ) ;
// Use external operator
inline
point3d
operator ^ ( point3d const & a, point3d const & b )
{ return vector_product( a, b ) ; }
inline
valueType
operator * ( point3d const & a, point3d const & b )
{ return dot( a, b ) ; }
// matrix 3 by 3 type
class matrix3d {
valueType m[3][3] ;
} ;
#endif /* close LIB3D_HH */
File: lib3d.cc:
/*
File: lib3d.c
Simple vector/matrix library for 3d vector and 3x3 matrix.
*/
#include "lib3d.hh"
// define the copy opersator = for class point3d
point3d const &
point3d::operator = ( point3d const & in ) {
std::cout << "pass to copy operator\n" ;
this -> x = in . x ;
this -> y = in . y ;
this -> z = in . z ;
}
// define the method setup of class point3d
void
point3d::setup( valueType x, valueType y, valueType z ) {
this -> x = x ;
this -> y = y ;
this -> z = z ;
}
std::ostream & // return a reference (pointer) to the object
// ostream is into the namespace std
operator << ( std::ostream & s, // left argumenet of left << right
point3d const & v ) { // right argumenet of left << right
s << "[ " << v.getx() << " , " << v.gety() << " , " << v.getz() << " ]" ;
return s ;
}
point3d
scal( valueType s, point3d const & v ) {
valueType x = v . getx() * s ;
valueType y = v . gety() * s ;
valueType z = v . getz() * s ;
//point3d res( x, y, z ) ;
//return res ;
return point3d(x, y, z) ;
}
point3d
add( point3d const & v1,
point3d const & v2 ) {
return point3d( v1 . getx() + v2 . getx(),
v1 . gety() + v2 . gety(),
v1 . getz() + v2 . getz() ) ;
}
point3d
sub( point3d const & v1,
point3d const & v2 ) {
return point3d( v1 . getx() - v2 . getx(),
v1 . gety() - v2 . gety(),
v1 . getz() - v2 . getz() ) ;
}
point3d
vector_product( point3d const & v1,
point3d const & v2 ) {
return point3d( v1 . gety() * v2 . getz() - v1 . getz() * v2 . gety(),
v1 . getz() * v2 . getx() - v1 . getx() * v2 . getz(),
v1 . getx() * v2 . gety() - v1 . gety() * v2 . getx() ) ;
}
valueType
dot( point3d const & v1,
point3d const & v2 ) {
return v1 . getx() * v2 . getx() +
v1 . gety() * v2 . gety() +
v1 . getz() * v2 . getz() ;
}
/*
void
l3d_zero_matrix( matrix3d m ) {
m[0][0] = m[0][1] = m[0][2] =
m[1][0] = m[1][1] = m[1][2] =
m[2][0] = m[2][1] = m[2][2] = 0 ;
}
void
l3d_id_matrix( matrix3d m ) {
m[0][1] = m[0][2] = m[1][0] =
m[1][2] = m[2][0] = m[2][1] = 0 ;
m[0][0] = m[1][1] = m[2][2] = 1 ;
}
void
l3d_ones_matrix( matrix3d m ) {
m[0][0] = m[0][1] = m[0][2] =
m[1][0] = m[1][1] = m[1][2] =
m[2][0] = m[2][1] = m[2][2] = 1 ;
}
void
l3d_mv( matrix3d m,
point3d const * v,
point3d * pRes ) {
valueType tmp1 = m[0][0] * v -> x + m[0][1] * v -> y + m[0][2] * v -> z ;
valueType tmp2 = m[1][0] * v -> x + m[1][1] * v -> y + m[1][2] * v -> z ;
pRes -> z = m[2][0] * v -> x + m[2][1] * v -> y + m[2][2] * v -> z ;
pRes -> y = tmp2 ;
pRes -> x = tmp1 ;
}
*/
File: test.cc:
#include "lib3d.hh"
#include <cmath>
using namespace std ;
int
main() {
cout << "begin program\n" ;
point3d a, b, c ;
cout << "v1 and v2 defined and instanced\n" ;
matrix3d M ;
cout << "M and instanced\n" ;
a . setup( 1, sqrt(3.0), 0 ) ;
b . setup( 0.1, 1, 0 ) ;
c . setup( 0, 1, 2.1 ) ;
cout << "Volume = " << dot( vector_product(a,b), c ) << '\n' ;
cout << "Volume = " << (a^b)*c << '\n' ;
a = b ;
// is equivalent
a . operator = ( b ) ;
operator * ( (operator ^(a,b)), c ) ;
// add( v1, v2, v3 ) ;
// sub( v1, v2, v3 ) ;
// vector_product( v1, v2, v3 ) ;
cout << "before point3d v3 = scal( 3, a ) \n" ;
point3d v3 = scal( 3, a ) ;
cout << "after point3d v3 = scal( 3, a ) \n" ;
std::cout << "V3 = " << v3 << '\n' ;
return 0 ;
}
Lesson of 21 July 2009 (morning)
Simple vector/matrix library for 3d vector using templates
File: lib3d.hh:
/*
File: lib3d.hh
Simple vector/matrix library for 3d vector and 3x3 matrix.
Improved version by using template
*/
/* first trick, avoid double inclusion using conditional compilation */
/* check if LIB3D_H is defined, if NOT the lines up to #endif are expanded */
#ifndef LIB3D_HH
#define LIB3D_HH // define an empty macro, only to define the symbol LIB3D_HH
#include <iostream>
#ifdef DEBUG
#define DEBUG_MSG(A) std::cout << A
#else
#define DEBUG_MSG(A)
#endif
// A vector is a CLASS with 3 field, x y z
template <typename T>
class point3d {
public:
// make an alias of the type T
typedef T valueType ;
private:
// the data of the vector
valueType v[3] ;
public:
// constructor
inline
point3d() {
DEBUG_MSG("point3d contructor\n") ;
} // do nothing
inline
point3d( point3d const & a ) {
DEBUG_MSG("point3d copy contructor\n") ;
v[0] = a . v[0] ; // accessing the pribate part of a!.
v[1] = a . v[1] ;
v[2] = a . v[2] ;
}
inline
point3d( valueType x, valueType y, valueType z ) {
DEBUG_MSG("point3d(x,y,z) constructor \n") ;
v[0] = x ;
v[1] = y ;
v[2] = z ;
}
// destructor
~point3d() {
DEBUG_MSG("point3d destructor\n") ;
} // do nothing
/* comment produced using figlet.
_ _ _ _
(_)_ __ | |_ ___ _ __ _ __ __ _| | ___ _ __ ___ _ __ __ _| |_ ___ _ __
| | '_ \| __/ _ \ '__| '_ \ / _` | | / _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__|
| | | | | || __/ | | | | | (_| | | | (_) | |_) | __/ | | (_| | || (_) | |
|_|_| |_|\__\___|_| |_| |_|\__,_|_| \___/| .__/ \___|_| \__,_|\__\___/|_|
|_|
*/
// assigment operator
point3d const &
operator = ( point3d const & a ) {
DEBUG_MSG("point3d assign (=) operator\n") ;
v[0] = a . v[0] ; // accessing the pribate part of a!.
v[1] = a . v[1] ;
v[2] = a . v[2] ;
return *this ;
}
// add operator
point3d const &
operator += ( point3d const & a ) {
DEBUG_MSG("point3d assign (=) operator\n") ;
v[0] += a . v[0] ; // accessing the pribate part of a!.
v[1] += a . v[1] ;
v[2] += a . v[2] ;
return *this ;
}
// sub operator
point3d const &
operator -= ( point3d const & a ) {
DEBUG_MSG("point3d assign (=) operator\n") ;
v[0] -= a . v[0] ; // accessing the pribate part of a!.
v[1] -= a . v[1] ;
v[2] -= a . v[2] ;
return *this ;
}
// multiply element by element operator
point3d const &
operator *= ( point3d const & a ) {
DEBUG_MSG("point3d assign (=) operator\n") ;
v[0] *= a . v[0] ; // accessing the pribate part of a!.
v[1] *= a . v[1] ;
v[2] *= a . v[2] ;
return *this ;
}
// division element by element operator
point3d const &
operator /= ( point3d const & a ) {
DEBUG_MSG("point3d assign (=) operator\n") ;
v[0] /= a . v[0] ; // accessing the pribate part of a!.
v[1] /= a . v[1] ;
v[2] /= a . v[2] ;
return *this ;
}
// accessor
valueType const & x() const { return v[0] ; }
valueType const & y() const { return v[1] ; }
valueType const & z() const { return v[2] ; }
// initialier
point3d &
setup( valueType x, valueType y, valueType z ) {
DEBUG_MSG("execut point3d::setup\n") ;
this -> v[0] = x ;
this -> v[1] = y ;
this -> v[2] = z ;
return *this ;
}
} ;
/*
_ _
_____ _| |_ ___ _ __ _ __ __ _| |
/ _ \ \/ / __/ _ \ '__| '_ \ / _` | |
| __/> <| || __/ | | | | | (_| | |
\___/_/\_\\__\___|_| |_| |_|\__,_|_|
_
___ _ __ ___ _ __ __ _| |_ ___ _ __
/ _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__|
| (_) | |_) | __/ | | (_| | || (_) | |
\___/| .__/ \___|_| \__,_|\__\___/|_|
|_|
*/
// printing of a vector
template <typename T>
std::ostream &
operator << ( std::ostream & s, point3d<T> const & a ) {
s << "[ x= " << a.x()
<< ", y= " << a.y()
<< ", z= " << a.z()
<< " ]" ;
return s ;
}
// addition of two vectors
template <typename T>
point3d<T>
operator +
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("point3d operator +\n") ;
return point3d<T>( a.x()+b.x(),
a.y()+b.y(),
a.z()+b.z() ) ;
}
// subtraction of two vectors
template <typename T>
point3d<T>
operator -
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("point3d operator -\n") ;
return point3d<T>( a.x()-b.x(),
a.y()-b.y(),
a.z()-b.z() ) ;
}
// multiplication (element by element) of two vectors
template <typename T>
point3d<T>
operator *
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("point3d operator *\n") ;
return point3d<T>( a.x()*b.x(),
a.y()*b.y(),
a.z()*b.z() ) ;
}
// division (element by element) of two vectors
template <typename T>
point3d<T>
operator /
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("point3d operator /\n") ;
return point3d<T>( a.x()/b.x(),
a.y()/b.y(),
a.z()/b.z() ) ;
}
// vector product two vectors
template <typename T>
point3d<T>
operator ^
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("point3d operator ^\n") ;
return point3d<T>( a . y() * b . z() - a . z() * b . y(),
a . z() * b . x() - a . x() * b . z(),
a . x() * b . y() - a . y() * b . x() ) ;
}
// scalar product two vectors
template <typename T>
T // return type
dot
( point3d<T> const & a, point3d<T> const & b ) {
DEBUG_MSG("dot(point3d,point3d)\n") ;
return a.x()*b.x()+a.y()*b.y()+a.z()*b.z() ;
}
#endif /* close LIB3D_HH */
File: test.cc:
#include "lib3d.hh"
#include <cmath>
using namespace std ;
//
// in a large library it is a good habit to
// make alias of the used parameterized objects
typedef point3d<double> vec3 ;
int
main() {
// define the vector a,b,c
vec3 a, b(1,2,3), c ;
c = a . setup(2,3,4) / b ;
// equivalent operation
// a . setup(2,3,4) ;
// c = operator / ( a , b ) ;
cout << a << '\n' ;
cout << b << '\n' ;
cout << c << '\n' ;
cout << "dot(a,b^c) = " << dot(a,b^c) << '\n' ;
cout << "end of program\n" ;
return 0 ;
}
Lesson of 21 July 2009 (afternoon)
Example of the use of class and inheritance
File: inheritance.cc:
/*
Example of the use of class and inheritance
*/
// some include files
#include <iostream>
#include <string> // string support
using namespace std ; // load standard namespace
// standard alias for real numbers
typedef double valueType ;
/*
To activate debugging use
#define DEBUG
or in compilation use
g++ -DDEBUG ....
*/
#ifdef DEBUG
#define MSG_DEBUG(A) std::cout << A
#else
#define MSG_DEBUG(A)
#endif
/*
Define the base class for geometric shape
*/
class shape {
private:
std::string const theName ; // std::string STL class for string
// bouding box for the shape
valueType xmin, ymin, xmax, ymax ;
shape() ; // disable default constructor
public:
shape( std::string const & n )
: theName(n)
{
MSG_DEBUG("shape(\"" << n << "\") constructor\n") ;
// default constructor
}
shape( std::string const & n,
valueType xm,
valueType ym,
valueType xM,
valueType yM )
// begin of the list of initializer calls
: theName(n) // call the constructor for the string theName
, xmin(xm) // call the consructor for xMin
, ymin(ym)
, xmax(xM)
, ymax(yM)
// end of the list of initializer calls
{
MSG_DEBUG("shape(\"" << n << "\",xMin,yMin,xMax,yMax) constructor\n") ;
}
~shape() {
MSG_DEBUG("shape destructor\n") ;
} ; // destructor
std::string const & // return a constant reference to rthe string theName
name() const // method to access the private string theName
{ return theName ; }
valueType const & xMin() const { return xmin ; }
valueType const & yMin() const { return ymin ; }
valueType const & xMax() const { return xmax ; }
valueType const & yMax() const { return ymax ; }
} ;
// operator for I/O
std::ostream &
operator << ( std::ostream & s, shape const & sp ) {
s << "CLASS = '" << sp . name() << "'\n"
<< "bounding box = [ " << sp . xMin() << ", " << sp . yMin()
<< ", " << sp . xMax() << ", " << sp . yMax() << " ] " ;
}
class quadrilateral : public shape { // define class quadrilateral inheriting by shape
private:
quadrilateral() ; // block the default constructor
public:
quadrilateral( std::string const & n,
valueType xm,
valueType ym,
valueType xM,
valueType yM )
: shape( n, xm, ym, xM, yM )
{
MSG_DEBUG("quadrilateral(\"" << n << "\",xMin,yMin,xMax,yMax) constructor\n") ;
}
valueType perimeter() const {
return 2*(xmax-xmin)+2*(ymax-ymin) ;
}
} ;
class square : public quadrilateral {
private:
square() ; // block the default constructor
public:
square( std::string const & n,
valueType xc,
valueType yc,
valueType len )
: quadrilateral( n, xc - len/2, yc - len/2, xc + len/2, yc + len/2 )
{
MSG_DEBUG("square(\"" << n << "\",xMin,yMin,xMax,yMax) constructor\n") ;
}
} ;
int
main() {
shape s("a shape",-1,-1,2,3) ;
cout << s << "\n" ;
quadrilateral q("a quadrilateral", 1,-1,2,3) ;
cout << q << "\n" ;
square sq("a square", 1,1,20) ;
cout << sq << "\n" ;
return 0 ;
}
Virtual methods
File: inheritance2.cc:
/*
Example of the use of class and inheritance
with functions
*/
// some include files
#include <iostream>
#include <string> // string support
using namespace std ; // load standard namespace
// standard alias for real numbers
typedef double valueType ;
/*
To activate debugging use
#define DEBUG
or in compilation use
g++ -DDEBUG ....
*/
#ifdef DEBUG
#define MSG_DEBUG(A) std::cout << A
#else
#define MSG_DEBUG(A)
#endif
/*
Define the base class for geometric shape
*/
class shape {
private:
std::string const theName ; // std::string STL class for string
shape() ; // disable default constructor
public:
shape( std::string const & n )
: theName(n)
{
MSG_DEBUG("shape(\"" << n << "\") constructor\n") ;
// default constructor
}
virtual ~shape() {
MSG_DEBUG("shape destructor\n") ;
} ; // destructor
std::string const & // return a constant reference to rthe string theName
name() const // method to access the private string theName
{ return theName ; }
// define all the methods of the shape
// of type
virtual valueType xMin() const = 0 ; // make the class abstract
virtual valueType yMin() const = 0 ; // the methods are not defined in shape
virtual valueType xMax() const = 0 ; // but are defined in inherited classes
virtual valueType yMax() const = 0 ;
virtual valueType perimeter() const { return 0 ; } ; // = 0 ;
virtual void print( std::ostream & s ) const { s << "NONE" ; } ; // = 0 ;
} ;
// operator for I/O
std::ostream &
operator << ( std::ostream & s, shape const & sp ) {
sp . print( s ) ;
return s ;
}
class quadrilateral : public shape { // define class quadrilateral inheriting by shape
private:
valueType xm, ym, xM, yM ;
quadrilateral() ; // block the default constructor
public:
quadrilateral( std::string const & n,
valueType xm,
valueType ym,
valueType xM,
valueType yM )
: shape( n )
, xm(xm)
, ym(ym)
, xM(xM)
, yM(xM)
{
MSG_DEBUG("quadrilateral(\"" << n << "\",xMin,yMin,xMax,yMax) constructor\n") ;
}
valueType xMin() const { MSG_DEBUG("quadrilateral::xMin()\n") ; return xm ; }
valueType yMin() const { MSG_DEBUG("quadrilateral::yMin()\n") ; return ym ; }
valueType xMax() const { MSG_DEBUG("quadrilateral::xMax()\n") ; return xM ; }
valueType yMax() const { MSG_DEBUG("quadrilateral::yMax()\n") ; return yM ; }
valueType perimeter() const {
MSG_DEBUG("quadrilateral::perimeter()\n") ;
return 2*(xM-xm)+2*(yM-ym) ;
}
void print( std::ostream & s ) const {
MSG_DEBUG("quadrilateral::print(...)\n") ;
s << "quadrilateral CLASS = '" << name() << "'\n"
<< "bounding box = [ " << xm << ", " << ym << ", " << xM << ", " << yM << " ] " ;
}
} ;
class square : public shape {
private:
valueType xc, yc, len ;
square() ; // block the default constructor
public:
square( std::string const & n,
valueType xc,
valueType yc,
valueType len )
: shape( n )
, xc(xc)
, yc(yc)
, len(len)
{
MSG_DEBUG("square(\"" << n << "\",xMin,yMin,xMax,yMax) constructor\n") ;
}
valueType xMin() const { MSG_DEBUG("quadrilateral::xMin()\n") ; return xc - len/2 ; }
valueType yMin() const { MSG_DEBUG("quadrilateral::yMin()\n") ; return yc - len/2 ; }
valueType xMax() const { MSG_DEBUG("quadrilateral::xMax()\n") ; return xc + len/2 ; }
valueType yMax() const { MSG_DEBUG("quadrilateral::yMax()\n") ; return yc + len/2 ; }
valueType perimeter() const {
MSG_DEBUG("quadrilateral::perimeter()\n") ;
return 4*len ;
}
void print( std::ostream & s ) const {
MSG_DEBUG("square::print(...)\n") ;
s << "square CLASS = '" << name() << "'\n"
<< "center = [ " << xc << ", " << yc << "] edge legth = " << len ;
}
} ;
int
main() {
//shape s("a shape") ;
//cout << s << "\n" ;
quadrilateral q("a quadrilateral", 1,-1,2,3) ;
square sq("a square", 1,1,20) ;
shape * v [] = { &q, &sq } ;
cout << *v[0] << "\n" ;
cout << *v[1] << "\n" ;
return 0 ;
}
A class for solving a non linear system
File: inheritance3.cc:
/*
Example of the use of class and inheritance
with functions for a class that solve a non linear system
*/
// some include files
#include <iostream>
#include <string> // string support
#include <cmath> // for abs
using namespace std ; // load standard namespace
// standard alias for real numbers
typedef double valueType ;
typedef int indexType ;
/*
To activate debugging use
#define DEBUG
or in compilation use
g++ -DDEBUG ....
*/
#ifdef DEBUG
#define MSG_DEBUG(A) std::cout << A
#else
#define MSG_DEBUG(A)
#endif
void
GaussJordan(valueType a[], valueType b[], indexType n) {
for ( indexType i=0 ; i < n ; ++i ) {
// pivoting parziale
indexType k=i ;
for ( indexType j=i+1 ; j < n ; ++j )
if ( abs(a[j+i*n]) > abs(a[k+i*n]) )
k = j ;
// swap row i with row k
if ( k != i ) {
std::swap( b[i], b[k] ) ;
for ( indexType j=i ; j < n ; ++j )
std::swap( a[i+j*n], a[k+j*n] ) ;
}
// divide row i by a(i,i)
valueType bf = a[i+i*n] ;
b[i] /= bf ;
for ( indexType k=i+1 ; k < n ; ++k )
a[i+k*n] /= bf ;
// eliminazione
for ( indexType j=0 ; j < n ; ++j ) {
if ( j==i) continue ; // skip row i
valueType bf = a[j+i*n] ;
b[j] -= bf * b[i] ;
for ( indexType k=i+1 ; k < n ; ++k )
a[j+k*n] -= bf * a[i+k*n] ;
}
}
}
// an abstract class that store the interface for the non linear system
class nonlinear {
private:
std::string const theName ; // std::string STL class for string
nonlinear() ; // disable default constructor
valueType epsi ;
valueType * basePointer ;
valueType * Xk ;
valueType * Xkp1 ;
valueType * Fk ;
valueType * Jk ;
void
allocate( indexType neq ) {
indexType n = 3*neq + neq*neq ; // total number of float to allocate
basePointer = new valueType[n] ;
Xk = basePointer ;
Xkp1 = Xk + neq ;
Fk = Xkp1 + neq ;
Jk = Fk + neq ;
}
void
release() {
delete [] basePointer ;
}
public:
nonlinear( std::string const & n )
: theName(n)
, epsi(1e-8)
{
MSG_DEBUG("nonlinear(\"" << n << "\") constructor\n") ;
// default constructor
}
virtual ~nonlinear() {
MSG_DEBUG("nonlinear destructor\n") ;
} ; // destructor
std::string const & // return a constant reference to rthe string theName
name() const // method to access the private string theName
{ return theName ; }
// algorthm to find the solution
bool solve( valueType x[] ) ;
// interface for the nonlinear system
virtual indexType numEquation() const = 0 ;
virtual void functionEval( valueType const x[], valueType f[] ) = 0 ;
virtual void jacobianEval( valueType const x[], valueType J[] ) = 0 ;
virtual void guess( valueType x[] ) const = 0 ;
} ;
bool
nonlinear::solve( valueType x[] ) {
valueType err ;
indexType neq = numEquation() ;
// newton method
allocate( numEquation() ) ;
// initialize by guess
guess( Xk ) ;
for ( indexType k = 0 ; k < 100 ; ++k ) {
functionEval( Xk, Fk ) ;
jacobianEval( Xk, Jk ) ;
// compute J^(-1)*Fk by solving J*x = Fk and store the result in Fk
GaussJordan(Jk, Fk, neq ) ;
// Xk1 = Xk - J^(-1)*Fk
for ( indexType i = 0 ; i < neq ; ++i )
Xkp1[i] = Xk[i] - Fk[i]/2 ;
// check termination
err = 0 ;
for ( indexType i = 0 ; i < neq ; ++i )
err = max( err, abs( Xkp1[i]-Xk[i] ) ) ;
if ( err < epsi ) break ;
// Xk = Xkp1 ;
std::copy( Xkp1, Xkp1 + neq, Xk ) ;
}
// copy solution to x
std::copy( Xk, Xk + neq, x ) ;
release() ;
return err < epsi ;
}
// Using the class to solve the problem
//
// 10 x^2 + x^2 + y = 1
// x + 10 y^2 - y^2 = 2
//
class my_problem : public nonlinear {
public:
my_problem() : nonlinear( "my problem" )
{ }
virtual indexType numEquation() const { return 2 ; }
virtual void functionEval( valueType const X[], valueType F[] ) {
valueType const & x = X[0] ; // make alias for X[0] and X[1]
valueType const & y = X[1] ;
F[0] = 10*x + x*x + y - 1 ;
F[1] = x + 10*y - y*y - 2 ;
}
// 10+2*x 1
// 1 10-2*y
virtual void jacobianEval( valueType const X[], valueType J[] ) {
valueType const & x = X[0] ; // make alias for X[0] and X[1]
valueType const & y = X[1] ;
// store the matrix by column
J[0] /* J(0,0) */ = 10+2*x ;
J[1] /* J(1,0) */ = 1 ;
J[2] /* J(0,1) */ = 1 ;
J[3] /* J(1,1) */ = 10-2*y ;
}
virtual void guess( valueType X[] ) const {
valueType & x = X[0] ; // make alias for X[0] and X[1]
valueType & y = X[1] ;
x = y = 0 ;
}
} ;
int
main() {
my_problem p ;
valueType x[2] ;
bool ok = p . solve( x ) ; // call iterative method to solve non linear problem
if ( ok ) cout << "problem solved\n" ;
else cout << "problem NOT solved\n" ;
cout << "x = " << x[0] << " y = " << x[1] << '\n' ;
return 0 ;
}
Lesson of 22 July 2009
Example of the use of STL: the vector container
File: stl.cc:
/*
Example of use of STL (Standard Template Library)
the vector container
*/
#include <iostream> // for I/O
#include <string> // string support
#include <cmath> // for sin, cos, ...
#include <vector> // the definition of STL vector container
#include <algorithm> // the definition of the STL algorithm (sort, find,...)
using namespace std ;
int
main() {
// define a as a vector of int
vector<int> a ;
a . push_back(12) ;
a . push_back(4) ;
cout << "a.front() = " << a.front() << '\n' ; // the first element
cout << "a.back() = " << a.back() << '\n' ; // the last element
cout << "size of a = " << a . size() << '\n' ;
// define b as a vector of 10 float
vector<float> b(10) ;
cout << "size of b = " << b . size() << '\n' ;
b[2] = 30 ; // random access to the element of b
b[5] = 12 ;
b[9] = 1.34 ;
// loop on the vector C-style way
for ( int i=0 ; i < b.size() ; ++i )
cout << "b[" << i << "] = " << b[i] << '\n' ;
// ^
// |
// access to the i-th element of vector b
// loop on the vector STL-style way
for ( vector<float>::iterator i = b . begin() ;
i != b . end() ;
++i ) // increment the iterator to "point" to the next object in
// the vector b (an instance of vector<int>)
cout << *i << '\n' ;
// ^
// |
// access to the element of vector b pointed by iterator i
// Algorithms
cout << "do sort\n" ;
sort( b.begin(), b.end() ) ;
//reverse( b.begin(), b.end() ) ;
//sort( b.rbegin(), b.rend() ) ;
for ( vector<float>::iterator i = b . begin() ; i != b . end() ; ++i )
cout << *i << '\n' ;
vector<float>::iterator i = max_element( b.begin(), b.end() ) ;
cout << "maximum element = " << *i << '\n' ;
b . clear() ; // cancel all the elements of the vector
cout << "size of b = " << b . size() << '\n' ;
b . reserve( 21 ) ; // pre allocate memory for 21 elements
for ( int i=0 ; i < 21 ; ++i ) b . push_back( i ) ;
vector<float> c(30) ;
copy( b.begin(), b.end(), c.begin() ) ;
// ^ ^ ^
// +----------+ + "pointer" to the begin of the "destination" memory
// range to be copied
// it is equivalent to
for ( vector<float>::iterator i = b . begin(), j = c . begin() ;
i != b . end() ;
++i, ++j )
*j = *i ;
for ( int i = 0 ; i < b.size() ; ++i ) c[i] = b[i] ;
// simulation of a matrix
vector<vector<float> > m ;
// to allocate for a matrix 10x20
m . resize(10) ; // allocate for 10 vector
// C-way loop
for ( int i = 0 ; i < m . size() ; ++i ) m[i] . resize(20) ;
// STL-way loop
for ( vector<vector<float> >::iterator i = m.begin() ;
i != m . end() ; ++i ) i -> resize(20) ;
m[1][3] = 123 ; // m[1] access to 2nd element of m which is a vector
// m[1][3] access to 3rd element of vector m[1].
}
The dqueue
container
File: stl2.cc:
/*
Example of use of STL (Standard Template Library)
the dqueue container
*/
#include <iostream> // for I/O
#include <string> // string support
#include <cmath> // for sin, cos, ...
#include <deque> // the definition of STL deque container
#include <algorithm> // the definition of the STL algorithm (sort, find,...)
using namespace std ;
int
main() {
// define a as a vector of int
deque<int> a ;
a . push_back(12) ;
a . push_front(4) ;
cout << "a.front() = " << a.front() << '\n' ; // the first element
cout << "a.back() = " << a.back() << '\n' ; // the last element
cout << "size of a = " << a . size() << '\n' ;
// define b as a vector of 10 float
deque<float> b(10) ;
cout << "size of b = " << b . size() << '\n' ;
b[2] = 30 ; // random access to the element of b
b[5] = 12 ; // implemented internally by a loop!
b[9] = 1.34 ;
// loop on the vector STL-style way
for ( deque<float>::iterator i = b . begin() ;
i != b . end() ;
++i ) // increment the iterator to "point" to the next object in
// the vector b (an instance of vector<int>)
cout << *i << '\n' ;
// ^
// |
// access to the element of vector b pointed by iterator i
// Algorithms
cout << "do sort\n" ;
sort( b.begin(), b.end() ) ; // now use merge sort not quick sort
//reverse( b.begin(), b.end() ) ;
//sort( b.rbegin(), b.rend() ) ;
for ( deque<float>::iterator i = b . begin() ; i != b . end() ; ++i )
cout << *i << '\n' ;
deque<float>::iterator i = max_element( b.begin(), b.end() ) ;
cout << "maximum element = " << *i << '\n' ;
b . clear() ; // cancel all the elements of the vector
cout << "size of b = " << b . size() << '\n' ;
for ( int i=0 ; i < 21 ; ++i ) b . push_back( i ) ;
deque<float> c(30) ;
copy( b.begin(), b.end(), c.begin() ) ;
// ^ ^ ^
// +----------+ + "pointer" to the begin of the "destination" memory
// range to be copied
// it is equivalent to
for ( deque<float>::iterator i = b . begin(), j = c . begin() ;
i != b . end() ;
++i, ++j )
*j = *i ;
for ( int i = 0 ; i < b.size() ; ++i ) c[i] = b[i] ;
}
the set container
File: stl3.cc:
/*
Example of use of STL (Standard Template Library)
the set container
*/
#include <iostream> // for I/O
#include <string> // string support
#include <cmath> // for sin, cos, ...
#include <set> // the definition of STL set container
#include <algorithm> // the definition of the STL algorithm (sort, find,...)
using namespace std ;
int
main() {
// define a as a vector of int
set<int> a ;
a . insert(12) ;
a . insert(4) ;
a . insert(4) ;
a . insert(4) ;
a . insert(4) ;
a . insert(4) ;
cout << "size of a = " << a . size() << '\n' ;
// loop on the vector STL-style way
for ( set<int>::iterator i = a . begin() ;
i != a . end() ;
++i ) // increment the iterator to "point" to the next object in
// the vector b (an instance of vector<int>)
cout << *i << '\n' ;
// ^
// |
// access to the element of vector b pointed by iterator i
multiset<int> b ;
b . insert(12) ;
b . insert(4) ;
b . insert(4) ;
b . erase(4) ;
b . insert(4) ;
b . insert(4) ;
b . insert(4) ;
cout << "size of b = " << b . size() << '\n' ;
// loop on the vector STL-style way
for ( multiset<int>::iterator i = b . begin() ;
i != b . end() ;
++i ) // increment the iterator to "point" to the next object in
// the vector b (an instance of vector<int>)
cout << *i << '\n' ;
// ^
// |
// access to the element of vector b pointed by iterator i
multiset<int>::iterator i = max_element( b . begin(), b . end() ) ;
}
Lesson of 23 July 2009
Use of the string class
File: string-examples.cc:
/*
A simple program to test string class
*/
#include <iostream> // for I/O
#include <iomanip> // for hex, dec, width
#include <string> // string support
using namespace std ;
int
main() {
string a, b, c("$$$"), d("pippo") ;
a = d ;
char const * pa = a . c_str() ; // get the pointer to the C-string of a
char const * pd = d . c_str() ; // get the pointer to the C-string of d
cout << "address of string a = " << hex << setw(10) << (unsigned long)pa << '\n' ;
cout << "address of string d = " << hex << setw(10) << (unsigned long)pd << '\n' ;
//
// ^ ^ ^
// use hexadecimal numer -----------+ | |
// set width for next output to 10 charater -+ |
// cast: convert type from pointer to unsigned integer ------+
a += " pluto" ;
cout << "a = '" << a << "'\n" ;
cout << "b = '" << b << "'\n" ;
pa = a . c_str() ; // get the pointer to the C-string of a
pd = d . c_str() ; // get the pointer to the C-string of d
cout << "address of string a = " << hex << setw(10) << (unsigned long)pa << dec << '\n' ;
cout << "address of string d = " << hex << setw(10) << (unsigned long)pd << dec << '\n' ;
// main operation on string
// concatenation, concatenate string a and c
b = a+c ;
cout << "a = '" << a << "'\n" ;
cout << "c = '" << c << "'\n" ;
cout << "a+c = '" << b << "'\n" ;
// find
int i = a . find("plut") ;
cout << "a . find(\"plut\") = " << i << "\n" ;
i = a . find("asx") ;
cout << "a . find(\"asx\") = " << i << "\n" ;
// comparison
a = "pippo" ;
b = "pluto" ;
c = "paperino" ;
d = "pippo" ;
cout << "a = '" << a << "'\n" ;
cout << "b = '" << b << "'\n" ;
cout << "c = '" << c << "'\n" ;
cout << "d = '" << d << "'\n" ;
cout << "'" << a <<"' < '" << b << "' = " ;
if ( a < b ) cout << "true\n" ;
else cout << "false\n" ;
cout << "'" << a <<"' > '" << c << "' = " ;
if ( a > c ) cout << "true\n" ;
else cout << "false\n" ;
cout << "'" << a <<"' == '" << d << "' = " ;
if ( a == d ) cout << "true\n" ;
else cout << "false\n" ;
cout << "'" << b <<"' >= '" << c << "' = " ;
if ( b >= c ) cout << "true\n" ;
else cout << "false\n" ;
cout << "'" << c <<"' >= '" << a << "' = " ;
if ( c >= a ) cout << "true\n" ;
else cout << "false\n" ;
}
Use of the string class: convert a number to letter
File: convert.cc:
/*
A simple program to convert a number to string.
For example
1234 => onethousandtwohundredthirtythree
*/
#include <iostream> // for I/O
#include <string> // string support
using namespace std ;
string
convert0to19( unsigned n ) {
// vector of strings for the first 20 numbers
// *(str[]) = vector of pointer to character
char *str[] = {
"", // 0 must be empty
"one", // 1
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"nineteen"
} ;
return str[ n % 20 ] ; // here the constructor string(str[n]) is used
// to build the return object
}
string
convert0to99( unsigned n ) {
// vector of strings for the first 20 numbers
// *(str[]) = vector of pointer to character
char *str[] = {
"",
"ten",
"twenty",
"thirty",
"fourty",
"fifty",
"sixty",
"seventy",
"eighty",
"ninety",
} ;
if ( n < 20 ) return convert0to19(n) ;
return string( str[ (n/10) % 10 ] ) + convert0to19( n % 10 ) ;
}
string
convert0to999( unsigned n ) {
// vector of strings for the first 20 numbers
// *(str[]) = vector of pointer to character
char *str[] = {
"",
"onehundred",
"twohundred",
"threehundred",
"fourhundred",
"fivehundred",
"sixhundred",
"sevenhundred",
"eighthundred",
"ninehundred",
} ;
if ( n < 100 ) return convert0to99(n) ;
return string( str[ (n/100) % 10 ] ) + convert0to99( n % 10 ) ;
}
string
convert0to999999( unsigned n ) {
// vector of strings for the first 20 numbers
// *(str[]) = vector of pointer to character
if ( n < 1000 ) return convert0to999(n) ;
unsigned upper = n / 1000 ;
unsigned lower = n % 1000 ;
return convert0to999( upper ) + "thousand" + convert0to999( lower ) ;
}
string
convert( unsigned n ) {
string res = convert0to999999( n ) ;
if ( res . length() > 0 ) return res ;
else return "zero" ; // call the contructor string("zero")
}
int
main() {
cout << convert(10002) << "\n" ;
cout << convert(21222) << "\n" ;
cout << convert(1000) << "\n" ;
cout << convert(991234) << "\n" ;
}
Euler numerical scheme, C-like implementation
File: Euler.cc:
/*
A simple example to use class and numerical integrator.
Use Euler numerical method to "solve" a differential
equation
Y' = f(t,Y)
Y(0) = Y0
*/
#include <iostream> // for I/O
#include <fstream> // for I/O
#include <iomanip> // for hex, dec, width
#include <string> // string support
#include <algorithm>
#include <vector>
// define the problem
//
// x' = y
// y' = -x
// x(0) = 1
// y(0) = 0
//
// Y = (x,y)^T f(t,Y) = ( y, -x ) ^T
//
void
f( double t, double Y[], double Y1[] ) {
Y1[0] = Y[1] ;
Y1[1] = -Y[0] ;
}
// Euler solver (C-way)
void
Euler( void (*fun)( double t, double Y[], double Y1[] ), // function to be integrated
double const Y0[], // initial value
int const neq, // number of equation
int const N, // number of steps
double const h, // time step
double Y[] ) { // output vector
double * Fk = new double[neq] ;
// copy the initial condition
std::copy( Y0, Y0 + neq, Y ) ;
for ( int k=0 ; k < N ; ++k ) {
double * Yk = Y + neq * k ;
double * Ykp1 = Yk + neq ;
fun( k*h, Yk, Fk ) ;
// perform Euler step
for ( int i = 0 ; i < neq ; ++i )
Ykp1[i] = Yk[i] + h * Fk[i] ;
}
delete [] Fk ;
}
using namespace std ;
int
main() {
double Y[100][2] ;
double Y0[] = {1, 0} ;
Euler( f, Y0, 2, 100, 0.1, (double*)Y ) ;
ofstream file("out.txt") ;
file << "x\ty\n" ; // header of the output file
for ( int i=0 ; i < 100 ; ++i )
file << Y[i][0] << '\t' << Y[i][1] << '\n' ;
file . close() ;
}
Euler numerical scheme, C++ implementation
File: Euler1.cc:
/*
A simple example to use class and numerical integrator.
Use Euler numerical method to "solve" a differential
equation
Y' = f(t,Y)
Y(0) = Y0
better implementation using STL
*/
#include <iostream> // for I/O
#include <fstream> // for I/O
#include <iomanip> // for hex, dec, width
#include <string> // string support
#include <algorithm>
#include <vector>
using namespace std ;
// define the problem
//
// x' = y
// y' = -x
// x(0) = 1
// y(0) = 0
//
// Y = (x,y)^T f(t,Y) = ( y, -x ) ^T
//
void
f( double t, vector<double> const & Y, vector<double> & Y1 ) {
Y1[0] = Y[1] ;
Y1[1] = -Y[0] ;
}
// Euler solver
template <typename T, int neq>
void
Euler( void (*fun)( T t, vector<T> const &, vector<T> &), // function to be integrated
vector<T> const Y0, // initial value
int const N, // number of steps
T const h, // time step
vector<vector<T> > & Y ) { // output vector
std::vector<T> Ykp1(neq), Fk(neq) ;
Y . reserve( N ) ; // pre allocation for N elements
// copy the initial condition
std::copy( Y0 . begin(), Y0 . end(), Ykp1.begin() ) ;
Y . push_back( Ykp1 ) ;
for ( int k=0 ; k < N ; ++k ) {
fun( k*h, Y.back(), Fk ) ;
// perform Euler step
for ( int i = 0 ; i < neq ; ++i )
Ykp1[i] = Y.back()[i] + h * Fk[i] ;
Y . push_back( Ykp1 ) ; // copy the last computed value to the end
// of the output vector
}
}
int
main() {
vector<vector<double> > Y ;
vector<double> Y0 ;
Y0 . push_back(1) ;
Y0 . push_back(0) ;
Euler<double,2>( f, Y0, 100, 0.1, Y ) ;
ofstream file("out.txt") ;
file << "x\ty\n" ; // header of the output file
for ( vector<vector<double> >::iterator i = Y.begin() ;
i != Y . end() ; ++i )
file << (*i)[0] << '\t' << (*i)[1] << '\n' ;
file . close() ;
}
- Calcolo Numerico
- Numerical Analysis
- Metodi Matematici e Calcolo per Ingegneria
- Numerical Unconstrained Optimization
- Scientific Programming in C++
Corso di Calcolo Numerico (AA 2007/2008)
Esercitazioni di MATLAB: Lezione del 4 Marzo 2008
Esempio di programmazione
File: linearsistemsolve.m:
%
% Risolve il sistema lineare A*x = b
%
function x = linearsistemsolve( A, b )
[nr,nc] = size(A) ;
% controllo dimensioni
if nr ~= nc
error( sprintf( 'la matrice A (%d x %d) non e` quadrata ', nr,nc) ) ;
end
neq = length(b) ;
if nr ~= neq
error( sprintf( 'la matrice A (%d x %d) non e` compatibile\ncon la lunghezza del vettore b, length(b) = %d ', nr, nc, neq ) ) ;
end
M = [ A b ] ; % costruisco la matrice aumentata
for i=1:neq-1
% cerco l'elemento di massimo modulo colonna i-esima
[V,k] = max(abs(M(i:end,i))) ;
% rimetto l'indice k alla giusta posizione
k = k + i-1 ;
% scambio la riga i con la riga k
BF = M(i,:) ;
M(i,:) = M(k,:) ;
M(k,:) = BF ;
% controllo singolaritÃ
if V == 0
error( 'Matrice singolare' ) ;
end
% costruisco la matrice di Frobenius
L = eye(neq) ;
L(i+1:end,i) = -M(i+1:end,i)./M(i,i) ;
% azzero gli elementi della colonna i
M = L * M ;
end
% alloco il vettore soluzione
x = zeros(neq,1) ;
% a questo punto la matrice è in forma triangolare
% applichiamo le operazioni di ritorno
x(neq) = M(neq,neq) / M(neq,neq+1) ;
for i=neq-1:-1:1
x(i) = ( M(i,neq+1) - M(i,i+1:end-1) * x(i+1:end) ) / M(i,i) ;
end
Esercitazioni di MATLAB: Lezione del 17 Marzo 2008
Soluzione di problemi ellittici in dimensione 1
Solutore del BVP:
File: bvp.m:
%
% Genero la matrice dei coefficienti e il temine noto del
% problema ellittico
%
% u''(x) = f(x) su (0,1)
%
% u(0) = u0 u(1)=u1
%
% N = numero i suddivisioni dell'intervallo [0,1]
% f = funzione termine sorgente
% u0, u1 = condizioni al contorno
%
% A = matrice dei coefficienti
% b = termine noto
%
% la soluzione è posta nei vettori colonna X e Y che contengono
% i valori nodali nella mesh compreso i termini al bordo
%
% X = X(i) coodinata x del nodo (i)
% Z = Z(i) coodinata z della soluzione nel nodo (i)
%
% + +
% 1 | |
% ----- | 1 -2 1 | u_i = f_i
% h^2 | |
% + +
%
function [A,b,X,Y] = bvp(N,f,u0,u1)
%
h = 1/N ; % dimensione della mesh
neq = N-1 ;
% coefficienti dello stencil
h2 = h^2 ;
% costruzione della matrice dei coefficienti
A = sparse( neq, neq ) ;
b = zeros ( neq, 1 ) ;
for i=1:neq
x = i*h ;
% termine noto
b(i) = h2*feval( f, x ) ;
% coefficienti dello stencil
A(i,i) = -2 ;
if i > 1
A(i,i-1) = 1 ;
else
b(i) = b(i) - u0 ;
end
if i < neq
A(i,i+1) = 1 ;
else
b(i) = b(i) - u1 ;
end
end
% calcolo la soluzione
SOL = A\b ;
% riempio i vettori X e Y con la soluzione
Y = [ u0 ; SOL ; u1 ] ;
X = [ 0:h:1 ]' ;
end
Script per testare il codice:
File: testBVP.m:
function testBVP
N = 10 ;
[ A, b, X1, Y1 ] = bvp( N, @ff, ye(0), ye(1) ) ;
N = N*2 ;
[ A, b, X2, Y2 ] = bvp( N, @ff, ye(0), ye(1) ) ;
N = N*2 ;
[ A, b, X3, Y3 ] = bvp( N, @ff, ye(0), ye(1) ) ;
N = N*2 ;
[ A, b, X4, Y4 ] = bvp( N, @ff, ye(0), ye(1) ) ;
N = N*2 ;
[ A, b, X5, Y5 ] = bvp( N, @ff, ye(0), ye(1) ) ;
EX1 = ye(X1) ;
EX2 = ye(X2) ;
EX3 = ye(X3) ;
EX4 = ye(X4) ;
EX5 = ye(X5) ;
E1 = norm( Y1 - EX1, inf ) ;
E2 = norm( Y2 - EX2, inf ) ;
E3 = norm( Y3 - EX3, inf ) ;
E4 = norm( Y4 - EX4, inf ) ;
E5 = norm( Y5 - EX5, inf ) ;
disp( sprintf( 'E1 = %g', E1 ) ) ;
disp( sprintf( 'E2 = %g', E2 ) ) ;
disp( sprintf( 'E3 = %g', E3 ) ) ;
disp( sprintf( 'E4 = %g', E4 ) ) ;
disp( sprintf( 'E5 = %g', E5 ) ) ;
disp( sprintf( 'order = %g', log( E1/E2 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E2/E3 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E3/E4 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E4/E5 ) / log( 2 ) ) ) ;
end
function res = ff(x)
res = 100*sin(10*x) ;
end
function res = ye(x)
res = -sin(10*x) ;
end
Soluzione di problemi ellittici in dimensione 2
Solutore del problema ellittico:
File: elliptic.m:
%
% Genero la matrice dei coefficienti e il temine noto del
% problema ellittico
%
% u(x,y) + u(x,y) = f(x,y) su (0,1) x (0,1)
% xx yy
%
% u(x,y) = g(x,y) su bordo (0,1) x (0,1)
%
% N = numero i suddivisioni dell'intervallo [0,1]
% f = funzione termine sorgente
% g = funzione che implementa le condizioni al contorno
%
% A = matrice dei coefficienti
% b = termine noto
%
% la soluzione � posta nelle metrici X, Y, e Z che contengono
% i valori nodali nella mesh compreso i termini al bordo
%
% X = X(i,j) coodinata x del nodo (i,j)
% Y = Y(i,j) coodinata y del nodo (i,j)
% Z = Z(i,j) coodinata z della soluzione nel nodo (i,j)
%
%
% + +
% | 1 |
% 1 | |
% ----- | 1 -4 1 | u_ij = f_ij
% h^2 | |
% | 1 |
% + +
%
function [A,b,X,Y,Z] = elliptic(N,f,g)
%
h = 1/N ; % dimensione della mesh
% numerazione delle equazioni
EQ = zeros(N+1,N+1) ;
% numero le equazioni (solo punti interni)
EQ(2:end-1,2:end-1) = [1:N-1]'* ones(1,N-1) + ...
ones(N-1,1)*[0:N-2]*(N-1) ;
neq = (N-1)^2 ;
% questo corrisponde al ciclo
% neq = 0 ;
% for i=2:N
% for j=2:N
% neq = neq + 1 ;
% EQ(i,j) = neq ;
% end
% end
% ordinamento RED-BLACK
% neq = 0 ;
% for i=2:N
% for j=2:N
% if mod(i+j,2) == 0
% neq = neq + 1 ;
% EQ(i,j) = neq ;
% end
% end
% end
% for i=2:N
% for j=2:N
% if mod(i+j,2) == 1
% neq = neq + 1 ;
% EQ(i,j) = neq ;
% end
% end
% end
% coefficienti dello stencil
h2 = h^2 ;
% costruzione della matrice dei coefficienti
A = sparse( neq, neq ) ;
b = zeros ( neq, 1 ) ;
for i=2:N
x = (i-1)*h ;
for j=2:N
y = (j-1)*h ;
% numero equazioni vicine
ic = EQ(i,j) ;
il = EQ(i-1,j) ; % left
ir = EQ(i+1,j) ; % right
it = EQ(i,j+1) ; % top
ib = EQ(i,j-1) ; % bottom
% termine noto
b(ic) = h2*feval( f, x, y ) ;
% coefficienti dello stencil
A(ic,ic) = -4 ;
if il > 0
% Punto interno aggiungo alla matrice il pezzo di stencil
A(ic,il) = 1 ;
else
% Punto di bordo aggiungo al termine noto la BC
b(ic) = b(ic) - feval( g, x-h, y ) ;
end
if ir > 0
A(ic,ir) = 1 ;
else
b(ic) = b(ic) - feval( g, x+h, y ) ;
end
if it > 0
A(ic,it) = 1 ;
else
b(ic) = b(ic) - feval( g, x, y+h ) ;
end
if ib > 0
A(ic,ib) = 1 ;
else
b(ic) = b(ic) - feval( g, x, y-h ) ;
end
end
end
% calcolo la soluzione
SOL = A\b ;
% riempimento delle matrici in uscita, inizializzazione
Z = zeros(N+1,N+1) ;
[X,Y] = meshgrid(linspace(0,1,N+1),linspace(0,1,N+1)) ;
% Cerco gli indici dei nodi interni, quelli numerati
IDX = find( EQ > 0 ) ;
% copio la soluzione tenendo conto dell'ordine delle equazioni
Z(IDX) = SOL(EQ(IDX)) ;
% Cerco gli indici dei nodi di bordo
IDX = find( EQ == 0 ) ;
% copio i valori al contorno sulla soluzione
Z(IDX) = feval( g, X(IDX), Y(IDX) ) ;
end
Script per testare il codice:
File: testElliptic.m:
N = 5 ;
[ A, b, X1, Y1, Z1 ] = elliptic( N, @f, @g ) ;
N = N*2
[ A, b, X2, Y2, Z2 ] = elliptic( N, @f, @g ) ;
N = N*2
[ A, b, X3, Y3, Z3 ] = elliptic( N, @f, @g ) ;
N = N*2
[ A, b, X4, Y4, Z4 ] = elliptic( N, @f, @g ) ;
N = N*2
[ A, b, X5, Y5, Z5 ] = elliptic( N, @f, @g ) ;
EX1 = g(X1, Y1) ;
EX2 = g(X2, Y2) ;
EX3 = g(X3, Y3) ;
EX4 = g(X4, Y4) ;
EX5 = g(X5, Y5) ;
E1 = max(max( abs(Z1 - EX1) )) ;
E2 = max(max( abs(Z2 - EX2) )) ;
E3 = max(max( abs(Z3 - EX3) )) ;
E4 = max(max( abs(Z4 - EX4) )) ;
E5 = max(max( abs(Z5 - EX5) )) ;
disp( sprintf( 'E1 = %g', E1 ) ) ;
disp( sprintf( 'E2 = %g', E2 ) ) ;
disp( sprintf( 'E3 = %g', E3 ) ) ;
disp( sprintf( 'E4 = %g', E4 ) ) ;
disp( sprintf( 'E5 = %g', E5 ) ) ;
disp( sprintf( 'order = %g', log( E1/E2 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E2/E3 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E3/E4 ) / log( 2 ) ) ) ;
disp( sprintf( 'order = %g', log( E4/E5 ) / log( 2 ) ) ) ;
Funzione per disegnare la soluzione:
File: plotSol.m:
function plotSol(N,Z,EQ)
[X,Y] = meshgrid(linspace(0,1,N+1),linspace(0,1,N+1)) ;
surf(X,Y,Z) ;
Funzione termine sorgente:
File: f.m:
function res = f(x,y)
res = 2*exp(x+y) ;
%res = 12*(x.^2+y.^2) ;
%res = exp(x.*y).*(x.^2+y.^2) ;
end
Funzione valore al contorno:
File: g.m:
function res = g(x,y)
res = exp(x+y) ;
%res = x.^4+y.^4 ;
%res = x.*y+exp(x.*y) ;
end
Tutti i file MATLAB in un unico archivio
Esercitazioni di MATLAB: Lezione del 7 Aprile 2008
Metodo delle secanti
Una possibile implementazione del metodo delle secanti:
File: secanti.m:
%
% Metodo delle secanti
%
% Cerco lo zero della funzione fun(x) a partire
% da due approssimazioni distinte dello zero x0 ed x1.
% epsi e' la tolleranza sotto la quale le iterate vengono
% interrotte.
%
% In uscita viene resttuito il vettore con tutte
% le iterate calcolate.
%
function X = secanti(fun,x0,x1,epsi)
X = [x0;x1] ;
f0 = feval(fun,x0) ;
f1 = feval(fun,x1) ;
for i=1:100
% formula di avanzamento
df = (f1-f0)/(X(end)-X(end-1)) ;
xnew = X(end) - f1/df ;
% aggiorna i vettori
X = [X ; xnew ] ;
f0 = f1 ;
f1 = feval(fun,xnew) ;
% controlla se interrompere il ciclo
if abs(f1) < epsi ; break ; end ;
end
end
Uno script per plottare bene le iterate:
File: piter.m:
%
% Funzione per la stampa delle iterate per il metodo delle
% secanti
%
% fun = funzione alla quale e' stato applicato
% il metodo delle secanti
% X = vettore con la storia delle iterate
%
% xe = soluzione esatta
%
function piter(fun,X,xe)
% calcolo ingombro iterate per coordinata X
xmin = min(X) ;
xmax = max(X) ;
len = xmax-xmin ;
xmin = xmin - len/10 ;
xmax = xmax + len/10 ;
% vettori per il plot della funzione
XX = [xmin:len/1000:xmax] ;
YY = feval(fun,XX) ;
% calcolo ingombro iterate per coordinata Y
ymin = min(YY) ;
ymax = max(YY) ;
plot(XX,YY,'LineWidth',2);
hold on;
% assi centrati sullo zero
plot([xe;xe],[ymin;ymax],'k-','LineWidth',1);
plot([xmin;xmax],[0;0],'k-','LineWidth',1);
for i=1:length(X)
x = X(i) ;
% linea verticale
plot([x;x],[0;feval(fun,x)],'r--','LineWidth',2);
if i>2
x2 = X(i-2) ;
% secante
plot([x;x2],[0;feval(fun,x2)],'c-');
end
end
axis on ;
hold off;
end
Uno script per testare tutto:
File: test.m:
%
% Funzione per testare il medoto delle secanti
%
%
function test
% parametri per il problema
x0 = 3 ;
x1 = 1 ;
epsi = 1E-15 ;
% chiama il solutore
X = secanti(@fun,x0,x1,epsi) ;
% soluzione esatta
xe = 0;
% differenza con la soluzione esatta
ERR = X-xe
% stima ordine di convergenza
ORDER = log(ERR(3:end)./ERR(2:end-1)) ./ log(ERR(2:end-1)./ERR(1:end-2)) ;
% stampa stima degli ordini
disp(ORDER) ;
% plottaggio delle iterate a video
piter(@fun,X,xe) ;
end
function res = fun(x)
res = x.*exp(x)./(1+x.^2) ;
%res = (x-3).^3+(x-3)*0.1 ;
end
Tutti i file MATLAB in un unico archivio
Esercitazioni di MATLAB: Lezione del 5 Maggio 2008
Controesempio di runge
Uno script per plottare l’esempio di Runge con nodi equispaziati:
File: runge.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.4 (Enrico Bertolazzi)
%
% Esempio di Runge per verificare la NON CONVERGENZA
% della intepolazione polinomiale.
%
function runge
% metto i parametri per la interpolazione polinomiale in un cell array.
% I numeri sono il grado del polinomio interpolante,
% le stringhe sono la formattazione per il comanfo plot.
N = { {4,'-k'}, ...
{8,'-g'}, ...
{12,'-m'} } ;
% sopra il grado 12 ployfit da un avvertimento perche' non riesce
% a calcolare "bene" il polinomio interpolante a causa del
% cattivo condizionamento del problema
% x contiene le ascisse per il plottaggio delle curve e dei polinomi interpolanti
x = -5:0.01:5;
hold on ; % da adesso in poi il comando plot scrive sulla stessa finestra
axis([-5 5 -1 1.1]) ; % dimensiono l'area di plottaggio
plot( x, rfun(x), '-r', 'LineWidth', 2 ) ; % disegna la curva y = 1/(1+x^2)
for k=1:length(N)
% N{k}{1} = grado del polinomio interpolante
% N{k}{2} = stringa formattazione per plot
xp = -5:10/N{k}{1}:5 ; % costruisco vettore delle x con i punti di interpolazione equispaziati
p = polyfit( xp, rfun(xp), N{k}{1} ) ; % costruisco il polinomio interpolante,
% fai doc polyfit per avere piu' informazioni
plot( x, polyval(p, x), N{k}{2} ); % plottaggio del polinomio interpolante,
% fai doc polyval per avere piu' informazioni
end
hold off ; % da adesso in poi il comando plot NON scrive sulla stessa finestra
end
function y = rfun( x )
y = 1 ./ ( 1 + x .^ 2 ) ;
end
Uno script per plottare l’esempio di Runge con nodi di Chebishev:
File: chebyshev.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.4 (Enrico Bertolazzi)
%
% Esempio di Runge con nodi di Chebyshev.
%
function chebyshev
% metto i parametri per la interpolazione polinomiale in un cell array.
% I numeri sono il grado del polinomio interpolante,
% le stringhe sono la formattazione per il comanfo plot.
N = { {4,'-k'}, ...
{8,'-g'}, ...
{12,'-m'}, ...
{16,'-b'} } ;
% sopra il grado 12 ployfit da un avvertimento perche' non riesce
% a calcolare "bene" il polinomio interpolante a causa del
% cattivo condizionamento del problema
% x contiene le ascisse per il plottaggio delle curve e dei polinomi interpolanti
x = -5:0.01:5;
hold on ; % da adesso in poi il comando plot scrive sulla stessa finestra
axis([-5 5 -0.2 1]) ; % dimensiono l'area di plottaggio
plot( x, rfun(x), '-r', 'LineWidth', 2 ) ; % disegna la curva y = 1/(1+x^2)
for k=1:length(N)
% N{k}{1} = grado del polinomio interpolante
% N{k}{2} = stringa formattazione per plot
xp = 5*cheb( N{k}{1} ) % costruisco vettore delle x con i punti di interpolazione equispaziati
p = polyfit( xp, rfun(xp), N{k}{1} ) ; % costruisco il polinomio interpolante,
% fai doc polyfit per avere piu' informazioni
plot( x, polyval(p, x), N{k}{2} ); % plottaggio del polinomio interpolante,
% fai doc polyval per avere piu' informazioni
end
hold off ; % da adesso in poi il comando plot NON scrive sulla stessa finestra
end
% fuzione di Runge
function y = rfun( x )
y = 1 ./ ( 1 + x .^ 2 ) ;
end
% nodi di Chebyshev
function x = cheb( n )
x = cos( [0:1/n:1] .* pi ) ;
end
Integrazione numerica
La funzione di Runge:
File: rfun.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.4 (Enrico Bertolazzi)
%
% Funzione di Runge
%
function y = rfun( x )
y = 1 ./ ( 1 + x .^ 2 ) ;
end
Esercizio proposto dal prof. Ana Alonso
File: alonso.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.4 (Enrico Bertolazzi)
%
% Esercizio proposto dal prof. Ana Alonso
%
function alonso( N, a, b, fun )
% nodi di interpolazione equispaziati
xequ = [a:(b-a)/N:b] ;
% nodi di interpolazione di Chebichev
xcheb = (a+b)/2 + ((b-a)/2) * cheb(N) ;
% polinomio interpolante con nodi equispaziati
pequ = polyfit( xequ, feval( fun, xequ), N ) ;
% polinomio interpolante con nodi di Chebichev
pcheb = polyfit( xcheb, feval( fun, xcheb), N ) ;
% Primitiva del polinomio interpolante con nodi equispaziati
Ipequ = polyint( pequ ) ;
% Primitiva del polinomio interpolante con nodi di Chebichev
Ipcheb = polyint( pcheb ) ;
% calcolo integrale del polinomio pequ nell'intervallo [a,b]
Iequ = polyval( Ipequ, b) - polyval( Ipequ, a) ;
% calcolo integrale del polinomio pcheb nell'intervallo [a,b]
Icheb = polyval( Ipcheb, b) - polyval( Ipcheb, a) ;
% calcolo integrale della funzione fun con il comando quad
Iquad = quad( fun, a, b ) ;
% stampa dei risultati
disp( sprintf( 'Integrale con nodi equispaziati %f', Iequ) ) ;
disp( sprintf( 'Integrale con nodi di Chebyshev %f', Icheb) ) ;
disp( sprintf( 'Integrale con funzione MATLAB quad %f', Iquad) ) ;
disp( sprintf( 'Errore con nodi equispaziati %f', Iequ-Iquad) ) ;
disp( sprintf( 'Errore con nodi di Chebyshev %f', Icheb-Iquad) ) ;
end
% nodi di Chebyshev nell'intervallo [-1,1]
function x = cheb( n )
x = cos( [0:1/n:1] .* pi ) ;
end
Integrazione adattativa con il metodo dei trapezi:
File: trapezi.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.4 (Enrico Bertolazzi)
%
% Funzione che calcola con preciszione stimata epsi l'integrale della funzione fun
%
% fun = puntatore alla funzione da integrare
% a = estremo sinistro di integrazione
% b = estremo destro di integrazione
% epsi = tolleranza
%
function res = trapezi( fun, a, b, epsi )
% alcuni controlli sei dati
if b < a ; error( 'intervallo di integrazione errato b < a!' ) ; end ;
if epsi < 1E-10 ; error( 'tolleranza troppo stretta (<1E-10) eo negativa' ) ; end ;
% calcolo integrale con un solo trapezio
n = 1 ;
res = trap( fun, a, b, n ) ;
for k=1:10
% salva l'integrale precedentemente calcolato
res_old = res ;
% raddoppia il numero di intervalli
n = n * 2 ;
res = trap( fun, a, b, n ) ;
% stima dell'errore con la formula di estrapolazione
err = (res - res_old) / 3 ;
% se l'errore stimato e' sotto la tolleranza
% interrompo le iterate
if abs( err ) < epsi ; break ; end ;
end
end
%
% Calcola l'integrale approssimato con la formula dei trapezi
%
function res = trap( fun, a, b, n )
% nodi quadratura
h = (b-a)/n ;
xnode = [a+h:h:b-h] ;
% contributo nodi interni
res = h * sum(feval(fun, xnode)) ;
% contributo estremi
res = res + (h/2)*( feval( fun, a ) + feval( fun, b ) ) ;
end
Tutti i file MATLAB in un unico archivio
Esercitazioni di MATLAB: Lezione del 16 Maggio 2008
Problema proposto
Soluzione proposta
Implementazione del metodo di Eulero:
File: eulero.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.5 (Enrico Bertolazzi)
%
% Solutore di Eulero
%
function [t,y] = eulero( fun, t0, y0, T, N )
h = T/N ; % calcola passo avanzamento
t = t0:h:t0+T ; % calcola vettore tempi discrtizzati
y(1) = y0 ; % condizione iniziale
for k=1:N
% avanzamento con la formula di eulero
y(k+1) = y(k) + h*feval(fun, t(k), y(k) ) ;
end ;
end
Funzione per testare il solutore:
File: fun.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.5 (Enrico Bertolazzi)
%
% Funzione per ODE
%
function res = fun( t, y )
res = 2*y./t + t.^2 .* exp(t) ;
end
Soluzione esatta per la funzione proposta:
File: esatta.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.5 (Enrico Bertolazzi)
%
% Soluzione esatta per ODE
%
function res = esatta( t )
res = t.^2 .* ( exp(t) - exp(1) ) ;
end
Programma per testare il solutore:
File: checkOrder.m:
%
% Codici MATLAB per il corso di Calcolo Numerico 2007/2008
% Esercitazione n.5 (Enrico Bertolazzi)
%
% Controllo errore
clear all
Ns = { 5, 10, 20, 40, 80, 160, 320, 640 } ;
hold on
for k=1:length(Ns)
[t,y] = eulero( @fun, 1, 0, 2, Ns{k} ) ;
plot(t,y) ;
err(k) = norm(y-esatta(t),inf) ;
end
t=1:0.001:3 ;
plot(t, esatta(t),'-r', 'LineWidth', 2 ) ;
disp('controllo a posteriori dell''errore' ) ;
for k=2:length(Ns)
disp( sprintf('Ordine stimato %f', log(err(k-1)/err(k))/log(2) ) ) ;
end
hold off
Tutti i file MATLAB in un unico archivio
Course of Numerical Analysis (AA 2007/2008)
MATLAB lessons N.1
- Essential MATLAB commands: TutorialMatlab.pdf
MATLAB lessons N.2
- All MATLAB file for the lesson in a unique archive: lesson2.zip
Exercise on MATLAB ode solver
Example of ODE solver of MATLAB
File: ode1.m:
function Y = ode1(odefun,tspan,y0,varargin)
%ODE1 Solve differential equations with a non-adaptive method of order 1.
% Y = ODE1(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE1(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN.
% The solver implements the forward Euler method of order 1.
%
% Example
% tspan = 0:0.1:20;
% y = ode1(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
%
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
Y(:,1) = y0;
for i = 1:N-1
Y(:,i+1) = Y(:,i) + h(i)*feval(odefun,tspan(i),Y(:,i),varargin{:});
end
Y = Y.';
output of the command:
Changing tolerance parameters:
File: test2.m:
%
% Example of ODE solver of MATLAB
%
% set some option for the ODE numerical solver
options = odeset('RelTol',1e-7,'AbsTol',[1e-7 1e-7 1e-7]);
% se initial condition for the problem
Y0 = [ -7.5 -3.6 30 ] ;
% Set a vector specifying the interval of integration, [t0,tf].
% The solver imposes the initial conditions at TSPAN(1),
% and integrates from TSPAN(1) to TSPAN(end).
% To obtain solutions at specific times (all increasing or all decreasing),
% use TSPAN = [t0,t1,...,tf].
TSPAN = [ 0:0.01:10 ] ;
% load the "pointer" of the function to FUN
FUN = @lorenz ;
% Runge-Kutta embedded of order 2 and 3 by Bogaci and Shampine
[T1,Y1] = ode23 ( FUN, TSPAN, Y0, options ) ;
% Runge-Kutta embedded of order 4 and 5 by Dormand and Prince (first choice scheme)
[T2,Y2] = ode45 ( FUN, TSPAN, Y0, options ) ;
% Adams-bashforth-Moulton PECE
[T3,Y3] = ode113 ( FUN, TSPAN, Y0, options ) ;
% Numerical Differentiation Formula, similar to Backward Differetiation Formula
% by Gear. Useful for stiff problem.
[T4,Y4] = ode15s ( FUN, TSPAN, Y0, options ) ;
% Rosenbrock of order 2. For stiff problem.
[T5,Y5] = ode23s ( FUN, TSPAN, Y0, options ) ;
% Trapeziodal rule for moderately stiff problem
[T6,Y6] = ode23t ( FUN, TSPAN, Y0, options ) ;
% TR-BDF2 an implit Runge-Kutta where the first stage is the
% trapezoidal rule and teh second stage is a BDF formula of order 2
[T7,Y7] = ode23tb ( FUN, TSPAN, Y0, options ) ;
%
% plot the functions approximated by various solver
%
plot( T1, Y1(:,1), 'r-', ...
T2, Y2(:,1), 'g--', ...
T3, Y3(:,1), 'b:', ...
T4, Y4(:,1), 'c-.', ...
T5, Y5(:,1), 'm--', ...
T6, Y6(:,1), 'y:', ...
T7, Y7(:,1), 'k-.' )
this is the output of the command
File: test3.m:
%
% Check Van Der Pol equation
% this is a stiff test
%
% set some option for the ODE numerical solver
options = odeset('RelTol',1e-4) ; %,'AbsTol',[1e-7 1e-7 1e-7]);
% se initial condition for the problem
Y0 = [ 2 0 ] ;
% Set a vector specifying the interval of integration, [t0,tf].
% The solver imposes the initial conditions at TSPAN(1),
% and integrates from TSPAN(1) to TSPAN(end).
% To obtain solutions at specific times (all increasing or all decreasing),
% use TSPAN = [t0,t1,...,tf].
TSPAN = [ 0:1:3000 ] ;
% load the "pointer" of the function to FUN
FUN = @vanderpol ;
% This is a stiff problem, the first three solver do not work!
%[T1,Y1] = ode23 ( FUN, TSPAN, Y0 ) ;
%[T2,Y2] = ode45 ( FUN, TSPAN, Y0 ) ;
%[T3,Y3] = ode113 ( FUN, TSPAN, Y0 ) ;
% those solvers can solve a stiff problem
[T4,Y4] = ode15s ( FUN, TSPAN, Y0 ) ;
[T5,Y5] = ode23s ( FUN, TSPAN, Y0 ) ;
[T6,Y6] = ode23t ( FUN, TSPAN, Y0 ) ;
[T7,Y7] = ode23tb ( FUN, TSPAN, Y0 ) ;
%
% plot the functions approximated by various solver
%
% first component
plot( T4, Y4(:,1), 'c-.', ...
T5, Y5(:,1), 'm--', ...
T6, Y6(:,1), 'y:', ...
T7, Y7(:,1), 'k-.' )
% create a new window to plot
figure()
% second component
plot( T4, Y4(:,2), 'c-.', ...
T5, Y5(:,2), 'm--', ...
T6, Y6(:,2), 'y:', ...
T7, Y7(:,2), 'k-.' )
this is the output of the command
and this
Numerical ODE solver with constants step size
This routine are taken from mathworks
First order explicit Euler:
File: ode1.m:
function Y = ode1(odefun,tspan,y0,varargin)
%ODE1 Solve differential equations with a non-adaptive method of order 1.
% Y = ODE1(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE1(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN.
% The solver implements the forward Euler method of order 1.
%
% Example
% tspan = 0:0.1:20;
% y = ode1(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
%
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
Y(:,1) = y0;
for i = 1:N-1
Y(:,i+1) = Y(:,i) + h(i)*feval(odefun,tspan(i),Y(:,i),varargin{:});
end
Y = Y.';
Second order explicit Runge Kutta:
File: ode2.m:
function Y = ode2(odefun,tspan,y0,varargin)
%ODE2 Solve differential equations with a non-adaptive method of order 2.
% Y = ODE2(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE2(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN
% but the derivative function ODEFUN is evaluated multiple times per step.
% The solver implements the improved Euler (Heun's) method of order 2.
%
% Example
% tspan = 0:0.1:20;
% y = ode2(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
%
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
F = zeros(neq,2);
Y(:,1) = y0;
for i = 2:N
ti = tspan(i-1);
hi = h(i-1);
yi = Y(:,i-1);
F(:,1) = feval(odefun,ti,yi,varargin{:});
F(:,2) = feval(odefun,ti+hi,yi+hi*F(:,1),varargin{:});
Y(:,i) = yi + (hi/2)*(F(:,1) + F(:,2));
end
Y = Y.';
3rd order explicit Runge Kutta:
File: ode3.m:
function Y = ode3(odefun,tspan,y0,varargin)
%ODE3 Solve differential equations with a non-adaptive method of order 3.
% Y = ODE3(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE3(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN
% but the derivative function ODEFUN is evaluated multiple times per step.
% The solver implements the Bogacki-Shampine Runge-Kutta method of order 3.
%
% Example
% tspan = 0:0.1:20;
% y = ode3(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
%
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
F = zeros(neq,3);
Y(:,1) = y0;
for i = 2:N
ti = tspan(i-1);
hi = h(i-1);
yi = Y(:,i-1);
F(:,1) = feval(odefun,ti,yi,varargin{:});
F(:,2) = feval(odefun,ti+0.5*hi,yi+0.5*hi*F(:,1),varargin{:});
F(:,3) = feval(odefun,ti+0.75*hi,yi+0.75*hi*F(:,2),varargin{:});
Y(:,i) = yi + (hi/9)*(2*F(:,1) + 3*F(:,2) + 4*F(:,3));
end
Y = Y.';
4th order explicit Runge Kutta:
File: ode4.m:
function Y = ode4(odefun,tspan,y0,varargin)
%ODE4 Solve differential equations with a non-adaptive method of order 4.
% Y = ODE4(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE4(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN
% but the derivative function ODEFUN is evaluated multiple times per step.
% The solver implements the classical Runge-Kutta method of order 4.
%
% Example
% tspan = 0:0.1:20;
% y = ode4(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
%
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
F = zeros(neq,4);
Y(:,1) = y0;
for i = 2:N
ti = tspan(i-1);
hi = h(i-1);
yi = Y(:,i-1);
F(:,1) = feval(odefun,ti,yi,varargin{:});
F(:,2) = feval(odefun,ti+0.5*hi,yi+0.5*hi*F(:,1),varargin{:});
F(:,3) = feval(odefun,ti+0.5*hi,yi+0.5*hi*F(:,2),varargin{:});
F(:,4) = feval(odefun,tspan(i),yi+hi*F(:,3),varargin{:});
Y(:,i) = yi + (hi/6)*(F(:,1) + 2*F(:,2) + 2*F(:,3) + F(:,4));
end
Y = Y.';
5th order explicit Runge Kutta:
File: ode5.m:
function Y = ode5(odefun,tspan,y0,varargin)
%ODE5 Solve differential equations with a non-adaptive method of order 5.
% Y = ODE5(ODEFUN,TSPAN,Y0) with TSPAN = [T1, T2, T3, ... TN] integrates
% the system of differential equations y' = f(t,y) by stepping from T0 to
% T1 to TN. Function ODEFUN(T,Y) must return f(t,y) in a column vector.
% The vector Y0 is the initial conditions at T0. Each row in the solution
% array Y corresponds to a time specified in TSPAN.
%
% Y = ODE5(ODEFUN,TSPAN,Y0,P1,P2...) passes the additional parameters
% P1,P2... to the derivative function as ODEFUN(T,Y,P1,P2...).
%
% This is a non-adaptive solver. The step sequence is determined by TSPAN
% but the derivative function ODEFUN is evaluated multiple times per step.
% The solver implements the Dormand-Prince method of order 5 in a general
% framework of explicit Runge-Kutta methods.
%
% Example
% tspan = 0:0.1:20;
% y = ode5(@vdp1,tspan,[2 0]);
% plot(tspan,y(:,1));
% solves the system y' = vdp1(t,y) with a constant step size of 0.1,
% and plots the first component of the solution.
if ~isnumeric(tspan)
error('TSPAN should be a vector of integration steps.');
end
if ~isnumeric(y0)
error('Y0 should be a vector of initial conditions.');
end
h = diff(tspan);
if any(sign(h(1))*h <= 0)
error('Entries of TSPAN are not in order.')
end
try
f0 = feval(odefun,tspan(1),y0,varargin{:});
catch
msg = ['Unable to evaluate the ODEFUN at t0,y0. ',lasterr];
error(msg);
end
y0 = y0(:); % Make a column vector.
if ~isequal(size(y0),size(f0))
error('Inconsistent sizes of Y0 and f(t0,y0).');
end
neq = length(y0);
N = length(tspan);
Y = zeros(neq,N);
% Method coefficients -- Butcher's tableau
%
% C | A
% --+---
% | B
C = [1/5; 3/10; 4/5; 8/9; 1];
A = [ 1/5, 0, 0, 0, 0
3/40, 9/40, 0, 0, 0
44/45 -56/15, 32/9, 0, 0
19372/6561, -25360/2187, 64448/6561, -212/729, 0
9017/3168, -355/33, 46732/5247, 49/176, -5103/18656];
B = [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84];
% More convenient storage
A = A.';
B = B(:);
nstages = length(B);
F = zeros(neq,nstages);
Y(:,1) = y0;
for i = 2:N
ti = tspan(i-1);
hi = h(i-1);
yi = Y(:,i-1);
% General explicit Runge-Kutta framework
F(:,1) = feval(odefun,ti,yi,varargin{:});
for stage = 2:nstages
tstage = ti + C(stage-1)*hi;
ystage = yi + F(:,1:stage-1)*(hi*A(1:stage-1,stage-1));
F(:,stage) = feval(odefun,tstage,ystage,varargin{:});
end
Y(:,i) = yi + F*(hi*B);
end
Y = Y.';
Checking the order
Graphical plot of the order:
File: ode_test.m:
function ode_test
%ODE_TEST Run non-adaptive ODE solvers of different orders.
% ODE_TEST compares the orders of accuracy of several explicit Runge-Kutta
% methods. The non-adaptive ODE solvers are tested on a problem used in
% E. Hairer, S.P. Norsett, and G. Wanner, Solving Ordinary Differential
% Equations I, Nonstiff Problems, Springer-Verlag, 1987.
% The errors of numerical solutions obtained with several step sizes is
% plotted against the step size used. For a given solver, the slope of that
% line corresponds to the order of the integration method used.
%
solvers = {'ode1','ode2','ode3','ode4','ode5'};
Nsteps = [800 400 200 100 75 50 20 11];
x0 = 0;
y0 = [1;1;1;1];
xend = 1;
h = (xend-x0)./Nsteps;
err = zeros(length(solvers),length(h));
for i = 1:length(solvers)
solver = solvers{i};
for j = 1:length(Nsteps)
N = Nsteps(j);
x = linspace(x0,xend,N+1);
y = feval(solver,@f,x,y0);
err(i,j) = max(max(abs(y - yexact(x))));
end
end
figure
loglog(h,err);
title('Different slopes for methods of different orders...');
xlabel('log(h)');
ylabel('log(err)');
legend(solvers{:},4);
% -------------------------
function yp = f(x,y)
yp = [ 2*x*y(4)*y(1)
10*x*y(4)*y(1)^5
2*x*y(4)
-2*x*(y(3)-1) ];
% -------------------------
function y = yexact(x)
x2 = x(:).^2;
y = zeros(length(x),4);
y(:,1) = exp(sin(x2));
y(:,2) = exp(5*sin(x2));
y(:,3) = sin(x2)+1;
y(:,4) = cos(x2);
Numerical estimation of the order:
File: ode_check_error.m:
function ode_check_error
%ODE_TEST Run non-adaptive ODE solvers of different orders.
% ODE_TEST compares the orders of accuracy of several explicit Runge-Kutta
% methods. The non-adaptive ODE solvers are tested on a problem used in
% E. Hairer, S.P. Norsett, and G. Wanner, Solving Ordinary Differential
% Equations I, Nonstiff Problems, Springer-Verlag, 1987.
% The errors of numerical solutions obtained with several step sizes is
% plotted against the step size used. For a given solver, the slope of that
% line corresponds to the order of the integration method used.
%
solvers = { 'ode1', 'ode2', 'ode3', 'ode4', 'ode5' };
Nsteps = [ 10 20 40 80 160 320 640 1280 ];
x0 = 0 ;
y0 = [1;1;1;1] ;
xend = 1 ;
h = (xend-x0)./Nsteps ;
err = zeros(length(solvers),length(h));
for i = 1:length(solvers)
solver = solvers{i};
for j = 1:length(Nsteps)
N = Nsteps(j);
x = linspace(x0,xend,N+1);
y = feval(solver,@f,x,y0);
err(i,j) = max(max(abs(y - yexact(x))));
end
end
for i = 1:length(solvers)
disp( ' ' )
disp( ['estimate order for scheme = ' solvers{i}] );
disp( sprintf( 'Error = %-15g', err(i,1) ) ) ;
for j = 2:length(Nsteps)
order = log( err(i,j-1)/err(i,j) ) / log( h(j-1)/h(j) ) ;
disp( sprintf( 'Error = %-15g Order = %-15g', err(i,j), order) ) ;
end
end
% -------------------------
function yp = f(x,y)
yp = [ 2*x*y(4)*y(1)
10*x*y(4)*y(1)^5
2*x*y(4)
-2*x*(y(3)-1) ];
% -------------------------
function y = yexact(x)
x2 = x.^2;
y = zeros(length(x),4);
y(:,1) = exp(sin(x2));
y(:,2) = exp(5*sin(x2));
y(:,3) = sin(x2)+1;
y(:,4) = cos(x2);
output of command ode_test
MATLAB lessons N.3
A library to solve 1D hyperbolic equations with various methods
- All MATLAB file for the lesson in a unique archive: lesson3.zip
File: ClassRoomExample.m:
close all ;
LinearAdvectionModel( 'setup', 1 ) ;
LinearAdvectionModel( 'set_test', 'classroomproblem' ) ;
LinearAdvectionModel( 'set_numerical_flux', 'godunov' ) ;
LinearAdvectionModel( 'set_limiter', 'godunov' ) ;
PRB . CFL = 2*LinearAdvectionModel( 'get_cfl' ) ;
PRB . FinalTime = 1.5 ;
PRB . Ncells = 800 ; % select 100 cell inteval subdivision
PRB . StepTime = 8 ;
% call the solver
[ UFRAMES, TFRAMES ] = Solver(PRB,@LinearAdvectionModel) ;
U = UFRAMES(:,:,end) ; % extract the numerical solutions at the last computed time
X = LinearAdvectionModel( 'get_x' ) ;
handleFig = figure('Position',[10 10 1000 600],'color','w') ;
plot(X, U,'-ob','MarkerFaceColor','b');
Linear Adbvection Model:
File: LinearAdvectionModel.m:
% solve the linearised equations of Gas Dynamics in one space dimension
%
% u(t,x) + c u (t,x) = 0
% t x
%
% for t > 0 and -1 <= x <= 1
%
function [varargout] = LinearAdvectionModel( what, varargin )
% LinearAdvectionModel_paramaters
% c = velocity
% test = which test is used
% nflux = which numerical flux is used
% bc_left = left bounday condition
% bc_right = right boundaruy condition
%
global LinearAdvectionModel_paramaters ;
switch lower(what)
case 'setup'
expected( what, 1, nargin, 0, nargout ) ;
LinearAdvectionModel_paramaters = clear_struct(LinearAdvectionModel_paramaters) ;
LinearAdvectionModel_paramaters . speed = varargin{1} ;
case 'set_test'
expected( what, 1, nargin, 0, nargout ) ; % TEST
ChooseTest( varargin{1} ) ;
case 'set_limiter'
expected( what, 1, nargin, 0, nargout ) ;
LinearAdvectionModel_paramaters . limiter = lower( varargin{1} ) ;
case 'set_numerical_flux'
expected( what, 1, nargin, 0, nargout ) ;
LinearAdvectionModel_paramaters . nflux = lower( varargin{1} ) ;
case 'get_dim'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = 1 ;
case 'get_dx'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = LinearAdvectionModel_paramaters . DX ;
case 'get_x'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = LinearAdvectionModel_paramaters . X ;
case 'get_final_time'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = LinearAdvectionModel_paramaters . tf ;
case 'get_cfl'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = MaxCFL() ;
case 'names'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = 'u' ;
case 'flux'
expected( what, 1, nargin, 1, nargout ) ; % U
varargout{1} = Flux( varargin{1} ) ;
case 'init'
expected( what, 1, nargin, 1, nargout ) ; % N
varargout{1} = Init( varargin{1} ) ;
case 'exact'
expected( what, 2, nargin, 2, nargout ) ; % TIME, N
[ varargout{1} varargout{2} ] = Exact( varargin{1}, varargin{2} ) ;
case 'muscle_nflux'
expected( what, 2, nargin, 1, nargout ) ; % UL, UR
varargout{1} = Godunov( varargin{1}, varargin{2} ) ;
case 'conservative_to_physical'
varargout{1} = varargin{1} ;
case 'physical_to_conservative'
varargout{1} = varargin{1} ;
case 'conservative_to_characteristic'
varargout{1} = varargin{1} ;
case 'characteristic_to_conservative'
varargout{1} = varargin{1} ;
case 'dt_from_cfl'
expected( what, 2, nargin, 1, nargout ) ; % U, CFLcoeff
varargout{1} = DT_from_CFL( varargin{1}, varargin{2} ) ;
case 'extrapolate_for_bc'
expected( what, 1, nargin, 4, nargout ) ; % U
[ varargout{1}, varargout{2}, varargout{3}, varargout{4} ] = Extrapolate_for_BC( varargin{1} ) ;
case 'nflux'
expected( what, 2, nargin, 1, nargout ) ; % DT, U
varargout{1} = NFlux( varargin{1}, varargin{2} ) ;
otherwise
error(['LinearAdvectionModel bad argument: ', what]) ;
end
end
function SE = clear_struct(S)
if isstruct(S)
SE = rmfield( S, fieldnames(S) ) ;
else
SE = S ;
end
end
function expected( what, ein, nin, eout, nout )
if ein ~= nin-1
error( ['in LinearAdvectionModel call to ', what, ' expected ', int2str( ein ), ' input argument, found ', int2str(nin-1) ]) ;
end
if eout ~= nout
error( ['in LinearAdvectionModel call to ', what, ' expected ', int2str( eout ), ' output argument, found ', int2str(nout) ]) ;
end
end
% #######
% # # # # # #
% # # # # # #
% ##### # # # ##
% # # # # ##
% # # # # # #
% # ###### #### # #
% compute the flux
function F = Flux( U )
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
F = speed .* U ;
end
% ###
% # # # # #####
% # ## # # #
% # # # # # #
% # # # # # #
% # # ## # #
% ### # # # #
function U = Init(N)
global LinearAdvectionModel_paramaters ;
% Calculate mesh size DX
DX = 2.0/N ;
X = [-1+DX/2:DX:1-DX/2] ;
if isfield(LinearAdvectionModel_paramaters, 'test')
switch LinearAdvectionModel_paramaters . test
case 'classroomproblem'
DX = 8.0/N ;
X = [0+DX/2:DX:8-DX/2] ; % center of the cell
N1 = floor(3*N/8) ;
N2 = N - N1 ;
U = [ones(1,N1) zeros(1,N2) ] ;
case 'square'
N3 = floor(N/3) ;
M = N - N3 - N3 ;
U = [zeros(1,N3) ones(1,M) zeros(1,N3) ] ;
case 'smooth'
U = exp( -8 .* X .^ 2 ) ;
otherwise
error(['LinearAdvectionModel::Init unknown test ', LinearAdvectionModel_paramaters . test]) ;
end
else
error('LinearAdvectionModel::Init unknown test you must set it by set_test!') ;
end
LinearAdvectionModel_paramaters . DX = DX ;
LinearAdvectionModel_paramaters . X = X ;
end
% ##### #######
% # # # # #### #### #### ###### # ###### #### #####
% # # # # # # # # # # # # #
% # ###### # # # # #### ##### # ##### #### #
% # # # # # # # # # # # # #
% # # # # # # # # # # # # # # # #
% ##### # # #### #### #### ###### # ###### #### #
%
function ChooseTest(test)
global LinearAdvectionModel_paramaters ;
switch test
case 'classroomproblem'
tf = 3.5 ;
bc_left = 'free' ;
bc_right = 'free' ;
case 'square'
tf = 4 ;
bc_left = 'cyclic' ;
bc_right = 'cyclic' ;
case 'smooth'
tf = 4 ;
bc_left = 'cyclic' ;
bc_right = 'cyclic' ;
otherwise
error(['LinearAdvectionModel:ChooseTest test name',test] ) ;
end
LinearAdvectionModel_paramaters . test = test ;
LinearAdvectionModel_paramaters . bc_left = bc_left ;
LinearAdvectionModel_paramaters . bc_right = bc_right ;
LinearAdvectionModel_paramaters . tf = tf ;
end
% #######
% # # # ## #### #####
% # # # # # # # #
% ##### ## # # # #
% # ## ###### # #
% # # # # # # # #
% ####### # # # # #### #
function [X,U] = Exact(TIME,N)
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
% Calculate mesh size DX
DX = 2.0/N ;
X = [-1+DX/2:DX:1-DX/2] ;
X = X - speed*TIME ; % translate the mesh
% put the solution in [-1..1]
while min(X) < -1
IDX = find( X < -1 ) ;
X(IDX) = X(IDX)+2 ;
end
while max(X) > 1
IDX = find( X > 1 ) ;
X(IDX) = X(IDX)-2 ;
end
switch LinearAdvectionModel_paramaters . test
case 'square'
U = zeros(1,N) ;
IDX = find( X >= -1.0/3.0 & X <= 1.0/3.0 ) ;
U(IDX) = 1 ;
case 'smooth'
% use gauss quadrature to estimate status
XL = X + DX/sqrt(3)/2;
XR = X - DX/sqrt(3)/2 ;
U = (exp( -8 .* XL .^ 2 )+exp( -8 .* XR .^ 2 ))/2 ;
end
% ripristina la mesh
X = [-1+DX/2:DX:1-DX/2] ;
end
% ###### ####### ##### ####### #
% # # # ###### ##### #### # # # # # #
% # # # # # # # # ## ## # # #
% # # # ##### # # # # # ## # # ##### #
% # # # # ##### # # # # # # #
% # # # # # # # # # # # # # #
% ###### # # # # #### # # ##### # #######
% ####### #######
% Compute DT from CFL
function DT = DT_from_CFL( U, CFLcoeff )
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
DX = LinearAdvectionModel_paramaters . DX ;
DT = CFLcoeff * DX / abs(speed) ;
end
% #######
% # # # ##### ##### ## ##### #### # ## ##### ######
% # # # # # # # # # # # # # # # # #
% ##### ## # # # # # # # # # # # # # #####
% # ## # ##### ###### ##### # # # ###### # #
% # # # # # # # # # # # # # # # #
% ####### # # # # # # # # #### ###### # # # ######
%
% ###### #####
% ###### #### ##### # # # #
% # # # # # # # #
% ##### # # # # ###### #
% # # # ##### # # #
% # # # # # # # # #
% # #### # # ###### #####
% #######
% Extrapolate values for boundary condition
function [ULL, UL, UR, URR] = Extrapolate_for_BC( U )
global LinearAdvectionModel_paramaters ;
L = LinearAdvectionModel_paramaters . bc_left ;
R = LinearAdvectionModel_paramaters . bc_right ;
% Left boundary
switch L
case 'free' % Apply transmissive boundary conditions
UL = U(:,1) ;
ULL = U(:,2) ;
case 'cyclic' % Apply cyclic boundary conditions
UL = U(:,end) ;
ULL = U(:,end-1) ;
otherwise % Apply reflective boundary conditions
UL = [ U(1,1) ; -U(2,1) ] ;
ULL = [ U(1,2) ; -U(2,2) ] ;
end
% Right boundary
switch R
case 'free' % Apply transmissive boundary conditions
UR = U(:,end) ;
URR = U(:,end-1) ;
case 'cyclic' % Apply cyclic boundary conditions
UR = U(:,1) ;
URR = U(:,2) ;
otherwise % Apply reflective boundary conditions
UR = [ U(1,end) ; -U(2,end) ] ;
URR = [ U(1,end-1) ; -U(2,end-1) ] ;
end
end
% ####### ##### ####### #
% # # ##### ##### # # # ## # # # # #
% # # # # # # ## ## # # # # # #
% # # # # # # # ## # # # # # ##### #
% # # ##### # # # # ###### # # # #
% # # # # # # # # # # # # # #
% ####### # # # # # # # ###### ##### # #######
function CFL = MaxCFL
global LinearAdvectionModel_paramaters ;
nflux = LinearAdvectionModel_paramaters . nflux ;
%
switch nflux
case 'torobillett'
CFL = 2.0 ;
case { 'fromm', 'warmingbeam', 'waf', 'godunov' }
CFL = 1.0 ;
otherwise
CFL = StandardFlux( 'get_cfl', nflux ) ;
end
end
% # # # # # # ###### ##### # #### ## #
% ## # # # ## ## # # # # # # # # #
% # # # # # # ## # ##### # # # # # # #
% # # # # # # # # ##### # # ###### #
% # ## # # # # # # # # # # # # #
% # # #### # # ###### # # # #### # # ######
%
% ###### # # # # # ###### ####
% # # # # # # # #
% ##### # # # ## ##### ####
% # # # # ## # #
% # # # # # # # # #
% # ###### #### # # ###### ####
function FLUX = NFlux( DT, U )
global LinearAdvectionModel_paramaters ;
ULL = U(:,1:end-3) ;
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
URR = U(:,4:end-0) ;
nflux = LinearAdvectionModel_paramaters . nflux ;
DX = LinearAdvectionModel_paramaters . DX ;
limiter = LinearAdvectionModel_paramaters . limiter ;
switch nflux
% monolitic numerical fluxes
case 'godunov'
FLUX = Godunov(UL,UR) ;
case 'torobillett'
FLUX = ToroBillett(DT,ULL,UL,UR,URR) ;
case 'fromm'
FLUX = Fromm(DT,ULL,UL,UR,URR) ;
case 'warmingbeam'
FLUX = WarmingBeam(DT,ULL,UL,UR,URR) ;
case 'waf'
FLUX = Waf(DT,U) ;
otherwise
FLUX = StandardFlux( 'nflux', nflux, @Flux, DT, DX, U, limiter ) ;
end
end
% _ ___ _ __ ___ _ _ _ _ _
% |_ | |_) (_ | / \ |_) | \ |_ |_)
% | _|_ | \ __) | \_/ | \ |_/ |_ | \
%
% #####
% # # #### ##### # # # # #### # #
% # # # # # # # ## # # # # #
% # #### # # # # # # # # # # # # #
% # # # # # # # # # # # # # # #
% # # # # # # # # # ## # # # #
% ##### #### ##### #### # # #### ## %
%
% Compute the solution of the Riemann problem
%
function F = Godunov( UL, UR )
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
% the flux at interface i is computed
if speed > 0
F = speed .* UL ; % using the left state
else
F = speed .* UR ; % using the right state
end
end
% ####### ######
% # #### ##### #### # # # # # ###### ##### #####
% # # # # # # # # # # # # # # #
% # # # # # # # ###### # # # ##### # #
% # # # ##### # # # # # # # # # #
% # # # # # # # # # # # # # # #
% # #### # # #### ###### # ###### ###### ###### # #
%
% Compute intercell fluxes according to the Toro-Billett first order CFL-2 scheme
% See Eq. 13.22, Chapter 13, Ref. 1
function F = ToroBillett(DT,ULL,UL,UR,URR)
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
DX = LinearAdvectionModel_paramaters . DX ;
CN = abs(speed*DT/DX) ;
if CN <= 1
% Conventional Godunov upwind flux
F = Godunov(UL,UR) ;
else
a = (CN-1)/CN ;
b = 1-a ;
if speed > 0
% Information travels from the left
F = a .* Flux(ULL) + b .* Flux(UL) ;
else
% Information travels from the right
F = a .* Flux(URR) + b .* Flux(UR) ;
end
end
end
% __ _ _ _ _ _ _ _ _ _
% (_ |_ / / \ |\ | | \ / \ |_) | \ |_ |_)
% __) |_ \_ \_/ | \| |_/ \_/ | \ |_/ |_ | \
% #######
% # ##### #### # # # #
% # # # # # ## ## ## ##
% ##### # # # # # ## # # ## #
% # ##### # # # # # #
% # # # # # # # # #
% # # # #### # # # #
%
% Compute intercell fluxes according to the Fromm first order upwind method
% See Eq. 13.35, Chapter 13, Ref. 1
%
function F = Fromm(DT,ULL,UL,UR,URR)
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
DX = LinearAdvectionModel_paramaters . DX ;
CN = speed*DT/DX ;
if CN > 0
F = speed .* (UL + 0.25 .* (1-CN) .* (UR - ULL)) ;
else
F = speed .* (UR - 0.25 .* (1+CN) .* (URR - UR)) ;
end ;
end
% # # ######
% # # # ## ##### # # # # # #### # # ###### ## # #
% # # # # # # # ## ## # ## # # # # # # # # ## ##
% # # # # # # # # ## # # # # # # ###### ##### # # # ## #
% # # # ###### ##### # # # # # # # ### # # # ###### # #
% # # # # # # # # # # # ## # # # # # # # # #
% ## ## # # # # # # # # # #### ###### ###### # # # #
%
% Compute intercell fluxes according to the Warming-Beam method
% See Eq. 13.21, Chapter 13, Ref. 1
%
function FLUX = WarmingBeam(DT,ULL,UL,UR,URR)
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
DX = LinearAdvectionModel_paramaters . DX ;
CN = speed*DT/DX ;
if speed > 0
FLUX = (0.5*speed) .* ( (3-CN) .* UL - (1-CN) .* ULL ) ;
else
FLUX = (0.5*speed) .* ( (3+CN) .* UR - (1+CN) .* URR ) ;
end
end
% # # # #######
% # # # # # #
% # # # # # #
% # # # # # #####
% # # # ####### #
% # # # # # #
% ## ## # # #
%
% Compute the WAF flux with the exact Riemann solver,
% to be used in explicit conservative formula, subroutine UPDATE
function FLUX = Waf( DT, U )
global LinearAdvectionModel_paramaters ;
speed = LinearAdvectionModel_paramaters . speed ;
DX = LinearAdvectionModel_paramaters . DX ;
limiter = LinearAdvectionModel_paramaters . limiter ;
CN = speed*DT/DX ;
% Compute local jump DLOC. This is the change across the wave of speed c.
DLOC = U(:,3:end-1) - U(:,2:end-2) ;
% Identify the upwind direction
if speed > 0 % Information travels from the left
IUPW = -1 ;
else % Information travels from the right
IUPW = +1 ;
end
% Compute the upwind jump DUPW. This depends on the direction of the wave
% in the solution of the Riemann problem RP(UL, UR), namely the sign of c
DUPW = U(:,3+IUPW:end-1+IUPW) - U(:,2+IUPW:end-2+IUPW) ;
ONES = ones (size(DLOC)) ;
% Apply TVD condition to find WAF limiter function WAFLIM
WAFLIM = WafLimiter( DLOC, DUPW, CN, limiter ) ;
WL = 0.5 .* (ONES + WAFLIM) ;
WR = 0.5 .* (ONES - WAFLIM) ;
% Compute fluxes on data
FD = Flux( U(:,2:end-1) ) ;
% Compute WAF Flux FLUX(I) corresponding to RP(I,I+1)
FLUX = WL .* FD(1:end-1) + WR .* FD(2:end) ;
end
function WAFLIM = WafLimiter( DLOC, DUPW, CN, limiter )
TOLLIM = 1E-6 ;
% Select limiter function WAFLIM
ZEROS = zeros(size(DLOC)) ;
ONES = ones (size(DLOC)) ;
% Compute RATIO=DUPW/DLOC of upwind to local changes
% some workaround to avoid division by zero are added
RATIO = sign(DLOC).*DUPW./max(abs(DLOC),TOLLIM.*ONES) ;
switch ( limiter )
case 'godunov'
WAFLIM = sign(CN) .* ONES ;
return ;
case 'secondorder'
WAFLIM = CN .* ONES ;
return ;
case 'superbee'
B = max( min(2.*RATIO, ONES), min(RATIO, 2.*ONES) ) ;
case 'vanleer'
B = max(RATIO,ZEROS) ;
B = 2.*B./(ONES+B) ;
case 'vanalbada'
B = (RATIO + RATIO.^2 ) ./ (ONES + RATIO.^2) ;
case 'minmod'
B = min(RATIO, ONES) ;
end
% Transform to WAF limiter
WAFLIM = sign(CN) .* ( ONES - (ONES - abs(CN)) .* max(ZEROS, B) ) ;
end
Slope Limiter Model:
File: SlopeLimiterModel.m:
function [varargout] = SlopeLimiterModel( what, varargin )
global SlopeLimiter_parameters ;
switch ( what )
case 'setup'
expected( what, 1, nargin, 0, nargout ) ;
SlopeLimiter_parameters . limiter = lower( varargin{1} ) ;
case 'eval_slope'
expected( what, 1, nargin, 1, nargout ) ;
varargout{1} = SlopeLimiter( varargin{1} ) ;
otherwise
error(['SlopeLimiterModel bad argument: ' what]) ;
end
end
function expected( what, ein, nin, eout, nout )
if ein ~= nin-1
error( ['in SlopeLimiterModel call to ', what, ' expected ', int2str( ein ), ' input argument, found ', int2str(nin-1) ]) ;
end
if eout ~= nout
error( ['in SlopeLimiterModel call to ', what, ' expected ', int2str( eout ), ' output argument, found ', int2str(nout) ]) ;
end
end
function DELTA = SlopeLimiter( US )
global SlopeLimiter_parameters ;
limiter = SlopeLimiter_parameters . limiter ;
[r,c] = size(US) ;
for k=1:r
UL = US(r,1:end-2) ;
UC = US(r,2:end-1) ;
UR = US(r,3:end-0) ;
P = UR - UC ;
Q = UC - UL ;
EPSI = 1E-10 * ones(size(Q)) ;
% Compute RATIO=DUPW/DLOC of upwind to local changes
% some workaround to avoid division by zero are added
R = sign(Q).*P./max(abs(Q),EPSI) ;
S = sign(P).*Q./max(abs(P),EPSI) ;
DELTA(r,:) = min( Q .* StandardLimiter( limiter, R ), ...
P .* StandardLimiter( limiter, S ) ) ;
end
end
Check Order for Linear Advection:
File: LinearAdvectionCheckOrder.m:
nflux = { 'LaxFriedrichs', 'force', 'Richtmyer', ...
'slic', 'GodunovCentered', 'ToroBillett', ...
'Fromm', 'WarmingBeam', 'Waf' } ;
grid = [ 50 100 200 400 ];
for j=1:length(nflux)
LinearAdvectionModel( 'setup', -0.4 ) ;
LinearAdvectionModel( 'set_test', 'smooth' ) ;
LinearAdvectionModel( 'set_numerical_flux', nflux{j} ) ;
LinearAdvectionModel( 'set_limiter', 'superbee' ) ;
PRB . CFL = 0.9*LinearAdvectionModel( 'get_cfl' ) ;
PRB . FinalTime = LinearAdvectionModel( 'get_final_time' ) ;
PRB . StepTime = PRB . FinalTime / 100 ;
SlopeLimiterModel( 'setup', 'superbee' ) ;
% limiters:
% 'minbee', 'superbee', 'vanleer', 'vanalbada', 'minmod', 'warmingbeam', 'laxwendroff', 'fromm'
% call the solver
for i=1:4
PRB . Ncells = grid(i) ;
[UFRAMES,TFRAMES] = Solver(PRB,@LinearAdvectionModel) ;
%[UFRAMES,TFRAMES] = MUSCLSolver(PRB,@LinearAdvectionModel) ;
[NR1(i),NR2(i),NRi(i)] = ComputeError(UFRAMES,TFRAMES,@LinearAdvectionModel);
end
disp( sprintf('\n\n%s', nflux{j}) ) ;
for i=1:3
disp( sprintf('norm1[%d,%d] = %f',grid(i+1),grid(i),log(NR1(i)/NR1(i+1))/log(2))) ;
disp( sprintf('norm2[%d,%d] = %f',grid(i+1),grid(i),log(NR2(i)/NR2(i+1))/log(2))) ;
disp( sprintf('normi[%d,%d] = %f',grid(i+1),grid(i),log(NRi(i)/NRi(i+1))/log(2))) ;
end
end
Linear Advection Example:
File: LinearAdvectionExample.m:
test = { 'square', 'smooth' } ;
nflux = {'ToroBillet'} ;
nflux1 = { 'LaxFriedrichs', ...
'force', ...
'Richtmyer', ...
'slic', ...
'GodunovCentered', ...
'ToroBillet', ...
'Fromm', ...
'WarmingBeam', ...
'Waf' } ;
close all ;
for j=1:length(nflux)
ok = input( ['Start numerical flux: ' nflux{j} ' [q=quit] ' ], 's' ) ;
if ok == 'q'
break ;
end ;
handleFig = figure('Position',[10 10 1000 600],'color','w') ;
for i=1:length(test)
LinearAdvectionModel( 'setup', -0.4 ) ;
LinearAdvectionModel( 'set_test', test{i} ) ;
LinearAdvectionModel( 'set_numerical_flux', nflux{j} ) ;
LinearAdvectionModel( 'set_limiter', 'superbee' ) ;
PRB . CFL = 0.9*LinearAdvectionModel( 'get_cfl' ) ;
PRB . FinalTime = LinearAdvectionModel( 'get_final_time' ) ;
PRB . Ncells = 100 ; % select 100 cell inteval subdivision
PRB . StepTime = PRB . FinalTime / 100 ;
SlopeLimiterModel( 'setup', 'superbee' ) ;
% others limiters:
% 'minbee', 'superbee', 'vanleer', 'vanalbada', 'minmod', 'warmingbeam', 'laxwendroff', 'fromm'
% call the solver
[ UFRAMES2, TFRAMES ] = Solver(PRB,@LinearAdvectionModel) ;
PRB . CFL = 0.9 ; % change CFL for MUSCL
[ UFRAMES1, TFRAMES ] = MUSCLSolver(PRB, @LinearAdvectionModel, @SlopeLimiterModel) ;
[ Xe, Ue ] = LinearAdvectionModel( 'exact', PRB . FinalTime, 1000 ) ;
U1 = UFRAMES1(:,:,end) ;
U2 = UFRAMES2(:,:,end) ;
X = LinearAdvectionModel( 'get_x' ) ;
subplot(length(test),1,i);
plot(Xe, Ue,'-b', 'LineWidth',2, 'Color', 'green') ; hold on ;
plot(X, U1,'-ok','MarkerFaceColor','r');
plot(X, U2,'-ob','MarkerFaceColor','b');
title(['test case: ' test{i} ' solver: ' nflux{j} ' and MUSCL'], ...
'FontSize', 24, 'FontName', 'Arial' );
axis([X(1) X(end) -0.2 1.2]) ;
end
end
Solver:
File: Solver.m:
%
% Numerical scheme for the Conservation Law
%
% Name of program: Solver.m
%
% Purpose: ........
%
% Programer: Enrico Bertolazzi
% (based on the Fortran NUMERICA lib of prof. E. F. Toro )
%
% Last revision: 11 April 2008
%
% Theory is found in Chaps. 5, 13 and 14 of Reference 1
% and in original references therein
%
% 1. E. F. Toro, "Riemann Solvers and Numerical Methods for Fluid Dynamics"
% Springer-Verlag, 1997, Second Edition, 1999
%
% This program is inspired from the NUMERICA library:
%
% NUMERICA
% A Library of Source Codes for Teaching,
% Research and Applications,
% by E. F. Toro
% Published by NUMERITEK LTD,
% Website: www.numeritek.coM
%
% INPUT:
% PRB A Structure describing the problem with fields
% Ncells = number of cell discretizing [-1,1] the domain of the problems
% CFL = time step advancing CFL ratio
% StepTime = solution is saved every StepTime
% FinalTime = solution is computed up to FinalTime
%
% OUTPUT:
% X = the cell boundary of the subdivided interval [-1,1]; X(1) = -1,..., X(N) = 1
% UFRAMES = matrix with the frames of the computed solution.
% UFRAMES(:,:,k) is the solution at time level k-th
% TFRAMES = vector with the time frames. TFRAMES(i) the time of the computed frame UFRAMES(i,:).
%
function [ UFRAMES, TFRAMES ] = Solver(PRB,MODEL)
% Initial conditions are set up
U = feval( MODEL, 'init', PRB.Ncells ) ;
DX = feval( MODEL, 'get_dx' ) ;
kframe = 1 ;
Time = 0 ;
NextTime = PRB.StepTime ;
% save initial frame
UFRAMES(:,:,kframe) = U ;
TFRAMES(kframe) = Time ;
% Time marching procedure
for NITER=1:10000
% Extrapolate for Boundary conditions
[ ULL, UL, UR, URR ] = feval( MODEL, 'extrapolate_for_bc', U ) ;
Uold = [ ULL, UL, U, UR, URR ] ;
% Courant-Friedrichs-Lewy (CFL) condition imposed
DT = feval( MODEL, 'dt_from_cfl', U, PRB.CFL ) ;
Time = Time + DT ;
% adjust time step if necessary to match the time grid
while Time >= NextTime
% reduce DT in order to match NextTime
DT1 = DT - ( Time - NextTime ) ;
Time1 = NextTime ;
U1 = Update(MODEL, DT1, DX, Uold ) ;
kframe = kframe+1 ;
UFRAMES(:,:,kframe) = U1 ;
TFRAMES(kframe) = Time1 ;
NextTime = NextTime + PRB.StepTime ;
end
% Solution is updated according to conservative formula
U = Update(MODEL, DT, DX, Uold ) ;
if Time >= PRB.FinalTime ; break ; end
end
kframe = kframe+1 ;
UFRAMES(:,:,kframe) = U ;
TFRAMES(kframe) = Time ;
end
function Unew = Update( MODEL, DT, DX, U )
% Compute intercell flux FLUX
FLUX = feval( MODEL, 'nflux', DT, U ) ;
% Solution is updated according to conservative formula
Unew = U(:,3:end-2) + (DT/DX) .* (FLUX(:,1:end-1) - FLUX(:,2:end)) ;
end
Standard Numerical Fluxes:
File: StandardFlux.m:
% # # # # # # ###### ##### # #### ## #
% ## # # # ## ## # # # # # # # # #
% # # # # # # ## # ##### # # # # # # #
% # # # # # # # # ##### # # ###### #
% # ## # # # # # # # # # # # # #
% # # #### # # ###### # # # #### # # ######
%
% ###### # # # # # ###### ####
% # # # # # # # #
% ##### # # # ## ##### ####
% # # # # ## # #
% # # # # # # # # #
% # ###### #### # # ###### ####
function [varargout] = StandardFlux( what, varargin )
numerical_flux_name = lower(varargin{1}) ;
switch what
case 'nflux'
Flux = varargin{2} ;
DT = varargin{3} ;
DX = varargin{4} ;
U = varargin{5} ;
%
switch numerical_flux_name
case 'laxfriedrichs'
varargout{1} = LaxFriedrichs( Flux, DT, DX, U ) ;
case 'force'
varargout{1} = Force( Flux, DT, DX, U ) ;
case 'godunovcentered'
varargout{1} = GodunovCentered( Flux, DT, DX, U ) ;
case 'richtmyer'
varargout{1} = Richtmyer( Flux, DT, DX, U ) ;
case 'slic'
varargout{1} = Slic( Flux, DT, DX, varargin{6}, U ) ;
otherwise
error( [ 'StandardFlux nflux: ', varargin{1}, ' unknown' ] ) ;
end
case 'get_cfl'
switch numerical_flux_name
case { 'laxfriedrichs', 'force', 'richtmyer' }
varargout{1} = 1.0 ;
case { 'slic', 'godunovcentered' }
varargout{1} = 0.5 ;
otherwise
error( [ 'StandardFlux nflux: ', numerical_flux_name, ' unknown' ] ) ;
end
end
end
% _ _____ _ _ _ _
% | | __ ___ __ | ___| __(_) ___ __| |_ __(_) ___| |__ ___
% | | / _` \ \/ /____| |_ | '__| |/ _ \/ _` | '__| |/ __| '_ \/ __|
% | |__| (_| |> <_____| _|| | | | __/ (_| | | | | (__| | | \__ \
% |_____\__,_/_/\_\ |_| |_| |_|\___|\__,_|_| |_|\___|_| |_|___/
%
% Compute the Lax-Friedrichs flux
%
function F = LaxFriedrichs( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
F = 0.5 .* ( FL + FR + (DX/DT) .* (UL-UR) ) ;
end
% _____
% | ___|__ _ __ ___ ___
% | |_ / _ \| '__/ __/ _ \
% | _| (_) | | | (_| __/
% |_| \___/|_| \___\___|
%
% compute an intercell flux according to the FORCE scheme.
%
function F = Force( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
% Richtmyer
US = 0.5 .* ( UL + UR + (DT/DX) .* (FL-FR) ) ;
FRM = feval( FLUX, US ) ;
% LaxFriedrichs
FLF = 0.5 .* ( FL+FR + (DX/DT) .* (UL-UR) ) ;
F = 0.5 .* ( FRM + FLF ) ;
end
% ____ _ ____ _ _
% / ___| ___ __| |_ _ _ __ _____ __/ ___|___ _ __ | |_ ___ _ __ ___ __| |
% | | _ / _ \ / _` | | | | '_ \ / _ \ \ / / | / _ \ '_ \| __/ _ \ '__/ _ \/ _` |
% | |_| | (_) | (_| | |_| | | | | (_) \ V /| |__| __/ | | | || __/ | | __/ (_| |
% \____|\___/ \__,_|\__,_|_| |_|\___/ \_/ \____\___|_| |_|\__\___|_| \___|\__,_|
%
% compute an intercell flux according to the Godunov centred scheme (non-monotone).
% Stability: 0 < CFL Coefficient < 0.5 * sqrt(2), about 0.7
%
function F = GodunovCentered( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL ) ;
FR = feval( FLUX, UR ) ;
US = 0.5 .* (UL+UR) + (DT/DX) .* ( FL - FR ) ;
% Compute the flux at the state US
F = feval( FLUX, US ) ;
end
% ____ _ _ _
% | _ \(_) ___| |__ | |_ _ __ ___ _ _ ___ _ __
% | |_) | |/ __| '_ \| __| '_ ` _ \| | | |/ _ \ '__|
% | _ <| | (__| | | | |_| | | | | | |_| | __/ |
% |_| \_\_|\___|_| |_|\__|_| |_| |_|\__, |\___|_|
% |___/
% Compute intercell fluxes according to the Richtmyer method, or two step Lax-Wendroff method
% See Eq. 5.79, Chapter 5, Ref. 1
%
function F = Richtmyer( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
US = 0.5 * ( UL + UR + (DT/DX) * (FL-FR) ) ;
F = feval( FLUX, US ) ;
end
%
% ____ _ _
% / ___|| (_) ___
% \___ \| | |/ __|
% ___) | | | (__
% |____/|_|_|\___|
%
function F = Slic( FLUX, DT, DX, limiter, U )
%%
COE1 = 0.5*DT/DX ;
COE2 = 0.5*DX/DT ;
% Compute slope limiter functions.
SlopeLimiterModel('setup', limiter ) ;
DELTA = SlopeLimiterModel( 'eval_slope', U ) ;
% Boundary extrapolated values PIL and PIR are computed
PIL = U(:,2:end-1) - 0.5.* DELTA ;
PIR = U(:,2:end-1) + 0.5.* DELTA ;
% Compute boundary extrapolated fluxes
FIL = feval( FLUX, PIL ) ;
FIR = feval( FLUX, PIR ) ;
% Evolve boundary extrapolated values
% for conservedvariables in each cell i
DELFLUX = COE1.*(FIL - FIR) ;
EL = PIL + DELFLUX ;
ER = PIR + DELFLUX ;
% Compute intercell flux according to the FORCE method
CDL = ER(:,1:end-1) ;
CDR = EL(:,2:end) ;
FDL = feval( FLUX, CDL ) ;
FDR = feval( FLUX, CDR ) ;
% Compute Lax-Friedrichs flux
FLF = 0.5 .* (FDL+FDR) + COE2 .* (CDL-CDR) ;
% Compute Richtmyer state
URI = 0.5 .* (CDL+CDR) + COE1 .* (FDL-FDR) ;
% Compute Richtmyer flux
FRI = feval( FLUX, URI ) ;
% Compute FORCE intercell flux FLUX
F = 0.5 .*(FLF + FRI) ;
end
Standard Limiter:
File: StandardLimiter.m:
% #####
% # # ##### ## # # ##### ## ##### #####
% # # # # ## # # # # # # # # #
% ##### # # # # # # # # # # # # # #
% # # ###### # # # # # ###### ##### # #
% # # # # # # ## # # # # # # # #
% ##### # # # # # ##### # # # # #####
%
% #
% # # # # # ##### ###### #####
% # # ## ## # # # # #
% # # # ## # # # ##### # #
% # # # # # # # #####
% # # # # # # # # #
% ####### # # # # # ###### # #
%
function [varargout] = StandardLimiter( what, varargin )
if nargin > 1
R = varargin{1} ;
Z = zeros(size(R)) ;
ONE = ones(size(R)) ;
end
switch lower(what)
case 'charm' % [not 2nd order TVD]
% Zhou, G, (1995), Numerical simulations of physical discontinuities in single and multi-fluid flows
% for arbitrary Mach numbers, PhD Thesis, Chalmers Univ. of Tech., Goteborg, Sweden.
varargout{1} = R.*(3*R+1)./((R+1).^2) ;
case 'hcus' % [not 2nd order TVD]
% Waterson, N P and H Deconinck, (1995), A unified approach to the design and application of bounded
% higher-order convection schemes, VKI Preprint 1995-21.
varargout{1} = 1.5*(R+abs(R))./(R+2) ;
case 'hquick' % [not 2nd order TVD]
% Waterson, N P and H Deconinck, (1995)
varargout{1} = 2*(R+abs(R))./(R+3) ;
case 'koren'
% Koren, B, (1993), A robust upwind discretisation method for advection, diffusion and source terms,
% In: Numerical Methods for Advection-Diffusion Problems, Ed. C.B.Vreugdenhil & B.Koren, Vieweg, Braunschweig, p117.
varargout{1} = max(Z,min(2*R,min((1+2*R)/3,2*ONE))) ;
case { 'minmod', 'minbee' }
% Roe, P L, (1986), Characteristic-based schemes for the Euler equations, Ann. Rev. Fluid Mech., 18, p337.
varargout{1} = max(Z,min(ONE,R)) ;
case { 'mc', 'monotonizedcentraldifference' } % symmetric
% Van Leer, B, (1977), Towards the ultimate conservative difference scheme III.
% Upstream-centered finite-difference schemes for ideal compressible flow., J. Comp. Phys., 23, p263-75.
varargout{1} = max(Z,min((1+R)/2, 2*min(R,ONE))) ;
case 'osher'
% Chatkravathy, S R and S Osher, (1983), High resolution applications of the Osher upwind scheme for the Euler equations,
% AIAA Paper 83-1943, Proc. AIAA 6th Comutational Fluid Dynamics Conference, pp 363-73.
if nargin > 2
beta = varargin{2} ;
else
beta = 1.5 ;
end
varargout{1} = max(Z,min(R,beta*ONE)) ;
case 'ospre' % symmetric
% Waterson, N P and H Deconinck, (1995)
% A unified approach to the design and application of bounded higher-order convection schemes, VKI Preprint 1995-21.
R2 = R.*(R+1) ;
varargout{1} = 1.5 * R2./(R2+1);
case 'smart' % [not 2nd order TVD]
% Gaskell, P H and A K C Lau, (1988)
% Curvature-compensated convective transport: SMART, a new boundedness-preserving transport algorithm
% Int. J. Num. Meth. Fluids, 8, p617.
varargout{1} = max(Z, min(2*R,min(4*ONE, 0.25+0.75*R))) ;
case 'superbee' % symmetric
% Roe, P L, (1986), Characteristic-based schemes for the Euler equations, Ann. Rev. Fluid Mech., 18, p337.
varargout{1} = max(Z, max(min(ONE,2*R), min(2*ONE,R))) ;
case 'sweby' % symmetric
% Sweby, P K, (1984), High resolution schemes using flux-limiters for hyperbolic conservation laws.
% SIAM J. Num. Anal., 21, p995-1011.
if nargin > 2
beta = varargin{2} ;
else
beta = 1.5 ;
end
varargout{1} = max(Z,max(min(beta*R,ONE),min(R,beta*ONE))) ;
case 'umist'
% Lien, F S, and M. A. Leschziner, (1994)
% Upstream monotonic interpolation for scalar transport with application to complex turbulent flows
% Int. J. Num. Meth. Fluids, 19, p527.
varargout{1} = max(Z,min(2*min(R,ONE),min(0.25+0.75*R,0.75+0.25*R))) ;
case 'vanalbada' % symmetric
% Van Albada, G D, B. Van Leer and W. W. Roberts, (1982)
% A comparative study of computational methods in cosmic gas dynamics, Astron. Astrophysics, 108, p76.
varargout{1} = (R.^2+R) ./ (R.^2+1) ;
case 'vanalbada1' % Alternative form [not 2nd order TVD] used on high spatial order schemes
% Kermani, M. J., Gerber, A. G., and Stockie, J. M. (2003),
% Thermodynamically Based Moisture Prediction Using Roe’s Scheme, 4th Conference of Iranian AeroSpace Society
% Amir Kabir University of Technology, Tehran, Iran, January 27–29.
varargout{1} = 2*R ./ (R.^2+1) ;
case 'vanleer' % symmetric
% Van Leer, B, (1974), Towards the ultimate conservative difference scheme II.
% Monotonicity and conservation combined in a second order scheme. J. Comp. Phys., 14, p361-70.
varargout{1} = (R+abs(R)) ./ (R+1) ;
case 'upwind'
varargout{1} = Z ;
case 'laxwendroff'
varargout{1} = ONE ;
case 'beamwarming'
varargout{1} = R ;
case 'fromm'
varargout{1} = 0.5*(1+R) ;
case 'names'
varargout{1} = { 'charm', 'hcus', 'hquick', 'koren', 'minmod', 'mc', 'osher', 'ospre', 'smart', ...
'superbee', 'sweby', 'umist', 'vanalbada', 'vanalbada1', 'vanleer', 'upwind', ...
'laxwendroff', 'beamwarming', 'fromm' } ;
otherwise
error( [ 'StandardLimiter: ', what, ' unknown' ] ) ;
end
end
Compute Error:
File: ComputeError.m:
%
% Compute error in various norm:
%
function [NR1,NR2,NRi] = ComputeError( UFRAMES, TFRAMES, MODEL )
[dummy,nframes] = size(TFRAMES) ;
Un = UFRAMES(:,:,nframes) ;
[M,N] = size(Un) ;
[Xe,Ue] = feval( MODEL, 'exact', TFRAMES(nframes), N ) ;
Udiff = Ue - Un ;
NR1 = norm(Udiff,1)/N ;
NR2 = norm(Udiff,2)/sqrt(N) ;
NRi = norm(Udiff,inf) ;
end
MATLAB lessons N.4
A library to solve Bughers equation with various methods
- All MATLAB file for the lesson in a unique archive: Burgers.zip
Burgers Model:
File: BurgersModel.m:
% Model for the Burgers equations
%
% u(t,x) + u(t,x) * u (t,x) = 0
% t x
%
% for t > 0 and -1 <= x <= 1
%
function [varargout] = BurgerModel( what, varargin )
% BurgerModel_paramaters
% test = which test is used
% nflux = which numerical flux is used
% bc_left = left bounday condition
% bc_right = right boundaruy condition
global BurgerModel_paramaters ;
switch lower(what)
case 'setup'
expected( what, 0, nargin, 0, nargout ) ;
BurgerModel_paramaters = clear_struct(BurgerModel_paramaters) ;
case 'set_test'
expected( what, 1, nargin, 0, nargout ) ; % TEST
ChooseTest( varargin{1} ) ;
case 'set_limiter'
expected( what, 1, nargin, 0, nargout ) ;
BurgerModel_paramaters . limiter = lower( varargin{1} ) ;
case 'set_numerical_flux'
expected( what, 1, nargin, 0, nargout ) ;
BurgerModel_paramaters . nflux = lower( varargin{1} ) ;
case 'get_dim'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = 1 ;
case 'get_dx'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = BurgerModel_paramaters . DX ;
case 'get_x'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = BurgerModel_paramaters . X ;
case 'get_final_time'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = BurgerModel_paramaters . tf ;
case 'get_cfl'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = MaxCFL() ;
case 'names'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = 'u' ;
case 'flux'
expected( what, 1, nargin, 1, nargout ) ; % U
varargout{1} = Flux( varargin{1} ) ;
case 'init'
expected( what, 1, nargin, 1, nargout ) ; % N
varargout{1} = Init( varargin{1} ) ;
case 'muscle_nflux'
expected( what, 2, nargin, 1, nargout ) ; % UL, UR
varargout{1} = Godunov( varargin{1}, varargin{2} ) ;
case 'conservative_to_physical'
varargout{1} = varargin{1} ;
case 'physical_to_conservative'
varargout{1} = varargin{1} ;
case 'conservative_to_characteristic'
varargout{1} = varargin{1} ;
case 'characteristic_to_conservative'
varargout{1} = varargin{1} ;
case 'dt_from_cfl'
expected( what, 2, nargin, 1, nargout ) ; % U, CFLcoeff
varargout{1} = DT_from_CFL( varargin{1}, varargin{2} ) ;
case 'extrapolate_for_bc'
expected( what, 1, nargin, 4, nargout ) ; % U
[ varargout{1}, varargout{2}, varargout{3}, varargout{4} ] = Extrapolate_for_BC( varargin{1} ) ;
case 'nflux'
expected( what, 2, nargin, 1, nargout ) ; % DT, U
varargout{1} = NFlux( varargin{1}, varargin{2} ) ;
otherwise
error(['BurgerModel bad argument: ', what]) ;
end
end
function SE = clear_struct(S)
if isstruct(S)
SE = rmfield( S, fieldnames(S) ) ;
else
SE = S ;
end
end
function expected( what, ein, nin, eout, nout )
if ein ~= nin-1
error( ['in BurgerModel call to ', what, ' expected ', int2str( ein ), ' input argument, found ', int2str(nin-1) ]) ;
end
if eout ~= nout
error( ['in BurgerModel call to ', what, ' expected ', int2str( eout ), ' output argument, found ', int2str(nout) ]) ;
end
end
% #######
% # # # # # #
% # # # # # #
% ##### # # # ##
% # # # # ##
% # # # # # #
% # ###### #### # #
% compute the flux
function F = Flux( U )
F = 0.5 * U .^ 2 ;
end
% ###
% # # # # #####
% # ## # # #
% # # # # # #
% # # # # # #
% # # ## # #
% ### # # # #
function U = Init(N)
global BurgerModel_paramaters ;
% Calculate mesh size DX
DX = 2.0/N ;
X = [-1+DX/2:DX:1-DX/2] ;
if isfield(BurgerModel_paramaters, 'test')
switch BurgerModel_paramaters . test
case 'classroomproblem'
DX = 8.0/N ;
X = [0+DX/2:DX:8-DX/2] ; % center of the cell
N1 = floor(3*N/8) ;
N2 = N - N1 ;
U = [ones(1,N1) zeros(1,N2) ] ;
case 'square'
N3 = floor(N/3) ;
M = N - N3 - N3 ;
U = [zeros(1,N3) ones(1,M) zeros(1,N3) ] ;
case 'smooth'
U = exp( -8 .* X .^ 2 ) ;
otherwise
error(['BurgerModel::Init unknown test ', BurgerModel_paramaters . test]) ;
end
else
error('BurgerModel::Init unknown test you must set it by set_test!') ;
end
BurgerModel_paramaters . DX = DX ;
BurgerModel_paramaters . X = X ;
end
% ##### #######
% # # # # #### #### #### ###### # ###### #### #####
% # # # # # # # # # # # # #
% # ###### # # # # #### ##### # ##### #### #
% # # # # # # # # # # # # #
% # # # # # # # # # # # # # # # #
% ##### # # #### #### #### ###### # ###### #### #
%
function ChooseTest(test)
global BurgerModel_paramaters ;
switch test
case 'classroomproblem'
tf = 3.5 ;
bc_left = 'free' ;
bc_right = 'free' ;
case 'square'
tf = 3 ;
bc_left = 'cyclic' ;
bc_right = 'cyclic' ;
case 'smooth'
tf = 4 ;
bc_left = 'cyclic' ;
bc_right = 'cyclic' ;
otherwise
error(['BurgerModel:ChooseTest test name',test] ) ;
end
BurgerModel_paramaters . test = test ;
BurgerModel_paramaters . bc_left = bc_left ;
BurgerModel_paramaters . bc_right = bc_right ;
BurgerModel_paramaters . tf = tf ;
end
% ###### ####### ##### ####### #
% # # # ###### ##### #### # # # # # #
% # # # # # # # # ## ## # # #
% # # # ##### # # # # # ## # # ##### #
% # # # # ##### # # # # # # #
% # # # # # # # # # # # # # #
% ###### # # # # #### # # ##### # #######
% ####### #######
% Compute DT from CFL
function DT = DT_from_CFL( U, CFLcoeff )
global BurgerModel_paramaters ;
DX = BurgerModel_paramaters . DX ;
DT = CFLcoeff * DX / max(abs(U)) ;
end
% #######
% # # # ##### ##### ## ##### #### # ## ##### ######
% # # # # # # # # # # # # # # # # #
% ##### ## # # # # # # # # # # # # # #####
% # ## # ##### ###### ##### # # # ###### # #
% # # # # # # # # # # # # # # # #
% ####### # # # # # # # # #### ###### # # # ######
%
% ###### #####
% ###### #### ##### # # # #
% # # # # # # # #
% ##### # # # # ###### #
% # # # ##### # # #
% # # # # # # # # #
% # #### # # ###### #####
% #######
% Extrapolate values for boundary condition
function [ULL, UL, UR, URR] = Extrapolate_for_BC( U )
global BurgerModel_paramaters ;
L = BurgerModel_paramaters . bc_left ;
R = BurgerModel_paramaters . bc_right ;
% Left boundary
switch L
case 'free' % Apply transmissive boundary conditions
UL = U(:,1) ;
ULL = U(:,2) ;
case 'cyclic' % Apply cyclic boundary conditions
UL = U(:,end) ;
ULL = U(:,end-1) ;
otherwise % Apply reflective boundary conditions
UL = [ U(1,1) ; -U(2,1) ] ;
ULL = [ U(1,2) ; -U(2,2) ] ;
end
% Right boundary
switch R
case 'free' % Apply transmissive boundary conditions
UR = U(:,end) ;
URR = U(:,end-1) ;
case 'cyclic' % Apply cyclic boundary conditions
UR = U(:,1) ;
URR = U(:,2) ;
otherwise % Apply reflective boundary conditions
UR = [ U(1,end) ; -U(2,end) ] ;
URR = [ U(1,end-1) ; -U(2,end-1) ] ;
end
end
% ####### ##### ####### #
% # # ##### ##### # # # ## # # # # #
% # # # # # # ## ## # # # # # #
% # # # # # # # ## # # # # # ##### #
% # # ##### # # # # ###### # # # #
% # # # # # # # # # # # # # #
% ####### # # # # # # # ###### ##### # #######
function CFL = MaxCFL
global BurgerModel_paramaters ;
nflux = BurgerModel_paramaters . nflux ;
%
switch nflux
case 'godunov'
CFL = 1.0 ;
otherwise
CFL = StandardFlux( 'get_cfl', nflux ) ;
end
end
% # # # # # # ###### ##### # #### ## #
% ## # # # ## ## # # # # # # # # #
% # # # # # # ## # ##### # # # # # # #
% # # # # # # # # ##### # # ###### #
% # ## # # # # # # # # # # # # #
% # # #### # # ###### # # # #### # # ######
%
% ###### # # # # # ###### ####
% # # # # # # # #
% ##### # # # ## ##### ####
% # # # # ## # #
% # # # # # # # # #
% # ###### #### # # ###### ####
function FLUX = NFlux( DT, U )
global BurgerModel_paramaters ;
ULL = U(:,1:end-3) ;
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
URR = U(:,4:end-0) ;
nflux = BurgerModel_paramaters . nflux ;
DX = BurgerModel_paramaters . DX ;
switch nflux
% monolitic numerical fluxes
case 'godunov'
FLUX = Godunov(UL,UR) ;
otherwise
FLUX = StandardFlux( 'nflux', nflux, @Flux, DT, DX, U ) ;
end
end
% _ ___ _ __ ___ _ _ _ _ _
% |_ | |_) (_ | / \ |_) | \ |_ |_)
% | _|_ | \ __) | \_/ | \ |_/ |_ | \
%
% #####
% # # #### ##### # # # # #### # #
% # # # # # # # ## # # # # #
% # #### # # # # # # # # # # # # #
% # # # # # # # # # # # # # # #
% # # # # # # # # # ## # # # #
% ##### #### ##### #### # # #### ## %
%
% Compute the solution of the Riemann problem
%
function F = Godunov( UL, UR )
%%USTAR = zeros(size(UL)) ;
IDX = find( UL > UR ) ;
% Solution is a shock wave Compute shock speed S
S(IDX) = 0.5*(UL(IDX) + UR(IDX)) ;
% Sample the state along the t-axis
II = IDX( find( S(IDX) >= 0 )) ;
USTAR(II) = UL(II) ;
II = IDX( find( S(IDX) < 0 )) ;
USTAR(II) = UR(II) ;
IDX = find( UL <= UR ) ;
% Solution is a rarefaction wave. There are 3 cases:
II = IDX(find( UL(IDX) >= 0 )) ;
% Right supersonic rarefaction
USTAR(II) = UL(II) ;
II = IDX(find( UR(IDX) <= 0 )) ;
% Left supersonic rarefaction
USTAR(II) = UR(II) ;
II = IDX(find( UL(IDX) <= 0 & UR(IDX) >= 0 )) ;
% Transonic rarefaction
USTAR(II) = 0 ;
F = 0.5 * USTAR .^ 2 ;
end
Driver to test the Solver:
File: BurgersExample.m:
test = { 'square', 'smooth' } ;
nflux = { 'Godunov', ...
'force', ...
'LaxFriedrichs', ...
'Richtmyer', ...
'GodunovCentered' } ;
close all ;
for j=1:length(nflux)
ok = input( ['Start numerical flux: ' nflux{j} ' [q=quit] ' ], 's' ) ;
if ok == 'q'
break ;
end ;
handleFig = figure('Position',[10 10 1000 600],'color','w') ;
for i=1:length(test)
BurgersModel( 'setup' ) ;
BurgersModel( 'set_test', test{i} ) ;
BurgersModel( 'set_numerical_flux', nflux{j} ) ;
%%BurgersModel( 'set_limiter', 'superbee' ) ;
PRB . CFL = 0.9*BurgersModel( 'get_cfl' ) ;
PRB . FinalTime = BurgersModel( 'get_final_time' ) ;
PRB . Ncells = 100 ; % select 100 cell inteval subdivision
PRB . StepTime = PRB . FinalTime / 100 ;
% call the solver
[ UFRAMES, TFRAMES ] = Solver(PRB,@BurgersModel) ;
U = UFRAMES(:,:,end) ;
X = BurgersModel( 'get_x' ) ;
subplot(length(test),1,i);
plot(X,U,'-ob','MarkerFaceColor','b');
title(['test case: ' test{i} ' solver: ' nflux{j}], ...
'FontSize', 24, 'FontName', 'Arial' );
axis([X(1) X(end) -0.2 1.2]) ;
end
end
Solver:
File: Solver.m:
%
% Numerical scheme for the Conservation Law
%
% Name of program: Solver.m
%
% Purpose: ........
%
% Programer: Enrico Bertolazzi
% (based on the Fortran NUMERICA lib of prof. E. F. Toro )
%
% Last revision: 11 April 2008
%
% Theory is found in Chaps. 5, 13 and 14 of Reference 1
% and in original references therein
%
% 1. E. F. Toro, "Riemann Solvers and Numerical Methods for Fluid Dynamics"
% Springer-Verlag, 1997, Second Edition, 1999
%
% This program is inspired from the NUMERICA library:
%
% NUMERICA
% A Library of Source Codes for Teaching,
% Research and Applications,
% by E. F. Toro
% Published by NUMERITEK LTD,
% Website: www.numeritek.coM
%
% INPUT:
% PRB A Structure describing the problem with fields
% Ncells = number of cell discretizing [-1,1] the domain of the problems
% CFL = time step advancing CFL ratio
% StepTime = solution is saved every StepTime
% FinalTime = solution is computed up to FinalTime
%
% OUTPUT:
% X = the cell boundary of the subdivided interval [-1,1]; X(1) = -1,..., X(N) = 1
% UFRAMES = matrix with the frames of the computed solution.
% UFRAMES(:,:,k) is the solution at time level k-th
% TFRAMES = vector with the time frames. TFRAMES(i) the time of the computed frame UFRAMES(i,:).
%
function [ UFRAMES, TFRAMES ] = Solver(PRB,MODEL)
% Initial conditions are set up
U = feval( MODEL, 'init', PRB.Ncells ) ;
DX = feval( MODEL, 'get_dx' ) ;
kframe = 1 ;
Time = 0 ;
NextTime = PRB.StepTime ;
% save initial frame
UFRAMES(:,:,kframe) = U ;
TFRAMES(kframe) = Time ;
% Time marching procedure
for NITER=1:10000
% Extrapolate for Boundary conditions
[ ULL, UL, UR, URR ] = feval( MODEL, 'extrapolate_for_bc', U ) ;
Uold = [ ULL, UL, U, UR, URR ] ;
% Courant-Friedrichs-Lewy (CFL) condition imposed
DT = feval( MODEL, 'dt_from_cfl', U, PRB.CFL ) ;
Time = Time + DT ;
% adjust time step if necessary to match the time grid
while Time >= NextTime
% reduce DT in order to match NextTime
DT1 = DT - ( Time - NextTime ) ;
Time1 = NextTime ;
U1 = Update(MODEL, DT1, DX, Uold ) ;
kframe = kframe+1 ;
UFRAMES(:,:,kframe) = U1 ;
TFRAMES(kframe) = Time1 ;
NextTime = NextTime + PRB.StepTime ;
end
% Solution is updated according to conservative formula
U = Update(MODEL, DT, DX, Uold ) ;
if Time >= PRB.FinalTime ; break ; end
end
kframe = kframe+1 ;
UFRAMES(:,:,kframe) = U ;
TFRAMES(kframe) = Time ;
end
function Unew = Update( MODEL, DT, DX, U )
% Compute intercell flux FLUX
FLUX = feval( MODEL, 'nflux', DT, U ) ;
% Solution is updated according to conservative formula
Unew = U(:,3:end-2) + (DT/DX) .* (FLUX(:,1:end-1) - FLUX(:,2:end)) ;
end
Standard Numerical Fluxes:
File: StandardFlux.m:
% # # # # # # ###### ##### # #### ## #
% ## # # # ## ## # # # # # # # # #
% # # # # # # ## # ##### # # # # # # #
% # # # # # # # # ##### # # ###### #
% # ## # # # # # # # # # # # # #
% # # #### # # ###### # # # #### # # ######
%
% ###### # # # # # ###### ####
% # # # # # # # #
% ##### # # # ## ##### ####
% # # # # ## # #
% # # # # # # # # #
% # ###### #### # # ###### ####
function [varargout] = StandardFlux( what, varargin )
numerical_flux_name = lower(varargin{1}) ;
switch what
case 'nflux'
Flux = varargin{2} ;
DT = varargin{3} ;
DX = varargin{4} ;
U = varargin{5} ;
%
switch numerical_flux_name
case 'laxfriedrichs'
varargout{1} = LaxFriedrichs( Flux, DT, DX, U ) ;
case 'force'
varargout{1} = Force( Flux, DT, DX, U ) ;
case 'godunovcentered'
varargout{1} = GodunovCentered( Flux, DT, DX, U ) ;
case 'richtmyer'
varargout{1} = Richtmyer( Flux, DT, DX, U ) ;
otherwise
error( [ 'StandardFlux nflux: ', varargin{1}, ' unknown' ] ) ;
end
case 'get_cfl'
switch numerical_flux_name
case { 'laxfriedrichs', 'force', 'richtmyer' }
varargout{1} = 1.0 ;
case { 'slic', 'godunovcentered' }
varargout{1} = 0.5 ;
otherwise
error( [ 'StandardFlux nflux: ', numerical_flux_name, ' unknown' ] ) ;
end
end
end
% _ _____ _ _ _ _
% | | __ ___ __ | ___| __(_) ___ __| |_ __(_) ___| |__ ___
% | | / _` \ \/ /____| |_ | '__| |/ _ \/ _` | '__| |/ __| '_ \/ __|
% | |__| (_| |> <_____| _|| | | | __/ (_| | | | | (__| | | \__ \
% |_____\__,_/_/\_\ |_| |_| |_|\___|\__,_|_| |_|\___|_| |_|___/
%
% Compute the Lax-Friedrichs flux
%
function F = LaxFriedrichs( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
F = 0.5 .* ( FL + FR + (DX/DT) .* (UL-UR) ) ;
end
% _____
% | ___|__ _ __ ___ ___
% | |_ / _ \| '__/ __/ _ \
% | _| (_) | | | (_| __/
% |_| \___/|_| \___\___|
%
% compute an intercell flux according to the FORCE scheme.
%
function F = Force( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
% Richtmyer
US = 0.5 .* ( UL + UR + (DT/DX) .* (FL-FR) ) ;
FRM = feval( FLUX, US ) ;
% LaxFriedrichs
FLF = 0.5 .* ( FL+FR + (DX/DT) .* (UL-UR) ) ;
F = 0.5 .* ( FRM + FLF ) ;
end
% ____ _ ____ _ _
% / ___| ___ __| |_ _ _ __ _____ __/ ___|___ _ __ | |_ ___ _ __ ___ __| |
% | | _ / _ \ / _` | | | | '_ \ / _ \ \ / / | / _ \ '_ \| __/ _ \ '__/ _ \/ _` |
% | |_| | (_) | (_| | |_| | | | | (_) \ V /| |__| __/ | | | || __/ | | __/ (_| |
% \____|\___/ \__,_|\__,_|_| |_|\___/ \_/ \____\___|_| |_|\__\___|_| \___|\__,_|
%
% compute an intercell flux according to the Godunov centred scheme (non-monotone).
% Stability: 0 < CFL Coefficient < 0.5 * sqrt(2), about 0.7
%
function F = GodunovCentered( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL ) ;
FR = feval( FLUX, UR ) ;
US = 0.5 .* (UL+UR) + (DT/DX) .* ( FL - FR ) ;
% Compute the flux at the state US
F = feval( FLUX, US ) ;
end
% ____ _ _ _
% | _ \(_) ___| |__ | |_ _ __ ___ _ _ ___ _ __
% | |_) | |/ __| '_ \| __| '_ ` _ \| | | |/ _ \ '__|
% | _ <| | (__| | | | |_| | | | | | |_| | __/ |
% |_| \_\_|\___|_| |_|\__|_| |_| |_|\__, |\___|_|
% |___/
% Compute intercell fluxes according to the Richtmyer method, or two step Lax-Wendroff method
% See Eq. 5.79, Chapter 5, Ref. 1
%
function F = Richtmyer( FLUX, DT, DX, U )
UL = U(:,2:end-2) ;
UR = U(:,3:end-1) ;
%%
FL = feval( FLUX, UL) ;
FR = feval( FLUX, UR) ;
US = 0.5 * ( UL + UR + (DT/DX) * (FL-FR) ) ;
F = feval( FLUX, US ) ;
end
MATLAB lessons N.5
A solver for a 2 equation hyperbolic linear system
- All MATLAB file for the lesson in a unique archive: 2x2.zip
Linear2x2 Model:
File: Linear2x2Model.m:
%
% solve the linearised Hyperbolic system in one space dimension
%
% / \ / \ / \
% | q1 | | 0 -a | | 0 |
% D_t | | + D_x | | = | |
% | q2 | | -a 0 | | 0 |
% \ / \ / \ /
%
% for t > 0 and a <= x <= b
%
% P = parameter
%
% what
% 'setup'
% 'flux' compute flux
%
function [varargout] = Linear2x2Model( what, varargin )
global Linear2x2_paramaters ;
switch lower( what )
case 'setup'
expected( what, 1, nargin, 0, nargout ) ; % a
Linear2x2_paramaters = clear_struct(Linear2x2_paramaters) ;
Linear2x2_paramaters . a = varargin{1} ;
case 'get_dim'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = 2 ;
case 'get_names'
expected( what, 0, nargin, 1, nargout ) ;
varargout{1} = { 'q1', 'q2' } ;
case 'flux'
expected( what, 1, nargin, 1, nargout ) ; % U
varargout{1} = Flux( varargin{1} ) ;
case 'riemann'
expected( what, 4, nargin, 1, nargout ) ; % UL, UR, T, X
UL = varargin{1} ;
UR = varargin{2} ;
T = varargin{3} ;
X = varargin{4} ;
varargout{1} = RiemannExact( UL, UR, T, X ) ;
case 'max_speed'
expected( what, 1, nargin, 1, nargout ) ; % U
varargout{1} = maxSpeed( varargin{1} ) ;
case 'extrapolate'
expected( what, 3, nargin, 1, nargout ) ; % U, left_bc, right_bc
U = varargin{1} ;
left_bc = varargin{2} ;
right_bc = varargin{3} ;
varargout{1} = Extrapolate( U, left_bc, right_bc ) ;
otherwise
error(['Linear2x2Model bad argument: ', what]) ;
end
end
function SE = clear_struct(S)
if isstruct(S)
SE = rmfield( S, fieldnames(S) ) ;
else
SE = S ;
end
end
function expected( what, ein, nin, eout, nout )
if ein ~= nin-1
error( ['in Linear2x2 call to ', what, ' expected ', int2str( ein ), ' input argument, found ', int2str(nin-1) ]) ;
end
if eout ~= nout
error( ['in Linear2x2 call to ', what, ' expected ', int2str( eout ), ' output argument, found ', int2str(nout) ]) ;
end
end
% #######
% # # # # # #
% # # # # # #
% ##### # # # ##
% # # # # ##
% # # # # # #
% # ###### #### # #
% compute the flux
function F = Flux( US )
global Linear2x2_paramaters ;
a = Linear2x2_paramaters . a ;
F = [ 0, -a ; -a, 0 ] * US ;
end
% ######
% # # # ###### # # ## # # # #
% # # # # ## ## # # ## # ## #
% ###### # ##### # ## # # # # # # # # #
% # # # # # # ###### # # # # # #
% # # # # # # # # # ## # ##
% # # # ###### # # # # # # # #
%
function QS = RiemannStar( QL, QR )
global Linear2x2_paramaters ;
a = Linear2x2_paramaters . a ;
A = (QR + QL) ./ 2 ;
B = (QR - QL) ./ 2 ;
QS(1,:) = A(1,:) + B(2,:) ;
QS(2,:) = A(2,:) + B(1,:) ;
end
function US = RiemannExact( UL, UR, T, X )
global Linear2x2_paramaters ;
a = Linear2x2_paramaters . a ;
l1 = -abs(a) ;
l2 = +abs(a) ;
IDX = find( X - l1 * T >= 0 & X - l2 * T <= 0 ) ;
US(:,IDX) = RiemannStar( UL, UR ) * ones( size(IDX) ) ;
IDX = find( X - l1 * T < 0 ) ;
US(:,IDX) = UL * ones( size(IDX) ) ;
IDX = find( X - l2 * T > 0 ) ;
US(:,IDX) = UR * ones( size(IDX) ) ;
end
% #####
% # # ## # # # # ##### ###### ###### #####
% ## ## # # # # # # # # # # #
% # ## # # # ## ##### # # ##### ##### # #
% # # ###### ## # ##### # # # #
% # # # # # # # # # # # # #
% # # # # # # ##### # ###### ###### #####
%
function MS = maxSpeed( U )
global Linear2x2_paramaters ;
a = Linear2x2_paramaters . a ;
MS = abs(a) ;
end
% #######
% # # # ##### ##### ## ##### #### # ## ##### ######
% # # # # # # # # # # # # # # # # #
% ##### ## # # # # # # # # # # # # # #####
% # ## # ##### ###### ##### # # # ###### # #
% # # # # # # # # # # # # # # # #
% ####### # # # # # # # # #### ###### # # # ######
%
function Uextra = Extrapolate( U, L, R )
global Linear2x2_paramaters ;
a = Linear2x2_paramaters . a ;
% Left boundary
switch lower(L)
case 'free' % Apply transmissive boundary conditions
UL = U(:,1) ;
ULL = U(:,2) ;
case 'cyclic' % Apply cyclic boundary conditions
UL = U(:,end) ;
ULL = U(:,end-1) ;
otherwise
error( ['in Linear2x2 call to Extrapolate L=', L, ' unknown boundary condition']) ;
end
% Right boundary
switch lower(R)
case 'free' % Apply transmissive boundary conditions
UR = U(:,end) ;
URR = U(:,end-1) ;
case 'cyclic' % Apply cyclic boundary conditions
UR = U(:,1) ;
URR = U(:,2) ;
otherwise
error( ['in Linear2x2 call to Extrapolate R=', R, ' unknown boundary condition']) ;
end
% build vector of extrapolated values
Uextra = [ ULL, UL, U, UR, URR ] ;
end
Linear2x2 Example:
File: Linear2x2Example.m:
test = { 'sod' } ;
nflux = { 'LaxFriedrichs' } ;
% setup the model
Linear2x2Model( 'setup', 1 ) ;
% get names of variable
names = Linear2x2Model( 'get_names' ) ;
% Initial left and right state
UL = [0.5 ; 2 ];
UR = [1 ; 0.5 ];
PRB . Uinit = [ UL * ones(1,50) UR * ones(1,50) ] ; % initial condition
PRB . Xnodes = [ -1:2/100:1 ] ; % boundary cells nodes
PRB . FinalTime = 0.1 ; % final time
PRB . StepTime = 0.01 ; % save a frame every StepTime
PRB . CFL = 0.9 ;
PRB . left_bc = 'free' ; % left boundary condition type
PRB . right_bc = 'free' ; % right boundary condition type
% Exact solution of the riemann problem sampled of fine mesh
Xe = [ -1:2/1000:1 ] ;
Ue = Linear2x2Model( 'riemann', UL, UR, PRB . FinalTime, Xe ) ;
for j=1:length(nflux)
ok = input( ['Start flux: ' nflux{j} ' [q=quit] ' ], 's' ) ;
if ok == 'q' ; break ; end ;
handleFig = figure('Position',[10+j*25 10+j*25 1000 800],'color','w') ;
% call the solver
[ UFRAMES, TFRAMES ] = Solver(PRB,@Linear2x2Model,@LaxFriedrichs) ;
% evalute cell center
X = (PRB . Xnodes(1:end-1)+PRB . Xnodes(2:end))/2 ;
% extract last frame
U = UFRAMES(:,:,end) ;
for i=1:2
subplot(2,1,i);
plot(Xe, Ue(i,:), '-b', 'LineWidth', 2, 'Color', 'green') ; hold on ;
plot(X, U(i,:), '-ok', 'MarkerFaceColor','r');
title([names{i} ' solver: ' nflux{j}], 'FontSize', 24, 'FontName', 'Arial' );
end
end
Solver:
File: Solver.m:
%
% Numerical scheme for the Conservation Law
%
% Name of program: Solver.m
%
% Purpose: ........
%
% Programer: Enrico Bertolazzi
% (based on the Fortran NUMERICA lib of prof. E. F. Toro )
%
% Last revision: 11 April 2008
%
% Theory is found in Chaps. 5, 13 and 14 of Reference 1
% and in original references therein
%
% 1. E. F. Toro, "Riemann Solvers and Numerical Methods for Fluid Dynamics"
% Springer-Verlag, 1997, Second Edition, 1999
%
% This program is inspired from the NUMERICA library:
%
% NUMERICA
% A Library of Source Codes for Teaching,
% Research and Applications,
% by E. F. Toro
% Published by NUMERITEK LTD,
% Website: www.numeritek.coM
%
% INPUT:
% PRB A Structure describing the problem with fields
% Uinit = Initial solution
% Xnodes = Boundary cell nodes
% StepTime = solution is saved every StepTime
% FinalTime = solution is computed up to FinalTime
% CFL = advancing time step CFL
%
% MODEL A function with variable arguments.
% First argument simulate method name in Object Oriented Paradigm
% MODEL must support the following call:
% Uextr = MODEL( 'extrapolate', U, left_bc, right_bc )
% Extrapolate 4 cell of states(2 on left 2 on right) for boudary condition
% S = MODEL( 'max_speed', U )
% Evaluate maximum speed signal of the flux for CFL computation
% F = MODEL( 'flux', U )
% Ealuate model flux
% OUTPUT:
% UFRAMES = matrix with the frames of the computed solution.
% UFRAMES(:,:,k) is the solution at time level k-th
% TFRAMES = vector with the time frames. TFRAMES(i) the time of the computed frame UFRAMES(i,:).
%
function [ UFRAMES, TFRAMES ] = Solver(PRB,MODEL,NFLUX)
% Initial conditions are set up
U = PRB . Uinit ;
% Compute cell size
DX = PRB . Xnodes(2) - PRB . Xnodes(1) ; % equal spaced nodes!!
% save initial frame
UFRAMES(:,:,1) = U ;
TFRAMES(1) = 0 ;
kframe = 1 ; % number of saved framed
Time = 0 ; % initial time
NextTime = PRB.StepTime ; % Time to save next frame
% Time marching procedure
for NITER=1:10000
% Extrapolate for Boundary conditions
Uextra = feval( MODEL, 'extrapolate', U, PRB.left_bc, PRB.right_bc ) ;
% Courant-Friedrichs-Lewy (CFL) condition imposed
DT = DX * PRB.CFL / feval( MODEL, 'max_speed', U ) ;
% update time
Time = Time + DT ;
% adjust time step if necessary to match the time grid
while Time >= NextTime
% reduce DT in order to match NextTime
DT1 = DT - ( Time - NextTime ) ;
% Compute intercell flux FLUX
FLUX = feval( NFLUX, MODEL, DT1, DX, Uextra ) ;
kframe = kframe+1 ;
% Solution is updated according to conservative formula and saved in the frame
UFRAMES(:,:,kframe) = U + (DT/DX) * (FLUX(:,1:end-1) - FLUX(:,2:end)) ;
TFRAMES(kframe) = NextTime ;
% update next time frame
NextTime = NextTime + PRB.StepTime ;
end
% Compute intercell flux FLUX
FLUX = feval( NFLUX, MODEL, DT, DX, Uextra ) ;
% Solution is updated according to conservative formula
U = U + (DT/DX) * ( FLUX(:,1:end-1) - FLUX(:,2:end) ) ;
if Time >= PRB.FinalTime ; break ; end
end
% save last frame
kframe = kframe+1 ;
UFRAMES(:,:,kframe) = U ;
TFRAMES(kframe) = Time ;
end
LaxFriedrichs Numerical Fluxes:
File: LaxFriedrichs.m:
% _ _____ _ _ _ _
% | | __ ___ __ | ___| __(_) ___ __| |_ __(_) ___| |__ ___
% | | / _` \ \/ /____| |_ | '__| |/ _ \/ _` | '__| |/ __| '_ \/ __|
% | |__| (_| |> <_____| _|| | | | __/ (_| | | | | (__| | | \__ \
% |_____\__,_/_/\_\ |_| |_| |_|\___|\__,_|_| |_|\___|_| |_|___/
%
% Compute the Lax-Friedrichs flux
%
function Flux = LaxFriedrichs( MODEL, DT, DX, US )
FS = feval( MODEL, 'flux', US ) ;
%
UL = US(:,2:end-2) ;
UR = US(:,3:end-1) ;
FL = FS(:,2:end-2) ;
FR = FS(:,3:end-1) ;
%
Flux = 0.5 .* ( FL + FR + (DT/DX) * (UL-UR) ) ;
end
MATLAB lessons N.6
A solver for a 2 equation hyperbolic linear system with source term
Documentation: description.pdf
Documentation of MATLAB Code: HTML
All MATLAB file for the lesson in a unique archive: LinearModel2eq.zip
Sample of the results
Force VS MUSCL
Godunov Centered VS MUSCL
Lax Friedrichs VS MUSCL
Richtmyer VS MUSCL
Part I: Ordinary Differential Equations: project1.pdf
Part II: Partial Differential Equations: project2.pdf
Corso di Metodi Matematici e Calcolo per Ingegneria (AA 2007/2008)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 13:30 - 16:30 | T4 |
Giovedì | 8.30 - 10.30 | M1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11 - 12 | 505 |
Giovedì | 11 - 12 | 505 |
Dispense del corso
Lucidi sulla trasformata di Laplace
La trasformata di Laplace
- versione a schermo slides-laplace-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-laplace-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-laplace-2x2.pdf
Inversione della trasformata di Laplace
- versione a schermo slides-invlaplace-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-invlaplace-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-invlaplace-2x2.pdf
Esercizi svolti sulla trasformata di Laplace
- Tabella ed esercizi LaplaceTable.pdf
Lucidi sulla trasformata*
- versione a schermo slides-Z-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-Z-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-Z-2x2.pdf
Lucidi sulla serie di Fourier
- versione a schermo slides-Fourier-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-Fourier-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-Fourier-2x2.pdf
Lucidi sulla Trasformata di Fourier
- versione a schermo slides-TFourier-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-TFourier-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-TFourier-2x2.pdf
Esercizi svolti sulla trasformata di Fourier
- Tabella ed esercizi: TFourierTable.pdf
Lucidi sui Minimi Vincolati
- versione a schermo slides-Minimi-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-Minimi-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-Minimi-2x2.pdf
Lucidi sulle equazioni differenziali algebriche (DAE)
Introduzione
- versione a schermo slides-DAE-Intro-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-DAE-Intro-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-DAE-Intro-2x2.pdf
L’indice differenziale
- versione a schermo slides-DAE-Index-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-DAE-Index-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-DAE-Index-2x2.pdf
Alcuni esempi numerici
- versione a schermo slides-DAE-Esempi-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-DAE-Esempi-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-DAE-Esempi-2x2.pdf
Il metodi di partizionamento delle coordinate
- versione a schermo slides-DAE-Cpartition-1x1.pdf
- versione stampabile 2 lucidi per foglio slides-DAE-Cpartition-1x2.pdf
- versione stampabile 4 lucidi per foglio slides-DAE-Cpartition-2x2.pdf
Minidispensa sui numeri complessi
Esami Svolti
Appello 7 gennaio 2008
- Testo dell’appello (con soluzioni) mmci-2008-01-07.pdf
Appello 18 febbraio 2008
- Testo dell’appello (con soluzioni) mmci-2008-02-18.pdf
Appello 21 giugno 2008
- Testo dell’appello (con soluzioni) mmci-2008-06-21.pdf
Appello 18 luglio 2008
- Testo dell’appello (con soluzioni) mmci-2008-07-18.pdf
Appello 2 settembre 2008
- Testo dell’appello (con soluzioni) mmci-2008-09-02.pdf
Prontuario per l’esame
P.h.D. Course of Numerical Unconstrained Optimization (AA 2007/2008)
Lessons
Lessons of 8/5/2008
One Dimensional Non-Linear Problems
- full screen version slides-1D-1x1.pdf
- print version 2 slide by sheet slides-1D-1x2.pdf
- print version 4 slide by sheet slides-1D-2x2.pdf
One-Dimensional Minimization
- full screen version slides-m1D-1x1.pdf
- print version 2 slide by sheet slides-m1D-1x2.pdf
- print version 4 slide by sheet slides-m1D-2x2.pdf
Lessons of 9/5/2008
Unconstrained minimization
- full screen version slides-mND-1x1.pdf
- print version 2 slide by sheet slides-mND-1x2.pdf
- print version 4 slide by sheet slides-mND-2x2.pdf
Lessons of 15/5/2008
Conjugate Direction minimization
- full screen version slides-CG-1x1.pdf
- print version 2 slide by sheet slides-CG-1x2.pdf
- print version 4 slide by sheet slides-CG-2x2.pdf
Lessons of 23/5/2008
Non-linear problems in n
variable
- full screen version slides-ND-1x1.pdf
- print version 2 slide by sheet slides-ND-1x2.pdf
- print version 4 slide by sheet slides-ND-2x2.pdf
Lessons of 29/5/2008
Quasi-Newton methods for minimization
- full screen version slides-mQN-1x1.pdf
- print version 2 slide by sheet slides-mQN-1x2.pdf
- print version 4 slide by sheet slides-mQN-2x2.pdf
Lessons of 6/6/2008 and 12/6/2008
Trust Region methods
- full screen version `slides-TR-1x1.pdf
- print version 2 slide by sheet slides-TR-1x2.pdf
- print version 4 slide by sheet slides-TR-2x2.pdf
Some MATLAB codes for minimization
All MATLAB file sin a unique archive Codici.zip
The possible tasks
The Preconditioned Conjugate Gradient method
The Fletcher Reeves and Polack Ribiere method
The Broyden method for system of nonlinear equations
The SR1 method for uncostrained optimization
The DFP and BFGS method for uncostrained optimization
The double dogleg method
The exact trust region method
The Levemberg-Marquardt method
The Sequential Quadratic Programming (SQP) method
The multidimensional Newton method and the Kantorovich proofs of its local quadratic convergence
The candidate must choose an argument and permorm the following task:
Search in the literature to obtain a list of significative reference (10-20 reference)
Write a report describing the argument
Write a C++ code implementing the algorithm
The code should be commented in the report, or in alternative well documented using e.g. DOXIGEN.
P.h.D. Course of Scientific Programming in C++ (AA 2007/2008)
Suggested lectures
Bruce Eckel’s Free Electronic Books:
C++ Annotations
Some useful links
A small tutorial on Sturm Theorem (in italian)
The tutorial sturm.pdf
Lesson of 17 June 2008
Some simple C programs
A minimal program
File: 1.c:
/*
A multi line comment
start with a slash + star
end with a star + slash
*/
// single line comment (only in C++ or ANSI C)
// preprocessor directive
// include standard Input Output definition of C
#include <stdio.h>
/*
A program consist in a procedure named "main"
with o without arguments
*/
int // means integer is the
// return type of the routine main
main () // main is the name "fixed" of the program
// () contains eventual arguments
{ // open brace is the beginning of the body of the program
// printf is the function for the output
// printf write to the standard output
printf("hello world!\n") ;
// \n = is the new line
// \r = return to the beginning of the line
// \t = tabulation
// \a = alarm (ring the bell terminal)
// \b = backspace
// \f = form feed (advance one sheet)
// \' = print a ' character
// \\ = to print \ character
return 0 ;
} // closing brace is the end of the program
Print first 100
numbers
File: 2.c:
/*
Example to print first 100 numbers,
10 by line.
*/
#include <stdio.h>
int
main ()
{
int i ; // declare i as an integer variable
for ( i = 1 ; // initializing block (execute 1 time at the beginnig)
i < 100 ; // expression that evaluate to a boolean,
// executed ad the beginning of a cicle
// the cicle interrupt when evaluate to false
// comparison operators:
// a < b : a less than b
// a <= b : a less than or equal to b
// a > b : a greater than b
// a >= b : a greater than or equal to b
// a == b : a equal to b
// a != b : a not equal to b
++i ) // block executed at the end of each cicle
// ++ is the increment operator, equivalent i = i+1
{ // block of istruction executed at each cicle
// two different print depending if i is divisible by 10
// a % b = remainder of a/b i.e a = b*k+ r where a, b, k, r are integer
// a == b = return true if a is equal to b
// a || b = logical "or" true if a or b evaluate to true
// a && b = logial "and" true if both a and b evaluate to true
if ( (i % 10) == 0 || i == 99 ) {
printf("%5d\n", i) ;
} else {
printf("%5d,", i) ;
}
}
return 0 ;
} // closing brace is the end of the program
Print first N
numbers
File: 3.c:
/*
Example to print first N numbers,
M by line.
*/
#include <stdio.h>
// define M and N as a preprocess variable, will be substitued
// by the preprocessing phase
#define M 233
#define N 11
int
main ()
{
int i ; // declare i as an integer variable
for ( i = 1 ; // initializing block (execute 1 time at the beginnig)
i <= M ; // expression that evaluate to a boolean,
// executed ad the beginning of a cicle
// the cicle interrupt when evaluate to false
++i ) // block executed at the end of each cicle
// ++ is the increment operator, equivalent i = i+1
{ // block of istruction executed at each cicle
// two different print depending if i is divisible by 10
// a % b = remainder of a/b i.e a = b*k+ r where a, b, k, r are integer
// a == b = return true if a is equal to b
// a || b = logical "or" true if a or b evaluate to true
// a && b = logial "and" true if both a and b evaluate to true
if ( (i % N) == 0 || i == M ) {
printf("%5d\n", i) ;
} else {
printf("%5d,", i) ;
}
}
return 0 ;
} // closing brace is the end of the program
Example to print first N
numbers M
by line
File: 4.c:
/*
Example to print first N numbers,
M by line.
Now using while instead of for
*/
#include <stdio.h>
// define M and N as a preprocess variable, will be substitued
// by the preprocessing phase
#define M 233
#define N 11
int
main ()
{
int i ; // declare i as an integer variable
i = 1 ;
while ( i <= M ) // execute next block when expression evaluate to true
{ if ( (i % N) == 0 || i == M ) {
printf("%5d\n", i) ;
} else {
printf("%5d,", i) ;
}
// increment counter
++i ;
}
return 0 ;
} // closing brace is the end of the program
Print first N
prime numbers
File: 5.c:
/*
Example to print first N prime numbers,
*/
#include <stdio.h>
// include code for managing of system error message
#include <errno.h>
// define N as a preprocess variable, will be substitued
// by the preprocessing phase
#define N 1000
bool // boolean type, store true or false value only
// check if candidate is a prime number respect to the vector primes
// return true if primes[i] do not divide candidate for each i
checkPrime( int nPrimes,
int primes[],
int candidate ) {
int i ;
for ( i = 0 ; i < nPrimes ; ++i ) {
if ( ( candidate % primes[i] ) == 0 ) // if remainder is 0 it is not a prime!
return false ;
}
return true ;
}
void // void type, nothing to return!
addPrime( int nPrimes, // number of prime actually stored in primes
int primes[] // vector of at least nPrimes+1 elements
) {
int candidate = primes[nPrimes-1] + 1 ;
// ! is the negation operator ! true = false.
while ( ! checkPrime( nPrimes, primes, candidate) ) ++candidate ;
primes[nPrimes] = candidate ;
}
void
printNumbers( FILE * fd, // file descpritor for the output
int nPrimes, // number of prime actually stored in primes
int primes[] // vector with nPrimes elements
) {
int i = 0 ;
do {
// print the number to the file fd (can be stdout)
// no new line or others amenity
fprintf(fd, "%5d", primes[i]) ;
++i ; // increment the counter
// decide if to use comma of newline
if ( i == nPrimes || (i%10) == 0 ) fprintf(fd, "\n") ;
else fprintf(fd, ", ") ;
} while ( i < nPrimes ) ;
}
int
main ()
{
int nPrimes = 2 ; // define nPrimes as integer and initialize to 2
int primes[N+1] = { 2, 3 } ; // define primes as a vector of (N+1) integer and initialize
// the first two elements
FILE * fd ; // descriptor for the output file
do {
addPrime( nPrimes, primes ) ;
++nPrimes ;
} while ( nPrimes < N ) ; // chech if it must cycle again
printNumbers( stdout, nPrimes, primes ) ; // print the result to standard output
fd = fopen( "primi.txt", "w+" ) ;
if ( fd != NULL ) {
printNumbers( fd, nPrimes, primes ) ; // print the result to standard output
fclose( fd ) ;
} else {
perror("error in openening file");
}
return 0 ;
}
The prime program organized in multiple files with a simple makefile
Check if a number is prime
File: 6/checkPrime.c:
bool // boolean type, store true or false value only
// check if candidate is a prime number respect to the vector primes
// return true if primes[i] do not divide candidate for each i
checkPrime( int nPrimes,
int primes[],
int candidate ) {
int i ;
for ( i = 0 ; i < nPrimes ; ++i ) {
if ( ( candidate % primes[i] ) == 0 ) // if remainder is 0 it is not a prime!
return false ;
}
return true ;
}
Add a prime to a vector of prime numbers
File: 6/addPrime.c:
// definition of function checkPrime
bool checkPrime ( int nPrimes, int primes[], int candidate ) ;
void // void type, nothing to return!
addPrime( int nPrimes, // number of prime actually stored in primes
int primes[] // vector of at least nPrimes+1 elements
) {
int candidate = primes[nPrimes-1] + 1 ;
// ! is the negation operator ! true = false.
while ( ! checkPrime( nPrimes, primes, candidate) ) ++candidate ;
primes[nPrimes] = candidate ;
}
Print first N
prime numbers
File: 6/printNumbers.c:
#include <stdio.h>
void
printNumbers( FILE * fd, // file descpritor for the output
int nPrimes, // number of prime actually stored in primes
int primes[] // vector with nPrimes elements
) {
int i = 0 ;
do {
// print the number to the file fd (can be stdout)
// no new line or others amenity
fprintf(fd, "%5d", primes[i]) ;
++i ; // increment the counter
// decide if to use comma of newline
if ( i == nPrimes || (i%10) == 0 ) fprintf(fd, "\n") ;
else fprintf(fd, ", ") ;
} while ( i < nPrimes ) ;
}
The main program
File: 6/main.c:
/*
Example to print first N prime numbers,
*/
#include <stdio.h>
// include code for managing of system error message
#include <errno.h>
// define N as a preprocess variable, will be substitued
// by the preprocessing phase
#define N 1000
// definition of function checkPrime, addPrime, printNumbers
bool checkPrime ( int nPrimes, int primes[], int candidate ) ;
void addPrime ( int nPrimes, int primes[] ) ;
void printNumbers ( FILE * fd, int nPrimes, int primes[] ) ;
int
main ()
{
int nPrimes = 2 ; // define nPrimes as integer and initialize to 2
int primes[N+1] = { 2, 3 } ; // define primes as a vector of (N+1) integer and initialize
// the first two elements
FILE * fd ; // descriptor for the output file
do {
addPrime( nPrimes, primes ) ;
++nPrimes ;
} while ( nPrimes < N ) ; // chech if it must cycle again
printNumbers( stdout, nPrimes, primes ) ; // print the result to standard output
fd = fopen( "primi.txt", "w+" ) ;
if ( fd != NULL ) {
printNumbers( fd, nPrimes, primes ) ; // print the result to standard output
fclose( fd ) ;
} else {
perror("error in openening file");
}
return 0 ;
}
The makefile to compile the code
File: 6/makefile:
#
# Example of makefile
#
# cancel all impliti rules
.SUFFIXES:
# compile command with depenendencies
compile: addPrime.o checkPrime.o main.o printNumbers.o
g++ addPrime.o checkPrime.o main.o printNumbers.o -o main
# dependencies
addPrime.o: addPrime.c
g++ -c addPrime.c
checkPrime.o: checkPrime.c
g++ -c checkPrime.c
printNumbers.o: printNumbers.c
g++ -c printNumbers.c
main.o: main.c
g++ -c main.c
The prime program organized in multiple files with a simple makefile and a header file
The header file
File: 7/prime.h:
/*
Example to print first N prime numbers,
*/
#include <stdio.h>
// definition of function checkPrime, addPrime, printNumbers
bool checkPrime ( int nPrimes, int primes[], int candidate ) ;
void addPrime ( int nPrimes, int primes[] ) ;
void printNumbers ( FILE * fd, int nPrimes, int primes[] ) ;
Check if a number is prime
File: 7/checkPrime.c:
#include "prime.h"
bool // boolean type, store true or false value only
// check if candidate is a prime number respect to the vector primes
// return true if primes[i] do not divide candidate for each i
checkPrime( int nPrimes,
int primes[],
int candidate ) {
int i ;
for ( i = 0 ; i < nPrimes ; ++i ) {
if ( ( candidate % primes[i] ) == 0 ) // if remainder is 0 it is not a prime!
return false ;
}
return true ;
}
Add a prime to a vector of prime numbers
File: 7/addPrime.c:
// definition of function checkPrime
#include "prime.h"
void // void type, nothing to return!
addPrime( int nPrimes, // number of prime actually stored in primes
int primes[] // vector of at least nPrimes+1 elements
) {
int candidate = primes[nPrimes-1] + 1 ;
// ! is the negation operator ! true = false.
while ( ! checkPrime( nPrimes, primes, candidate) ) ++candidate ;
primes[nPrimes] = candidate ;
}
Print first N
prime numbers
File: 7/printNumbers.c:
#include "prime.h"
void
printNumbers( FILE * fd, // file descpritor for the output
int nPrimes, // number of prime actually stored in primes
int primes[] // vector with nPrimes elements
) {
int i = 0 ;
do {
// print the number to the file fd (can be stdout)
// no new line or others amenity
fprintf(fd, "%5d", primes[i]) ;
++i ; // increment the counter
// decide if to use comma of newline
if ( i == nPrimes || (i%10) == 0 ) fprintf(fd, "\n") ;
else fprintf(fd, ", ") ;
} while ( i < nPrimes ) ;
}
The main program
File: 7/main.c:
/*
Example to print first N prime numbers,
*/
#include "prime.h"
// include code for managing of system error message
#include <errno.h>
// define N as a preprocess variable, will be substitued
// by the preprocessing phase
#define N 1000
int
main ()
{
int nPrimes = 2 ; // define nPrimes as integer and initialize to 2
int primes[N+1] = { 2, 3 } ; // define primes as a vector of (N+1) integer and initialize
// the first two elements
FILE * fd ; // descriptor for the output file
do {
addPrime( nPrimes, primes ) ;
++nPrimes ;
} while ( nPrimes < N ) ; // chech if it must cycle again
printNumbers( stdout, nPrimes, primes ) ; // print the result to standard output
fd = fopen( "primi.txt", "w+" ) ;
if ( fd != NULL ) {
printNumbers( fd, nPrimes, primes ) ; // print the result to standard output
fclose( fd ) ;
} else {
perror("error in openening file");
}
return 0 ;
}
The makefile to compile the code
File: 7/makefile:
#
# Example of makefile, with use of variables and wildcard
# to parameterize compilation
#
#SRCS = $(wildcard *.c)
SRCS = main.c addPrime.c checkPrime.c printNumbers.c
OBJS = $(SRCS:.c=.o)
CXX = g++
CFLAGS = -Wall
LIBS =
# cancel all implitic rules
.SUFFIXES:
# add suffixes that can be used in rules
.SUFFIXES: .c .o
# compile command with depenendencies
compile: $(OBJS)
$(CXX) $(OBJS) -o main $(LIBS)
.c.o:
$(CXX) $(CFLAGS) -c $<
# explicit dependencies
addPrime.o: addPrime.c prime.h
checkPrime.o: checkPrime.c prime.h
printNumbers.o: printNumbers.c prime.h
main.o: main.c prime.h
clean:
rm -f *.o
The lesson in a zip file
The zip file lesson1.zip
Lesson of 19 June 2008
A C-like library for manipulation of polynomial
The header file
File: 8/poly.h:
/*
// A simple C-style interface for polynomials.
// It implements some operations on polynomials.
//
*/
#include <stdio.h>
// parametrize type: valueType is the type for floating point values
typedef double valueType ; // in STL value_type
// parametrize type: indexType is the type for integer values
typedef int indexType ;
/*
// The type struct Poly, contain the needed information
// to store a polynomial
//
*/
typedef struct {
valueType * coeffs ;
indexType order ;
} Poly ;
/*
// in the definition we use "const" when argument are input argument.
// This means that the referring value cannot be changed inside the function.
// If you try to change the compiler complain about it.
//
// The "const" keywork act on its left unless const is the first keywork.
// Some example
//
// double const * a : a is a pointer pointing to a CONSTANT piece of memory
// *a = 1 ; is not allowed
// ++a ; is allowed
// double * const a : a is a CONSTANT pointer pointing to a NON constant piece of memory
// *a = 1 ; is allowed
// ++a ; is not allowed
*/
// create a polynomial
// & means that p is a reference to p.
// reference is a pointer WITHOUT the boring use osf *
//
// For example
//
// void fun( int * pa ) { *pa = 1 ; }
// void fun( int & a ) { a = 1 ; }
//
void PolyCreate( Poly & p, indexType order ) ;
// resize the polynomial
void PolyResize( Poly & p, indexType neworder ) ;
// destroy a polynomial
void PolyDestroy( Poly & p ) ;
// copy polinomial q = p
void PolyCopy( Poly const & p, Poly & q ) ;
// set the i-th coefficient of the polynomial
void PolySet( Poly & p, valueType v, indexType i ) ;
// set coefficients of the polynomial
void PolySetValues( Poly & p, valueType v[], indexType nv ) ;
// get the i-th coefficient of the polynomial
valueType PolyGet( Poly const & p, indexType i ) ;
// return the true polynomial order
indexType PolyGetOrder( Poly const & p ) ;
// print in a human readable form the polinomial p to the file fd
void PolyPrint( Poly & p, FILE * fd ) ;
// multyply a polynomial by a scalar
// p = a * p
void PolySCAL( Poly & p, valueType a ) ;
// add a polynomial times a scalar to the polynomial
// p = p + a * q
void PolyAXPY( valueType a, Poly const & q, Poly & p ) ;
// multiply two polynomial
// p = q * r
void PolyMUL( Poly const & q, Poly const & r, Poly & p ) ;
// divide two polynomial a/b return the quotient and the remainder
// a = p * b + r
void PolyDIV( Poly const & a, Poly const &, Poly & p, Poly & r ) ;
// compute polynomial derivative
void PolyDiff( Poly const & p, Poly & q ) ;
// compute polynomial integral
void PolyInt( Poly const & p, Poly & q ) ;
// compute p(x)
valueType PolyEval( Poly const & p, valueType x ) ;
// compute Maximum Common Divisor
void PolyMCD( Poly const & p, Poly const & q, indexType & nPoly, Poly polys[] ) ;
// compute Sturm Sequence
void PolySturm( Poly const & p, indexType & nPoly, Poly polys[] ) ;
indexType PolySturmChanges( indexType nPoly, Poly const polys[], valueType x ) ;
void PolyPrintSturmChanges( FILE * fd, indexType nPoly, Poly const polys[], valueType x ) ;
Implementation of the library
File: 8/poly.cc:
/*
// A simple C-style interface for polynomials
//
//
//
*/
#include "poly.h"
#include <stdlib.h>
/*
// static = visibility only in this file
// inline = expand inline the function when called
//
// expression ? execute if true : execute if false ;
*/
static
inline
indexType
min( indexType a, indexType b )
{ return a < b ? a : b ; }
// equivalent
//
// if ( a < b )
// return a ;
// else
// return b ;
//
static
inline
indexType
max( indexType a, indexType b )
{ return a > b ? a : b ; }
/*
// create a polynomial
//
// the command
// new T[size]
// allocate memory for size element of type T.
// Return the pointer pointing to the first element
*/
void
PolyCreate( Poly & p, indexType order ) {
// in pure C allocation is done by malloc
p.coeffs = new valueType[order+1] ; // allocate memory
p.order = order ;
for ( indexType i = 0 ; i <= p.order ; ++i ) p.coeffs[i] = 0 ;
}
// resize the polynomial
void
PolyResize( Poly & p, indexType neworder ) {
if ( neworder > p.order ) {
valueType * bf = p.coeffs ;
p.coeffs = new valueType[neworder+1] ; // allocate memory
indexType i = 0 ;
for ( ; i <= p . order ; ++i ) p . coeffs[i] = bf[i] ;
for ( ; i <= neworder ; ++i ) p . coeffs[i] = 0 ;
delete [] bf ;
}
p.order = neworder ;
}
// destroy a polynomial
void
PolyDestroy( Poly & p ) {
delete [] p.coeffs ; // free memory
p.order = -1 ;
}
// copy polynomial q = p
void
PolyCopy( Poly const & p, Poly & q ) {
if ( q.order < p.order ) {
PolyDestroy(q) ;
PolyCreate(q,p.order) ;
}
q.order = p.order;
for ( indexType i = 0 ; i <= q.order ; ++i )
q.coeffs[i] = p.coeffs[i] ;
//p.coeffs[i] = q.coeffs[i] ; // error not signaled by the compiler
}
// set the i-th coefficient of the polynomial
void
PolySet( Poly & p, valueType v, indexType i ) {
if ( i < 0 ) {
printf( "PolySet(p,%f,%d) bad index\n", v, i ) ;
exit(1) ; // error found, exiting to the program
}
if ( i > p.order ) PolyResize( p, i ) ;
p.coeffs[i] = v ;
}
// set coefficients of the polynomial
void
PolySetValues( Poly & p, valueType v[], indexType nv ) {
PolyDestroy( p ) ;
PolyCreate( p, nv-1 ) ;
for ( indexType i = 0 ; i < nv ; ++i )
p.coeffs[i] = v[i] ;
}
// get the i-th coefficient of the polynomial
valueType
PolyGet( Poly const & p, indexType i ) {
if ( i > p . order || i < 0 )
return 0 ;
else
return p . coeffs[i] ;
}
// return the true polynomial order
indexType
PolyGetOrder( Poly const & p ) {
indexType order = p.order ;
for ( ; order >= 0 ; --order )
if ( p.coeffs[order] != 0 )
break ;
return order ;
}
// print in a human readable form the polinomial p to the file fd
// +1 + -1 x + -2 * x**2 + 0 * x**3
void
PolyPrint( Poly & p, FILE * fd ) {
for ( indexType i = 0 ; i <= p.order ; ++i ) {
valueType v = p.coeffs[i] ;
switch (i) {
case 0: fprintf( fd, "%g", v ) ; break ;
case 1:
// skip zero values, eliminates +-1
if ( v > 0 ) {
if ( v == 1 ) fprintf( fd, " + x" ) ;
else fprintf( fd, " + %g*x", v ) ;
} else if ( v < 0 ) {
if ( v == -1 ) fprintf( fd, " - x" ) ;
else fprintf( fd, " - %g*x", -v ) ;
}
break ;
default:
// skip zero values, eliminates +-1
if ( v > 0 ) {
if ( v == 1 ) fprintf( fd, " + x**%d", i ) ;
else fprintf( fd, " + %g*x**%d", v, i ) ;
} else if ( v < 0 ) {
if ( v == -1 ) fprintf( fd, " - x**%d", i ) ;
else fprintf( fd, " - %g*x**%d", -v, i ) ;
}
break ;
}
}
if ( p.order < 0 ) fprintf( fd, "0\n" ) ;
else fprintf( fd, "\n" ) ;
}
// multyply a polynomial by a scalar
// p = a * p
void
PolySCAL( Poly & p, valueType a ) {
for ( indexType i = 0 ; i <= p . order ; ++i )
p . coeffs[i] *= a ;
}
// add a polynomial times a scalar to the polynomial
// p = p + a * q
void
PolyAXPY( valueType a, Poly const & q, Poly & p ) {
if ( p . order < q . order ) PolyResize( p, q . order ) ;
for ( indexType i = 0 ; i <= p . order ; ++i )
p . coeffs[i] += a * q . coeffs[i] ;
}
// multiply two polynomial
// p(x) = q(x) * r(x)
// p(x) = p0 + p1 * x + p2 * x**2
// q(x) = q0 + q1 * x + q2 * x**2
// p(x)*q(x) = pq0 + pq1 * x + pq2 * x**2 + ... + pq4 * x**4
// pq0 = p0 * q0
// pq1 = p0 * q1 + p1 * q0
// pq2 = p0 * q2 + p1 * q1 + p2 * q0
//
// pqk = sum( i+j = k ) pi * qj
//
void
PolyMUL( Poly const & q, Poly const & r, Poly & p ) {
PolyResize( p, q.order + r.order ) ;
for ( indexType i = 0 ; i <= p . order ; ++i ) {
valueType v = 0 ;
for ( indexType k = max(0,i-r.order) ; k <= min(i,q.order) ; ++k )
v += q.coeffs[k] * r.coeffs[i-k] ;
p.coeffs[i] = v ;
}
}
// divide two polynomial a/b return the quotient and the rest
// a = p * b + r
void
PolyDIV( Poly const & a, Poly const & b, Poly & p, Poly & r ) {
// compute true order of a and b
indexType aOrder = PolyGetOrder(a) ;
indexType bOrder = PolyGetOrder(b) ;
if ( bOrder < 0 ) {
printf( "PolyDIV division by zero\n" ) ;
exit(1) ; // error found, exiting to the program
}
if ( bOrder > aOrder ) {
// if order b > order a then
// p = 0 and r = a
PolyDestroy(p) ;
PolyCreate(p,0) ;
PolyCopy(a,r) ;
return ;
}
// reserve memory for computation
PolyDestroy(p) ;
PolyCreate(p,aOrder-bOrder) ;
// initialize r = a
PolyCopy(a,r) ;
for ( indexType i = aOrder ; i >= bOrder ; --i ) {
// compute coeff to erase a.coeffs[i]
valueType cf = r.coeffs[i] / b.coeffs[bOrder] ;
for ( indexType j = 0 ; j < bOrder ; ++j ) {
r.coeffs[i+j-bOrder] -= cf * b.coeffs[j] ;
}
r.coeffs[i] = 0 ;
p.coeffs[i-bOrder] = cf ;
}
// drop quasi zero element
for ( indexType i = 0 ; i < bOrder ; ++i ) {
valueType & rr = r.coeffs[i] ;
if ( rr < 1E-10 && rr > -1E-10 ) rr = 0 ;
}
// compute true order of p and r
p.order = PolyGetOrder(p) ;
r.order = PolyGetOrder(r) ;
}
// compute polynomial derivative
void
PolyDiff( Poly const & p, Poly & q ) {
PolyDestroy(q) ;
PolyCreate(q,p.order-1) ;
for ( indexType i = 0 ; i < p.order ; ++i )
q.coeffs[i] = p.coeffs[i+1]*(i+1) ;
}
// compute polynomial integral
void
PolyInt( Poly const & p, Poly & q ) {
PolyDestroy(q) ;
PolyCreate(q,p.order+1) ;
q.coeffs[0] = 0 ;
for ( indexType i = 0 ; i <= p.order ; ++i )
q.coeffs[i+1] = p.coeffs[i]/(i+1) ;
}
// compute p(v)
// use Horner rule
// p(x) = p0 + p1 * x + p2 * x**2 + p3 * x**3 ;
// p(x) = p0 + x*(p1 + x * (p2 + x * p3)) ;
valueType
PolyEval( Poly const & p, valueType x ) {
valueType res = p.coeffs[p.order] ;
for ( indexType i=p.order-1 ; i >= 0 ; --i )
res = res * x + p.coeffs[i] ;
return res ;
}
// compute Maximum Common Divisor
void
PolyMCD( Poly const & p,
Poly const & q,
indexType & nPoly,
Poly polys[] ) {
PolyCreate( polys[0], 0 );
PolyCreate( polys[1], 0 );
// compute true order of p and r
indexType pOrder = PolyGetOrder(p);
indexType qOrder = PolyGetOrder(q);
if ( pOrder > qOrder ) {
PolyCopy( p, polys[0] ) ;
PolyCopy( q, polys[1] ) ;
} else {
PolyCopy( q, polys[0] ) ;
PolyCopy( p, polys[1] ) ;
}
Poly buffer ;
PolyCreate( buffer, 0 );
for ( nPoly=2 ; polys[nPoly-1] . order > 0 ; ++nPoly ) {
PolyCreate( polys[nPoly], 0 ) ;
PolyDIV( polys[nPoly-2], polys[nPoly-1], buffer, polys[nPoly] ) ;
PolySCAL( polys[nPoly], -1 ) ;
}
}
// compute Sturm Sequence
void
PolySturm( Poly const & p, indexType & nPoly, Poly polys[] ) {
Poly p1, A, R ;
PolyCreate(p1,0) ;
PolyCreate(A,0) ;
PolyCreate(R,0) ;
PolyDiff(p,p1) ; // compute polynomial derivative
PolyMCD( p, p1, nPoly, polys ) ; // compute MCP between p and p1
// divide polynomials sequence by MCD and make polynomials monic
for ( indexType i = 0 ; i < nPoly ; ++i ) {
// divide two polynomial a/b return the quotient and the rest
// a = p * b + r
PolyDIV( polys[i], polys[nPoly-1], A, R ) ;
PolyCopy( A, polys[i] ) ;
}
PolyDestroy(p1) ;
PolyDestroy(A) ;
PolyDestroy(R) ;
}
// compute sign changes
indexType
PolySturmChanges( indexType nPoly, Poly const polys[], valueType x ) {
indexType nChange = 0 ;
valueType v = PolyEval( polys[0], x) ;
bool p = v > 0 ;
for ( indexType i = 1 ; i < nPoly ; ++i ) {
valueType newv = PolyEval( polys[i], x) ;
bool newp = newv > 0 ;
if ( newv == 0 ) continue ; // skip
if ( p != newp ) ++nChange ;
p = newp ;
v = newv ;
}
return nChange ;
}
// compute sign changes
void
PolyPrintSturmChanges( FILE * fd,
indexType nPoly,
Poly const polys[],
valueType x ) {
valueType v = PolyEval( polys[0], x) ;
if ( v > 0 ) fprintf(fd, "[ + " );
else if ( v < 0 ) fprintf(fd, "[ - " );
else fprintf(fd, "[ 0 " );
for ( indexType i = 0 ; i < nPoly ; ++i ) {
valueType v = PolyEval( polys[i], x) ;
if ( v > 0 ) fprintf(fd, ", + " );
else if ( v < 0 ) fprintf(fd, ", - " );
else fprintf(fd, ", 0 " );
}
fprintf(fd, "]\n" );
}
A simple driver program
File: 8/main.cc:
/*
// A simple C-style library for polynomials
//
*/
#include "poly.h"
int
main() {
Poly p, q, r, pq ;
// create a polynomial
PolyCreate( p, 2 ) ;
PolyCreate( q, 2 ) ;
PolyCreate( r, 2 ) ;
PolyCreate( pq, 0 ) ;
PolySet(p, 1, 2) ;
PolySet(p, -1, 1) ;
PolySet(q, 2, 0) ;
PolySet(q, 1, 1) ;
printf("\npolynomial multiplication\n") ;
printf("p = ") ; PolyPrint( p, stdout ) ;
printf("q = ") ; PolyPrint( q, stdout ) ;
PolyMUL( p, q, r ) ;
printf("p*q = ") ; PolyPrint( r, stdout ) ;
printf("\npolynomial derivative\n") ;
printf("p = ") ; PolyPrint( p, stdout ) ;
PolyDiff( p, pq ) ;
printf("Dp = ") ; PolyPrint( pq, stdout ) ;
printf("\npolynomial integral\n") ;
printf("p = ") ; PolyPrint( p, stdout ) ;
PolyInt( p, pq ) ;
printf("Ip = ") ; PolyPrint( pq, stdout ) ;
printf("\npolynomial evaluation\n") ;
printf("p = ") ; PolyPrint( p, stdout ) ;
valueType v = 10 ;
printf("p(%f)=%f\n",v, PolyEval(p,v) ) ;
v = -10 ;
printf("p(%f)=%f\n",v, PolyEval(p,v) ) ;
printf("\npolynomial division\n") ;
valueType cfp[] = {1,2,3,4,5,6,7,8} ;
valueType cfq[] = {1,2,3,4,5} ;
PolySetValues( p, cfp, 8 ) ;
PolySetValues( q, cfq, 5 ) ;
PolyDIV( p, q, pq, r ) ;
printf("p = ") ; PolyPrint( p, stdout ) ;
printf("q = ") ; PolyPrint( q, stdout ) ;
printf("p/q = ") ; PolyPrint( pq, stdout ) ;
printf("r = ") ; PolyPrint( r, stdout ) ;
printf("\npolynomial MCD\n") ;
indexType nPoly ;
Poly polys[100] ;
PolyMCD( p, q, nPoly, polys ) ;
for ( indexType i = 0 ; i < nPoly ; ++i )
{ printf("p%d = ",i) ; PolyPrint( polys[i], stdout ) ; }
printf("\nSturm sequence\n") ;
PolySturm( p, nPoly, polys ) ;
for ( indexType i = 0 ; i < nPoly ; ++i )
{ printf("p%d = ",i) ; PolyPrint( polys[i], stdout ) ; }
for ( valueType x = -1 ; x < 1 ; x += 0.1 ) {
printf( "Sturm changes x=%f %d : ", x, PolySturmChanges( nPoly, polys, x ) ) ;
PolyPrintSturmChanges( stdout, nPoly, polys, x ) ;
}
return 0 ;
}
The library rewritten in object oriented way
The header file for the class Poly
File: 9/poly.h:
/*
// A simple C++-style interface for polynomials.
// It implements some operations on polynomials.
//
*/
#include <iostream>
using namespace std ;
// parametrize type: valueType is the type for floating point values
typedef double valueType ; // in STL value_type
// parametrize type: indexType is the type for integer values
typedef int indexType ;
/*
// The type struct Poly, contain the needed information to store a polynomial
*/
class Poly {
public:
// constructors
Poly(Poly const &) ;
explicit Poly() ;
explicit Poly(indexType order) ;
explicit Poly(valueType coeffs[], indexType numCoeffs) ;
// destructor
~Poly() ;
Poly const & operator = ( Poly const & p ) ;
Poly const & operator = ( valueType s ) ;
valueType operator () ( valueType x ) const ;
Poly const & operator += ( Poly const & p ) ;
Poly const & operator -= ( Poly const & p ) ;
valueType const & operator [] (indexType i) const
{ return coeffs[i] ; }
valueType & operator [] (indexType i)
{ return coeffs[i] ; }
void setup (valueType coeffs[], indexType numCoeffs) ;
void resize( indexType newOrder ) ;
void drop ( valueType epsi ) ;
void print( ostream & s ) const ;
indexType getOrder() const ;
valueType leading() const ;
private:
valueType * coeffs ;
indexType order ;
};
// define the operator (ostream << Poly)
inline
ostream &
operator << ( ostream & s, Poly const & p )
{ p.print(s) ; return s ; }
// negate a polynomial
Poly operator - ( Poly const & a ) ;
// algebra for polynomial
Poly operator + ( Poly const & a, Poly const & b ) ;
Poly operator - ( Poly const & a, Poly const & b ) ;
Poly operator * ( Poly const & a, Poly const & b ) ;
// mixed scalar/polynomial
Poly operator + ( valueType a, Poly const & b ) ;
Poly operator - ( valueType a, Poly const & b ) ;
Poly operator * ( valueType a, Poly const & b ) ;
Poly operator - ( Poly const & a, valueType b ) ;
Poly operator + ( Poly const & a, valueType b ) ;
Poly operator * ( Poly const & a, valueType b ) ;
Poly operator / ( Poly const & a, valueType b ) ;
// divide two polynomial a/b return the quotient and the rest
// a = p * b + r
void div( Poly const & a, Poly const & b, Poly & p, Poly & r ) ;
void mcd( Poly const & p, Poly const & q, indexType & nPoly, Poly polys[] ) ;
// compute polynomial derivative
Poly diff( Poly const & p ) ;
void Sturm( Poly const & p, indexType & nPoly, Poly polys[] ) ;
indexType SturmChanges( indexType nPoly, Poly const polys[], valueType epsi, valueType x ) ;
void SturmChanges( ostream & s, indexType nPoly, Poly const polys[], valueType epsi, valueType x ) ;
// end of file poly.h
Implementation of the class Poly
File: 9/poly.cc:
/*
// A simple C++-style interface for polynomials
//
//
//
*/
#include "poly.h"
#include <cmath>
// use this command to avoiud std::cout
using namespace std ;
/* _ _
// ___ ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __
// / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__|
// | (_| (_) | | | \__ \ |_| | | |_| | (__| || (_) | |
// \___\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_|
*/
Poly::Poly() {
order = -1 ;
coeffs = NULL ;
}
Poly::Poly(Poly const & a) {
order = a.getOrder() ;
coeffs = new valueType[order+1] ;
for ( indexType i = 0 ; i <= order ; ++i )
coeffs[i] = a.coeffs[i] ;
}
Poly::Poly(indexType order) {
this -> order = order ;
this -> coeffs = new valueType[order+1] ; // allocation
for ( indexType i = 0 ; i <= order ; ++i ) coeffs[i] = 0 ;
}
Poly::Poly(valueType coeffs[], indexType numCoeffs) {
order = numCoeffs-1 ;
// this is a pointer to the actual class.
// equivalence (*this).coeffs == this -> coeffs ;
this -> coeffs = new valueType[numCoeffs] ; // allocation
// copy values
for ( indexType i=0; i < numCoeffs ; ++i )
this -> coeffs[i] = coeffs[i] ;
}
/* _ _ _
// __| | ___ ___| |_ _ __ _ _ ___| |_ ___ _ __
// / _` |/ _ \/ __| __| '__| | | |/ __| __/ _ \| '__|
// | (_| | __/\__ \ |_| | | |_| | (__| || (_) | |
// \__,_|\___||___/\__|_| \__,_|\___|\__\___/|_|
*/
Poly::~Poly() {
if ( coeffs != NULL ) delete [] coeffs ;
}
/* _
// ___ ___| |_ _ _ _ __
// / __|/ _ \ __| | | | '_ \
// \__ \ __/ |_| |_| | |_) |
// |___/\___|\__|\__,_| .__/
// |_|
*/
void
Poly::setup (valueType cfs[], indexType numCoeffs) {
// this is a pointer to the actual class.
// equivalence (*this).coeffs == this -> coeffs ;
if ( order+1 < numCoeffs ) {
if ( coeffs != NULL ) delete [] coeffs ;
coeffs = new valueType[numCoeffs] ; // allocation
order = numCoeffs-1 ;
}
// copy values
indexType i = 0 ;
for ( ; i < numCoeffs ; ++i ) coeffs[i] = cfs[i] ;
for ( ; i <= order ; ++i ) coeffs[i] = 0 ;
}
/* _
// _ __ ___ ___(_)_______
// | '__/ _ \/ __| |_ / _ \
// | | | __/\__ \ |/ / __/
// |_| \___||___/_/___\___|
*/
void
Poly::resize( indexType newOrder ) {
if ( newOrder > order ) {
valueType * bf = coeffs ;
coeffs = new valueType[newOrder+1] ; // allocate memory
indexType i = 0 ;
for ( ; i <= order ; ++i ) coeffs[i] = bf[i] ;
for ( ; i <= newOrder ; ++i ) coeffs[i] = 0 ;
delete [] bf ;
}
order = newOrder ;
}
/* _
// __| |_ __ ___ _ __
// / _` | '__/ _ \| '_ \
// | (_| | | | (_) | |_) |
// \__,_|_| \___/| .__/
// |_|
*/
// set to zero all element less thn epsi
void
Poly::drop( valueType epsi ) {
for ( indexType i = 0 ; i <= order ; ++i )
if ( abs(coeffs[i]) <= epsi )
coeffs[i] = 0 ;
}
/* _ _
// _ __ _ __(_)_ __ | |_
// | '_ \| '__| | '_ \| __|
// | |_) | | | | | | | |_
// | .__/|_| |_|_| |_|\__|
// |_|
*/
void
Poly::print( ostream & s ) const {
// print in a human readable form the polinomial p to the file fd
// +1 + -1 x + -2 * x**2 + 0 * x**3
for ( indexType i = 0 ; i <= order ; ++i ) {
valueType v = coeffs[i] ;
switch (i) {
case 0: s << v ; break ;
case 1:
// skip zero values, eliminates +-1
if ( v > 0 ) {
if ( v == 1 ) s << " + x" ;
else s << " + " << v << "*x" ;
} else if ( v < 0 ) {
if ( v == -1 ) s << " - x" ;
else s << " - " << -v << "*x" ;
}
break ;
default:
// skip zero values, eliminates +-1
if ( v > 0 ) {
if ( v == 1 ) s << " + x**" << i ;
else s << " + " << v << "*x**" << i ;
} else if ( v < 0 ) {
if ( v == -1 ) s << " - x**" << i ;
else s << " - " << -v << "*x**" << i ;
}
break ;
}
}
if ( order < 0 ) s << '0' ;
}
/* _ ___ _
// __ _ ___| |_ / _ \ _ __ __| | ___ _ __
// / _` |/ _ \ __| | | | '__/ _` |/ _ \ '__|
// | (_| | __/ |_| |_| | | | (_| | __/ |
// \__, |\___|\__|\___/|_| \__,_|\___|_|
// |___/
*/
// return the true order of the polynomial
indexType
Poly::getOrder() const {
indexType trueOrder = order ;
for ( ; trueOrder >= 0 ; --trueOrder )
if ( coeffs[trueOrder] != 0 )
break ;
return trueOrder ;
}
/*
// _ _ _
// | | ___ __ _ __| (_)_ __ __ _
// | |/ _ \/ _` |/ _` | | '_ \ / _` |
// | | __/ (_| | (_| | | | | | (_| |
// |_|\___|\__,_|\__,_|_|_| |_|\__, |
// |___/
*/
// return the leading coefficient of the polynomial
valueType
Poly::leading() const {
return coeffs[getOrder()] ;
}
/* _
// ___ _ __ ___ _ __ __ _| |_ ___ _ __ _____
// / _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__| |_____|
// | (_) | |_) | __/ | | (_| | || (_) | | _____
// \___/| .__/ \___|_| \__,_|\__\___/|_| |_____|
// |_|
*/
Poly const &
Poly::operator = ( Poly const & p ) {
// if necessary reallocate memory
indexType pOrder = p.getOrder() ;
if ( order < pOrder ) {
if ( coeffs != NULL ) delete [] coeffs ;
coeffs = new valueType[pOrder+1] ;
order = pOrder;
}
indexType i = 0 ;
for ( ; i <= pOrder ; ++i ) coeffs[i] = p.coeffs[i] ;
for ( ; i <= order ; ++i ) coeffs[i] = 0 ;
return *this ; // return reference to itself
// this permits multiple assignment
// like p = q = r ;
}
Poly const &
Poly::operator = ( valueType s ) {
for ( indexType i = 0 ; i <= order ; ++i ) coeffs[i] = 0 ;
coeffs[0] = s ;
return *this ;
}
/* _
// ___ _ __ ___ _ __ __ _| |_ ___ _ __ _ _____
// / _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__| _| |_|_____|
// | (_) | |_) | __/ | | (_| | || (_) | | |_ _|_____
// \___/| .__/ \___|_| \__,_|\__\___/|_| |_| |_____|
// |_|
*/
Poly const &
Poly::operator += ( Poly const & p ) {
indexType pOrder = p.getOrder() ;
if ( pOrder > order ) resize( pOrder ) ;
for ( indexType i = 0 ; i <= pOrder ; ++i )
coeffs[i] += p.coeffs[i] ;
return *this ;
}
/* _
// ___ _ __ ___ _ __ __ _| |_ ___ _ __ _____
// / _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__| _____|_____|
// | (_) | |_) | __/ | | (_| | || (_) | | |_____|_____
// \___/| .__/ \___|_| \__,_|\__\___/|_| |_____|
// |_|
*/
Poly const &
Poly::operator -= ( Poly const & p ) {
indexType pOrder = p.getOrder() ;
if ( pOrder > order ) resize( pOrder ) ;
for ( indexType i = 0 ; i <= pOrder ; ++i )
coeffs[i] -= p.coeffs[i] ;
return *this ;
}
/*
// _ ____
// ___ _ __ ___ _ __ __ _| |_ ___ _ __ / /\ \
// / _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__| | | | |
// | (_) | |_) | __/ | | (_| | || (_) | | | | | |
// \___/| .__/ \___|_| \__,_|\__\___/|_| | | | |
// |_| \_\/_/
*/
valueType
Poly::operator () ( valueType x ) const {
// compute p(v) using Horner rule
// p(x) = p0 + p1 * x + p2 * x**2 + p3 * x**3 ;
// p(x) = p0 + x*(p1 + x * (p2 + x * p3)) ;
valueType res = coeffs[order] ;
for ( indexType i=order-1 ; i >= 0 ; --i )
res = res * x + coeffs[i] ;
return res ;
}
/*
_ _
_____ _| |_ ___ _ __ _ __ __ _| |
/ _ \ \/ / __/ _ \ '__| '_ \ / _` | |
| __/> <| || __/ | | | | | (_| | |
\___/_/\_\\__\___|_| |_| |_|\__,_|_|
_
___ _ __ ___ _ __ __ _| |_ ___ _ __ ___
/ _ \| '_ \ / _ \ '__/ _` | __/ _ \| '__/ __|
| (_) | |_) | __/ | | (_| | || (_) | | \__ \
\___/| .__/ \___|_| \__,_|\__\___/|_| |___/
|_|
*/
// negate a polynomial
Poly
operator - ( Poly const & a ) {
indexType aOrder = a.getOrder() ;
Poly res(aOrder) ;
for ( indexType i = 0 ; i <= aOrder ; ++i ) res[i] = -a[i] ;
return res ;
}
Poly
operator + ( Poly const & a, Poly const & b ) {
indexType aOrder = a.getOrder() ;
indexType bOrder = b.getOrder() ;
indexType resOrder = max(aOrder,bOrder) ;
Poly res(resOrder) ;
for ( indexType i = 0 ; i <= resOrder ; ++i ) res[i] = a[i] + b[i] ;
return res ;
}
Poly
operator - ( Poly const & a, Poly const & b ) {
indexType aOrder = a.getOrder() ;
indexType bOrder = b.getOrder() ;
indexType resOrder = max(aOrder,bOrder) ;
Poly res(resOrder) ;
for ( indexType i = 0 ; i <= resOrder ; ++i )
res[i] = a[i] - b[i] ;
return res ;
}
// multiply two polynomial
// p(x) = a(x) * b(x)
// a(x) = a0 + a1 * x + a2 * x**2
// b(x) = b0 + b1 * x + b2 * x**2
// a(x)*b(x) = p0 + p1 * x + p2 * x**2 + ... + p4 * x**4
// p0 = a0 * b0
// p1 = a0 * b1 + a1 * b0
// p2 = a0 * b2 + a1 * b1 + a2 * b0
//
// pk = sum( i+j = k, i>=0, j>=0 ) ai * bj
Poly
operator * ( Poly const & a, Poly const & b ) {
indexType aOrder = a.getOrder() ;
indexType bOrder = b.getOrder() ;
indexType resOrder = aOrder+bOrder ;
Poly res(resOrder) ;
for ( indexType i = 0 ; i <= resOrder ; ++i )
res[i] = a[i] - b[i] ;
for ( indexType i = 0 ; i <= resOrder ; ++i ) {
valueType v = 0 ;
for ( indexType k = max(0,i-bOrder) ; k <= min(i,aOrder) ; ++k )
v += a[k] * b[i-k] ;
res[i] = v ;
}
return res ;
}
Poly
operator + ( valueType a, Poly const & b ) {
Poly res(b) ;
res[0] += a ;
return res ;
}
Poly
operator - ( valueType a, Poly const & b ) {
Poly res(b) ;
res[0] = a - res[0] ;
return res ;
}
Poly
operator * ( valueType a, Poly const & b ) {
Poly res(b) ;
indexType bOrder = b.getOrder() ;
for ( indexType i=0 ; i <= bOrder ; ++i ) res[i] *= a ;
return res ;
}
Poly
operator + ( Poly const & a, valueType b ) {
Poly res(a) ;
res[0] += b ;
return res ;
}
Poly
operator - ( Poly const & a, valueType b ) {
Poly res(a) ;
res[0] -= b ;
return res ;
}
Poly
operator * ( Poly const & a, valueType b ) {
Poly res(a) ;
indexType aOrder = a.getOrder() ;
for ( indexType i=0 ; i <= aOrder ; ++i ) res[i] *= b ;
return res ;
}
Poly
operator / ( Poly const & a, valueType b ) {
Poly res(a) ;
indexType aOrder = a.getOrder() ;
for ( indexType i=0 ; i <= aOrder ; ++i ) res[i] /= b ;
return res ;
}
/* _ __ _
// ___ _ __ __| | ___ / _| _ __ ___ | |_ _ ___ ___
// / _ \ '_ \ / _` | / _ \| |_ | '_ \ / _ \| | | | | / __/ __|
// | __/ | | | (_| | | (_) | _| | |_) | (_) | | |_| || (_| (__
// \___|_| |_|\__,_| \___/|_| | .__/ \___/|_|\__, (_)___\___|
// |_| |___/
*/
Implementation of the algorithms
File: 9/polyAlgorithm.cc:
/*
// A simple C++-style interface for polynomials
//
//
//
*/
#include "poly.h"
#include <cmath>
// use this command to avoiud std::cout
using namespace std ;
/*
// static = visibility only in this file
// inline = expand inline the function when called
//
// expression ? execute if true : execute if false ;
*/
static
inline
indexType
min( indexType a, indexType b )
{ return a < b ? a : b ; }
// equivalent
//
// if ( a < b )
// return a ;
// else
// return b ;
//
static
inline
indexType
max( indexType a, indexType b )
{ return a > b ? a : b ; }
/*
// _ _
// __| (_)_ __
// / _` | \ \ / /
// | (_| | |\ V /
// \__,_|_| \_/
*/
// divide two polynomial a/b return the quotient and the rest
// a = p * b + r
void
div( Poly const & a, Poly const & b, Poly & p, Poly & r ) {
// compute true order of a and b
indexType aOrder = a.getOrder() ;
indexType bOrder = b.getOrder() ;
if ( bOrder < 0 ) {
cerr << "div division by zero\n" ;
exit(1) ; // error found, exiting to the program
}
r = a ;
if ( bOrder > aOrder ) {
// if order b > order a then
// p = 0 and r = a
p = 0 ;
return ;
}
p.resize(aOrder-bOrder) ;
for ( indexType i = aOrder ; i >= bOrder ; --i ) {
// compute coeff to erase a.coeffs[i]
valueType cf = r[i] / b[bOrder] ;
for ( indexType j = 0 ; j < bOrder ; ++j )
r[i+j-bOrder] -= cf * b[j] ;
r[i] = 0 ;
p[i-bOrder] = cf ;
}
}
/*
// _
// _ __ ___ ___ __| |
// | '_ ` _ \ / __/ _` |
// | | | | | | (_| (_| |
// |_| |_| |_|\___\__,_|
*/
// compute Maximum Common Divisor
void
mcd( Poly const & p,
Poly const & q,
indexType & nPoly,
Poly polys[] ) {
// compute true order of p and r
indexType pOrder = p.getOrder() ;
indexType qOrder = q.getOrder() ;
if ( pOrder > qOrder ) {
polys[0] = p ;
polys[1] = q ;
} else {
polys[0] = q ;
polys[1] = p ;
}
Poly buffer ;
for ( nPoly=2 ; polys[nPoly-1] . getOrder() > 0 ; ++nPoly ) {
div( polys[nPoly-2],
polys[nPoly-1],
buffer,
polys[nPoly] ) ;
polys[nPoly] . drop(1E-10) ;
polys[nPoly] = -polys[nPoly] ;
}
}
/* _ _ __ __
// __| (_)/ _|/ _|
// / _` | | |_| |_
// | (_| | | _| _|
// \__,_|_|_| |_|
*/
// compute polynomial derivative
Poly
diff( Poly const & p ) {
indexType pOrder = p . getOrder() ;
if ( pOrder <= 0 ) return Poly(0) ;
Poly res( pOrder - 1 ) ;
for ( indexType i = 0 ; i < pOrder ; ++i )
res[i] = p[i+1]*(i+1) ;
return res ;
}
/*
// ____ _
// / ___|| |_ _ _ _ __ _ __ ___
// \___ \| __| | | | '__| '_ ` _ \
// ___) | |_| |_| | | | | | | | |
// |____/ \__|\__,_|_| |_| |_| |_|
*/
// compute Sturm Sequence
void
Sturm( Poly const & p, indexType & nPoly, Poly polys[] ) {
Poly p1 = diff(p) ; // compute polynomial derivative
mcd( p, p1, nPoly, polys ) ; // compute MCP between p and p1
// divide polynomials sequence by MCD and make polynomials monic
Poly A, R ;
for ( indexType i = 0 ; i < nPoly ; ++i ) {
// divide two polynomial a/b return the quotient and the rest
// a = p * b + r
div( polys[i], polys[nPoly-1], A, R ) ;
polys[i] = A / abs(A.leading()) ;
}
}
/* ____ _ ____ _
// / ___|| |_ _ _ _ __ _ __ ___ / ___| |__ __ _ _ __ __ _ ___ ___
// \___ \| __| | | | '__| '_ ` _ \| | | '_ \ / _` | '_ \ / _` |/ _ \/ __|
// ___) | |_| |_| | | | | | | | | |___| | | | (_| | | | | (_| | __/\__ \
// |____/ \__|\__,_|_| |_| |_| |_|\____|_| |_|\__,_|_| |_|\__, |\___||___/
// |___/
*/
// compute sign changes
indexType
SturmChanges( indexType nPoly,
Poly const polys[],
valueType epsi,
valueType x ) {
indexType nChange = 0 ;
valueType v = polys[0](x) ;
bool p = v > epsi ;
for ( indexType i = 1 ; i < nPoly ; ++i ) {
valueType newv = polys[i](x) ;
if ( abs(newv) < epsi ) continue ; // skip
bool newp = newv > epsi ;
if ( p != newp ) ++nChange ;
p = newp ;
v = newv ;
}
return nChange ;
}
/*
// ____ _ ____ _
// / ___|| |_ _ _ _ __ _ __ ___ / ___| |__ __ _ _ __ __ _ ___ ___
// \___ \| __| | | | '__| '_ ` _ \| | | '_ \ / _` | '_ \ / _` |/ _ \/ __|
// ___) | |_| |_| | | | | | | | | |___| | | | (_| | | | | (_| | __/\__ \
// |____/ \__|\__,_|_| |_| |_| |_|\____|_| |_|\__,_|_| |_|\__, |\___||___/
// |___/
*/
void
SturmChanges( ostream & s,
indexType nPoly,
Poly const polys[],
valueType epsi,
valueType x ) {
valueType v = polys[0](x) ;
if ( v > epsi ) s << "[ + " ;
else if ( v < -epsi ) s << "[ - " ;
else s << "[ 0 " ;
for ( indexType i = 1 ; i < nPoly ; ++i ) {
valueType v = polys[i](x) ;
if ( v > epsi ) s << ", + " ;
else if ( v < -epsi ) s << ", - " ;
else s << ", 0 " ;
}
s << "]\n" ;
}
#if 0
// compute polynomial integral
void
PolyInt( Poly const & p, Poly & q ) {
PolyDestroy(q) ;
PolyCreate(q,p.order+1) ;
q.coeffs[0] = 0 ;
for ( indexType i = 0 ; i <= p.order ; ++i )
q.coeffs[i+1] = p.coeffs[i]/(i+1) ;
}
#endif
A simple driver program
File: 9/main.cc:
/*
// A simple C++-style interface for polynomials
//
*/
#include "poly.h"
#include <iostream>
#include <iomanip>
using namespace std ;
int
main() {
valueType cfs[] = {1,2,3,4,5} ;
indexType numCfs = sizeof(cfs)/sizeof(cfs[0]) ;
Poly p(10), q(10), r(10), pq(cfs,numCfs) ;
p[2] = 1 ;
p[1] = -1 ;
p[0] = 2 ;
q[1] = 1 ;
r = p*q ;
cout << "\npolynomial multiplication\n"
<< "p = " << p << '\n'
<< "q = " << q << '\n'
<< "p*q = " << r << '\n' ;
pq = diff(p) ;
cout << "\npolynomial derivative\n"
<< "p = " << p << '\n'
<< "Dp = " << pq << '\n' ;
//cout << "\npolynomial integral\n") ;
//printf("p = ") ; PolyPrint( p, stdout ) ;
//PolyInt( p, pq ) ;
// printf("Ip = ") ; PolyPrint( pq, stdout ) ;
cout << "\npolynomial evaluation\n"
<< "p = " << p << '\n'
<< "p(10) = " << p(10) << '\n'
<< "p(-10) = " << p(-10) << '\n' ;
valueType cfp[] = {1,2,3,4,5,6,7,8} ;
valueType cfq[] = {1,2,3,4,5} ;
p . setup( cfp, 8 ) ;
q . setup( cfq, 5 ) ;
cout << "\npolynomial division\n" ;
div( p, q, pq, r ) ;
cout << "p = " << p << '\n'
<< "q = " << q << '\n'
<< "p/q = " << pq << '\n'
<< "r = " << r << '\n' ;
cout << "\npolynomial MCD\n" ;
indexType nPoly ;
Poly polys[100] ;
mcd( p, q, nPoly, polys ) ;
for ( indexType i = 0 ; i < nPoly ; ++i )
cout << "p" << i << " = " << polys[i] << '\n' ;
cout << "\nSturm sequence\n" ;
//valueType cfpp[] = {-6,11,-6,1} ;
//p . setup( cfpp, 4 ) ;
Sturm( p, nPoly, polys ) ;
for ( indexType i = 0 ; i < nPoly ; ++i )
cout << "p" << i << " = " << polys[i] << '\n' ;
for ( valueType x = -1 ; x < 1 ; x += 0.5 ) {
cout << "Sturm changes x=" << setw(10) << x << " "
<< SturmChanges( nPoly, polys, 1E-10, x ) ;
SturmChanges( cout, nPoly, polys, 1E-10, x ) ;
}
return 0 ;
}
The lesson in a zip file
The zip file lesson2.zip
Lesson of 24 June 2008
An example of overloading
File: 10/overloading.cc:
/*
// An example of overloading
//
*/
#include <iostream>
using namespace std ;
// define the function factorial with integer argument
int
factorial( int a ) {
cout << "using factorial(int) with a = " << a << "\n" ;
if ( a > 1 ) return a*factorial(a-1) ;
else return 1 ;
}
// define the function factorial with unsigned long integer argument
unsigned long
factorial( unsigned long a ) {
cout << "using factorial(unsigned long) with a = " << a << "\n" ;
if ( a > 1 ) return a*factorial(a-1) ;
else return 1 ;
}
int
main() {
unsigned long ula = 10 ;
int ia = 10 ;
cout << factorial(ia) << "\n" ;
cout << factorial(ula) << "\n" ;
long b = factorial(ia) ;
return 0 ;
}
An example of Inheritance
File: 10/inherith.cc:
/*
// An example of inheritance
//
*/
#include <iostream>
using namespace std ;
// define a base class
class base_class {
int value ; // declare private variable
public:
base_class()
: value(0) // calling the costructor for value
{ cout << "base_class constructor\n" ; }
/* this is similar to
base_class(){ value = 0 ; }
the difference is on the order of the operatio.
in this latter case the default costrutor for
value is performed and next is assigned to 0.
using the proposed costruct the variable value
is initialized to 0 directly. Thus is a better
performing design
*/
// a public method
void printName(ostream & s)
{ s << "I am base class\n" ; }
// accessor method
int getValue() const { return value ; }
} ;
// define extend_class inherithing from base_class
class extend_class : public base_class {
public:
extend_class()
: base_class() // call the base_class constructor
{ cout << "extend_class constructor\n" ; }
// redefine the method printName
void printName(ostream & s)
{ s << "I am extend_class class\n" ; }
} ;
int
main() {
base_class bc ; // instance bc with the default constructor
extend_class ec ; // instance ec with the default constructor
bc . printName( cout ) ;
ec . printName( cout ) ;
return 0 ;
}
An example of Inheritance (bis)
File: 10/inherith2.cc:
/*
// An example of inheritance
//
*/
#include <iostream>
using namespace std ;
typedef double valueType ;
typedef int indexType ;
class point2d {
protected:
valueType x, y ;
public:
point2d() : x(0), y(0) // calling the costructor for value
{ cout << "point2d constructor\n" ; }
point2d(valueType xx, valueType yy) : x(xx), y(yy) // calling the costructor for value
{ cout << "point2d constructor N.2\n" ; }
~point2d()
{ cout << "point2d destructor\n" ; }
point2d const &
operator = (point2d const & a) {
cout << "assign operator\n" ;
x = a.x ;
y = a.y ;
return *this ;
}
valueType getX() const { return x ; }
valueType getY() const { return y ; }
void set( valueType x, valueType y ) {
this -> x = x ;
this -> y = y ;
}
} ;
class point3d : public point2d {
valueType z ;
public:
point3d() : point2d(0,0), z(0) // calling the costructor for value
{ cout << "point3d constructor\n" ; }
point3d(valueType xx, valueType yy, valueType zz)
: point2d(xx,yy), z(zz) // calling the costructor for value
{ cout << "point3d constructor N.2\n" ; }
~point3d()
{ cout << "point3d destructor\n" ; }
point3d const &
operator = (point3d const & a) {
cout << "assign operator\n" ;
x = a.x ;
y = a.y ;
z = a.z ;
return *this ;
}
valueType getZ() const { return z ; }
void set( valueType x, valueType y, valueType z ) {
point2d::set(x,y) ;
this -> z = z ;
}
} ;
// define external operator for addition
point2d
operator + ( point2d const & a, point2d const & b)
{ cout << "perform + operator\n" ;
return point2d( a.getX()+b.getX(), a.getY() + b.getY()) ; }
/*
*/
int
main() {
cout << "before point2d a, b ;\n" ;
point2d a, b, c ;
cout << "after point2d a, b ;\n" ;
c = a + b ;
// this is eqauivalent to
c . operator = ( operator + (a,b) ) ;
cout << "before to exit;\n" ;
// the same operatio without temporary class production
a . set( a.getX() + b.getX(), a.getY() + b.getY() ) ;
return 0 ;
}
The lesson in a zip file
The zip file lesson3.zip
Lesson of 25 June 2008
A simple C-like library for numerical integration
The declaration file
File: 11/intrule.h:
/*
// A simple procedural implementation of some numerical
// integration rules.
//
*/
#include <stdio.h>
typedef double valueType ;
typedef int indexType ;
typedef valueType (*functionType) ( valueType x ) ;
// declaration of the prototype of the trapezoidal integration rule
valueType
trap( functionType fun, // pointer to the function to integrate
valueType a, // left boundary
valueType b, // right boundary
indexType N ) ; // number of interval
// declaration of the prototype of the midpoint integration rule
valueType
midpoint( functionType fun, // pointer to the function to integrate
valueType a, // left boundary
valueType b, // right boundary
indexType N ) ; // number of interval
// declaration of the prototype of the Simpson integration rule
valueType
simpson( functionType fun, // pointer to the function to integrate
valueType a, // left boundary
valueType b, // right boundary
indexType N ) ; // number of interval
The definition file file
File: 11/intrule.cc:
/*
// A simple procedural implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
// definition of the prototype of the trapezoidal integration rule
valueType
trap( functionType fun,
valueType a,
valueType b,
indexType N ) {
valueType h = (b-a)/N ;
valueType res = h*((*fun)(a) + fun(b))/2 ;
// ^ ^
// | + a shortcut or syntactic glue from C
// + the "correct way"
for ( indexType i = 1 ; i < N ; ++i ) {
valueType xi = a + h*i ;
res += h*fun(xi) ;
}
return res ;
}
// definition of the prototype of the midpoint integration rule
valueType
midpoint( functionType fun,
valueType a,
valueType b,
indexType N ) {
valueType h = (b-a)/N ;
valueType res = 0 ;
for ( indexType i = 0 ; i < N ; ++i ) {
valueType xi_plus_half = a + h*(i+0.5) ;
res += h*fun(xi_plus_half) ;
}
return res ;
}
// definition of the prototype of the Simpson integration rule
valueType
simpson( functionType fun,
valueType a,
valueType b,
indexType N ) { // N must be even!
valueType h = (b-a)/N ;
valueType res = h*((*fun)(a) + fun(b))/3 ;
for ( indexType i = 1 ; i < N ; i += 2 ) {
valueType xi = a + h*i ;
res += (4*h/3)*fun(xi) ;
}
for ( indexType i = 2 ; i < N-1 ; i += 2 ) {
valueType xi = a + h*i ;
res += (2*h/3)*fun(xi) ;
}
return res ;
}
A driver program
File: 11/main.cc:
/*
// A simple procedural implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
#include <math.h>
static
valueType
testFun( valueType x ) {
return x*exp(-x) ;
}
int
main() {
valueType a = 0 ;
valueType b = 10 ;
for ( indexType N = 10 ; N <= 1000 ; N *= 2 ) {
valueType t = trap ( testFun, a, b, N ) ; // call trapeziodal integrator
valueType m = midpoint ( testFun, a, b, N ) ; // call midpoint integrator
valueType s = simpson ( testFun, a, b, N ) ; // call Simpson integrator
// print the result
printf( "Integration with %d intervals\n", N);
printf( "Trapezoidal rule %10lf\n", t);
printf( "Midpoint rule %10lf\n", m);
printf( "Simspon rule %10lf\n", s);
}
printf( "All done!\n");
return 0;
}
An Object Oriented version of the library
The declaration file
File: 12/intrule.h:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
typedef double valueType ;
typedef int indexType ;
typedef valueType (*functionType) ( valueType x ) ;
class numericalIntegrator {
protected:
functionType fun ;
public:
// default initialilizer
numericalIntegrator()
: fun(0)
{}
numericalIntegrator(functionType ffun)
: fun(ffun)
{}
// set up a funtion to integrate
void
setup( functionType ffun ) {
fun = ffun ;
}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
valueType
operator () ( valueType a, valueType b, indexType N ) ;
} ;
class trap : public numericalIntegrator {
public:
// default initialilizer
trap()
: numericalIntegrator()
{}
trap(functionType ffun )
: numericalIntegrator(ffun)
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
valueType
operator () ( valueType a, valueType b, indexType N ) ;
} ;
class midpoint : public numericalIntegrator {
public:
// default initialilizer
midpoint()
: numericalIntegrator()
{}
midpoint(functionType ffun )
: numericalIntegrator(ffun)
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
valueType
operator () ( valueType a, valueType b, indexType N ) ;
} ;
class simpson : public numericalIntegrator {
public:
// default initialilizer
simpson()
: numericalIntegrator()
{}
simpson(functionType ffun )
: numericalIntegrator(ffun)
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
valueType
operator () ( valueType a, valueType b, indexType N ) ;
} ;
The definition file file
File: 12/intrule.cc:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
valueType
trap::operator () ( valueType a, valueType b, indexType N ) {
valueType h = (b-a)/N ;
valueType res = h*(fun(a) + fun(b))/2 ;
for ( indexType i = 1 ; i < N ; ++i ) {
valueType xi = a + h*i ;
res += h*fun(xi) ;
}
return res ;
}
valueType
midpoint::operator () ( valueType a, valueType b, indexType N ) {
valueType h = (b-a)/N ;
valueType res = 0 ;
for ( indexType i = 0 ; i < N ; ++i ) {
valueType xi_plus_half = a + h*(i+0.5) ;
res += h*fun(xi_plus_half) ;
}
return res ;
}
valueType
simpson::operator () ( valueType a, valueType b, indexType N ) {
valueType h = (b-a)/N ;
valueType res = h*((*fun)(a) + fun(b))/3 ;
for ( indexType i = 1 ; i < N ; i += 2 ) {
valueType xi = a + h*i ;
res += (4*h/3)*fun(xi) ;
}
for ( indexType i = 2 ; i < N-1 ; i += 2 ) {
valueType xi = a + h*i ;
res += (2*h/3)*fun(xi) ;
}
return res ;
}
A driver program
File: 12/main.cc:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
#include <cmath>
#include <iostream>
using namespace std ;
static
valueType
testFun( valueType x ) {
return x*exp(-x) ;
}
int
main() {
trap tInstance( testFun ) ;
midpoint mInstance ;
simpson sInstance ;
mInstance . setup( testFun ) ;
sInstance . setup( testFun ) ;
valueType a = 0 ;
valueType b = 10 ;
for ( indexType N = 10 ; N <= 1000 ; N *= 2 ) {
valueType t = tInstance( a, b, N ) ; // call trapeziodal integrator
valueType m = mInstance( a, b, N ) ; // call midpoint integrator
valueType s = sInstance( a, b, N ) ; // call Simpson integrator
// print the result
cout << "Integration with " << N << " intervals\n"
<< "Trapezoidal rule " << t << "\n"
<< "Midpoint rule " << m << "\n"
<< "Simspon rule " << s << "\n" ;
}
cout << "All done!\n" ;
return 0;
}
An Object Oriented version of the library with virtual interface
The declaration file
File: 13/intrule.h:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
#include <iostream>
typedef double valueType ;
typedef int indexType ;
typedef valueType (*functionType) ( valueType x ) ;
class numericalIntegrator {
protected:
functionType fun ;
public:
// default initialilizer
numericalIntegrator()
: fun(0)
{}
numericalIntegrator(functionType ffun)
: fun(ffun)
{}
virtual
~numericalIntegrator()
{}
// set up a funtion to integrate
void
setup( functionType ffun ) {
fun = ffun ;
}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
// declaring the operator PURE VIRTUAL
virtual
valueType
operator () ( valueType a, valueType b, indexType N ) const = 0 ;
} ;
class trap : public numericalIntegrator {
public:
// default initialilizer
trap()
: numericalIntegrator()
{}
trap(functionType ffun )
: numericalIntegrator(ffun)
{}
virtual
~trap()
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
virtual
valueType
operator () ( valueType a, valueType b, indexType N ) const ;
} ;
class midpoint : public numericalIntegrator {
public:
// default initialilizer
midpoint()
: numericalIntegrator()
{}
midpoint(functionType ffun )
: numericalIntegrator(ffun)
{}
virtual
~midpoint()
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
virtual
valueType
operator () ( valueType a, valueType b, indexType N ) const ;
} ;
class simpson : public numericalIntegrator {
public:
// default initialilizer
simpson()
: numericalIntegrator()
{}
simpson(functionType ffun )
: numericalIntegrator(ffun)
{}
virtual
~simpson()
{}
//
// To integrate a function if INT is of type numericalIntegrator
// INT . setup(fun);
// res = INT(a,b,N) ;
//
virtual
valueType
operator () ( valueType a, valueType b, indexType N ) const ;
} ;
The definition file
File: 13/intrule.cc:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
valueType
trap::operator () ( valueType a, valueType b, indexType N ) const {
valueType h = (b-a)/N ;
valueType res = h*(fun(a) + fun(b))/2 ;
for ( indexType i = 1 ; i < N ; ++i ) {
valueType xi = a + h*i ;
res += h*fun(xi) ;
}
return res ;
}
valueType
midpoint::operator () ( valueType a, valueType b, indexType N ) const {
valueType h = (b-a)/N ;
valueType res = 0 ;
for ( indexType i = 0 ; i < N ; ++i ) {
valueType xi_plus_half = a + h*(i+0.5) ;
res += h*fun(xi_plus_half) ;
}
return res ;
}
valueType
simpson::operator () ( valueType a, valueType b, indexType N ) const {
valueType h = (b-a)/N ;
valueType res = h*((*fun)(a) + fun(b))/3 ;
for ( indexType i = 1 ; i < N ; i += 2 ) {
valueType xi = a + h*i ;
res += (4*h/3)*fun(xi) ;
}
for ( indexType i = 2 ; i < N-1 ; i += 2 ) {
valueType xi = a + h*i ;
res += (2*h/3)*fun(xi) ;
}
return res ;
}
A driver program
File: 13/main.cc:
/*
// A simple object oriented implementation of some numerical
// integration rules.
//
*/
#include "intrule.h"
#include <cmath>
#include <iostream>
using namespace std ;
static
valueType
testFun( valueType x ) {
return x*exp(-x) ;
}
int
main() {
numericalIntegrator * tInstance = new trap( testFun ) ;
numericalIntegrator * mInstance = new midpoint( testFun ) ;
numericalIntegrator * sInstance = new simpson( testFun ) ;
valueType a = 0 ;
valueType b = 10 ;
for ( indexType N = 10 ; N <= 1000 ; N *= 2 ) {
valueType t = (*tInstance)( a, b, N ) ; // call trapeziodal integrator
valueType m = (*mInstance)( a, b, N ) ; // call midpoint integrator
valueType s = (*sInstance)( a, b, N ) ; // call Simpson integrator
// print the result
cout << "Integration with " << N << " intervals\n"
<< "Trapezoidal rule " << t << "\n"
<< "Midpoint rule " << m << "\n"
<< "Simspon rule " << s << "\n" ;
}
delete tInstance ;
delete mInstance ;
delete sInstance ;
cout << "All done!\n" ;
return 0;
}
The lesson in a zip file
The zip file lesson4.zip
Lesson of 7 July 2008
Overloading and template
An example of overloading
File: 14/example_overloading.cc:
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
// this function order a vector of integer
void
sort( int size, int v[] ) {
cout << "Order the vector of integer with bubble sort\n" ;
for ( int i = 0 ; i < size-1 ; ++i )
// find minimum of v[i]...v[size-1] ;
for ( int j = i+1 ; j < size ; ++j )
if ( v[i] > v[j] )
swap(v[i],v[j]) ; // uso swap function of STL algorithm
}
// this function order a vector of double
void
sort( int size, double v[] ) {
cout << "Order the vector of double with bubble sort\n" ;
for ( int i = 0 ; i < size-1 ; ++i )
// find minimum of v[i]...v[size-1] ;
for ( int j = i+1 ; j < size ; ++j )
if ( v[i] > v[j] )
swap(v[i],v[j]) ; // uso swap function of STL algorithm
}
int v[] = {4,5,2, -1, 3, 0, -23, 123 } ;
int sv = sizeof(v) / sizeof(v[0]) ;
// size in byte of v / size in bite of first element
double rv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int srv = sizeof(rv) / sizeof(rv[0]) ;
int
main() {
sort( sv, v ) ;
for ( int i = 0 ; i < sv ; ++i )
cout << "v[" << i << "] = " << v[i] << "\n" ;
sort( srv, rv ) ;
for ( int i = 0 ; i < sv ; ++i )
cout << "rv[" << i << "] = " << rv[i] << "\n" ;
return 0 ;
}
An example of template function
File: 14/example_template.cc:
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
// this function order a vector of type Type
template <typename Type>
void
sort( int size, Type v[] ) {
cout << "Order the vector with bubble sort\n" ;
for ( int i = 0 ; i < size-1 ; ++i )
// find minimum of v[i]...v[size-1] ;
for ( int j = i+1 ; j < size ; ++j )
if ( v[i] > v[j] )
swap(v[i],v[j]) ; // uso swap function of STL algorithm
}
int v[] = {4,5,2, -1, 3, 0, -23, 123 } ;
int sv = sizeof(v) / sizeof(v[0]) ;
// size in byte of v / size in bite of first element
double rv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int srv = sizeof(rv) / sizeof(rv[0]) ;
int
main() {
sort( sv, v ) ;
for ( int i = 0 ; i < sv ; ++i )
cout << "v[" << i << "] = " << v[i] << "\n" ;
sort( srv, rv ) ;
for ( int i = 0 ; i < sv ; ++i )
cout << "rv[" << i << "] = " << rv[i] << "\n" ;
return 0 ;
}
Splitting template on multiple files
File: 14/example_template2a.cc:
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
// declare the function sort to order a vector
// it is a template function
template <typename Type>
void
sort( int size, Type v[] ) ;
int v[] = {4,5,2, -1, 3, 0, -23, 123 } ;
int sv = sizeof(v) / sizeof(v[0]) ;
// size in byte of v / size in bite of first element
double rv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int srv = sizeof(rv) / sizeof(rv[0]) ;
float fv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int sfv = sizeof(fv) / sizeof(fv[0]) ;
int
main() {
sort( sv, v ) ;
for ( int i = 0 ; i < sv ; ++i )
cout << "v[" << i << "] = " << v[i] << "\n" ;
sort( srv, rv ) ;
for ( int i = 0 ; i < srv ; ++i )
cout << "rv[" << i << "] = " << rv[i] << "\n" ;
sort( sfv, fv ) ;
for ( int i = 0 ; i < sfv ; ++i )
cout << "fv[" << i << "] = " << fv[i] << "\n" ;
return 0 ;
}
File: 14/example_template2b.cc:
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
// define the function sort that order a vector
template <typename Type>
void
sort( int size, Type v[] ) {
cout << "Order the vector with bubble sort\n" ;
for ( int i = 0 ; i < size-1 ; ++i )
// find minimum of v[i]...v[size-1] ;
for ( int j = i+1 ; j < size ; ++j )
if ( v[i] > v[j] )
swap(v[i],v[j]) ; // uso swap function of STL algorithm
}
// tell the compiler to generate code for Type = int, float and double
template void sort<int> ( int size, int v[] ) ;
template void sort<float> ( int size, float v[] ) ;
template void sort<double>( int size, double v[] ) ;
Using sort of STL
File: 14/example_template3.cc:
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
int v[] = {4,5,2, -1, 3, 0, -23, 123 } ;
int sv = sizeof(v) / sizeof(v[0]) ;
// size in byte of v / size in bite of first element
double rv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int srv = sizeof(rv) / sizeof(rv[0]) ;
float fv[] = {-0.1, 4.1, 5.3,2.2, -1.1, 3.2234, 0.0213, -23.1, 123. } ;
int sfv = sizeof(fv) / sizeof(fv[0]) ;
int
main() {
sort( v, v + sv ) ; // call the STL sort routine
for ( int i = 0 ; i < sv ; ++i )
cout << "v[" << i << "] = " << v[i] << "\n" ;
sort( rv, rv + srv ) ;
for ( int i = 0 ; i < srv ; ++i )
cout << "rv[" << i << "] = " << rv[i] << "\n" ;
sort( fv, fv + sfv ) ;
for ( int i = 0 ; i < sfv ; ++i )
cout << "fv[" << i << "] = " << fv[i] << "\n" ;
return 0 ;
}
Class template and STL
A simple example of class template
File: 15/class_template.cc:
/*
// Example of template of a class
//
*/
#include <iostream>
#include <algorithm>
using namespace std ;
// define the generic class PointXY
template <typename Type>
class PointXY {
Type x, y ;
public:
} ;
int
main() {
PointXY<int> p1 ; // instatiate the class PointXY with type int
PointXY<double> p2 ; // instatiate the class PointXY with type double
return 0 ;
}
An example using vector of STL
File: 15/vector_example.cc:
/*
// Example of use of tempatye class vector
//
*/
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;
/*
// Example of overloading
//
*/
#include <iostream>
#include <algorithm>
/*
// Common methos for neal all containers
//
// begin() return an iterator pointing to the first element
// end() return an iterator pointing to past to last element
// operator ++ move the iterator forward by an element
// operator -- move the iterator backward by an element
// front() equivalent to *begin()
// back() near equivalent to *(end()-1)
//
// push_back(element) add an element to the tail of the container
//
// size() return the number of element of the container
//
//
// resize(new_size) (for vector like container)
//
// insert (various way, see documentation)
//
// for more documentation see e.g. http://www.sgi.com/tech/stl/
//
*/
using namespace std ;
int
main() {
vector<double> v ;
v . push_back(-0.1) ;
v . push_back(4.1) ;
v . push_back(5.3) ;
v . push_back(2.2) ;
v . push_back(-1.1) ;
v . push_back(3.2234 ) ;
v . push_back(0.0213 ) ;
v . push_back(-23.1) ;
v . push_back(123.) ;
sort( v . begin(), // iterator pointing to the first element
v . end() ) ; // iterator pointing to past to the last element
// loop to the elements of vector (old way)
for ( int i = 0 ; i < v.size() ; ++i )
cout << "v[" << i << "] = " << v[i] << "\n" ;
vector<double>::iterator iv ;
for ( iv = v.begin() ; iv != v.end() ; ++iv ) {
cout << *iv << "\n" ;
}
return 0 ;
}
Using STL in an old example
The prime number calculation with vector of STL
File: 16/16.cc:
/*
Example to print first N prime numbers,
*/
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std ;
// define N as a preprocess variable, will be substitued
// by the preprocessing phase
#define N 1000
template <typename IntType>
bool // boolean type, store true or false value only
// check if candidate is a prime number respect to the vector primes
// return true if primes[i] do not divide candidate for each i
checkPrime( vector<IntType> const & primes, IntType const & candidate ) {
typename vector<IntType>::const_iterator i ;
for ( i = primes . begin() ; i != primes.end() ; ++i ) {
if ( ( candidate % (*i) ) == 0 ) // if remainder is 0 it is not a prime!
return false ;
}
return true ;
}
template <typename IntType>
void // void type, nothing to return!
addPrime( vector<IntType> & primes ) {
IntType candidate = primes . back() + 1 ;
// ! is the negation operator ! true = false.
while ( ! checkPrime( primes, candidate) ) ++candidate ;
primes . push_back(candidate) ;
}
template <typename IntType>
void
printNumbers( ostream & s,
vector<IntType> const & primes ) {
int kk = 0 ;
typename vector<IntType>::const_iterator i ;
for ( i = primes . begin() ; i != primes.end() ; ++i ) {
// print the number to the file fd (can be stdout)
// no new line or others amenity
s << setw(5) << *i ;
++kk ; // increment the counter
// decide if to use comma of newline
if ( (kk%10) == 0 ) s << "\n" ;
else s << ", " ;
}
s << "\n" ;
}
int
main ()
{
vector<long int> primes ;
primes . push_back(2) ;
primes . push_back(3) ;
primes . push_back(5) ;
primes . push_back(7) ;
do {
addPrime( primes ) ;
} while ( primes . size() < N ) ; // chech if it must cycle again
printNumbers( cout, primes ) ; // print the result to standard output
return 0 ;
}
A generic graphics driver with a postscript driver
Declaration of Gr::Driver
class
File: 17/GrDriver.hh:
#ifndef GR_DRIVER_H
#define GR_DRIVER_H
#include <string>
namespace Gr {
using namespace std ;
typedef double valueType ;
typedef int indexType ;
typedef enum { GR_TIMES=0,
GR_HELVETICA,
GR_COURIER } FontType ;
typedef enum { GR_NORMAL=0,
GR_BOLD,
GR_OBLIQUE,
GR_BOLDOBLIQUE } FontFace ;
typedef enum { GR_ALIGN_UP_LEFT=0,
GR_ALIGN_UP_CENTER,
GR_ALIGN_UP_RIGHT,
GR_ALIGN_LEFT,
GR_ALIGN_CENTER,
GR_ALIGN_RIGHT,
GR_ALIGN_DOWN_LEFT,
GR_ALIGN_DOWN_CENTER,
GR_ALIGN_DOWN_RIGHT } FontAlign ;
typedef enum { GR_ARROW_SIMPLE=0,
GR_ARROW_EMPTY,
GR_ARROW_FILL,
GR_ARROW_SIMPLE_EMPTY,
GR_ARROW_SIMPLE_FILL } ArrowType ;
class RgbGolor {
valueType r, g, b ;
public:
RgbGolor() ;
RgbGolor( valueType rr, valueType gg, valueType bb ) ;
void
operator () ( valueType rr,
valueType gg,
valueType bb )
{ r = rr ; g = gg ; b = bb ; }
valueType red() const { return r ; }
valueType green() const { return g ; }
valueType blue() const { return b ; }
} ;
#define GR_DRIVER_INTERFACE(PV) \
virtual void window( valueType xm, \
valueType xM, \
valueType ym, \
valueType yM ) PV ; \
\
virtual void clip ( valueType x1, \
valueType y1, \
valueType x2, \
valueType y2 ) PV ; \
\
virtual void setFont( FontType, FontFace, indexType size ) PV ; \
\
virtual void rgbColor( valueType r, valueType g, valueType b ) PV ; \
virtual void hsbColor( valueType r, valueType g, valueType b ) PV ; \
\
virtual void setLineWidth( valueType w ) PV ; \
virtual void setLineStyle( string const & s ) PV ; \
virtual void setLineStyle( int s ) PV ; \
virtual void line( valueType x1, \
valueType y1, \
valueType x2, \
valueType y2 ) PV ; \
\
virtual void box( valueType x1, \
valueType y1, \
valueType x2, \
valueType y2, \
bool fill = false) PV ; \
\
virtual void roundBox( valueType x1, \
valueType y1, \
valueType x2, \
valueType y2, \
valueType r, \
bool fill = false) PV ; \
\
virtual void circle( valueType x, \
valueType y, \
valueType r, \
bool fill = false) PV ; \
\
virtual void ellipse( valueType x, \
valueType y, \
valueType r1, \
valueType r2, \
bool fill = false) PV ; \
\
virtual void poly( indexType n, \
valueType const x[], \
valueType const y[], \
bool close = false, \
bool fill = false) PV ; \
\
virtual void polyOffset( indexType n, \
valueType const x[], \
valueType const y[], \
valueType dx = 0, \
valueType dy = 0, \
bool close = false, \
bool fill = false) PV ; \
\
virtual void bezier( valueType x1, valueType y1, \
valueType x2, valueType y2, \
valueType x3, valueType y3, \
valueType x4, valueType y4) PV ; \
\
virtual void arc( valueType cx, \
valueType cy, \
valueType r, \
valueType t1, \
valueType t2, \
bool fill = false) PV ; \
\
virtual void drawText( valueType x, \
valueType y, \
string const & str, \
FontAlign align, \
valueType angle ) PV ; \
\
virtual void arrow( valueType x, \
valueType y, \
valueType dx, \
valueType dy, \
ArrowType at) ; \
\
virtual void square( valueType x, \
valueType y, \
valueType r, \
bool fill = false) ; \
\
virtual void diamond( valueType x, \
valueType y, \
valueType r, \
bool fill = false) ; \
\
virtual void plus( valueType x, \
valueType y, \
valueType r ) ; \
\
virtual void cross( valueType x, \
valueType y, \
valueType r ) ; \
\
virtual void star( valueType x, \
valueType y, \
valueType r, \
bool fill = false )
class Driver {
public:
Driver() {} ;
~Driver() {} ;
GR_DRIVER_INTERFACE(=0);
void rgbColor( RgbGolor const & c)
{ rgbColor(c.red(),c.green(),c.blue()) ; }
void red() { rgbColor(1,0,0) ; }
void green() { rgbColor(0,1,0) ; }
void blue() { rgbColor(0,0,1) ; }
void yellow() { rgbColor(1,1,0) ; }
void pink() { rgbColor(1,0,1) ; }
void cyan() { rgbColor(0,1,1) ; }
void white() { rgbColor(0.9,0.9,0.9) ; }
void black() { rgbColor(0,0,0) ; }
} ;
}
#endif
Definition of Gr::Driver class
File: 17/GrDriver.cc:
#include "GrDriver.hh"
namespace Gr {
RgbGolor::RgbGolor()
: r(0), g(0), b(0)
{}
RgbGolor::RgbGolor( valueType rr,
valueType gg,
valueType bb )
: r(rr), g(gg), b(bb)
{}
static valueType xf[8] = { 0, 0.8, 0.8, 1, 0.8, 0.8, 0, 0.8} ;
static valueType yf[8] = { -0.025, -0.025, -0.1, 0, 0.1, 0.025, 0.025, 0 } ;
void
Driver::arrow( valueType xx,
valueType yy,
valueType dx,
valueType dy,
ArrowType at ) {
valueType x[8], y[8] ;
for ( int i=0 ; i < 8 ; i++ ) {
x[i] = xx+(dx*xf[i]-dy*yf[i]) ;
y[i] = yy+(dy*xf[i]+dx*yf[i]) ;
}
switch (at) {
case GR_ARROW_SIMPLE:
line(xx,yy,x[3],y[3]) ;
line(x[3],y[3],x[2],y[2]) ;
line(x[3],y[3],x[4],y[4]) ;
break ;
case GR_ARROW_EMPTY:
poly(7,x,y,true,false) ;
break ;
case GR_ARROW_FILL:
poly(7,x,y,true,true) ;
break ;
case GR_ARROW_SIMPLE_EMPTY:
line(xx,yy,x[7],y[7]) ;
poly(3,x+2,y+2,true,false) ;
break ;
case GR_ARROW_SIMPLE_FILL:
line(xx,yy,x[7],y[7]) ;
poly(3,x+2,y+2,true,true) ;
break ;
}
} ;
void
Driver::square( valueType x,
valueType y,
valueType r,
bool fill ) {
box(x-r,y-r,x+r,y+r,fill) ;
} ;
void
Driver::diamond( valueType xx,
valueType yy,
valueType r,
bool fill ) {
valueType x[4], y[4] ;
x[0] = xx ; y[0] = yy-r ;
x[1] = xx+r ; y[1] = yy ;
x[2] = xx ; y[2] = yy+r ;
x[3] = xx-r ; y[3] = yy ;
poly(4,x,y,true,fill) ;
}
void
Driver::plus( valueType x, valueType y, valueType r ) {
line(x,y-r,x,y+r) ;
line(x-r,y,x+r,y) ;
}
void
Driver::cross( valueType x, valueType y, valueType r ) {
line(x-r,y-r,x+r,y+r) ;
line(x+r,y-r,x-r,y+r) ;
}
void
Driver::star( valueType xx, valueType yy, valueType r, bool fill ) {
valueType x[10], y[10] ;
x[0] = xx ; y[0] = yy + r ;
x[1] = xx - 0.196 * r ; y[1] = yy + 0.27 * r ;
x[2] = xx - 0.95 * r ; y[2] = yy + 0.31 * r ;
x[3] = xx - 0.32 * r ; y[3] = yy - 0.103 * r ;
x[4] = xx - 0.59 * r ; y[4] = yy - 0.81 * r ;
x[5] = xx ; y[5] = yy - 0.33333* r ;
x[6] = xx + 0.59 * r ; y[6] = yy - 0.81 * r ;
x[7] = xx + 0.32 * r ; y[7] = yy - 0.103 * r ;
x[8] = xx + 0.95 * r ; y[8] = yy + 0.31 * r ;
x[9] = xx + 0.196 * r ; y[9] = yy + 0.27 * r ;
poly(10,x,y,true,fill) ;
}
}
Declaration of Gr::PsDriver
(the postscript driver class)
File: 17/PsDriver.hh:
#ifndef PSDRV_H
#define PSDRV_H
#include <fstream>
#include "GrDriver.hh"
namespace Gr {
using namespace std ;
class PsDriver : public Driver {
ofstream psf ;
bool blackandwhite ;
valueType width, height ;
void moveto(valueType x, valueType y) ;
void rmove(valueType x, valueType y) ;
void lineto(valueType x, valueType y) ;
void rline(valueType x, valueType y) ;
void outstr(const char str[]) ;
void translate(valueType tx, valueType ty) ;
void rotate(valueType angle) ;
void rotate(valueType dx, valueType dy) ;
void scale(valueType sx, valueType sy) ;
void arcto(valueType x1, valueType y1, valueType x2, valueType y2, valueType r) ;
void newpath() ;
void closepath() ;
void stroke() ;
void close_fill(bool c, bool f) ;
public:
PsDriver( string const & of, valueType w, valueType h, bool bw, bool ls) ;
~PsDriver() ;
void setLineCap(indexType i) ;
void setLineJoin(indexType i) ;
void setLineMiterLimit(valueType d) ;
GR_DRIVER_INTERFACE() ;
} ;
}
#endif
Definition of Gr::PsDriver
(the postscript driver class)
File: 17/PsDriver.cc:
#include "PsDriver.hh"
#include <cmath>
#include <iostream>
using namespace std ;
namespace Gr {
static char *ps_macros[] = {
"/dl{2 mul} bind def",
"/M {moveto} bind def",
"/L {lineto} bind def",
"/R {rmoveto} bind def",
"/V {rlineto} bind def",
"/TT {translate} bind def",
"/RR {rotate} bind def",
"/SS {scale} bind def",
"/VV {gsave newpath 0 0 M (o) true charpath",
" flattenpath pathbbox grestore",
" exch pop exch pop exch pop} def",
"/HH {dup stringwidth pop} def",
"/showAT {/posy exch def /posx exch def gsave TT RR newpath 0 0 M",
" HH posx mul VV posy mul R show stroke grestore} def",
"/LDshowAT {-1 -1 showAT} def",
"/RDshowAT {0 -1 showAT} def",
"/CDshowAT {-0.5 -1 showAT} def",
"/LCshowAT {-1 -0.5 showAT} def",
"/RCshowAT {0 -0.5 showAT} def",
"/CCshowAT {-0.5 -0.5 showAT} def",
"/LUshowAT {-1 0 showAT} def",
"/RUshowAT {0 0 showAT} def",
"/CUshowAT {-0.5 0 showAT} def",
"/SAVE {/cmtx matrix currentmatrix def} def",
"/CHVIEW {/ty exch def /tx exch def /dy exch def /dx exch def /ndy {dy neg} def",
" SAVE [dx dy ndy dx tx ty] concat} def",
"/RESTORE {cmtx setmatrix} def",
"/ELL {gsave SAVE TT SS newpath 0 0 1 0 360 arc RESTORE closepath stroke grestore} def",
"/ELLF{gsave SAVE TT SS newpath 0 0 1 0 360 arc RESTORE closepath fill grestore} def",
"/BOX {gsave SAVE TT SS newpath 0 0 M 1 0 L 1 1 L 0 1 L 0 0 L RESTORE closepath stroke grestore} def",
"/BOXF{gsave SAVE TT SS newpath 0 0 M 1 0 L 1 1 L 0 1 L 0 0 L RESTORE closepath fill grestore} def",
"/LINE{newpath M L stroke} def",
"/ARPATH {newpath 0 -0.025 M 0.8 -0.025 L 0.8 -0.1 L 1 0 L 0.8 0.1 L 0.8 0.025 L 0 0.025 L closepath} def",
"/ARPATHB {newpath 0 0 M 0.8 0 L 0.8 -0.1 L 1 0 L 0.8 0.1 L 0.8 0 L closepath} def",
"/ARS {CHVIEW newpath 0 0 M 1 0 L 0.8 0.025 M 0 1 L 0.8 -0.025 L",
" RESTORE stroke grestore} def",
"/ARE {gsave CHVIEW ARPATH RESTORE stroke grestore} def",
"/ARF {gsave CHVIEW ARPATH RESTORE fill grestore} def",
"/ARSE {gsave CHVIEW ARPATHB RESTORE stroke grestore} def",
"/ARSF {gsave CHVIEW ARPATHB RESTORE fill grestore} def",
"/SE {gsave SAVE TT dup SS newpath -1 -1 M 1 -1 L 1 1 L -1 1 L RESTORE closepath stroke grestore} def",
"/SF {gsave SAVE TT dup SS newpath -1 -1 M 1 -1 L 1 1 L -1 1 L RESTORE closepath fill grestore} def",
"/DE {gsave SAVE TT dup SS newpath 0 -1 M 1 0 L 0 1 L -1 0 L RESTORE closepath stroke grestore} def",
"/DF {gsave SAVE TT dup SS newpath 0 -1 M 1 0 L 0 1 L -1 0 L RESTORE closepath fill grestore} def",
"/P {gsave SAVE TT dup SS newpath 0 -1 M 0 1 L -1 0 M 1 0 L RESTORE stroke grestore} def",
"/C {gsave SAVE TT dup SS newpath -1 -1 M 1 1 L -1 1 M 1 -1 L RESTORE stroke grestore} def",
"/SPATH {newpath 0 1 M -0.196 0.27 L -0.95 0.31 L -0.32 -0.103 L",
" -0.59 -0.81 L 0 -0.333333 L 0.59 -0.81 L 0.32 -0.103 L",
" 0.95 0.31 L 0.196 0.27 L closepath} def",
"/STARE { gsave SAVE TT dup SS SPATH RESTORE stroke grestore} def",
"/STARF { gsave SAVE TT dup SS SPATH RESTORE fill grestore} def",
"/TR {/size exch def /Times-Roman findfont size scalefont setfont} def",
"/TRB {/size exch def /Times-Bold findfont size scalefont setfont} def",
"/TRO {/size exch def /Times-Italic findfont size scalefont setfont} def",
"/TRBO {/size exch def /Times-BoldItalic findfont size scalefont setfont} def",
"/HE {/size exch def /Helvetica findfont size scalefont setfont} def",
"/HEB {/size exch def /Helvetica-Bold findfont size scalefont setfont} def",
"/HEO {/size exch def /Helvetica-Oblique findfont size scalefont setfont} def",
"/HEBO {/size exch def /Helvetica-BoldOblique size findfont scalefont setfont} def",
"/CO {/size exch def /Courier findfont size scalefont setfont} def",
"/COB {/size exch def /Courier-Bold findfont size scalefont setfont} def",
"/COO {/size exch def /Courier-Oblique findfont size scalefont setfont} def",
"/COBO {/size exch def /Courier-BoldOblique findfont size scalefont setfont} def",
NULL } ;
PsDriver::PsDriver( string const & of,
valueType w,
valueType h,
bool bw,
bool landscape )
: width(w)
, height(h)
, blackandwhite(bw) {
psf.open(of.c_str()) ;
psf << "%%!PS-Adobe-2.0 EPSF-2.0\n"
<< "%%Creator: EasyGraph\n"
<< "%%Title: " << of << "\n"
<< "%%CreationDate: no date\n"
<< "%%%%BoundingBox: -1 -1 " << width+1 << " " << height+1 << "\n"
<< "%%%%EndComments\n"
<< "%%%%EndProlog\n" ;
for ( char **ppstr = ps_macros ; *ppstr != NULL ; ppstr++ )
psf << *ppstr << endl ;
psf << "24 TR" << endl
<< "gsave" << endl
<< (landscape?"-90 RR\n":"\n") ;
}
PsDriver::~PsDriver() {
psf << "showpage grestore\n%%%%Trailer\n" ;
psf.close() ;
}
void
PsDriver::moveto(valueType x, valueType y) {
psf << " " << x << " " << y << " M" ;
}
void
PsDriver::rmove (valueType x, valueType y) {
psf << " " << x << " " << y << " R" ;
}
void
PsDriver::lineto(valueType x, valueType y) {
psf << " " << x << " " << y << " L" ;
}
void
PsDriver::rline (valueType x, valueType y) {
psf << " " << x << " " << y << " V" ;
}
void
PsDriver::arcto( valueType x1, valueType y1,
valueType x2, valueType y2,
valueType r) {
psf << " " << x1 << " " << y1 << " " << x2 << " " << y2 << " " << r << " arcto" ;
}
void
PsDriver::translate(valueType tx, valueType ty) {
psf << " " << tx << " " << ty << " TT" ;
}
void
PsDriver::rotate(valueType angle) {
psf << " " << angle << " RR" ;
}
void
PsDriver::rotate(valueType dx, valueType dy) {
psf << " " << dy << " " << dx << " atan RR" ;
}
void
PsDriver::scale(valueType sx, valueType sy) {
psf << " " << sx << " " << sy << " SS" ;
}
void
PsDriver::newpath() {
psf << " newpath" ;
}
void
PsDriver::closepath() {
psf << " closepath" ;
}
void
PsDriver::close_fill(bool c, bool f) {
psf << (c?" closepath":"") << ( f? " fill" : " stroke") << endl ;
}
void PsDriver::stroke() {
psf << " stroke" ;
}
void
PsDriver::outstr(const char *s) {
psf << " (" ;
for ( const char *pc = s ; *pc != 0 ; ++pc ) {
psf << ( ( *pc == '(' || *pc == ')' || *pc == '\\' ) ? "\\" : "" ) << *pc ;
}
psf << ") " ;
}
void
PsDriver::window(valueType xm, valueType xM, valueType ym, valueType yM) {
translate(xm,ym) ;
scale(width/(xM-xm),height/(yM-ym)) ;
psf << "\n" ;
}
void
PsDriver::clip(valueType x1, valueType y1, valueType x2, valueType y2) {
newpath() ;
moveto(x1,y1) ;
lineto(x1,y2) ;
lineto(x2,y2) ;
lineto(x2,y1) ;
psf << " closepath clip\n" ;
}
void
PsDriver::setFont(FontType f, FontFace fa, indexType size) {
psf << " " << size ;
switch (f) {
case GR_TIMES: psf << " TR" ; break ;
case GR_HELVETICA: psf << " HE" ; break ;
case GR_COURIER: psf << " CO" ; break ;
}
switch (fa) {
case GR_NORMAL: psf << "\n" ; break ;
case GR_BOLD: psf << "B\n" ; break ;
case GR_OBLIQUE: psf << "O\n" ; break ;
case GR_BOLDOBLIQUE: psf << "BO\n" ; break ;
}
}
static char *align_show[] = {" LUshowAT", " CUshowAT", " RUshowAT",
" LCshowAT", " CCshowAT", " RCshowAT",
" LDshowAT", " CDshowAT", " RDshowAT" } ;
void
PsDriver::drawText( valueType x,
valueType y,
string const & s,
FontAlign align,
valueType angle ) {
outstr(s.c_str()) ;
psf << angle << " " << x << " " << y << align_show[align] << "\n" ;
}
void
PsDriver::rgbColor(valueType r, valueType g, valueType b) {
if (blackandwhite)
psf << " " << (3*r+2*g+b)/6 << " setgray\n" ;
else
psf << " " << r << " " << g << " " << b << " setrgbcolor\n" ;
}
void
PsDriver::hsbColor(valueType h, valueType s, valueType l) {
if (blackandwhite)
psf << " " << l << " setgray\n" ;
else
psf << " " << h << " " << s << " " << l << " sethsbcolor\n" ;
}
// lcap, 0= butt, 1=round, 2=projecting square
void
PsDriver::setLineCap(indexType i) {
psf << i << " setlinecap\n" ;
}
void
PsDriver::setLineJoin(indexType i) {
psf << i << " setlinejoin\n" ;
}
void
PsDriver::setLineMiterLimit(valueType d) {
psf << d << " setmiterlimit\n" ;
}
void
PsDriver::setLineWidth(valueType w) {
psf << w << " setlinewidth\n" ;
}
void
PsDriver::setLineStyle( string const & s ) {
psf << "[" << s << "] 0 setdash\n" ;
}
void
PsDriver::setLineStyle(indexType i) {
static char *defline[] = {
"", "1 dl 2 dl", "4 dl 2 dl", "2 dl 3 dl",
"1 dl 1.5 dl", "5 dl 2 dl 1 dl 2 dl", "4 dl 3 dl 1 dl 3 dl",
"2 dl 2 dl 2 dl 4 dl", "2 dl 2 dl 2 dl 2 dl 2 dl 4 dl",
"2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 4 dl"} ;
setLineStyle(defline[i<0 ? 0 : ( i>9 ? 9 : i)]) ;
}
void
PsDriver::line(valueType x1, valueType y1, valueType x2, valueType y2) {
psf << " " << x1 << " " << y1
<< " " << x2 << " " << y2
<< " LINE\n" ;
}
void
PsDriver::box(valueType x1, valueType y1, valueType x2, valueType y2, bool fill) {
psf << " " << x2-x1 << " " << y2-y1
<< " " << x1 << " " << y1
<< (fill?" BOXF\n":" BOX\n") ;
}
void
PsDriver::roundBox( valueType x1,
valueType y1,
valueType x2,
valueType y2,
valueType r,
bool fill ) {
newpath() ;
moveto(x2-r,y1) ;
arcto(x2,y1,x2,y1+r,r) ;
lineto(x2,y2-r) ;
arcto(x2,y2,x2-r,y2,r) ;
lineto(x1+r,y2) ;
arcto(x1,y2,x1,y2-r,r) ;
lineto(x1,y1+r) ;
arcto(x1,y1,x1+r,y1,r) ;
lineto(x2-r,y1) ;
close_fill(true,fill) ;
}
void
PsDriver::circle(valueType x, valueType y, valueType r, bool fill) {
ellipse(x,y,r,r,fill) ;
}
void
PsDriver::ellipse(valueType x, valueType y, valueType r1, valueType r2, bool fill) {
psf << " " << r1 << " " << r2
<< " " << x << " " << y
<< (fill? " ELLF\n" : " ELL\n") ;
}
void
PsDriver::poly( indexType n,
valueType const x[],
valueType const y[],
bool close,
bool fill) {
newpath() ;
moveto(x[0],y[0]) ;
for (int i=1 ; i < n ; i++ )
{ lineto(x[i],y[i]) ; if ( (i%6) == 0 ) psf << "\n" ; }
close_fill(close,fill) ;
}
void
PsDriver::polyOffset( indexType n,
valueType const x[],
valueType const y[],
valueType dx,
valueType dy,
bool close,
bool fill) {
newpath() ;
moveto(dx+x[0],dy+y[0]) ;
for (int i=1 ; i < n ; i++ )
{ lineto(dx+x[i],dy+y[i]) ; if ( (i%6) == 0 ) psf << "\n" ; }
close_fill(close,fill) ;
}
void
PsDriver::arc( valueType cx,
valueType cy,
valueType r,
valueType t1,
valueType t2,
bool fill ) {
newpath() ;
if ( fill) moveto(cx,cy) ;
psf << " " << cx << " " << cy << " " << r
<< " " << t1 << " " << t2 << " arc" ;
close_fill(fill,fill) ;
}
void
PsDriver::bezier( valueType x1, valueType y1,
valueType x2, valueType y2,
valueType x3, valueType y3,
valueType x4, valueType y4) {
newpath() ;
moveto(x1,y1) ;
psf << " " << x2 << " " << y2
<< " " << x3 << " " << y3
<< " " << x4 << " " << y4
<< " curveto stroke"<< endl ;
}
static char *artype[] = { " ARS", " ARE", " ARF", " ARSE", " ARSF" } ;
void
PsDriver::arrow( valueType xx,
valueType yy,
valueType dx,
valueType dy,
ArrowType at ) {
psf << " " << dx << " " << dy
<< " " << xx << " " << yy
<< artype[at] << "\n" ;
} ;
void
PsDriver::square(valueType x, valueType y, valueType r, bool fill) {
psf << " " << r << " " << x << " " << y << (fill?" SF\n":" SE\n") ;
}
void
PsDriver::diamond(valueType x, valueType y, valueType r, bool fill) {
psf << " " << r << " " << x << " " << y << (fill?" DF\n":" DE\n") ;
}
void
PsDriver::plus(valueType x, valueType y, valueType r) {
psf << " " << r << " " << x << " " << y << " P\n" ;
}
void PsDriver::cross(valueType x, valueType y, valueType r) {
psf << " " << r << " " << x << " " << y << " C\n" ;
}
void
PsDriver::star(valueType x, valueType y, valueType r, bool fill) {
psf << " " << r << " " << x << " " << y << (fill?" STARF\n":" STARE\n") ;
}
}
Declaration of Gr::Object
class
File: 17/GrObject.hh:
#ifndef GR_OBJ_H
#define GR_OBJ_H
#include "GrDriver.hh"
#include <string>
namespace Gr {
using namespace std ;
typedef struct { valueType x, y ; } GrXY ;
typedef struct { GrXY min, max ; } Bbox ;
/*
// ___ _ _ _
// / _ \| |__ (_) ___ ___| |_
// | | | | '_ \| |/ _ \/ __| __|
// | |_| | |_) | | __/ (__| |_
// \___/|_.__// |\___|\___|\__|
// |__/
*/
class Object {
protected:
Bbox bb ; // bounding box
void setbb( valueType xm, valueType ym, valueType xM, valueType yM ) ;
public:
Object() ;
Object( valueType _cx, valueType _cy, valueType _hdx, valueType _hdy ) ;
virtual ~Object() {} ;
virtual void draw(Driver *gr) = 0 ;
valueType wx() const { return bb.max.x-bb.min.x ; }
valueType wy() const { return bb.max.y-bb.min.y ; }
valueType cx() const { return (bb.max.x+bb.min.x)/2 ; }
valueType cy() const { return (bb.max.y+bb.min.y)/2 ; }
} ;
/*
// ____ _ _
// | _ \ ___ ___| |_ __ _ _ __ __ _| | ___
// | |_) / _ \/ __| __/ _` | '_ \ / _` | |/ _ \
// | _ < __/ (__| || (_| | | | | (_| | | __/
// |_| \_\___|\___|\__\__,_|_| |_|\__, |_|\___|
// |___/
*/
class Rectangle : public Object {
bool filled ;
public:
Rectangle( valueType xm, valueType ym,
valueType xM, valueType yM,
bool e) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _ ____ _ _
// | _ \ ___ _ _ _ __ __| | _ \ ___ ___| |_ __ _ _ __ __ _| | ___
// | |_) / _ \| | | | '_ \ / _` | |_) / _ \/ __| __/ _` | '_ \ / _` | |/ _ \
// | _ < (_) | |_| | | | | (_| | _ < __/ (__| || (_| | | | | (_| | | __/
// |_| \_\___/ \__,_|_| |_|\__,_|_| \_\___|\___|\__\__,_|_| |_|\__, |_|\___|
// |___/
*/
class RoundRectangle : public Object {
bool filled ;
valueType ray ;
public:
RoundRectangle( valueType xm, valueType ym,
valueType xM, valueType yM,
valueType r, bool e) ;
virtual void draw(Driver *gr) ;
} ;
/*
// _____ _ _ _
// | ____| | (_)_ __ ___ ___
// | _| | | | | '_ \/ __|/ _ \
// | |___| | | | |_) \__ \ __/
// |_____|_|_|_| .__/|___/\___|
// |_|
*/
class Ellipse : public Object {
bool filled ;
valueType ray1, ray2 ;
public:
Ellipse( valueType x, valueType y,
valueType r1, valueType r2,
bool e) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _ _
// / ___| _ _ _ __ ___ | |__ ___ | |
// \___ \| | | | '_ ` _ \| '_ \ / _ \| |
// ___) | |_| | | | | | | |_) | (_) | |
// |____/ \__, |_| |_| |_|_.__/ \___/|_|
// |___/
*/
class Symbol : public Object {
public:
Symbol(valueType _cx, valueType _cy, valueType _hdx, valueType _hdy) ;
virtual ~Symbol() {} ;
void move(valueType xx, valueType yy);
} ;
/*
// ____
// / ___| __ _ _ _ __ _ _ __ ___
// \___ \ / _` | | | |/ _` | '__/ _ \
// ___) | (_| | |_| | (_| | | | __/
// |____/ \__, |\__,_|\__,_|_| \___|
// |_|
*/
class Square : public Symbol {
bool filled ;
public:
Square(valueType x, valueType y, valueType r, bool e) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _ _
// / ___(_)_ __ ___| | ___
// | | | | '__/ __| |/ _ \
// | |___| | | | (__| | __/
// \____|_|_| \___|_|\___|
*/
class Circle : public Symbol {
valueType ray ;
bool filled ;
public:
Circle(valueType x, valueType y, valueType r, bool e) ;
virtual void draw(Driver *gr) ;
} ;
/*
// _____ ____ _ _
// | ___| _ _ __ _ __ _ _ / ___(_)_ __ ___| | ___
// | |_ | | | | '_ \| '_ \| | | | | | | '__/ __| |/ _ \
// | _|| |_| | | | | | | | |_| | |___| | | | (__| | __/
// |_| \__,_|_| |_|_| |_|\__, |\____|_|_| \___|_|\___|
// |___/
*/
class FunnyCircle : public Symbol {
valueType ray ;
public:
FunnyCircle(valueType x, valueType y, valueType r) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _ _
// | _ \(_) __ _ _ __ ___ ___ _ __ __| |
// | | | | |/ _` | '_ ` _ \ / _ \| '_ \ / _` |
// | |_| | | (_| | | | | | | (_) | | | | (_| |
// |____/|_|\__,_|_| |_| |_|\___/|_| |_|\__,_|
*/
class Diamond : public Symbol {
bool filled ;
public:
Diamond( valueType _x, valueType _y, valueType _r, bool _e ) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _
// / ___|| |_ __ _ _ __
// \___ \| __/ _` | '__|
// ___) | || (_| | |
// |____/ \__\__,_|_|
*/
class Star : public Symbol {
bool filled ;
public:
Star(valueType _x, valueType _y, valueType _r, bool _e ) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _
// | _ \| |_ _ ___
// | |_) | | | | / __|
// | __/| | |_| \__ \
// |_| |_|\__,_|___/
*/
class Plus : public Symbol {
public:
Plus(valueType x, valueType y, valueType r) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____
// / ___|_ __ ___ ___ ___
// | | | '__/ _ \/ __/ __|
// | |___| | | (_) \__ \__ \
// \____|_| \___/|___/___/
*/
class Cross : public Symbol {
public:
Cross(valueType x, valueType y, valueType r) ;
virtual void draw(Driver *gr) ;
} ;
/*
// ____ _ ____
// | _ \| |_ _ ___ / ___|_ __ ___ ___ ___
// | |_) | | | | / __| | | '__/ _ \/ __/ __|
// | __/| | |_| \__ \ |___| | | (_) \__ \__ \
// |_| |_|\__,_|___/\____|_| \___/|___/___/
*/
class PlusCross : public Symbol {
public:
PlusCross(valueType x, valueType y, valueType r) ;
virtual void draw(Driver *gr) ;
} ;
/*
// _
// / \ _ __ _ __ _____ __
// / _ \ | '__| '__/ _ \ \ /\ / /
// / ___ \| | | | | (_) \ V V /
// /_/ \_\_| |_| \___/ \_/\_/
*/
class Arrow : public Object {
ArrowType artype ;
valueType x, y, dx, dy ;
public:
Arrow( valueType _x,
valueType _y,
valueType _dx,
valueType _dy,
ArrowType at = GR_ARROW_SIMPLE) ;
virtual void draw(Driver *gr) ;
} ;
/*
// _____ _
// |_ _|____ _| |_
// | |/ _ \ \/ / __|
// | | __/> <| |_
// |_|\___/_/\_\\__|
*/
class Text : public Object {
FontAlign align ;
FontType font ;
FontFace face ;
indexType size ;
valueType angle ;
string str ;
public:
Text( valueType x,
valueType y,
string const & _str,
FontType _font,
FontFace _face,
indexType _size,
FontAlign _align,
valueType _angle = 0) ;
void setText( string const & s ) { str = s ; }
virtual void draw(Driver *gr) ;
} ;
}
#endif
Definition of Gr::Object
classfile
File: 17/GrObject.cc:
#include "GrObject.hh"
namespace Gr {
/*
// ___ _ _ _
// / _ \| |__ (_) ___ ___| |_
// | | | | '_ \| |/ _ \/ __| __|
// | |_| | |_) | | __/ (__| |_
// \___/|_.__// |\___|\___|\__|
// |__/
*/
Object::Object()
{} ;
Object::Object( valueType _cx,
valueType _cy,
valueType _hdx,
valueType _hdy)
{ setbb(_cx-_hdx,_cy-_hdy,_cx+_hdy,_cy+_hdy) ; }
void
Object::setbb( valueType xm,
valueType ym,
valueType xM,
valueType yM ) {
bb.min.x = xm ;
bb.max.x = xM ;
bb.min.y = ym ;
bb.max.y = yM ;
}
/*
// ____ _ _
// | _ \ ___ ___| |_ __ _ _ __ __ _| | ___
// | |_) / _ \/ __| __/ _` | '_ \ / _` | |/ _ \
// | _ < __/ (__| || (_| | | | | (_| | | __/
// |_| \_\___|\___|\__\__,_|_| |_|\__, |_|\___|
// |___/
*/
Rectangle::Rectangle( valueType xm,
valueType ym,
valueType xM,
valueType yM,
bool e )
: filled(e)
{ setbb(xm, ym, xM, yM) ; }
void
Rectangle::draw(Driver *gr) {
gr -> box(bb.min.x,bb.min.y,bb.max.x,bb.max.y,filled) ;
} ;
/*
// ____ _ ____ _ _
// | _ \ ___ _ _ _ __ __| | _ \ ___ ___| |_ __ _ _ __ __ _| | ___
// | |_) / _ \| | | | '_ \ / _` | |_) / _ \/ __| __/ _` | '_ \ / _` | |/ _ \
// | _ < (_) | |_| | | | | (_| | _ < __/ (__| || (_| | | | | (_| | | __/
// |_| \_\___/ \__,_|_| |_|\__,_|_| \_\___|\___|\__\__,_|_| |_|\__, |_|\___|
// |___/
*/
RoundRectangle::RoundRectangle( valueType xm,
valueType ym,
valueType xM,
valueType yM,
valueType r,
bool e )
: ray(r)
, filled(e)
{ setbb(xm, ym, xM, yM) ; }
void
RoundRectangle::draw(Driver *gr) {
gr -> roundBox(bb.min.x,bb.min.y,bb.max.x,bb.max.y,ray,filled) ;
} ;
/*
// _____ _ _ _
// | ____| | (_)_ __ ___ ___
// | _| | | | | '_ \/ __|/ _ \
// | |___| | | | |_) \__ \ __/
// |_____|_|_|_| .__/|___/\___|
// |_|
*/
Ellipse::Ellipse( valueType x, valueType y,
valueType r1, valueType r2,
bool e )
: Object(x,y,r1,r2)
, ray1(r1)
, ray2(r2)
, filled(e)
{}
void
Ellipse::draw(Driver *gr) {
gr -> ellipse(cx(),cy(),ray1,ray2,filled) ;
} ;
/*
// ____ _ _
// / ___| _ _ _ __ ___ | |__ ___ | |
// \___ \| | | | '_ ` _ \| '_ \ / _ \| |
// ___) | |_| | | | | | | |_) | (_) | |
// |____/ \__, |_| |_| |_|_.__/ \___/|_|
// |___/
*/
Symbol::Symbol( valueType _cx,
valueType _cy,
valueType _hdx,
valueType _hdy )
: Object(_cx,_cy,_hdx,_hdy)
{}
void
Symbol::move( valueType xx, valueType yy ) {
valueType tx = xx - cx(), ty = yy - cy() ;
bb.min.x += tx ; bb.max.x += tx ;
bb.min.y += ty ; bb.max.y += ty ;
}
/*
// ____
// / ___| __ _ _ _ __ _ _ __ ___
// \___ \ / _` | | | |/ _` | '__/ _ \
// ___) | (_| | |_| | (_| | | | __/
// |____/ \__, |\__,_|\__,_|_| \___|
// |_|
*/
Square::Square( valueType x,
valueType y,
valueType r,
bool e )
: Symbol(x,y,r,r)
, filled(e)
{}
void
Square::draw(Driver *gr) {
gr -> box(bb.min.x,bb.min.y,bb.max.x,bb.max.y,filled) ;
}
/*
// ____ _ _
// / ___(_)_ __ ___| | ___
// | | | | '__/ __| |/ _ \
// | |___| | | | (__| | __/
// \____|_|_| \___|_|\___|
*/
Circle::Circle( valueType x,
valueType y,
valueType r,
bool e )
: Symbol(x,y,r,r)
, ray(r)
, filled(e)
{}
void
Circle::draw(Driver *gr) {
gr -> circle(cx(),cy(),ray,filled) ;
}
/*
// _____ ____ _ _
// | ___| _ _ __ _ __ _ _ / ___(_)_ __ ___| | ___
// | |_ | | | | '_ \| '_ \| | | | | | | '__/ __| |/ _ \
// | _|| |_| | | | | | | | |_| | |___| | | | (__| | __/
// |_| \__,_|_| |_|_| |_|\__, |\____|_|_| \___|_|\___|
// |___/
*/
FunnyCircle::FunnyCircle( valueType x,
valueType y,
valueType r )
: Symbol(x,y,r,r)
, ray(r)
{}
void
FunnyCircle::draw(Driver *gr) {
gr -> arc(cx(),cy(),ray,-45,45,true) ;
gr -> arc(cx(),cy(),ray,90-45,90+45,false) ;
gr -> arc(cx(),cy(),ray,180-45,180+45,true) ;
gr -> arc(cx(),cy(),ray,270-45,270+45,false) ;
}
/*
// ____ _ _
// | _ \(_) __ _ _ __ ___ ___ _ __ __| |
// | | | | |/ _` | '_ ` _ \ / _ \| '_ \ / _` |
// | |_| | | (_| | | | | | | (_) | | | | (_| |
// |____/|_|\__,_|_| |_| |_|\___/|_| |_|\__,_|
*/
Diamond::Diamond( valueType _x,
valueType _y,
valueType _r,
bool _e )
: Symbol(_x,_y,_r,_r)
, filled(_e)
{}
void
Diamond::draw(Driver *gr) {
gr -> diamond(cx(),cy(),bb.max.x-cx(),filled) ;
}
/*
// ____ _
// / ___|| |_ __ _ _ __
// \___ \| __/ _` | '__|
// ___) | || (_| | |
// |____/ \__\__,_|_|
*/
Star::Star( valueType _x,
valueType _y,
valueType _r,
bool _e )
: Symbol(_x,_y,_r,_r)
, filled(_e)
{}
void
Star::draw(Driver *gr) {
gr -> star(cx(),cy(),bb.max.x-cx(),filled) ;
}
/*
// ____ _
// | _ \| |_ _ ___
// | |_) | | | | / __|
// | __/| | |_| \__ \
// |_| |_|\__,_|___/
*/
Plus::Plus( valueType x, valueType y, valueType r )
: Symbol(x,y,r,r)
{}
void
Plus::draw(Driver *gr) {
gr -> plus(cx(),cy(),bb.max.x-cx()) ;
}
/*
// ____
// / ___|_ __ ___ ___ ___
// | | | '__/ _ \/ __/ __|
// | |___| | | (_) \__ \__ \
// \____|_| \___/|___/___/
*/
Cross::Cross( valueType x, valueType y, valueType r )
: Symbol(x,y,r,r)
{}
void
Cross::draw(Driver *gr) {
gr -> cross(cx(),cy(),bb.max.x-cx()) ;
}
/*
// ____ _ ____
// | _ \| |_ _ ___ / ___|_ __ ___ ___ ___
// | |_) | | | | / __| | | '__/ _ \/ __/ __|
// | __/| | |_| \__ \ |___| | | (_) \__ \__ \
// |_| |_|\__,_|___/\____|_| \___/|___/___/
*/
PlusCross::PlusCross( valueType x, valueType y, valueType r )
: Symbol(x,y,r,r)
{}
void
PlusCross::draw(Driver *gr) {
gr -> plus(cx(),cy(),bb.max.x-cx()) ;
gr -> cross(cx(),cy(),bb.max.x-cx()) ;
}
/*
// _
// / \ _ __ _ __ _____ __
// / _ \ | '__| '__/ _ \ \ /\ / /
// / ___ \| | | | | (_) \ V V /
// /_/ \_\_| |_| \___/ \_/\_/
*/
Arrow::Arrow( valueType _x,
valueType _y,
valueType _dx,
valueType _dy,
ArrowType at )
: x(_x)
, y(_y)
, dx(_dx)
, dy(_dy)
, artype(at)
, Gr::Object(_x+0.5*_dx, _y+0.5*_dy, 0.5*(_dx>0?_dx:-_dx), 0.5*(_dy>0?_dy:-_dy))
{}
void
Arrow::draw(Driver *gr) {
gr->arrow(x,y,dx,dy,artype) ;
}
/*
// _____ _
// |_ _|____ _| |_
// | |/ _ \ \/ / __|
// | | __/> <| |_
// |_|\___/_/\_\\__|
*/
Text::Text( valueType x,
valueType y,
string const & _str,
FontType _font,
FontFace _face,
indexType _size,
FontAlign _align,
valueType _angle )
: font(_font)
, face(_face)
, size(_size)
, align(_align)
, angle(_angle)
{
setText(_str) ;
Gr::Object::setbb(x,y,x,y) ;
}
void
Text::draw(Driver *gr) {
gr -> setFont(font,face,size) ;
gr -> drawText(bb.min.x,bb.min.y,str.c_str(),align,angle) ;
}
}
Declaration of Gr::Graph
class
File: 17/GrGraph.hh:
#ifndef GR_GRAPH_H
#define GR_GRAPH_H
#include "GrObject.hh"
#include <list>
#include <vector>
namespace Gr {
using namespace std ;
typedef struct { valueType xvalue, yvalue ; } Point2D ;
typedef struct {
string name ;
list<Point2D> pnts ;
RgbGolor color ;
Symbol * symbol ;
valueType width ;
indexType lineStyle ;
} GraphItem ;
typedef struct {
FontType font ;
FontFace face ;
indexType size ;
indexType position ;
} Legend ;
class Graph : public Object {
bool drawAxes, drawGrid ;
Text *Title, *subTitle, *xLabel, *yLabel ;
Legend legend ;
valueType title_space, subtitle_space, label_space, item_sep ;
Bbox gbb, gc ;
GrXY step ;
string fmtx, fmty ;
vector<GraphItem> items ;
bool xlog, ylog ;
GrXY tras, scale ;
valueType X(valueType x) { return (x+tras.x)*scale.x ; }
valueType Y(valueType y) { return (y+tras.y)*scale.y ; }
public:
Graph(valueType x, valueType y, valueType dx, valueType dy) ;
virtual ~Graph() ;
void setTitle ( string const & s ) ;
void setSubTitle ( string const & s ) ;
void setXlabel ( string const & s ) ;
void setYlabel ( string const & s ) ;
void xRange(valueType _xmin, valueType _xmax) ;
void yRange(valueType _ymin, valueType _ymax) ;
void setXstep(valueType _xstep) { step.x = _xstep ; }
void setYstep(valueType _ystep) { step.y = _ystep ; }
void setFormatX(string const & s) { fmtx = s ; }
void setFormatY(string const & s) { fmty = s ; }
void setAxesLogarithmic(bool _xlog, bool _ylog) { xlog = _xlog ; ylog = _ylog ; }
void setAxesVisible(bool _axes) { drawAxes = _axes ; }
void setGridVisible(bool _grid) { drawGrid = _grid ; }
void setLegendPosition(indexType pos) { legend.position = pos ; } ;
void newCurve( string const & name,
Symbol * sy,
valueType w,
indexType st,
valueType r,
valueType g,
valueType b ) ;
void addPoint(valueType x, valueType y) ;
void addToCurve(indexType i, valueType x, valueType y) ;
void drawTics(Driver *gr) ;
void drawCurves(Driver *gr) ;
void drawLegend(Driver *gr) ;
virtual void draw(Driver *gr) ;
} ;
}
# endif
Definition of Gr::Graph
class
File: 17/GrGraph.cc:
#include <cmath>
#include <iostream>
#include "GrGraph.hh"
namespace Gr {
using namespace std ;
indexType TITLE_SIZE = 18 ;
indexType SUBTITLE_SIZE = 14 ;
indexType LABEL_SIZE = 12 ;
indexType LEGEND_SIZE = 12 ;
FontType LEGEN_FONT = GR_HELVETICA ;
FontFace LEGEND_FACE = GR_NORMAL ;
indexType TICS_LEN = 3 ;
indexType ITEM_SEP = 3 ;
valueType LINE_WIDTH = 0.6 ;
indexType LINE_STYLE = 0 ;
Graph::Graph(valueType x, valueType y, valueType x1, valueType y1)
: Title(NULL)
, subTitle(NULL)
, xLabel(NULL)
, yLabel(NULL)
, xlog(false)
, ylog(false)
, drawAxes(false)
, drawGrid(false)
{
setbb(x,y,x1,y1) ;
title_space = TITLE_SIZE+4 ;
subtitle_space = SUBTITLE_SIZE+4 ;
label_space = 2*LABEL_SIZE+4 ;
item_sep = ITEM_SEP ;
legend.size = LEGEND_SIZE ;
legend.font = LEGEN_FONT ;
legend.face = LEGEND_FACE ;
legend.position = 0 ;
gc.min.x = gbb.min.x = bb.min.x+label_space ;
gc.min.y = gbb.min.y = bb.min.y+label_space ;
gc.max.x = gbb.max.x = bb.max.x-label_space ;
gc.max.y = gbb.max.y = bb.max.y-title_space-subtitle_space ;
tras.x = tras.y = 0 ;
scale.x = scale.y = 1 ;
step.x = step.y = .2 ;
fmtx = fmty = "%.2lg" ;
} ;
Graph::~Graph() {
if ( Title != NULL ) delete Title ;
if ( subTitle != NULL ) delete subTitle ;
if ( xLabel != NULL ) delete xLabel ;
if ( yLabel != NULL ) delete yLabel ;
} ;
void
Graph::setTitle( string const & s ) {
if ( Title == NULL ) {
Title = new Text(cx(),
bb.max.y-title_space/2,
s,
GR_HELVETICA,
GR_BOLD,
TITLE_SIZE,
GR_ALIGN_CENTER) ;
} else {
Title -> setText(s) ;
}
} ;
void
Graph::setSubTitle( string const & s ) {
if ( subTitle == NULL ) {
subTitle = new Text(cx(),
bb.max.y-title_space-subtitle_space/2,
s,
GR_HELVETICA,
GR_NORMAL,
SUBTITLE_SIZE,
GR_ALIGN_CENTER) ;
} else {
subTitle->setText(s) ;
}
}
void
Graph::setXlabel( string const & s ) {
if ( xLabel == NULL ) {
xLabel = new Text( cx(),
bb.min.y+LABEL_SIZE/2+1,
s,
GR_HELVETICA,
GR_NORMAL,
LABEL_SIZE,
GR_ALIGN_CENTER ) ;
} else {
xLabel -> setText(s) ;
}
}
void
Graph::setYlabel( string const & s ) {
if ( yLabel == NULL ) {
yLabel = new Text( bb.min.x+LABEL_SIZE/2+1,
cy(),
s,
GR_HELVETICA,
GR_NORMAL,
LABEL_SIZE,
GR_ALIGN_CENTER,90 ) ;
} else {
yLabel -> setText(s) ;
}
}
void
Graph::xRange( valueType _xmin, valueType _xmax ) {
gc.min.x = _xmin ;
gc.max.x = _xmax ;
scale.x = (gbb.max.x-gbb.min.x)/(_xmax-_xmin) ;
tras.x = - _xmin + gbb.min.x/scale.x ;
}
void
Graph::yRange( valueType _ymin, valueType _ymax ) {
gc.min.y = _ymin ;
gc.max.y = _ymax ;
scale.y = (gbb.max.y-gbb.min.y)/(_ymax-_ymin) ;
tras.y = - _ymin + gbb.min.y/scale.y ;
}
void
Graph::newCurve( string const & n,
Symbol * sy,
valueType w,
indexType st,
valueType r,
valueType g,
valueType b ) {
GraphItem bf_item ;
bf_item.name = n ;
bf_item.color = RgbGolor(r,g,b) ;
bf_item.symbol = sy ;
bf_item.width = w ;
bf_item.lineStyle = st ;
items.push_back(bf_item) ;
}
void
Graph::addToCurve( indexType i, valueType x, valueType y ) {
Point2D bf ;
bf.xvalue = x ;
bf.yvalue = y ;
items[i-1].pnts.push_back(bf) ;
}
void
Graph::addPoint( valueType x, valueType y ) {
addToCurve(items.size(),x,y) ;
}
void
Graph::drawTics( Driver *gr ) {
gr -> black() ;
if ( drawAxes ) {
gr->line(gbb.min.x,Y(0),gbb.max.x,Y(0)) ;
gr->line(X(0),gbb.min.y,X(0),gbb.max.y) ;
}
string str ;
if ( step.x > 0 ) {
valueType ymi, yma ;
if ( drawGrid ) {
ymi = gbb.min.y ;
yma = gbb.max.y ;
} else {
ymi = gbb.min.y-TICS_LEN ;
yma = gbb.min.y ;
}
indexType is = gc.min.x/step.x - 0.1,
ie = gc.max.x/step.x + 0.1 ;
for ( int i = is ; i <= ie ; i++ ) {
char msg[1000] ;
valueType xx = i*step.x ;
sprintf(msg,fmtx.c_str(),xx) ;
xx = X(xx) ;
gr -> line(xx,ymi,xx,yma) ;
gr -> drawText(xx,ymi-0.6*LABEL_SIZE,msg,GR_ALIGN_CENTER,0) ;
}
}
if ( step.y > 0 ) {
valueType xmi, xma ;
if ( drawGrid ) {
xmi = gbb.min.x ;
xma = gbb.max.x ;
} else {
xmi = gbb.min.x-TICS_LEN ;
xma = gbb.min.x ;
}
indexType js = gc.min.y/step.y - 0.1,
je = gc.max.y/step.y + 0.1 ;
for ( int j = js ; j <= je ; j++ ) {
valueType yy = j*step.y ;
char msg[1000];
sprintf( msg, fmty.c_str(),yy) ;
yy = Y(yy) ;
gr -> line(xmi,yy,xma,yy) ;
gr -> drawText(xmi-0.6*LABEL_SIZE,yy,msg,GR_ALIGN_CENTER,90) ;
}
}
}
void
Graph::drawCurves( Driver *gr ) {
gr -> clip(gbb.min.x,gbb.min.y,gbb.max.x,gbb.max.y) ;
for ( vector<GraphItem>::iterator i = items . begin() ;
i != items . end() ;
++i ) {
Symbol * s = i -> symbol ;
if ( i -> pnts.size() == 0 ) break ;
gr -> rgbColor ( i -> color ) ;
gr -> setLineWidth ( i -> width ) ;
gr -> setLineStyle ( i -> lineStyle ) ;
list<Point2D>::iterator p = i -> pnts . begin() ;
valueType ox = X(p->xvalue) ;
valueType oy = Y(p->yvalue) ;
for ( ++p ; p != i -> pnts . end() ; ++p ) {
valueType nx = X(p->xvalue) ;
valueType ny = Y(p->yvalue) ;
gr -> line(ox,oy,nx,ny) ;
ox = nx ;
oy = ny ;
}
gr->setLineWidth(LINE_WIDTH) ;
gr->setLineStyle(LINE_STYLE) ;
for ( p = i -> pnts . begin() ; p != i->pnts . end() ; ++p ) {
s -> move(X(p->xvalue),Y(p->yvalue)) ;
s -> draw(gr) ;
}
}
}
void
Graph::drawLegend( Driver *gr ) {
if ( legend.position < 1 || items.size() == 0 ) return ;
gr -> setFont(legend.font, legend.face, legend.size) ;
vector<GraphItem>::const_iterator i ;
valueType msx=0, msy=0 ;
for ( i = items . begin() ; i != items . end() ; ++i ) {
Symbol *s = i -> symbol ;
if ( s->wx() > msx ) msx = s->wx() ;
if ( s->wy() > msy ) msy = s->wy() ;
}
// 1 2 3
// 4 5 6
// 7 8 9
valueType xsy, y;
bool on_left = true ;
switch ( legend.position % 3 ) {
case 1:
xsy = gbb.min.x + msx + item_sep ;
on_left = false ;
break ;
case 2:
xsy = (gbb.min.x+gbb.max.x)/2 + msx + item_sep ;
break ;
default:
xsy = gbb.max.x - msx - item_sep ;
break ;
}
switch ( legend.position/3 ) {
case 1:
y = gbb.max.y+item_sep ;
break ;
case 2:
y = (gbb.min.y+gbb.max.y+items.size()*(msy+item_sep))/2 ;
break ;
default:
y = gbb.min.y+items.size()*(msy+item_sep)+item_sep ;
break ;
}
y -= msy/2 ;
for ( i = items . begin() ; i != items . end() ; ++i ) {
gr -> rgbColor ( i -> color ) ;
gr -> setLineWidth ( i -> width ) ;
gr -> setLineStyle ( i -> lineStyle ) ;
Symbol *s = i -> symbol ;
gr -> line(xsy-msx,y,xsy+msx,y) ;
gr -> setLineWidth(LINE_WIDTH) ;
gr -> setLineStyle(LINE_STYLE) ;
s -> move(xsy,y) ;
s -> draw(gr) ;
if ( on_left )
gr -> drawText(xsy-msx-item_sep,y,i->name,GR_ALIGN_LEFT,0) ;
else
gr -> drawText(xsy+msx+item_sep,y,i->name,GR_ALIGN_RIGHT,0) ;
y -= item_sep+msy ;
}
}
void
Graph::draw( Driver *gr ) {
if ( Title != NULL ) Title -> draw(gr) ;
if ( subTitle != NULL ) subTitle -> draw(gr) ;
if ( xLabel != NULL ) xLabel -> draw(gr) ;
if ( yLabel != NULL ) yLabel -> draw(gr) ;
gr->red() ;
gr->box(bb.min.x,bb.min.y,bb.max.x,bb.max.y,false) ;
gr->blue() ;
gr->box(gbb.min.x,gbb.min.y,gbb.max.x,gbb.max.y,false) ;
drawTics(gr) ;
drawCurves(gr) ;
drawLegend(gr) ;
}
}
A driver test program
File: 17/main.cc:
#include <iostream>
#include <cmath>
#include "PsDriver.hh"
#include "GrGraph.hh"
Gr::Graph *G ;
int
main() {
G = new Gr::Graph(10,10,490,400) ;
G->setTitle("Titolo") ;
G->setSubTitle("Sotto Titolo") ;
G->setXlabel("X label") ;
G->setYlabel("Y label") ;
G->newCurve("PIPPO", new Gr::Diamond(0,0,5,true), .5,3,0,0,0) ;
G->newCurve("PLUTO", new Gr::Circle(0,0,5,false), 1,4,1,0,0) ;
G->newCurve("Paperino", new Gr::Square(0,0,5,false),1,5,1,0,0) ;
for ( int i=0 ; i <= 20 ; i++ ) {
Gr::valueType x = 2*i/20.0-1 ;
G->addToCurve(1,x,x) ;
G->addToCurve(2,x,x*x) ;
G->addToCurve(3,x,x*x*x) ;
}
G->setLegendPosition(7) ;
G->xRange(-1,1) ;
G->yRange(-1,1) ;
G->setXstep(0.3) ;
G->setYstep(0.3) ;
G->setAxesVisible(false) ;
//
Gr::PsDriver * ps = new Gr::PsDriver("prova.ps",500,500,false,false) ;
ps->window(0,500,0,500) ;
ps->blue() ;
G->draw(ps) ;
delete ps ;
}
The lesson in a zip file
The zip file lesson5.zip
Lesson of 14 July 2008
Use of map and vector of STL
Read a file and count the words
File: wordcount/main.cc:
/*
A simple program that count words from a file
and print with some statistics.
*/
#include <iostream>
#include <fstream>
#include <cmath>
// from STL
#include <string>
#include <map>
/*
> main pippo pluto
argc = 3
argv[0] = "main"
argv[1] = "pippo"
argv[2] = "pluto"
Usage of the program
> main filename
*/
using namespace std ;
int
main( int argc, char * argv[] ) {
string fileName ;
if ( argc > 2 ) {
// too nuch argument, issue an error
cerr << "usage: " << argv[0] << " file\n" ;
return 1 ;
}
if ( argc == 1 ) {
// only one argument, ask to the user the file name
cout << "File: " ;
cin >> fileName ;
} else {
// two argument, get file name from command line
fileName = argv[1] ;
}
// open the file
ifstream file( fileName . c_str() ) ;
// check if the file exist is opened etc.
if ( file . bad() ) {
cerr << "error in openeing : " << fileName << "\n" ;
return 1 ;
}
map<string,int> wc ; // associative array to store word count
// loop to read all the words
while ( file . good() ) {
string w ;
file >> w ;
// check if w is present in the associative array wc
map<string,int>::iterator i = wc.find(w) ;
if ( i == wc.end() ) {
// element not found
wc[w] = 1 ;
} else {
// element found!
// wc[w]++ ;
// i->first keyword
// i->second value
i->second++ ;
}
}
// close the file
file . close() ;
// write the output
for ( map<string,int>::const_iterator i = wc.begin() ; i != wc.end() ; ++i ) {
cout << i -> first << " " << i -> second << "\n" ;
}
}
Read a file and count the words, resort the count and print only the most frequents
File: wordcount2/main.cc:
/*
A simple program that count word from a file
and print with some statistics.
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <cctype>
// from STL
#include <string>
#include <vector>
#include <map>
/*
> main pippo pluto
argc = 3
argv[0] = "main"
argv[1] = "pippo"
argv[2] = "pluto"
Usage of the program
> main filename
*/
using namespace std ;
// comparator for sort (ascending order)
typedef struct less_than {
//! return always true
bool operator () (pair<string,int> pa, pair<string,int> pb) const {
if ( pa . second < pb . second ) return true ;
if ( pa . second == pb . second ) {
return pa . first < pb . first ;
}
return false ;
}
} ;
// comparator for sort (sescending order)
typedef struct greater_than {
//! return always true
bool operator () (pair<string,int> pa, pair<string,int> pb) const {
if ( pa . second > pb . second ) return true ;
if ( pa . second == pb . second ) {
return pa . first > pb . first ;
}
return false ;
}
} ;
less_than lt ;
greater_than gt ;
int
main( int argc, char * argv[] ) {
string fileName ;
if ( argc > 2 ) {
// too much argument, issue an error
cerr << "usage: " << argv[0] << " file\n" ;
return 1 ;
}
if ( argc == 1 ) {
// only one argument, ask to the user the file name
cout << "File: " ;
cin >> fileName ;
} else {
// two argument, get file name from command line
fileName = argv[1] ;
}
// open the file
ifstream file( fileName . c_str() ) ;
// check if the file exist is opened etc.
if ( file . bad() ) {
cerr << "error in openeing : " << fileName << "\n" ;
return 1 ;
}
map<string,int> wc ; // word count
// loop to read all the words
while ( file . good() ) {
string w1, w ;
file >> w1 ;
w = "" ;
for ( string::iterator i = w1.begin() ; i != w1.end() ; ++i ) {
// string::value_type is the type of the element of the string
// normally string::value_type == char
string::value_type c = tolower(*i) ;
// consider only letters
if ( isalpha(c) ) w . push_back(c) ;
}
// check if w is present in the associative array wc
map<string,int>::iterator i = wc.find(w) ;
if ( i == wc.end() ) {
// element not found, create and initailize to 1
// only if lenght > 0
if ( w . length() > 0 ) wc[w] = 1 ;
} else {
// element found!
i->second++ ;
}
}
// close the file
file . close() ;
// define a vector to store the results
vector<pair<string,int> > vec ;
copy( wc.begin(), wc.end(), back_inserter(vec) ) ;
// the code is equivalent to
// for ( map<string,int>::const_iterator i = wc.begin() ;
// i != wc . end() ; ++i )
// vec . push_back(*i) ;
//
// the "back_inserter" function return an object which implement
// the operator ++ and =. ++ do nothing while
// back_inserter(vec) = rhs
// is transformed to vec.push_back(rhs)!.
// sort the vector
sort( vec.begin(), vec.end(), gt );
// write the output
int nmax = 10 ;
for ( vector<pair<string,int> >::const_iterator i = vec.begin() ;
i != vec.end() && nmax-- > 0 ; ++i ) {
cout << "word = " << setw(10) << left << i -> first
<< " counted N. " << i -> second << " times\n" ;
}
}
The lesson in a zip file
The zip file lesson6.zip
Lesson of 16 July 2008
Solving a Boundary Value Problem with the use of Lapack routines
Solve a simple BVP problem
File: bvp/main.cc:
/*
A simple program that compute approximate solution of
the boundary value problem
y'' + p y' + q y = r
y(a) = ya
y(b) = yb
by finite difference
*/
#include <iostream>
#include <fstream>
#include <cmath>
// from STL
#include <string>
#include <vector>
using namespace std ;
typedef double valueType ;
typedef int indexType ;
/*
Parameter for the specific problem
y'' + y' - x*y = -x^2 ;
*/
static valueType p( valueType x ) { return 1 ; }
static valueType q( valueType x ) { return -x ; }
static valueType r( valueType x ) { return -x*x ; }
/*
Build the coefficient of the tridiagonal matrix
for the problem
// first row
alpha[0] * y[0] + gamma[0] * y[1] = omega[0] - beta[0] * ya
// internal rows
beta[k-1] * y[k-1] + alpha[k] * y[k] + gamma[k] * y[k+1] = omega[k]
// last row
beta[n-2] * y[n-2] + alpha[n-1] * y[n-1] = omega[n-1] - gamma[n-1] * yb
alpha[k] =
| alpha[0] gamma[0] 0 0 0 |
| beta[0] alpha[1] gamma[1] 0 0 |
T = | 0 beta[1] alpha[2] gamma[2] 0 |
| 0 0 beta[2] alpha[3] gamma[3] |
| 0 0 0 beta[3] alpha[4] |
b = [ omega[0], omega[1],...., omega[n-2] ]^T ;
alpha[k] = -2/h^2 + q(x[k+1])
beta[k] = 1/h^2 + p(x[k+2])/(2h)
gamma[k] = 1/h^2 - p(x[k+1])/(2h)
omega[k] = r(x[k+1])
omega[0] = r(x[1])-beta[0]*ya
omega[N-2] = r(x[N-1])-gamma[N-2]*yb
*/
static
void
buildSystem( indexType const N, // number of interval of subdivision
valueType const a, // left boundary
valueType const ya, // value of the solution on left boundary
valueType const b, // right boundary
valueType const yb, // value of the solution on right boundary
vector<valueType> & alpha, // main diagonal
vector<valueType> & beta, // lower diagonal
vector<valueType> & gamma, // upper diagonal
vector<valueType> & omega // r.h.s.
) {
// some check
if ( b <= a ) throw "bad interval" ; // interrupt the code with an exception
if ( N <= 1 ) throw "N must be > 0" ;
// compute the cell size
valueType h = (b-a)/N ;
// initialize the vectors (to size 0)
alpha . clear() ;
beta . clear() ;
gamma . clear() ;
omega . clear() ;
// reserve memory to avoid multiple allocation
alpha . reserve(N-1) ;
beta . reserve(N-2) ;
gamma . reserve(N-2) ;
omega . reserve(N-1) ;
// fill the vector alpha and omega
for ( indexType k = 0 ; k < N-1 ; ++k ) {
valueType xkp1 = a + h * (k+1) ;
alpha . push_back( -2/(h*h) + q(xkp1) ) ;
omega . push_back( r(xkp1) ) ;
}
// fill the vector beta
for ( indexType k = 0 ; k < N-2 ; ++k ) {
valueType xkp2 = a + h * (k+2) ;
beta . push_back( 1/(h*h) + p(xkp2)/(2*h) ) ;
}
// fill the vector gamma
for ( indexType k = 0 ; k < N-2 ; ++k ) {
valueType xkp1 = a + h * (k+1) ;
gamma . push_back( 1/(h*h) - p(xkp1)/(2*h) ) ;
}
// setup boundary conditions
omega.front() -= beta.front() * ya ;
omega.back() -= gamma.back() * yb ;
}
/*
solve the tridiagonal system
| alpha[0] gamma[0] 0 0 0 |
| beta[0] alpha[1] gamma[1] 0 0 |
T = | 0 beta[1] alpha[2] gamma[2] 0 |
| 0 0 beta[2] alpha[3] gamma[3] |
| 0 0 0 beta[3] alpha[4] |
b = [ omega[0], omega[1],...., omega[n-2] ]^T ;
*/
/*
Access to the FORTRAN routine DGTSV
*/
extern "C" void dgtsv( int * N,
int * NRHS,
double * DL,
double * D,
double * DU,
double * B,
int * LDB,
int * INFO );
static
void
solveSystem( vector<valueType> const & alpha, // main diagonal
vector<valueType> const & beta, // lower diagonal
vector<valueType> const & gamma, // upper diagonal
vector<valueType> const & omega, // r.h.s.
vector<valueType> & sol // the solution
) {
// some check
indexType N = alpha.size()+1 ;
if ( beta.size() != N-2 ) throw "bad size for beta " ; // interrupt the code with an exception
if ( gamma.size() != N-2 ) throw "bad size for gamma " ; // interrupt the code with an exception
if ( omega.size() != N-1 ) throw "bad size for omega " ; // interrupt the code with an exception
sol . resize( N-1 ) ;
copy( omega.begin(), omega.end(), sol.begin() ) ;
// working vector
vector<valueType> D(alpha), DU(gamma), DL(beta) ;
indexType n = N-1 ;
indexType one = 1 ;
indexType INFO ;
dgtsv( &n, &one, &DL.front(),
&D.front(),
&DU.front(),
&sol.front(),
&n,
&INFO ) ;
/* INFO (output) INTEGER
* = 0: successful exit
* < 0: if INFO = -i, the i-th argument had an illegal value
* > 0: if INFO = i, U(i,i) is exactly zero, and the solution
* has not been computed. The factorization has not been
* completed unless i = N.
*/
if ( INFO < 0 ) throw "bad argument for dgtsv" ;
if ( INFO > 0 ) throw "singular tridiagonal matrix for for dgtsv" ;
}
int
main( int argc, char * argv[] ) {
indexType N ;
if ( argc > 2 ) {
// too nuch argument, issue an error
cerr << "usage: " << argv[0] << " N\n" ;
return 1 ;
}
if ( argc == 1 ) {
// only one argument, ask to the user the file name
cout << "Number of interval: " ;
cin >> N ;
} else {
// two argument, get file name from command line
scanf( argv[1], "%d", &N ) ;
}
// open the file
ofstream file( "result.txt" ) ;
// check if the file exist is opened etc.
if ( file . bad() ) {
cerr << "error in openeing : result.txt\n" ;
return 1 ;
}
valueType a = 0 ;
valueType ya = 0 ;
valueType b = 1 ;
valueType yb = 2 ;
vector<valueType> alpha, beta, gamma, omega, sol ;
try {
buildSystem( N, a, ya, b, yb, alpha, beta, gamma, omega ) ;
solveSystem( alpha, beta, gamma, omega, sol ) ;
// add initial and final boundary value
sol . push_back( yb ) ;
sol . insert( sol.begin(), ya ) ;
}
catch ( char const msg[] ) {
cerr << "Error found: " << msg << "\n" ;
exit(0) ;
}
catch ( ... ) { // catch any kind of error
cerr << "Unknown error\n" ;
exit(0) ;
}
file << "x\ty\n" ;
indexType k = 0 ;
for ( vector<valueType>::const_iterator i = sol.begin() ;
i != sol.end() ; ++i )
file << (a + (k++)*(b-a)/N) << "\t" << *i << "\n" ;
// close the file
file . close() ;
}
Solve a simple BVP problem with a more customizable interface
File: bvpbetter/main.cc:
/*
A simple program that compute approximate solution of
the boundary value problem
y'' + p y' + q y = r
y(a) = ya
y(b) = yb
by finite difference
*/
#include <iostream>
#include <fstream>
#include <cmath>
// from STL
#include <string>
#include <vector>
#include "Blas.hh"
#include "Lapack.hh"
using namespace std ;
typedef double valueType ;
typedef int indexType ;
/*
Parameter for the specific problem
y'' + y' - x*y = -x^2 ;
*/
static valueType p( valueType x ) { return 1 ; }
static valueType q( valueType x ) { return -x ; }
static valueType r( valueType x ) { return -x*x ; }
/*
Build the coefficient of the tridiagonal matrix
for the problem
// first row
alpha[0] * y[0] + gamma[0] * y[1] = omega[0] - beta[0] * ya
// internal rows
beta[k-1] * y[k-1] + alpha[k] * y[k] + gamma[k] * y[k+1] = omega[k]
// last row
beta[n-2] * y[n-2] + alpha[n-1] * y[n-1] = omega[n-1] - gamma[n-1] * yb
alpha[k] =
| alpha[0] gamma[0] 0 0 0 |
| beta[0] alpha[1] gamma[1] 0 0 |
T = | 0 beta[1] alpha[2] gamma[2] 0 |
| 0 0 beta[2] alpha[3] gamma[3] |
| 0 0 0 beta[3] alpha[4] |
b = [ omega[0], omega[1],...., omega[n-2] ]^T ;
alpha[k] = -2/h^2 + q(x[k+1])
beta[k] = 1/h^2 + p(x[k+2])/(2h)
gamma[k] = 1/h^2 - p(x[k+1])/(2h)
omega[k] = r(x[k+1])
omega[0] = r(x[1])-beta[0]*ya
omega[N-2] = r(x[N-1])-gamma[N-2]*yb
*/
static
void
buildSystem( indexType const N, // number of interval of subdivision
valueType const a, // left boundary
valueType const ya, // value of the solution on left boundary
valueType const b, // right boundary
valueType const yb, // value of the solution on right boundary
vector<valueType> & alpha, // main diagonal
vector<valueType> & beta, // lower diagonal
vector<valueType> & gamma, // upper diagonal
vector<valueType> & omega // r.h.s.
) {
// some check
if ( b <= a ) throw "bad interval" ; // interrupt the code with an exception
if ( N <= 1 ) throw "N must be > 0" ;
// compute the cell size
valueType h = (b-a)/N ;
// initialize the vectors (to size 0)
alpha . clear() ;
beta . clear() ;
gamma . clear() ;
omega . clear() ;
// reserve memory to avoid multiple allocation
alpha . reserve(N-1) ;
beta . reserve(N-2) ;
gamma . reserve(N-2) ;
omega . reserve(N-1) ;
// fill the vector alpha and omega
for ( indexType k = 0 ; k < N-1 ; ++k ) {
valueType xkp1 = a + h * (k+1) ;
alpha . push_back( -2/(h*h) + q(xkp1) ) ;
omega . push_back( r(xkp1) ) ;
}
// fill the vector beta
for ( indexType k = 0 ; k < N-2 ; ++k ) {
valueType xkp2 = a + h * (k+2) ;
beta . push_back( 1/(h*h) + p(xkp2)/(2*h) ) ;
}
// fill the vector gamma
for ( indexType k = 0 ; k < N-2 ; ++k ) {
valueType xkp1 = a + h * (k+1) ;
gamma . push_back( 1/(h*h) - p(xkp1)/(2*h) ) ;
}
// setup boundary conditions
omega.front() -= beta.front() * ya ;
omega.back() -= gamma.back() * yb ;
}
/*
solve the tridiagonal system
| alpha[0] gamma[0] 0 0 0 |
| beta[0] alpha[1] gamma[1] 0 0 |
T = | 0 beta[1] alpha[2] gamma[2] 0 |
| 0 0 beta[2] alpha[3] gamma[3] |
| 0 0 0 beta[3] alpha[4] |
b = [ omega[0], omega[1],...., omega[n-2] ]^T ;
*/
/*
Access to the FORTRAN routine DGTSV
*/
extern "C" void sgtsv( int * N,
int * NRHS,
float * DL,
double * D,
double * DU,
double * B,
int * LDB,
int * INFO );
static
void
solveSystem( vector<valueType> const & alpha, // main diagonal
vector<valueType> const & beta, // lower diagonal
vector<valueType> const & gamma, // upper diagonal
vector<valueType> const & omega, // r.h.s.
vector<valueType> & sol // the solution
) {
// some check
indexType N = alpha.size()+1 ;
if ( beta.size() != N-2 ) throw "bad size for beta " ; // interrupt the code with an exception
if ( gamma.size() != N-2 ) throw "bad size for gamma " ; // interrupt the code with an exception
if ( omega.size() != N-1 ) throw "bad size for omega " ; // interrupt the code with an exception
sol . resize( N-1 ) ;
copy( omega.begin(), omega.end(), sol.begin() ) ;
// working vector
vector<valueType> D(alpha), DU(gamma), DL(beta) ;
indexType INFO = lapack::gtsv( N-1, 1,
&DL.front(),
&D.front(),
&DU.front(),
&sol.front(),
N-1 ) ;
/* INFO (output) INTEGER
* = 0: successful exit
* < 0: if INFO = -i, the i-th argument had an illegal value
* > 0: if INFO = i, U(i,i) is exactly zero, and the solution
* has not been computed. The factorization has not been
* completed unless i = N.
*/
if ( INFO < 0 ) throw "bad argument for dgtsv" ;
if ( INFO > 0 ) throw "singular tridiagonal matrix for for dgtsv" ;
}
int
main( int argc, char * argv[] ) {
indexType N ;
if ( argc > 2 ) {
// too nuch argument, issue an error
cerr << "usage: " << argv[0] << " N\n" ;
return 1 ;
}
if ( argc == 1 ) {
// only one argument, ask to the user the file name
cout << "Number of interval: " ;
cin >> N ;
} else {
// two argument, get file name from command line
scanf( argv[1], "%d", &N ) ;
}
// open the file
ofstream file( "result.txt" ) ;
// check if the file exist is opened etc.
if ( file . bad() ) {
cerr << "error in openeing : result.txt\n" ;
return 1 ;
}
valueType a = 0 ;
valueType ya = 0 ;
valueType b = 1 ;
valueType yb = 2 ;
vector<valueType> alpha, beta, gamma, omega, sol ;
try {
buildSystem( N, a, ya, b, yb, alpha, beta, gamma, omega ) ;
solveSystem( alpha, beta, gamma, omega, sol ) ;
// add initial and final boundary value
sol . push_back( yb ) ;
sol . insert( sol.begin(), ya ) ;
}
catch ( char const msg[] ) {
cerr << "Error found: " << msg << "\n" ;
exit(0) ;
}
catch ( ... ) { // catch any kind of error
cerr << "Unknown error\n" ;
exit(0) ;
}
file << "x\ty\n" ;
indexType k = 0 ;
for ( vector<valueType>::const_iterator i = sol.begin() ;
i != sol.end() ; ++i )
file << (a + (k++)*(b-a)/N) << "\t" << *i << "\n" ;
// close the file
file . close() ;
}
Blas C/FORTRAN interaface
File: bvpbetter/Blas.hh:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2008 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
///
/// file: Blas.hh
///
#ifndef BLAS_HH
#define BLAS_HH
#ifndef F77NAME
#define F77NAME(A) A##_
#endif
#ifndef ATLASNAME
#define ATLASNAME(A) ATL_##A
#endif
namespace blas {
typedef char character ;
typedef int integer ;
typedef float single_precision ;
typedef double double_precision ;
#ifdef USE_ATLAS
/*
// # ####### # # #####
// # # # # # # # #
// # # # # # # #
// # # # # # # #####
// ####### # # ####### #
// # # # # # # # #
// # # # ####### # # #####
*/
enum ATLAS_ORDER {AtlasRowMajor=101, AtlasColMajor=102 };
enum ATLAS_TRANS {AtlasNoTrans=111, AtlasTrans=112,
AtlasConjTrans=113, AtlasConj=114};
enum ATLAS_UPLO {AtlasUpper=121, AtlasLower=122};
enum ATLAS_DIAG {AtlasNonUnit=131, AtlasUnit=132};
extern "C" {
void
ATLASNAME(scopy)( const int N,
const float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(dcopy)( const int N,
const double *X, const int incX,
double *Y, const int incY );
void
ATLASNAME(sswap)( const int N,
float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(dswap)( const int N,
double *X, const int incX,
double *Y, const int incY );
void
ATLASNAME(sscal)( const int N,
const float alpha,
float *X, const int incX );
void
ATLASNAME(dscal)( const int N,
const double alpha,
double *X, const int incX );
void
ATLASNAME(saxpy)( const int N,
const float alpha,
const float *X, const int incX,
float *Y, const int incY );
void
ATLASNAME(daxpy)( const int N,
const double alpha,
const double *X, const int incX,
double *Y, const int incY );
void
ATLASNAME(sger)( const int M, const int N,
const float alpha,
const float *X, const int incX,
const float *Y, const int incY,
float *A, const int lda );
void
ATLASNAME(dger)( const int M, const int N,
const double alpha,
const double *X, const int incX,
const double *Y, const int incY,
double *A, const int lda );
void
ATLASNAME(sgemv)( const enum ATLAS_TRANS TransA,
const int M, const int N,
const float alpha,
const float *A, const int lda,
const float *X, const int incX,
const float beta,
float *Y, const int incY );
void
ATLASNAME(dgemv)( const enum ATLAS_TRANS TransA,
const int M, const int N,
const double alpha,
const double *A, const int lda,
const double *X, const int incX,
const double beta,
double *Y, const int incY );
void
ATLASNAME(sgemm)( const enum ATLAS_TRANS TransA,
const enum ATLAS_TRANS TransB,
const int M, const int N, const int K,
const float alpha,
const float *A, const int lda,
const float *B, const int ldb,
const float beta,
float *C, const int ldc );
void
ATLASNAME(dgemm)( const enum ATLAS_TRANS TransA,
const enum ATLAS_TRANS TransB,
const int M, const int N, const int K,
const double alpha,
const double *A, const int lda,
const double *B, const int ldb,
const double beta,
double *C, const int ldc );
void
ATLASNAME(szero)( const int N, float *X, const int incX );
void
ATLASNAME(dzero)( const int N, double *X, const int incX );
float
ATLASNAME(snrm2)( const int N, const float *X, const int incX );
double
ATLASNAME(dnrm2)( const int N, const double *X, const int incX );
float
ATLASNAME(sasum)( const int N, const float *X, const int incX );
double
ATLASNAME(dasum)( const int N, const double *X, const int incX );
int
ATLASNAME(isamax)( const int N, const float *X, const int incX );
int
ATLASNAME(idamax)( const int N, const double *X, const int incX );
float
ATLASNAME(sdot)( const int N,
const float *X, const int incX,
const float *Y, const int incY );
double
ATLASNAME(ddot)( const int N,
const double *X, const int incX,
const double *Y, const int incY );
}
inline
ATLAS_TRANS
trans_atlas(character const TRANS ) {
switch ( TRANS ) {
case 'N': return AtlasNoTrans ;
case 'T': return AtlasTrans ;
case 'C': return AtlasConjTrans ;
default: throw runtime_error("bad traspose mode selection\n") ;
}
}
inline
ATLAS_UPLO
uplo_atlas(character const UPLO ) {
switch ( UPLO ) {
case 'U': return AtlasUpper ;
case 'L': return AtlasLower ;
default: throw runtime_error("bad UP/LOW mode selection\n") ;
}
}
inline
ATLAS_DIAG
diag_atlas(character const DIAG ) {
switch ( DIAG ) {
case 'U': return AtlasUnit ;
case 'N': return AtlasNonUnit ;
default: throw runtime_error("bad diagonal mode selection\n") ;
}
}
#else
/*
// ##### # ## ####
// # # # # # #
// ##### # # # ####
// # # # ###### #
// # # # # # # #
// ##### ###### # # ####
*/
extern "C" {
void
F77NAME(scopy)( integer const * N,
single_precision const X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
F77NAME(dcopy)( integer const * N,
double_precision const X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
F77NAME(sswap)( integer const * N,
single_precision X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
F77NAME(dswap)( integer const * N,
double_precision X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
F77NAME(sscal)( integer const * N,
single_precision const * S,
single_precision X[],
integer const * INCX ) ;
void
F77NAME(dscal)( integer const * N,
double_precision const * S,
double_precision X[],
integer const * INCX ) ;
void
F77NAME(saxpy)( integer const * N,
single_precision const * A,
single_precision const X[],
integer const * INCX,
single_precision Y[],
integer const * INCY ) ;
void
F77NAME(daxpy)( integer const * N,
double_precision const * A,
double_precision const X[],
integer const * INCX,
double_precision Y[],
integer const * INCY ) ;
void
F77NAME(strsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision X[],
integer const * INCX ) ;
void
F77NAME(dtrsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision X[],
integer const * INCX ) ;
void
F77NAME(sger)( integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const X[],
integer const * INCX,
single_precision const Y[],
integer const * INCY,
single_precision A[],
integer const * LDA ) ;
void
F77NAME(dger)( integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const X[],
integer const * INCX,
double_precision const Y[],
integer const * INCY,
double_precision A[],
integer const * LDA ) ;
void
F77NAME(sgemv)( character const TRANS[],
integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const A[],
integer const * LDA,
single_precision const X[],
integer const * INCX,
single_precision const * BETA,
single_precision Y[],
integer const * INCY ) ;
void
F77NAME(dgemv)( character const TRANS[],
integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const A[],
integer const * LDA,
double_precision const X[],
integer const * INCX,
double_precision const * BETA,
double_precision Y[],
integer const * INCY ) ;
void
F77NAME(sgemm)( character const TRANSA[],
character const TRANSB[],
integer const * M,
integer const * N,
integer const * K,
single_precision const * ALPHA,
single_precision const A[],
integer const * LDA,
single_precision const B[],
integer const * LDB,
single_precision const * BETA,
single_precision C[],
integer const * LDC ) ;
void
F77NAME(dgemm)( character const TRANSA[],
character const TRANSB[],
integer const * M,
integer const * N,
integer const * K,
double_precision const * ALPHA,
double_precision const A[],
integer const * LDA,
double_precision const B[],
integer const * LDB,
double_precision const * BETA,
double_precision C[],
integer const * LDC ) ;
single_precision
F77NAME(snrm2)( integer const * N,
single_precision const X[],
integer const * INCX ) ;
double_precision
F77NAME(dnrm2)( integer const * N,
double_precision const X[],
integer const * INCX ) ;
single_precision
F77NAME(sasum)( integer const * N,
single_precision const X[],
integer const * INCX ) ;
double_precision
F77NAME(dasum)( integer const * N,
double_precision const X[],
integer const * INCX ) ;
integer
F77NAME(isamax)( integer const * N,
single_precision const X[],
integer const * INCX ) ;
integer
F77NAME(idamax)( integer const * N,
double_precision const X[],
integer const * INCX ) ;
single_precision
F77NAME(sdot)( integer const * N,
single_precision const SX[],
integer const * INCX,
single_precision const SY[],
integer const * INCY ) ;
double_precision
F77NAME(ddot)( integer const * N,
double_precision const SX[],
integer const * INCX,
double_precision const SY[],
integer const * INCY ) ;
}
#endif
/* ____ ____ ___ _ _
// | | | |__] \_/
// |___ |__| | |
*/
inline
void
copy( integer const N,
single_precision const X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(scopy)( N, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(scopy)( &N, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
copy( integer const N,
double_precision const X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dcopy)( N, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(dcopy)( &N, X, &INCX, Y, &INCY ) ; }
#endif
/* __ _
// (_ \ / /\ |_)
// __) \/\/ /--\ |
*/
inline
void
swap( integer const N,
single_precision X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(sswap)( N, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(sswap)( &N, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
swap( integer const N,
double_precision X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dswap)( N, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(dswap)( &N, X, &INCX, Y, &INCY ) ; }
#endif
/* ____ ____ ____ _
// [__ | |__| |
// ___] |___ | | |___
*/
inline
void
scal( integer const N,
single_precision const S,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(sscal)(N, S, X, INCX) ; }
#else
{ F77NAME(sscal)(&N, &S, X, &INCX) ; }
#endif
inline
void
scal( integer const N,
double_precision const S,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dscal)(N, S, X, INCX) ; }
#else
{ F77NAME(dscal)(&N, &S, X, &INCX) ; }
#endif
/* ____ _ _ ___ _ _
// |__| \/ |__] \_/
// | | _/\_ | |
*/
inline
void
axpy( integer const N,
single_precision const A,
single_precision const X[],
integer const INCX,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(saxpy)( N, A, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(saxpy)( &N, &A, X, &INCX, Y, &INCY ) ; }
#endif
inline
void
axpy( integer const N,
double_precision const A,
double_precision const X[],
integer const INCX,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(daxpy)( N, A, X, INCX, Y, INCY ) ; }
#else
{ F77NAME(daxpy)( &N, &A, X, &INCX, Y, &INCY ) ; }
#endif
/* __ _ _ _
// / |_ |_) / \
// /_ |_ | \ \_/
*/
inline
void
zero( integer const N,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(szero)( N, X, INCX ) ; }
#else
{ single_precision z = 0 ;
integer iz = 0 ;
F77NAME(scopy)( &N, &z, &iz, X, &INCX ) ; }
#endif
inline
void
zero( integer const N,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dzero)( N, X, INCX ) ; }
#else
{ double_precision z = 0 ;
integer iz = 0 ;
F77NAME(dcopy)( &N, &z, &iz, X, &INCX ) ; }
#endif
/* __ _ _
// /__ |_ |_)
// \_| |_ | \
*/
inline
void
ger( integer const M,
integer const N,
single_precision const ALPHA,
single_precision const X[],
integer const INCX,
single_precision const Y[],
integer const INCY,
single_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(sger)( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) ; }
#else
{ F77NAME(sger)( &M, &N, &ALPHA, X, &INCX, Y, &INCY, A, &LDA ) ; }
#endif
inline
void
ger( integer const M,
integer const N,
double_precision const ALPHA,
double_precision const X[],
integer const INCX,
double_precision const Y[],
integer const INCY,
double_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(dger)( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) ; }
#else
{ F77NAME(dger)( &M, &N, &ALPHA, X, &INCX, Y, &INCY, A, &LDA ) ; }
#endif
/* __ _
// /__ |_ |\/| \ /
// \_| |_ | | \/
*/
inline
void
gemv( character const TRANS[],
integer const M,
integer const N,
single_precision const ALPHA,
single_precision const A[],
integer const LDA,
single_precision const X[],
integer const INCX,
single_precision const BETA,
single_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(sgemv)( trans_atlas(TRANS[0]), M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) ; }
#else
{ F77NAME(sgemv)( TRANS, &M, &N, &ALPHA, A, &LDA, X, &INCX, &BETA, Y, &INCY ) ; }
#endif
inline
void
gemv( character const TRANS[],
integer const M,
integer const N,
double_precision const ALPHA,
double_precision const A[],
integer const LDA,
double_precision const X[],
integer const INCX,
double_precision const BETA,
double_precision Y[],
integer const INCY )
#ifdef USE_ATLAS
{ ATLASNAME(dgemv)( trans_atlas(TRANS[0]), M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) ; }
#else
{ F77NAME(dgemv)( TRANS, &M, &N, &ALPHA, A, &LDA, X, &INCX, &BETA, Y, &INCY ) ; }
#endif
/* ___ _ __
// | |_) (_ \ /
// | | \ __) \/
*/
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
single_precision const A[],
integer const LDA,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(strsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ F77NAME(strsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
double_precision const A[],
integer const LDA,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dtrsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ F77NAME(dtrsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
/* __ _
// /__ |_ |\/| |\/|
// \_| |_ | | | |
*/
inline
void
gemm( character const TRANSA[],
character const TRANSB[],
integer const M,
integer const N,
integer const K,
single_precision const ALPHA,
single_precision const A[],
integer const LDA,
single_precision const B[],
integer const LDB,
single_precision const BETA,
single_precision C[],
integer const LDC )
#ifdef USE_ATLAS
{ ATLASNAME(sgemm)( trans_atlas(TRANSA[0]), trans_atlas(TRANSB[0]),
M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ; }
#else
{ F77NAME(sgemm)( TRANSA, TRANSB,
&M, &N, &K,
&ALPHA, A, &LDA,
B, &LDB,
&BETA, C, &LDC ) ; }
#endif
inline
void
gemm( character const TRANSA[],
character const TRANSB[],
integer const M,
integer const N,
integer const K,
double_precision const ALPHA,
double_precision const A[],
integer const LDA,
double_precision const B[],
integer const LDB,
double_precision const BETA,
double_precision C[],
integer const LDC )
#ifdef USE_ATLAS
{ ATLASNAME(dgemm)( trans_atlas(TRANSA[0]), trans_atlas(TRANSB[0]),
M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ; }
#else
{ F77NAME(dgemm)( TRANSA, TRANSB,
&M, &N, &K,
&ALPHA, A, &LDA,
B, &LDB,
&BETA, C, &LDC ) ; }
#endif
/* _ _
// |\ | |_) |\/| )
// | \| | \ | | /_
*/
inline
single_precision
nrm2( integer const N,
single_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(snrm2)( N, X, INCX ) ; }
#else
{ return F77NAME(snrm2)( &N, X, &INCX ) ; }
#endif
inline
double_precision
nrm2( integer const N,
double_precision const X[],
integer const INCX )
#ifdef USE_ATLAS
{ return ATLASNAME(dnrm2)( N, X, INCX ) ; }
#else
{ return F77NAME(dnrm2)( &N, X, &INCX ) ; }
#endif
/* __
// /\ (_ | ||\/|
// /--\__)|_|| |
*/
inline
single_precision
asum(integer const N,
single_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return ATLASNAME(sasum)( N, X, INCX ) ; }
#else
{ return F77NAME(sasum)( &N, X, &INCX ) ; }
#endif
inline
double_precision
asum(integer const N,
double_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return ATLASNAME(dasum)( N, X, INCX ) ; }
#else
{ return F77NAME(dasum)( &N, X, &INCX ) ; }
#endif
/*
// /\ |\/| /\ \/
// /--\ | | /--\ /\
*/
inline
single_precision
amax(integer const N,
single_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return X[ATLASNAME(isamax)( N, X, INCX )-1] ; }
#else
{ return X[F77NAME(isamax)( &N, X, &INCX )-1] ; }
#endif
inline
double_precision
amax(integer const N,
double_precision const X[],
integer const INCX)
#ifdef USE_ATLAS
{ return X[ATLASNAME(idamax)( N, X, INCX )-1] ; }
#else
{ return X[F77NAME(idamax)( &N, X, &INCX )-1] ; }
#endif
/* _ _ ___
// | \ / \ |
// |_/ \_/ |
*/
inline
single_precision
dot(integer const N,
single_precision const SX[],
integer const INCX,
single_precision const SY[],
integer const INCY)
#ifdef USE_ATLAS
{ return ATLASNAME(sdot)( N, SX, INCX, SY, INCY ) ; }
#else
{ return F77NAME(sdot)( &N, SX, &INCX, SY, &INCY ) ; }
#endif
inline
double_precision
dot(integer const N,
double_precision const SX[],
integer const INCX,
double_precision const SY[],
integer const INCY)
#ifdef USE_ATLAS
{ return ATLASNAME(ddot)( N, SX, INCX, SY, INCY ) ; }
#else
{ return F77NAME(ddot)( &N, SX, &INCX, SY, &INCY ) ; }
#endif
} // end namespace blas
#endif
///
/// eof: Blas.hh
///
Lapack C/FORTRAN interaface
File: bvpbetter/Lapack.hh:
/*--------------------------------------------------------------------------*\
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| Copyright (C) 2008 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Meccanica e Strutturale |
| Universita` degli Studi di Trento |
| Via Mesiano 77, I-38050 Trento, Italy |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
///
/// file: Lapack.hh
///
#ifndef LAPACK_HH
#define LAPACK_HH
#ifndef F77NAME
#define F77NAME(A) A##_
#endif
#ifndef ATLASNAME
#define ATLASNAME(A) ATL_##A
#endif
namespace lapack {
typedef char character ;
typedef int integer ;
typedef float single_precision ;
typedef double double_precision ;
#ifdef USE_ATLAS
/*
// # ####### # # #####
// # # # # # # # #
// # # # # # # #
// # # # # # # #####
// ####### # # ####### #
// # # # # # # # #
// # # # ####### # # #####
*/
enum ATLAS_ORDER {AtlasRowMajor=101, AtlasColMajor=102 };
enum ATLAS_TRANS {AtlasNoTrans=111, AtlasTrans=112,
AtlasConjTrans=113, AtlasConj=114};
enum ATLAS_UPLO {AtlasUpper=121, AtlasLower=122};
enum ATLAS_DIAG {AtlasNonUnit=131, AtlasUnit=132};
extern "C" {
void
ATLASNAME(sgetrs)( const enum ATLAS_ORDER Order,
const enum ATLAS_TRANS Trans,
const int N,
const int NRHS,
const float *A, const int lda,
const int *ipiv,
float *B, const int ldb );
void
ATLASNAME(dgetrs)( const enum ATLAS_ORDER Order,
const enum ATLAS_TRANS Trans,
const int N,
const int NRHS,
const double *A, const int lda,
const int *ipiv,
double *B, const int ldb );
int
ATLASNAME(sgetrf)( const enum ATLAS_ORDER Order,
const int M, const int N,
float *A, const int lda,
int *ipiv );
int
ATLASNAME(dgetrf)( const enum ATLAS_ORDER Order,
const int M, const int N,
double *A, const int lda,
int *ipiv );
void
ATLASNAME(strsv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const float *A, const int lda,
float *X, const int incX );
void
ATLASNAME(dtrsv)( const enum ATLAS_UPLO Uplo,
const enum ATLAS_TRANS TransA,
const enum ATLAS_DIAG Diag,
const int N,
const double *A, const int lda,
double *X, const int incX );
void
ATLASNAME(szero)( const int N, float *X, const int incX );
void
ATLASNAME(dzero)( const int N, double *X, const int incX );
void
ATLASNAME(sgezero)( const int M, const int N, float *C, const int ldc );
void
ATLASNAME(dgezero)( const int M, const int N, double *C, const int ldc );
void
ATLASNAME(sgecopy)( const int M, const int N,
const float *A, const int lda,
float *C, const int ldc );
void
ATLASNAME(dgecopy)( const int M, const int N,
const double *A, const int lda,
double *C, const int ldc );
}
inline
ATLAS_TRANS
trans_atlas(character const TRANS ) {
switch ( TRANS ) {
case 'N': return AtlasNoTrans ;
case 'T': return AtlasTrans ;
case 'C': return AtlasConjTrans ;
default: throw runtime_error("bad traspose mode selection\n") ;
}
}
inline
ATLAS_UPLO
uplo_atlas(character const UPLO ) {
switch ( UPLO ) {
case 'U': return AtlasUpper ;
case 'L': return AtlasLower ;
default: throw runtime_error("bad UP/LOW mode selection\n") ;
}
}
inline
ATLAS_DIAG
diag_atlas(character const DIAG ) {
switch ( DIAG ) {
case 'U': return AtlasUnit ;
case 'N': return AtlasNonUnit ;
default: throw runtime_error("bad diagonal mode selection\n") ;
}
}
#else
/*
// # ## ##### ## #### # #
// # # # # # # # # # # #
// # # # # # # # # ####
// # ###### ##### ###### # # #
// # # # # # # # # # #
// ###### # # # # # #### # #
*/
extern "C" {
void
F77NAME(dgetrf)( integer const * N,
integer const * M,
double_precision A[],
integer const * LDA,
integer IPIV[],
integer * INFO ) ;
void
F77NAME(sgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
single_precision const A[],
integer const * LDA,
integer const IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(dgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
double_precision const A[],
integer const * LDA,
integer const IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(sgetrf)( integer const * N,
integer const * M,
single_precision A[],
integer const * LDA,
integer IPIV[],
integer * INFO ) ;
void
F77NAME(dgetrf)( integer const * N,
integer const * M,
double_precision A[],
integer const * LDA,
integer IPIV[],
integer * INFO ) ;
void
F77NAME(sgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
single_precision const A[],
integer const * LDA,
integer const IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(dgetrs)( character const TRANS[],
integer const * N,
integer const * NRHS,
double_precision const A[],
integer const * LDA,
integer const IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(sgesv)( integer const * N,
integer const * NRHS,
single_precision A[],
integer const * LDA,
integer IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(dgesv)( integer const * N,
integer const * NRHS,
double_precision A[],
integer const * LDA,
integer IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(strsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision X[],
integer const * INCX ) ;
void
F77NAME(dtrsv)( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision X[],
integer const * INCX ) ;
void
F77NAME(slaset)( character const UPLO[],
integer const * M,
integer const * N,
single_precision const * ALPHA,
single_precision const * BETA,
single_precision A[],
integer const * LDA ) ;
void
F77NAME(dlaset)( character const UPLO[],
integer const * M,
integer const * N,
double_precision const * ALPHA,
double_precision const * BETA,
double_precision A[],
integer const * LDA ) ;
void
F77NAME(slacpy)( character const UPLO[],
integer const * M,
integer const * N,
single_precision const A[],
integer const * LDA,
single_precision B[],
integer const * LDB) ;
void
F77NAME(dlacpy)( character const UPLO[],
integer const * M,
integer const * N,
double_precision const A[],
integer const * LDA,
double_precision B[],
integer const * LDB ) ;
}
#endif
/* ____ ____ ___ _ _
// | | | |__] \_/
// |___ |__| | |
*/
inline
void
gecopy( integer const M,
integer const N,
single_precision const A[],
integer const LDA,
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(sgecopy)( M, N, A, LDA, B, LDB ) ; }
#else
{ F77NAME(slacpy)( "A", &M, &N, A, &LDA, B, &LDB ) ; }
#endif
inline
void
gecopy( integer const M,
integer const N,
double_precision const A[],
integer const LDA,
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dgecopy)( M, N, A, LDA, B, LDB ) ; }
#else
{ F77NAME(dlacpy)( "A", &M, &N, A, &LDA, B, &LDB ) ; }
#endif
/* __ _ _ _
// / |_ |_) / \
// /_ |_ | \ \_/
*/
inline
void
gezero( integer const M,
integer const N,
single_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(sgezero)( M, N, A, LDA ) ; }
#else
{ single_precision zero = 0 ;
F77NAME(slaset)( "A", &M, &N, &zero, &zero, A, &LDA ) ; }
#endif
inline
void
gezero( integer const M,
integer const N,
double_precision A[],
integer const LDA )
#ifdef USE_ATLAS
{ ATLASNAME(dgezero)( M, N, A, LDA ) ; }
#else
{ double_precision zero = 0 ;
F77NAME(dlaset)( "A", &M, &N, &zero, &zero, A, &LDA ) ; }
#endif
/* ___ _ __
// | |_) (_ \ /
// | | \ __) \/
*/
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
single_precision const A[],
integer const LDA,
single_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(strsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ F77NAME(strsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
inline
void
trsv( character const UPLO[],
character const TRANS[],
character const DIAG[],
integer const N,
double_precision const A[],
integer const LDA,
double_precision X[],
integer const INCX )
#ifdef USE_ATLAS
{ ATLASNAME(dtrsv)( uplo_atlas(UPLO[0]),
trans_atlas(TRANS[0]),
diag_atlas(DIAG[0]),
N, A, LDA, X, INCX ) ; }
#else
{ F77NAME(dtrsv)( UPLO, TRANS, DIAG, &N, A, &LDA, X, &INCX ) ; }
#endif
/* __ _ ___ _ _
// /__ |_ | |_) |_
// \_| |_ | | \ |
*/
inline
integer
getrf( integer const N,
integer const M,
single_precision A[],
integer const LDA,
integer IPIV[] )
#ifdef USE_ATLAS
{ return ATLASNAME(sgetrf)( AtlasColMajor, N, M, A, LDA, IPIV ) ; }
#else
{ integer INFO ;
F77NAME(sgetrf)( &N, &M, A, &LDA, IPIV, &INFO ) ;
return INFO ; }
#endif
inline
integer
getrf( integer const N,
integer const M,
double_precision A[],
integer const LDA,
integer IPIV[] )
#ifdef USE_ATLAS
{ return ATLASNAME(dgetrf)( AtlasColMajor, N, M, A, LDA, IPIV ) ; }
#else
{ integer INFO ;
F77NAME(dgetrf)( &N, &M, A, &LDA, IPIV, &INFO ) ;
return INFO ; }
#endif
/* __ _ ___ _ __
// /__ |_ | |_) (_
// \_| |_ | | \ __)
*/
inline
integer
getrs( character const TRANS[],
integer const N,
integer const NRHS,
single_precision const A[],
integer const LDA,
integer const IPIV[],
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(sgetrs)( AtlasColMajor, trans_atlas(TRANS[0]), N, NRHS, A, LDA, IPIV, B, LDB ) ;
return 0 ; }
#else
{ integer INFO ;
F77NAME(sgetrs)( TRANS, &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
inline
integer
getrs( character const TRANS[],
integer const N,
integer const NRHS,
double_precision const A[],
integer const LDA,
integer const IPIV[],
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ ATLASNAME(dgetrs)( AtlasColMajor, trans_atlas(TRANS[0]), N, NRHS, A, LDA, IPIV, B, LDB ) ;
return 0 ; }
#else
{ integer INFO ;
F77NAME(dgetrs)( TRANS, &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
/* __ _ __
// /__ |_ (_ \ /
// \_| |_ __) \/
*/
inline
integer
gesv( integer const N,
integer const NRHS,
single_precision A[],
integer const LDA,
integer IPIV[],
single_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ integer INFO = ATLASNAME(sgetrf)(AtlasColMajor, N, N, A, LDA, IPIV);
if ( INFO == 0 ) ATLASNAME(sgetrs)(AtlasColMajor, AtlasNoTrans,
N, NRHS, A, LDA, IPIV, B, LDB) ;
return INFO ; }
#else
{ integer INFO ;
F77NAME(sgesv)( &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
inline
integer
gesv( integer const N,
integer const NRHS,
double_precision A[],
integer const LDA,
integer IPIV[],
double_precision B[],
integer const LDB )
#ifdef USE_ATLAS
{ integer INFO = ATLASNAME(dgetrf)(AtlasColMajor, N, N, A, LDA, IPIV);
if ( INFO == 0 ) ATLASNAME(dgetrs)(AtlasColMajor, AtlasNoTrans,
N, NRHS, A, LDA, IPIV, B, LDB) ;
return INFO ; }
#else
{ integer INFO ;
F77NAME(dgesv)( &N, &NRHS, A, &LDA, IPIV, B, &LDB, &INFO ) ;
return INFO ; }
#endif
extern "C" {
void
F77NAME(sgttrf)( integer const * N,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision DU2[],
integer IPIV[],
integer * INFO ) ;
void
F77NAME(dgttrf)( integer const * N,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision DU2[],
integer IPIV[],
integer * INFO ) ;
void
F77NAME(sgttrs)( character TRANS[],
integer const * N,
integer const * NRHS,
single_precision const DL[],
single_precision const D[],
single_precision const DU[],
single_precision const DU2[],
integer const IPIV[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(dgttrs)( character TRANS[],
integer const * N,
integer const * NRHS,
double_precision const DL[],
double_precision const D[],
double_precision const DU[],
double_precision const DU2[],
integer const IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(sgtsv)( integer const * N,
integer const * NRHS,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision B[],
integer const * LDB,
integer * INFO ) ;
void
F77NAME(dgtsv)( integer const * N,
integer const * NRHS,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision B[],
integer const * LDB,
integer * INFO ) ;
}
/* __ ___ ___ _ _
// /__ | | |_) |_
// \_| | | | \ |
*/
inline
integer
gttrf( integer const N,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision DU2[],
integer IPIV[] )
{ integer INFO ;
F77NAME(sgttrf)( &N, DL, D, DU, DU2, IPIV, &INFO) ;
return INFO ; }
inline
integer
gttrf( integer const N,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision DU2[],
integer IPIV[] )
{ integer INFO ;
F77NAME(dgttrf)( &N, DL, D, DU, DU2, IPIV, &INFO) ;
return INFO ; }
/* __ ___ ___ _ __
// /__ | | |_) (_
// \_| | | | \ __)
*/
inline
integer
gttrs( character TRANS[],
integer const N,
integer const NRHS,
single_precision const DL[],
single_precision const D[],
single_precision const DU[],
single_precision const DU2[],
integer const IPIV[],
single_precision B[],
integer const LDB )
{ integer INFO ;
F77NAME(sgttrs)( TRANS, &N, &NRHS, DL, D, DU, DU2, IPIV, B, &LDB, &INFO) ;
return INFO ; }
inline
integer
gttrs( character TRANS[],
integer const N,
integer const NRHS,
double_precision const DL[],
double_precision const D[],
double_precision const DU[],
double_precision const DU2[],
integer const IPIV[],
double_precision B[],
integer const LDB )
{ integer INFO ;
F77NAME(dgttrs)( TRANS, &N, &NRHS, DL, D, DU, DU2, IPIV, B, &LDB, &INFO) ;
return INFO ; }
/* __ ___ __
// /__ | (_ \ /
// \_| | __) \/
*/
inline
integer
gtsv( integer const N,
integer const NRHS,
single_precision DL[],
single_precision D[],
single_precision DU[],
single_precision B[],
integer const LDB )
{ integer INFO ;
F77NAME(sgtsv)( &N, &NRHS, DL, D, DU, B, &LDB, &INFO ) ;
return INFO ; }
inline
integer
gtsv( integer const N,
integer const NRHS,
double_precision DL[],
double_precision D[],
double_precision DU[],
double_precision B[],
integer const LDB )
{ integer INFO ;
F77NAME(dgtsv)( &N, &NRHS, DL, D, DU, B, &LDB, &INFO ) ;
return INFO ; }
} // end namespace lapack
#endif
///
/// eof: Lapack.hh
///
The lesson in a zip file
The zip file lesson7.zip
Lesson of 17 July 2008
Examples of template metaprograms
Example of class specialization
File: spec1.cc:
/*
Example of class specialization
*/
#include <iostream>
#include <fstream>
#include <cmath>
/*
Define the class vec parametrized with integer N.
*/
template <int N>
class vec {
double vals[N] ;
public:
vec()
{ std::fill( vals, vals + N, 0 ) ; }
vec<N> const & operator = ( vec<N> const & v ) {
std::copy( v.vals, v.vals + N, vals ) ;
}
// many other operators may be defined
double const & operator [] ( int i ) const { return vals[i] ; }
double & operator [] ( int i ) { return vals[i] ; }
} ;
/*
Define external operator + for the class vec parametrized with integer N.
*/
template <int N>
vec<N>
operator + ( vec<N> const & a, vec<N> const & b ) {
vec<N> res ;
for ( int i = 0 ; i < N ; ++i )
res[i] = a[i] + b[i] ;
return res ;
}
/*
Define external operator << for the class vec parametrized with integer N.
*/
template <int N>
std::ostream &
operator << ( std::ostream & s, vec<N> const & a ) {
s << "[ " ;
for ( int i = 0 ; i < N ; ++i )
s << a[i] << " " ;
s << "]" ;
return s ;
}
/*
driver program to test specialization
*/
int
main() {
vec<5> a5 ;
vec<10> a10 ;
a5[3] = 1 ;
a5[2] = 12 ;
a5[1] = 3 ;
std::cout << a5 << "\n" ;
a10[3] = 1 ;
a10[2] = 12 ;
a10[1] = 3 ;
std::cout << a10 << "\n" ;
return 0 ;
}
Another example of class specialization
File: spec2.cc:
/*
Example of class specialization
*/
#include <iostream>
#include <fstream>
#include <cmath>
/*
Define the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
class vec {
public:
// define the type valueType as an alias of type T.
// this will be accessible in this way
// VEC::valueType
// if VEC is an alias of vec<T,N>
typedef T valueType ;
private:
T vals[N] ;
public:
vec()
{ std::fill( vals, vals + N, 0 ) ; }
vec<T,N> const & operator = ( vec<T,N> const & v ) {
std::copy( v.vals, v.vals + N, vals ) ;
}
// many other operators may be defined
T const & operator [] ( int i ) const { return vals[i] ; }
T & operator [] ( int i ) { return vals[i] ; }
} ;
/*
Define external operator + for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
vec<T,N>
operator + ( vec<T,N> const & a, vec<T,N> const & b ) {
vec<T,N> res ;
for ( int i = 0 ; i < N ; ++i )
res[i] = a[i] + b[i] ;
return res ;
}
/*
Define external function "dot" for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
vec<T,N>
dot( vec<T,N> const & a, vec<T,N> const & b ) {
typename vec<T,N>::valueType res ;
res = 0 ;
for ( int i = 0 ; i < N ; ++i )
res += a[i] + b[i] ;
return res ;
}
/*
Define external operator << for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
std::ostream &
operator << ( std::ostream & s, vec<T,N> const & a ) {
s << "[ " ;
for ( int i = 0 ; i < N ; ++i )
s << a[i] << " " ;
s << "]" ;
return s ;
}
int
main() {
vec<double,5> a5 ;
vec<float,10> a10 ;
vec<double,5>::valueType scalar ; // scalar is of type double!.
a5[3] = 1.2 ;
a5[2] = 12 ;
a5[1] = 3 ;
std::cout << a5 << "\n" ;
a10[3] = 1.2 ;
a10[2] = 12 ;
a10[1] = 3 ;
std::cout << a10 << "\n" ;
return 0 ;
}
Example of PARTIAL class specialization
File: partial.cc:
/*
Example of PARTIAL class specialization
*/
#include <iostream>
#include <fstream>
#include <cmath>
/*
Define the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
class vec {
public:
typedef T valueType ;
private:
T vals[N] ;
public:
vec()
{ std::fill( vals, vals + N, 0 ) ; }
vec<T,N> const & operator = ( vec<T,N> const & v ) {
std::copy( v.vals, v.vals + N, vals ) ;
return *this ;
}
// many other operators may be defined
T const & operator [] ( int i ) const { return vals[i] ; }
T & operator [] ( int i ) { return vals[i] ; }
} ;
/*
Define external operator + for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
vec<T,N>
operator + ( vec<T,N> const & a, vec<T,N> const & b ) {
std::cout << "using operator +\n" ;
vec<T,N> res ;
for ( int i = 0 ; i < N ; ++i )
res[i] = a[i] + b[i] ;
return res ;
}
// add a partial specialization of operator +
// for improving performance
template <typename T>
vec<T,2>
operator + ( vec<T,2> const & a, vec<T,2> const & b ) {
std::cout << "using operator + specialized for N=2\n" ;
vec<T,2> res ;
res[0] = a[0] + b[0] ;
res[1] = a[1] + b[1] ;
return res ;
}
// add a partial specialization of operator +
// for improving performance
template <typename T>
vec<T,3>
operator + ( vec<T,3> const & a, vec<T,3> const & b ) {
std::cout << "using operator + specialized for N=3\n" ;
vec<T,3> res ;
res[0] = a[0] + b[0] ;
res[1] = a[1] + b[1] ;
return res ;
}
/*
Define external function "dot" for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
vec<T,N>
dot( vec<T,N> const & a, vec<T,N> const & b ) {
typename vec<T,N>::valueType res ;
res = 0 ;
for ( int i = 0 ; i < N ; ++i )
res += a[i] + b[i] ;
return res ;
}
/*
Define external operator << for the class vec parametrized with integer N and type T.
*/
template <typename T, int N>
std::ostream &
operator << ( std::ostream & s, vec<T,N> const & a ) {
s << "[ " ;
for ( int i = 0 ; i < N ; ++i )
s << a[i] << " " ;
s << "]" ;
return s ;
}
int
main() {
vec<double,2> a2, b2 ;
vec<double,3> a3, b3 ;
vec<double,4> a4, b4 ;
a2 = a2 + b2 ;
a3 = a3 + b3 ;
a4 = a4 + b4 ;
return 0 ;
}
Use of a class as a function, example with midpoint rule
File: midpoint.cc:
/*
Example of class used as function
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
/*
define the class stupid
with the operator () defined and used as a function
*/
class stupid {
double a ;
public:
stupid( double _a ) : a(_a) {}
void setup( double x ) { a = x ; }
double
operator () ( double x ) const
{ return sin(a*x) ; }
} ;
/*
non template version:
double
midpoint( double const a,
double const b,
int const N,
double (FUN*)(double) ) {
}
the function midpoint implement the numerical integration rule
by midpoint formula.
*/
template <typename T>
T
midpoint( T const a,
T const b,
int const N,
T (*FUN)(T) ) {
T res = 0 ;
T h = (b-a)/N ;
for ( int i = 1 ; i < N ; ++i )
res += FUN( a + h * (i-0.5) ) ;
return res * h ;
}
/*
This version of midpoint integration rule is paramtetrized also
with the function argument.
In this way FUN can be any thing that understand operator ()
i.e. a function or an object with deefined the operator ()!.
*/
template <typename T, typename FTYPE>
T
midpoint2( T const a,
T const b,
int const N,
FTYPE FUN ) {
T res = 0 ;
T h = (b-a)/N ;
for ( int i = 1 ; i < N ; ++i )
res += FUN( a + h * (i-0.5) ) ;
return res * h ;
}
/*
a simple function for test
*/
inline
double
fun( double a )
{ return a*a ; }
int
main() {
stupid like_a_function(2) ;
std::cout << like_a_function(1.23) << "\n" ;
double res = midpoint2<double>( 0, 2*M_PI, 1000, like_a_function ) ;
std::cout << "integral = " << res << "\n" ;
res = midpoint2<double>( 0, 2*M_PI, 1000, fun ) ;
std::cout << "integral = " << res << "\n" ;
return 0 ;
}
Example of very simple template metaprogram
File: factorial.cc:
/*
Example of very simple template metaprogram
*/
#include <iostream>
#include <fstream>
#include <cmath>
/*
Define the class factorial.
This class is empty and has a static integer value.
Static variables are "common" to all the instance of the
classes.
*/
template <int N>
class factorial {
public:
/*
Define the static value with the following recurrence.
In this way compiler must instance classes
factorial<N-1>
factorial<N-2>
....
*/
static int const value = N*factorial<N-1>::value ;
/* old compiler must use this trick insted of static int const value:
enum { value = N*factorial<N-1>::value } ;
*/
} ;
/*
Define the s[ecialization of class factorial for N=0.
This close the recursion when a class factorial<N> is instanced.
*/
template <>
class factorial<0> {
public:
static int const value = 1 ;
/* old compiler must use this trick insted of static int const value:
enum { value = 1 } ;
*/
} ;
int
main() {
std::cout << "1! = " << factorial<1>::value << "\n" ;
std::cout << "2! = " << factorial<2>::value << "\n" ;
std::cout << "5! = " << factorial<5>::value << "\n" ;
std::cout << "10! = " << factorial<10>::value << "\n" ;
return 0 ;
}
Bubble sort with template metaprogram
File: bubble.cc:
/*
Example of compile time ordering
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
// standard bubble sort
void
bubbleSort( int data[], int N ) {
for ( int i = N-1 ; i > 0 ; --i )
for ( int j = 0 ; j < i ; ++j )
if ( data[j] > data[i] )
std::swap( data[i], data[j] ) ;
}
// recursive ordering of a vector
void
recursiveSort( int data[], int N ) {
// loop on the vector and put maximum at the end of the vector
for ( int j = 0 ; j < N-1 ; ++j )
if ( data[j] > data[j+1] )
std::swap( data[j], data[j++] ) ;
// at the end of this loop
// data[N-1] is the maximum of the vector
// if N > 2 reapply the algorithm to the vector vec[0..N-2]
if ( N > 2 ) recursiveSort( data, N-1 ) ;
}
// recursive ordering of a vector using template metaprogram
/*
This class implement method compareAndSwap which
compare data[I] and data[J] and if necessary swap it.
*/
template <int I, int J>
class Swap {
public:
static inline void
compareAndSwap( int data[] ) {
if ( data[I] > data[J] ) std::swap( data[I], data[J] ) ;
}
} ;
/*
this class implement method loop which
recursively get the maximum of the vector data[0..N-1]
and put in data[N-1]
*/
template <int N>
class MaxLoop {
public:
static inline void
loop( int data[] ) {
MaxLoop<N-1>::loop(data) ;
Swap<N-2,N-1>::compareAndSwap(data) ;
}
} ;
/*
if the length of the vector is 1 nothing to do
*/
template <>
class MaxLoop<1> {
public:
static inline void
loop( int data[] ) {}
} ;
/*
Sort the vector
*/
template <int N>
class Sort {
public:
static inline void
doSort( int data[] ) {
MaxLoop<N>::loop(data) ;
Sort<N-1>::doSort(data) ;
}
} ;
/*
if the length of the vector is 1 nothing to do
*/
template <>
class Sort<1> {
public:
static inline void
doSort( int data[] ) {}
} ;
/*
Check the ordering
*/
int
main() {
{
int data[] = { 4, 3, -1, 2, 3, -2, 1, 4 } ;
int const N = sizeof(data)/sizeof(data[0]) ;
bubbleSort( data, N ) ;
for ( int i = 0 ; i < N ; ++i )
std::cout << data[i] << ", " ;
std::cout << "\n" ;
}
{
int data[] = { 4, 3, -1, 2, 3, -2, 1, 4 } ;
int const N = sizeof(data)/sizeof(data[0]) ;
recursiveSort( data, N) ;
for ( int i = 0 ; i < N ; ++i )
std::cout << data[i] << ", " ;
std::cout << "\n" ;
}
{
int data[] = { 4, 3, -1, 2, 3, -2, 1, 4 } ;
int const N = sizeof(data)/sizeof(data[0]) ;
Sort<N>::doSort( data ) ;
for ( int i = 0 ; i < N ; ++i )
std::cout << data[i] << ", " ;
std::cout << "\n" ;
}
return 0 ;
}
The lesson in a zip file
The zip file lesson8.zip
Lesson of 23 July 2008
The Barton Nackman trick
File: bntrick.cc:
#include <iostream>
using namespace std ;
/*
The Barton Nackman permit to use "virtual"
function without the overhead of the virtual table
dispatch.
The trick is based on the "derivation" of the base class
from its derived class by the use of template.
This circular definition is perfectly regular due to the
characteristic of C++ compiler which produce instance
of the code only when necessary.
In particular the base class is instaced only when the derived
class is (partially) defined.
*/
/*
* Classical method with VIRTUAL method
*
* A base class with some virtual methods
*/
class Base {
public:
Base() {}
virtual ~Base() {}
virtual void a_method() = 0 ;
} ;
class Derived : public Base {
public:
Derived() : Base() {}
virtual ~Derived() {}
virtual void a_method() {
cout << "a_method, Derived\n" ;
}
} ;
/*
The Barton Nackman trick
*/
/* define the base class parametrizing it with the
derived class */
template <typename DERIVED>
class BaseBN {
public:
BaseBN() {}
~BaseBN() {}
void
a_method() {
/*
* At this point the instruction
* static_cast<DERIVED*>(this)
* reinterpret the pointer this as a pointer to class DERIVED.
* This function is defined only when DERIVED is known
* and the call of the method a_method() is expanded inline
* so that a good compiler with a minimum of optimization
* produce a code without overhead.
*
*/
return static_cast<DERIVED*>(this) -> a_method() ;
}
} ;
/* the derived class inherith from the base class
which is parametrized with the deribed class.
It seems a loop, but the compiler can solve it */
class DerivedBN : public BaseBN<DerivedBN> {
public:
DerivedBN() : BaseBN<DerivedBN>() {}
~DerivedBN() {}
void
a_method() {
cout << "a_method, DerivedBN\n" ;
}
} ;
/*
* In usingBaseClass1 the class Base has a_method virtual so that
* the a_method() is the one of the derived class.
*/
void
usingBaseClass1( Base & derived ) {
derived . a_method() ;
}
/*
* In usingBaseClass2 the class BaseBN has a_method NON virtual but
* the a_method() in base class use the template DERIVED to perform
* the dispatch call to the derived class method.
*/
template <typename DERIVED>
void
usingBaseClass2( BaseBN<DERIVED> & derived ) {
derived . a_method() ;
}
int
main() {
DerivedBN derived2 ;
Derived derived1 ;
cout << "VIRTUAL CLASS\n" ;
derived1 . a_method() ;
usingBaseClass1( derived1 ) ;
cout << "NON VIRTUAL CLASS, STATIC POLIMORPHIS\n" ;
derived2 . a_method() ;
usingBaseClass2( derived2 ) ;
}
Examples of calling C++ from FORTRAN
A supersimple parser written in C++
File: parser.cc:
/*
A simple example of FORTRAN that call C++ code.
The interface pass to routine with C-link interface
in order that FORTRAN can call it.
The interface read from a file the data organized
as columns with the first line a headers
C1 C2 CN <- header line
V1 V2 V2 <- data line with numbers
V1 V2 V2 <- data line with numbers
V1 V2 V2 <- data line with numbers
V1 V2 V2 <- data line with numbers
...
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std ;
// normally fortran add _ (underscore) at the end of the name
#define F77NAME(A) A##_
//mappint of the type with fortran DOUBLE PRECISION and INTEGER
typedef double double_precision ;
typedef int integer ;
/*
Declaration of the C-interface, FORTRAN callable.
*/
extern "C" {
// routine called to parse the file
void
F77NAME(parser_load_file)( char fileName[] ) ;
// ask for the readed dimension (for dynamical allocation or checl).
void
F77NAME(parser_get_dimension)( integer & numRows,
integer & numColumn ) ;
void
F77NAME(parser_get_data)( double_precision A[],
integer & ldA, // dimension of row of matrix A
char S[],
integer & ldS ) ;
}
/* memorize the read data to this vectors */
static vector<vector<double_precision> > a ;
static vector<string> strs ;
extern "C"
void
F77NAME(parser_load_file)( char fileName[] ) {
// step 1: open the file
ifstream file(fileName) ;
// some check ...
// step 2: read the header
string line, str ;
getline( file, line ) ;
// wrap the readed line to the object lineStream of type
// istringstream. This object is a stream object the result
// is that now the string can be read as a file...
istringstream lineStream(line) ;
strs . clear();
while ( lineStream.good() ) {
lineStream >> str ;
if ( str . length() > 0 )
strs . push_back(str) ;
}
// step 2: read the data
a . resize(strs.size()) ;
while ( file.good() ) {
getline( file, line ) ;
// same trick as for the header
istringstream lineStream(line) ;
if ( line . length() > 0 ) {
for ( integer i = 0 ; i < strs.size() ; ++i ) {
double_precision bf ;
lineStream >> bf ;
a[i] . push_back(bf) ;
}
}
}
file . close() ;
}
extern "C"
void
F77NAME(parser_get_dimension)( integer & numRows,
integer & numColumn ) {
numRows = a[0].size() ;
numColumn = a.size() ;
}
extern "C"
void
F77NAME(parser_get_data)( double_precision A[],
integer & ldA, // dimension of row of matrix A
char S[],
integer & ldS ) {
integer numRows = a[0].size() ;
integer numColumn = a.size() ;
for ( integer j = 0 ; j < numColumn ; ++j )
for ( integer i = 0 ; i < numRows ; ++i )
A[i+j*ldA] = a[j][i] ; // j+i*ldA addess of the (i,j) in FORTRAN convection
fill( S, S+numColumn*ldS, ' ' ) ;
for ( integer j = 0 ; j < numColumn ; ++j ) {
copy( strs[j].begin(), strs[j].end(), S+j*ldS ) ;
//for ( integer k = 0 ; k < 100 ; ++k )
// cout << k << " " << (int)S[j*ldS+k] << endl ;
}
}
A fortran driver program
File: main.f:
C
C A driver FORTRAN code to call the C++ code
C
PROGRAM EXAMPLE
DOUBLE PRECISION A(100,100)
CHARACTER*100 fileName, str(100)
INTEGER numRows, numColumn
fileName = 'PIPPO.TXT' // CHAR(0)
CALL parser_load_file( fileName )
CALL parser_get_dimension( numRows, numColumn )
TYPE *, 'numRows=', numRows, ' numColumn=', numColumn
CALL parser_get_data( A, 100, str, 100 )
TYPE *,(TRIM(str(i)),' ',i=1,numColumn)
DO i=1,numRows
TYPE *,(A(i,j),j=1,numColumn)
END DO
END
Using STL string class
A simple program that convert number in letters
File: numberToString.cc:
/*
Convert a number to a string.
For example
123456 = one hundred and twenty three thousads and four hundred and fifty six
*/
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <numeric>
using namespace std ;
typedef int indexType ;
void
splitDigit( indexType number,
vector<indexType> & digits ) {
digits.clear() ;
while ( number > 0 ) {
digits . push_back(number % 10) ;
number /= 10 ;
}
}
// the first 20 number
string num0to19[] = {
"",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eightteen",
"nineteen"
} ;
string num10to100[] = {
"",
"ten",
"twenty",
"thity",
"fourty",
"fifty",
"sixty",
"sevety",
"eighty",
"ninety"
} ;
// convert number from 0 to 999
string
num3digitToString( indexType num ) {
indexType n = num%100 ;
string res = "" ;
if ( n < 20 ) res = num0to19[n] ;
else res = num10to100[n/10]+" "+ num0to19[n%10] ;
indexType c = (num/100) % 10 ;
if ( c > 0 ) {
if ( n > 0 ) res = num0to19[c] + " hundred and " + res ;
else res = num0to19[c] + " hundred " ;
}
return res ;
}
// convert number collect 3 digits at iteration
string
numToString( indexType n ) {
// special case n = 0
if ( n == 0 ) return "zero" ;
string tmb[] = { " ", " thousads ", " millions ", " billions " } ;
string res = "" ;
for ( indexType k = 0 ; n > 0 ; n /= 1000, ++k ) {
string num = num3digitToString( n ) ;
if ( num . length() > 0 && res . length() > 0 ) res = "and " + res ;
if ( num . length() > 0 ) res = num + tmb[k] + res ;
}
return res ;
}
int
main() {
vector<indexType> digits ;
indexType num = 123456 ;
splitDigit( num, digits ) ;
cout << "Split digits for " << num << "=" ;
copy( digits.begin(), digits.end(),
ostream_iterator<indexType>(cout, ":") ) ;
cout << '\n' ;
indexType nums[] = {100, 1000, 1000000, 123, 123456, 10000001, 0, -1 } ;
for ( indexType i = 0 ; nums[i] >= 0 ; ++i ) {
cout << setw(10) << nums[i] << " = " << numToString(nums[i]) << '\n' ;
}
}
The lesson in a zip file
The zip file lesson9.zip
- Modellistica e Simulazione dei Sistemi Meccanici
- Numerical Analysis
- Metodi Matematici e Calcolo per Ingegneria
- Programmazione in C
Corso di Modellistica e Simulazione dei Sistemi Meccanici (AA 2006/2007)
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 10:30 - 13:30 | B4 |
Venerdì | 10.30 - 13.30 | PC OVEST |
versione a schermo modellistica-1x1.pdf
versione stampabile 2 lucidi per foglio modellistica-1x2.pdf
versione stampabile 4 lucidi per foglio modellistica-2x2.pdf
Course of Numerical Analysis (AA 2006/2007)
DAY | HOUR | ROOM |
---|---|---|
Thursday | 11:30 - 13:30 | 203 |
Friday | 10.30 - 13.30 | 203 |
At the homepage ofl Prof. David F. Griffiths of Department of Mathematics, University of Dundee you can find MATLAB lessons (and many more)
Lezione del 1 marzo 2007
Esempio con una ODE elementare
Implementazione MATLAB del metodo di Eulero esplicito per la equazione di un circuito RL:
File: circuito.m:
%
% Soluzione esatta e approssimata con il metodo di Eulero
% della equazione differenziale
% L di(t)/dt + R i(t) = V
% i(0) = i0
%
% Ingresso:
% i0 = corrente iniziale
% V = tensione ai capi del circuito
% R = resistenza
% L = induttanza
% T = tempo finale
% N = numero di punti di griglia da calcolare
% restituisce i vettori
% t(:) = vettore con gli istanti temporali dove la soluzione è calcolata
% i(:) = andamento della corrente calcolato con il metodo di Eulero
% e(:) = andamento della corrente con soluzione esatta
%
function [t,i,e]=circuito(i0,V,R,L,T,N)
t(1) = 0 ;
i(1) = i0 ;
e(1) = i0 ;
h = T/N ;
for k=1:N
% griglia temporale
t(k+1) = t(k) + h;
% soluzione approssimata col metodo di Eulero
i(k+1) = i(k) + (V-R*i(k))*h/L;
% soluzione esatta
e(k+1) = i0*exp(-t(k+1)*R/L) ...
+(V/R)*(1-exp(-t(k+1)*R/L)) ;
end;
end
Programma driver per verificare il codice:
File: test_circuito.m:
i0 = 1 ;
V = 10 ;
R = 1 ;
L = 2 ;
T = 10 ;
N = 30 ;
[t,i,e] = circuito(i0,V,R,L,T,N);
hold off ;
plot(t,i,'.-b');
hold on ;
plot(t,e,'-r');
legend('approssimata','esatta');
Esempio di output:
Metodo di Eulero esplicito
Implementazione MATLAB del metodo di Eulero esplicito:
File: Eulero_esplicito.m:
%
% Metodo di Collatz o Eulero Migliorato per sistemi di equazioni differenziali
%
% Ingresso
% f = funzione per il sistema y'=f(x,y)
% x0, y0 = dato iniziale del problema y(x0) = y0
% xf = estremo superiore dell'intervallo di calcolo [x0,xf]
% N = numero di intervalli in cui suddividere [x0,xf]
%
% Uscita
% x(:) = vettore soluzione delle 'x'
% y(:) = vettore soluzione delle 'y'
%
function [x,y]=Eulero_esplicito(f,x0,y0,X,N)
x(1) = x0;
y(1,:) = y0;
h = X/N ;
for k=1:N
% griglia spazio
x(k+1) = x(k) + h;
% soluzione approssimata col metodo di Eulero
y(k+1,:) = y(k,:) + h*feval(f,x(k),y(k,:));
end;
end
Metodo basato sullo sviluppo di Taylor al secondo ordine
ODE per l’esempio considerato:
File: test_1_yp.m:
%
% Esempio di metodo basato sullo sviluppo di Taylor
%
% funzione f(x,y)
%
function yp=test_1_yp(x,y)
yp = -20.*y+20.*sin(x)+cos(x);
end
Derivata prima della ODE:
File: test_1_ypp.m:
%
% Esempio di metodo basato sullo sviluppo di Taylor
%
% funzione
%
% d f(x,y)
% -------
% d x
%
function ypp=test_1_ypp(x,y)
f = - 20.*y+20.*sin(x)+cos(x);
fx = 20.*cos(x)-sin(x);
fy = - 20.*onex(size(x)) ;
ypp = fx+fy.*f ;
end
Programma MATLAB che implementa il metodo basato sullo sviluppo di Taylor:
File: test_1_taylor.m:
%
% Esempio di metodo basato sullo sviluppo di Taylor
%
% calcolo della soluzione approssimata
%
function [x,y]=test_1_taylor(x0,y0,X,N)
x(1) = x0;
y(1) = y0;
h = X/N ;
for k=1:N
% griglia spazio
x(k+1) = x(k) + h;
% soluzione approssimata col metodo basato su Taylor
yp = test_1_yp(x(k),y(k)) ;
ypp = test_1_ypp(x(k),y(k)) ;
y(k+1) = y(k) + h*yp + (h*h/2)*ypp ;
end;
end
Soluzione esatta del problema:
File: test_1_esatta.m:
%
% Esempio di metodo basato sullo sviluppo di Taylor
%
% soluzione esatta
%
function y=test_1_esatta(x)
y=exp(-20.*x)+sin(x);
end
Programma driver per verificare il codice:
File: test_taylor.m:
x0 = 0 ;
y0 = 1 ;
X = 2 ;
N = 30 ;
[x,y]=test_1_taylor(x0,y0,X,N) ;
hold off ;
plot(x,y,'.-b');
hold on ;
x = [x0:(X-x0)/200:X];
plot(x,test_1_esatta(x),'-r');
legend('approssimata','esatta');
Esempio di output:
Metodo al secondo ordine
Implementazione MATLAB del metodo di Collatz:
File: Collatz.m:
%
% Metodo di Collatz o Eulero Migliorato per sistemi di equazioni differenziali
%
% Ingresso
% f = funzione per il sistema y'=f(x,y)
% x0, y0 = dato iniziale del problema y(x0) = y0
% xf = estremo superiore dell'intervallo di calcolo [x0,xf]
% N = numero di intervalli in cui suddividere [x0,xf]
%
% Uscita
% x(:) = vettore soluzione delle 'x'
% y(:) = vettore soluzione delle 'y'
%
function [x,y]=Collatz(f,x0,y0,xf,N)
x(1) = x0;
y(1,:) = y0;
h = (xf-x0)/N ;
for k=1:N
% griglia spazio
x(k+1) = x(k) + h;
% mezzo passo di Eulero
% y(k+1/2) = y(k) + (h/2)*f(x(k),y(k))
fk = feval(f,x(k),y(k,:));
ykh = y(k,:) + (h/2).*fk;
% correzione di Collatz
% y(k+1) = y(k) + h*f(x(k+1/2),y(k+1/2))
fkh = feval(f,x(k) + h/2,ykh);
y(k+1,:) = y(k,:) + h.*fkh ;
end;
end
Implementazione MATLAB del metodo di Heun:
File: Heun.m:
%
% Metodo di Heun per sistemi di equazioni differenziali
%
% Ingresso
% f = funzione per il sistema y'=f(x,y)
% x0, y0 = dato iniziale del problema y(x0) = y0
% xf = estremo superiore dell'intervallo di calcolo [x0,xf]
% N = numero di intervalli in cui suddividere [x0,xf]
%
% Uscita
% x(:) = vettore soluzione delle 'x'
% y(:) = vettore soluzione delle 'y'
%
%
function [x,y]=Heun(f,x0,y0,xf,N)
x(1) = x0 ;
y(1,:) = y0 ;
h = (xf-x0)/N ;
for k=1:N
% griglia spazio
x(k+1) = x(k) + h;
% passo di Eulero
% ytilde(k+1) = y(k) + h*f(x(k),y(k))
fk = feval(f,x(k),y(k,:));
ytilde = y(k,:) + h*fk;
% correzione di Heun
% y(k+1) = y(k) + (h/2)*(f(x(k),y(k))+f(x(k+1),ytilde(k+1)))
fk1 = feval(f,x(k+1),ytilde);
y(k+1,:) = y(k,:) + h*(fk+fk1)/2 ;
end;
end
Programma driver per verificare i metodi di Collatz, Heun e Eulero:
File: test_multiplo.m:
x0 = 0 ;
y0 = 1 ;
X = 2 ;
N = 30 ;
[x,ye] = Eulero_esplicito (@test_1_yp,x0,y0,X,N) ;
[x,yc] = Collatz (@test_1_yp,x0,y0,X,N) ;
[x,yh] = Heun (@test_1_yp,x0,y0,X,N) ;
hold off ;
plot(x,ye,'.-b');
hold on ;
plot(x,yc,'.-k');
plot(x,yh,'-gs');
x = [x0:(X-x0)/200:X];
plot(x,test_1_esatta(x),'-r','LineWidth',2);
legend('Eulero', ...
'Collatz', ...
'Heun', ...
'Esatta');
Esempio di output:
Esempio per un sistema di ODE
Definizione della ODE:
File: cerchio_yp.m:
%
% Equazioni per il sistema differenziale
%
% x' = y
% y' = -x
%
function Zp=cerchio_yp(t,Z)
Zp(1) = Z(2);
Zp(2) = -Z(1);
end
Programma driver per verificare i metodi di Collatz, Heun e Eulero sulla ODE:
File: test_cerchio.m:
x0 = 0 ;
y0 = 1 ;
X = 10 ;
N = 30 ;
[t,e] = Eulero_esplicito (@cerchio_yp,0,[x0,y0],X,N*2) ;
[t,c] = Collatz (@cerchio_yp,0,[x0,y0],X*2,N) ;
[t,h] = Heun (@cerchio_yp,0,[x0,y0],X*2,N) ;
hold off ;
plot(e(:,1),e(:,2),'.-b');
hold on ;
plot(c(:,1),c(:,2),'.-k');
plot(h(:,1),h(:,2),'-gs');
t = [0:0.01:2*pi];
x = cos(t) ;
y = sin(t) ;
plot(x,y,'-r','LineWidth',2);
legend('Eulero', ...
'Collatz', ...
'Heun', ...
'Esatta');
Esempio di output:
Lezione del 8 marzo 2007
Metodi di Runge-Kutta
Implementazione MATLAB di un generico metodo di Runge-Kutta esplicito:
File: RK.m:
%
% Metodo di Runge-Kutta per sistemi di equazioni differenziali
%
% Ingresso
% f = funzione per il sistema y'=f(x,y)
% x0, y0 = dato iniziale del problema y(x0) = y0
% xf = estremo superiore dell'intervallo di calcolo [x0,xf]
% N = numero di intervalli in cui suddividere [x0,xf]
%
% Tableau struttura con campi
% ns = numero di stadi per il metodo di Runge Kutta
% a(:,:) = matrice
% b(:) = vettore
% c(:) = vettore
%
%
% Uscita
% x(:) = vettore soluzione delle 'x'
% y(:) = vettore soluzione delle 'y'
%
function [x,y]=RK(f,x0,y0,xf,N,TABLEAU)
x(1) = x0 ;
y(1) = y0 ;
h = (xf-x0)/N ;
for k=1:N
% griglia spazio
x(k+1) = x(k) + h;
for s=1:TABLEAU.ns
% calcolo del coefficente Ks
ys = y(k) ;
for j=1:s-1
ys = ys + TABLEAU.a(s,j)*K(j,:) ;
end ;
% xs = x(k) + c(s)*h
% ys = y(k) + somma( a(s,j)* Kj)
xs = x(k)+TABLEAU.c(s)*h ;
K(s,:) = h*feval(f,xs,ys) ;
end;
% y(k+1) = y(k) + somma( b(s) * Ks)
y(k+1,:) = y(k,:) ;
for s=1:TABLEAU.ns
y(k+1,:) = y(k+1,:) + TABLEAU.b(s) * K(s,:) ;
end ;
end;
end
il codice ha bisogno del TABLEAU del metodo in ingresso.
Generazione del TABLEAU per un Runge-Kutta di ordine 3:
File: RK3.m:
function TABLEAU=RK3()
TABLEAU.ns = 3 ;
TABLEAU.c = [0 1/3 2/3] ;
TABLEAU.b = [1/4 0 3/4] ;
TABLEAU.a = [ 0 0 0 ; ...
1/3 0 0 ; ...
0 2/3 0 ] ;
end
Generazione del TABLEAU per un Runge-Kutta di ordine 4:
File: RK4.m:
%
% Tableau di Butcher per Runge-Kutta
% al quarto ordine esplicito (classico)
%
function TABLEAU=RK4()
TABLEAU.ns = 4 ;
TABLEAU.c = [0 1/2 1/2 1] ;
TABLEAU.b = [1/6 1/3 1/3 1/6] ;
TABLEAU.a = [ 0 0 0 0 ; ...
1/2 0 0 0 ; ...
0 1/2 0 0 ; ...
0 0 1 0 ] ;
end
Generazione del TABLEAU per il metodo di Heun:
File: RKHeun.m:
function TABLEAU=RKHeun()
TABLEAU.ns = 2 ;
TABLEAU.c = [0,1] ;
TABLEAU.b = [1/2,1/2] ;
TABLEAU.a = [ 0 0 ; ...
1 0 ] ;
end
Lezione del 9 marzo 2007
Metodi multistep e instabilità
Funzione di test:
File: fun_exp.m:
%
% funzione standard per testare la stabilità
%
function yp=fun_exp(x,y)
yp=-10*y;
end
Metodo multistep instabile:
File: instabile.m:
%
% Risolve la ODE
% y' = -a*y
% y(0) = 1
%
% con il metodo
% y(1) = y(0) + h f(x(0),y(0))
% y(k+1) = y(k-1) + 2 h f(x(k),y(k))
%
function [x,y]=instabile(fun,xf,N)
h = xf / N ;
x(1) = 0 ;
y(1,:) = 1 ;
%% passo Eulero Esplicito
x(2) = x(1) + h ;
f1 = feval(fun,x(1),y(1,:));
y(2,:) = y(1,:) + h * f1 ;
%% ciclo con il metodo multistep
for k=2:N
fk = feval(fun,x(k),y(k,:));
x(k+1) = x(k)+h ;
y(k+1,:) = y(k-1,:)+2*h*fk ;
end
end
Programma driver per verificare il codice:
File: test_instabile.m:
N = 100 ;
[x,y] = instabile (@fun_exp,1,N) ;
hold off ;
plot(x,y,'.-b');
hold on ;
x = [0:0.01:1];
y = exp(-10.*x) ;
plot(x,y,'-r','LineWidth',2);
axis([0 1 -1 2]);
legend('Instabile','Esatta');
Esempio di output:
Metodo multistep instabile con condizioni iniziali esatte:
File: instabile1.m:
%
% Risolve la ODE
% y' = -a*y
% y(0) = 1
%
% con il metodo
% y(1) = 1/(sqrt(1+alpha^2*h^2) + h*alpha)
% y(k+1) = y(k-1) + 2 h f(x(k),y(k))
%
function [x,y]=instabile1(xf,N)
h = xf / N ;
x(1) = 0 ;
y(1,:) = 1 ;
alpha = 10 ;
%% passo Eulero Esplicito
x(2) = x(1) + h ;
y(2,:) = 1/(sqrt(1+alpha^2*h^2) + h*alpha) ;
%% ciclo con il metodo multistep
for k=2:N
fk = - alpha * y(k,:) ;
x(k+1) = x(k)+h ;
y(k+1,:) = y(k-1,:)+2*h*fk ;
end
end
Programma driver per verificare il codice:
File: test_instabile.m:
N = 100 ;
[x,y] = instabile (@fun_exp,1,N) ;
hold off ;
plot(x,y,'.-b');
hold on ;
x = [0:0.01:1];
y = exp(-10.*x) ;
plot(x,y,'-r','LineWidth',2);
axis([0 1 -1 2]);
legend('Instabile','Esatta');
Esempio di output:
Lezione del 15 marzo 2007
Differenze finite per BVP
Funzione di test:
File: p.m:
%
%
function y=p(x)
y = (x-1).*(x+1);
%y = x ;
end
File: q.m:
%
%
function y=q(x)
y = -1-x.^2;
end
File: r.m:
%
%
function y=r(x)
y = -exp(-x) .* (-3 .* sin(x) + 2 .* x.^2.*cos(x) + x.^2.*sin(x));
%y = -exp(-x) .* (-2 * sin(x) + x .* cos(x) + x .* sin(x) + cos(x) + x .^ 2 .* cos(x));
end
Soluzione esatta del problema:
File: yesatta.m:
%
%
function y=yesatta(x)
y = exp(-x) .* cos(x);
end
Solutore:
File: BVPsolve.m:
%
% Risolve il problema BVP
%
% y'' + p(x) y' + q(x) y = r(x)
%
% con diferenze centrate al secondo ordine.
% Il sistema risultante
%
% + + + + + +
% | alpha(1) gamma(1) | | y(1) | | b(1) |
% | beta(2) alpha(2) gamma(2) | | | | |
% | ....... | | .. | = | |
% | | | | | |
% | beta(N-1) alpha(N-1) | | y(N-1) | | b(N-1) |
% + + + + + +
%
% E' risolto con le primitive di MATLAB
%
function [x,y]=BVPsolve(a,ya,b,yb,N)
h = (b-a)/N ;
%for i=1:N-1
% x(i) = a + i*h ;
%end
x = [a+h:h:b-h] ;
% riempimento del vettore alpha
al = -2 + (h^2).*q(x) ;
% riempimento del vettore beta
be = 1 - h.*p(x)./2 ;
% riempimento del vettore gamma
ga = 1 + h.*p(x)./2 ;
% riempimento del vettore r
bvec = h^2.*r(x) ;
% condizioni al contorno
bvec(1) = bvec(1) - be(1) * ya ;
bvec(N-1) = bvec(N-1) - ga(N-1) * yb ;
%
A = sparse(diag(al(1:N-1),0)) + ...
sparse(diag(be(2:N-1),-1)) + ...
sparse(diag(ga(1:N-2),+1)) ;
%A = diag(al(1:N-1),0) + ...
% diag(be(2:N-1),-1) + ...
% diag(ga(1:N-2),+1) ;
% soluzione del sistema
y = A\bvec' ;
spy(A)
end
Programma driver per verificare il codice:
File: test.m:
xi = 0 ;
xf = 10 ;
h = (xf-xi)/1000;
[x,y]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),10);
plot(x,y,'.-b','LineWidth',1.5);
hold;
xe = [xi:h:xf] ;
plot(xe,yesatta(xe),'-r','LineWidth',0.5);
legend('Numerica','Esatta');
Esempio di output
Programma per controllare l’ordine delle differenze finite:
File: testordine.m:
%
% controllo ordine della approssimazione alle
% differenze centrate
%
xi = 0 ;
xf = 10 ;
[x10,y10]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),10);
[x20,y20]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),20);
[x40,y40]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),40);
[x80,y80]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),80);
[x160,y160]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),160);
[x320,y320]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),320);
[x640,y640]=BVPsolve(xi,yesatta(xi),xf,yesatta(xf),640);
err10 = max(abs(y10-yesatta(x10')));
err20 = max(abs(y20-yesatta(x20')));
err40 = max(abs(y40-yesatta(x40')));
err80 = max(abs(y80-yesatta(x80')));
err160 = max(abs(y160-yesatta(x160')));
err320 = max(abs(y320-yesatta(x320')));
err640 = max(abs(y640-yesatta(x640')));
[s,err]=sprintf('log(E10/E20)/log(2) = %f\n',log(err10/err20)/log(2)) ;
disp(s);
[s,err]=sprintf('log(E20/E40)/log(2) = %f\n',log(err20/err40)/log(2)) ;
disp(s);
[s,err]=sprintf('log(E40/E80)/log(2) = %f\n',log(err40/err80)/log(2)) ;
disp(s);
[s,err]=sprintf('log(E80/E160)/log(2) = %f\n',log(err80/err160)/log(2)) ;
disp(s);
[s,err]=sprintf('log(E160/E320)/log(2) = %f\n',log(err160/err320)/log(2)) ;
disp(s);
[s,err]=sprintf('log(E320/E640)/log(2) = %f\n',log(err320/err640)/log(2)) ;
disp(s);
Lezione del 16 marzo 2007
Metodo upwind
Programma che implementa un solutore a differenze finite centrate per un boundary layer (non funziona ovviamente):
File: BLsolve.m:
%
% Risolve il problema BVP
%
% y'' + (1/epsi) y' = (1/epsi)
% y(0) = y(1) = 0
%
% con diferenze centrate al secondo ordine.
% Il sistema risultante
%
% + + + + + +
% | alpha(1) gamma(1) | | y(1) | | b(1) |
% | beta(2) alpha(2) gamma(2) | | | | |
% | ....... | | .. | = | |
% | | | | | |
% | beta(N-1) alpha(N-1) | | y(N-1) | | b(N-1) |
% + + + + + +
%
% E' risolto con le primitive di MATLAB
%
function [x,y]=BLsolve(epsi,N)
h = 1.0/N ;
x = [h:h:1-h] ;
% riempimento del vettore alpha
al = -2.*ones(N-1);
% riempimento del vettore beta
be = (1 - h/(2*epsi)).*ones(N-1) ;
% riempimento del vettore gamma
ga = (1 + h/(2*epsi)).*ones(N-1) ;
% riempimento del vettore r
bvec = h^2.*ones(N-1)./epsi ;
%
A = sparse(diag(al(1:N-1),0)) + ...
sparse(diag(be(2:N-1),-1)) + ...
sparse(diag(ga(1:N-2),+1)) ;
y = A\bvec' ;
end
Programma driver per verificare il codice:
File: test.m:
epsi=1E-6;
[x,y]=BLsolve(epsi,100);
hold off ;
plot(x,y,'.-b','LineWidth',1.5);
hold on ;
xe = [xi:h:xf] ;
plot(xe,yesatta(xe,epsi),'-r','LineWidth',0.5);
legend('Numerica');
axis([0,1,-2,1]);
Programma che implementa un solutore upwind per un boundary layer:
File: BLsolve1.m:
%
% Risolve il problema BVP
%
% y'' + (1/epsi) y' = (1/epsi)
% y(0) = y(1) = 0
%
% con diferenze in avanti per il termine di trasporto (y').
% Il sistema risultante
%
% + + + + + +
% | alpha(1) gamma(1) | | y(1) | | b(1) |
% | beta(2) alpha(2) gamma(2) | | | | |
% | ....... | | .. | = | |
% | | | | | |
% | beta(N-1) alpha(N-1) | | y(N-1) | | b(N-1) |
% + + + + + +
%
% E' risolto con le primitive di MATLAB
%
function [x,y]=BLsolve1(epsi,N)
h = 1.0/N ;
x = [h:h:1-h] ;
% riempimento del vettore alpha
al = -(2+h/epsi).*ones(1,N-1);
% riempimento del vettore beta
be = ones(N-1) ;
% riempimento del vettore gamma
ga = (1 + h/epsi).*ones(1,N-1) ;
% riempimento del vettore r
bvec = h^2.*ones(1,N-1)./epsi ;
%
A = sparse(diag(al(1:N-1),0)) + ...
sparse(diag(be(2:N-1),-1)) + ...
sparse(diag(ga(1:N-2),+1)) ;
y = A\bvec' ;
end
Programma driver per verificare il codice:
File: test1.m:
epsi=1E-6;
[x,y]=BLsolve1(epsi,100);
hold off ;
plot(x,y,'.-b','LineWidth',1.5);
hold on ;
xe = [xi:h:xf] ;
plot(xe,yesatta(xe,epsi),'-r','LineWidth',0.5);
legend('Numerica');
axis([0,1,-2,1]);
Soluzione esatta per fare confronti:
File: yesatta.m:
%
%
function y=yesatta(x,epsi)
y = x - (1-exp(-x.*(1/epsi))) ./ ...
(1-exp(-1/epsi)) ;
end
Lezioni del 13 e 20 aprile 2007
Metodi Numerici per l’equazione del trasporto lineare
Vari dati iniziali: Funzione di Heaviside:
File: h0.m:
%
% Funzione di Heaviside (rovesciata)
%
% -----+
% |
% +---------------
%
function y=h0(x)
%
% se x`e' uno scalare si puo' scrivere cosi:
%
% if (x > 0)
% y = 0;
% else
% y = 1;
% end
%
% nel caso vettoriale bisogna fare un ciclo sulle componenti di x
%
y = zeros(size(x)) ;
[n,m] = size(x) ;
for i=1:n
for j=1:m
if ( x(i,j) < 0 )
y(i,j) = 1;
end
end
end
end
Onda sinusuidale modulata con una campana:
File: p0.m:
%
% onda sinusuidale modulata con una campana
%
% sin(x) / (1+x^2)
%
function y=p0(x)
y = sin(x) ./ (1+x.^2 );
end
Funzione scalino in \([-1,1]\):
File: q0.m:
%
% Funzione scalino in [-1,1]
%
% +-----+
% | |
% ----------+ +---------------
%
function y=q0(x)
%
% se x`e' uno scalare si puo' scrivere cosi:
%
% if (x < -1)
% y = 0;
% else if ( x > 1 )
% y = 0;
% else
% y = 1;
% end
%
% nel caso vettoriale bisogna fare un ciclo sulle componenti di x
%
y = zeros(size(x)) ;
[n,m] = size(x) ;
for i=1:n
for j=1:m
if ( x(i,j) > -1 && x(i,j) < 1 )
y(i,j) = 1;
end
end
end
end
Il seguente programma costruisce la soluzione esatta del problema (con dato iniziale p0.m):
File: p.m:
%
% Soluzione esatta del problema
%
% q (x,t) - x t q (x,t) = 0 dato iniziale q(x,0) = q0(x)
% t x
%
%
% q(x,t) = q0(x e^(t^2/2) )
%
function y=p(x,t)
y = p0( x .* exp(t^2/2) ) ;
end
\[ q_t(x,t)-xtq(x,t)=0 \]
Il seguente programma costruisce la soluzione esatta del problema (con dato iniziale q0.m
):
File: q.m:
%
% Soluzione esatta del problema
%
% q (x,t) - x t q (x,t) = 0 dato iniziale q(x,0) = q0(x)
% t x
%
%
% q(x,t) = q0(x e^(t^2/2) )
%
function y=q(x,t)
y = q0( x .* exp(t^2/2) ) ;
end
Programmi driver per verificare varie soluzioni:
File: test.m:
hold off ;
x = [-2:0.01:2] ;
plot(x,q0(x),'.-b','LineWidth',1.5) ; hold on ;
plot(x,q(x,1),'+-r') ; hold on ;
plot(x,q(x,2),'o-y') ; hold on ;
plot(x,q(x,3),'.-m') ; hold on ;
plot(x,q(x,4),'.-g') ; hold on ;
legend('q0','t=1','t=2','t=3','t=4');
axis([-2,2,-0.1,1.1]);
File: test1.m:
hold off ;
x = [-2:0.01:2] ;
plot(x,p0(x),'.-b','LineWidth',1.5) ; hold on ;
plot(x,p(x,1),'+-r') ; hold on ;
plot(x,p(x,2),'o-y') ; hold on ;
plot(x,p(x,3),'.-m') ; hold on ;
plot(x,p(x,4),'.-g') ; hold on ;
legend('p0','t=1','t=2','t=3','t=4');
axis([-2,2,-0.5,0.5]);
File: test2.m:
hold off ;
beta = -0.5 ;
x = [-2:0.01:2] ;
plot(x,q0(x),'.-b','LineWidth',1.5) ; hold on ;
plot(x,esatta(x,1,beta,@q0),'+-r') ; hold on ;
plot(x,esatta(x,2,beta,@q0),'o-y') ; hold on ;
plot(x,esatta(x,3,beta,@q0),'.-m') ; hold on ;
plot(x,esatta(x,4,beta,@q0),'.-g') ; hold on ;
legend('p0','t=1','t=2','t=3','t=4');
axis([-2,2,-0.1,1.1]);
File: test3.m:
hold off ;
alpha = 0.5 ;
x = [-5:0.01:5] ;
plot(x,h0(x),'.-b','LineWidth',1.5) ; hold on ;
plot(x,trasporto(x,1,alpha,@h0),'+-r') ; hold on ;
plot(x,trasporto(x,2,alpha,@h0),'o-y') ; hold on ;
plot(x,trasporto(x,3,alpha,@h0),'.-m') ; hold on ;
plot(x,trasporto(x,4,alpha,@h0),'.-g') ; hold on ;
legend('p0','t=1','t=2','t=3','t=4');
axis([-5,5,-0.1,1.1]);
Programma driver che permette di generare la soluzione esatta dato un profilo iniziale:
File: trasporto.m:
%
% Soluzione esatta del problema
%
% q (x,t) + alpha q (x,t) = 0 dato iniziale q(x,0) = q0(x)
% t x
%
%
% q(x,t) = q0(x - alpha * t )
%
function y=trasporto(x,t,alpha,q0)
y = q0( x - alpha .* t ) ;
end
Lezione del 10 maggio 2007
Metodi Numerici per l’equazione del trasporto lineare
Programma che implementa vari solutori per l’equazione del trasporto lineare:
File: LagenSolver.m:
%
% A selection of 8 schemes for the linear advection equation
%
% Name of program: LagenSolver
%
% Purpose: to solve the linear advection equation with constant
% coefficient by a selection of 8 schemes, namely:
%
% The Godunov first-order upwind scheme
% The Toro-Billett first-order upwind scheme
% The Lax-Friedrichs scheme (first-order centred)
% The FORCE scheme (first-order centred)
% The Godunov first-order centred scheme
% The Lax-Wendroff scheme (second order, oscillatory)
% The Fromm scheme (second order, oscillatory)
% The Warming-Beam scheme (second order, oscillatory)
%
% Programer: Enrico Bertolazzi
% (based on the Fortran NUMERICA lib of prof. E. F. Toro )
%
% Last revision: 10st May 2007
%
% Theory is found in Chaps. 5, 7 and 13 of Reference 1
% and in original references therein
%
% 1. E. F. Toro, "Riemann Solvers and Numerical Methods for Fluid Dynamics"
% Springer-Verlag, 1997
% Second Edition, 1999
%
% This program is transaled in MATLAB from the NUMERICA library:
%
% NUMERICA
% A Library of Source Codes for Teaching,
% Research and Applications,
% by E. F. Toro
% Published by NUMERITEK LTD,
% Website: www.numeritek.coM
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PURPOSE:
%
% solve the linear advection problem
%
% u (t,x) + a u (t,x) = 0 t > 0, -1 <= x <= 1
% t x
%
% u(0,x) = u0(x) -1 <= x <= 1
%
% INPUT:
% PRB A Structure describing the problem with fields
% problem = an integer selectiong the numerical flux used
% 1 - The Godunov first-order upwind scheme
% 2 - The Toro-Billett first-order upwind scheme
% 3 - The Lax-Friedrichs scheme (first-order centred)
% 4 - The FORCE scheme (first-order centred)
% 5 - The Godunov first-order centred scheme
% 6 - The Lax-Wendroff scheme (second order, oscillatory)
% 7 - The Fromm scheme (second order, oscillatory)
% 8 - The Warming-Beam scheme (second order, oscillatory)
% init = an integer selectiong the initial data used
% 1 - square wave
% 2 - smooth wave
% Ncells = number of cell discretizing [-1,1] the domain of the problems
% CFL = time step advancing CFL ratio
% a = speed of the signal of the PDE
% StepTime = solution is saved every StepTime
% FinalTime = solution is computed up to FinalTime
%
% OUTPUT:
% X = the cell boundary of the subdivided interval [-1,1]; X(1) = -1,..., X(N) = 1
% UFRAMES = matrix with the frames of the computed solution. UFRAMES(i,:) is the solution
% at time level i-th
% TFRAMES = vector with the time frames. TFRAMES(i) the time of the computed frame UFRAMES(i,:).
%
% Example of use
%
% PRB . problem = 1 % select Godunov first-order upwind scheme
% PRB . init = 1 % select square wave for initial data
% PRB . Ncells = 100 % select 100 cell inteval subdivision
% PRB . CFL = 0.9 % advance with DT do not excede 0.9 * CFL
% PRB . a = 0.1 % speed of teh signal
% PRB . StepTime = 0.5 % save the frame every 0.5 second
% PRB . FinalTime = 3 % compute the solution op to 3 second
%
% call the solver
% [X,UFRAMES,TFRAMES] = LagenSolver(PRB) ;
%
% plot the solution al frame n. 30
% plot( X, UFRAMES(30,:) );
%
function [X,UFRAMES,TFRAMES] = LagenSolver(PRB)
N = PRB.Ncells ;
% Initial conditions are set up
switch( PRB . init )
case 1
[X,U,DX] = InitSquare(N) ;
case 2
[X,U,DX] = InitSmooth(N) ;
end
% maximum speed
SMAX = abs(PRB.a) ;
k = 1 ;
Time = 0 ;
NextTime = PRB.StepTime ;
% save initial frame
UFRAMES(k,:) = U ;
TFRAMES(k) = Time ;
% Time marching procedure
for i=1:1000
% Boundary conditions are cyclic so we set ciclycally the vectors
ULL = [ U(N-1), U(N), U(1:N-1) ] ;
UL = [ U(N), U ] ;
UR = [ U, U(1) ] ;
URR = [ U(2:N), U(1), U(2) ] ;
% Courant-Friedrichs-Lewy (CFL) condition imposed
DT = PRB.CFL*DX/SMAX ;
Time = Time + DT ;
% adjust time step if necessary to match the time grid
if Time >= NextTime
% reduce DT in order to match NextTime
DT = DT - ( Time - NextTime ) ;
Time = NextTime ;
NextTime = NextTime + PRB.StepTime ;
k = -k ; % mark solution to be saved
end
% Intercell numerical fluxes are computed.
switch( PRB . problem )
case 0
FLUX = Centered (UL, UR, PRB.a, DT, DX ) ;
case 1
FLUX = Godunov (UL, UR, PRB.a, DT, DX ) ;
case 2
FLUX = ToroBillet (ULL, UL, UR, URR, PRB.a, DT, DX ) ;
case 3
FLUX = LaxFriedrichs (UL, UR, PRB.a, DT, DX ) ;
case 4
FLUX = Force (UL, UR, PRB.a, DT, DX ) ;
case 5
FLUX = GodunovCentered (UL, UR, PRB.a, DT, DX ) ;
case 6
FLUX = Richtmyer (UL, UR, PRB.a, DT, DX ) ;
case 7
FLUX = Fromm (ULL, UL, UR, URR, PRB.a, DT, DX ) ;
case 8
FLUX = WarmingBeam (ULL, UL, UR, URR, PRB.a, DT, DX ) ;
end
% Solution is updated according to conservative formula
U = U + (DT/DX) .* (FLUX(1:N) - FLUX(2:N+1)) ;
% if k < 0 solution must be saved
if k < 0
k = -k+1 ;
UFRAMES(k,:) = U ;
TFRAMES(k) = Time ;
end
if Time >= PRB.FinalTime
break ;
end
end
end
%
% Purpose: to set initial conditions for solution U
%
function [X,U,DX] = InitSmooth(N)
% Calculate mesh size DX
DX = 2.0/N ;
% Initialise arrays (index 1,2 and IDIM+3, IDIM+4 are used for "ghost cells")
% smooth profile
X = [-1+DX/2:DX:1-DX/2] ;
U = exp( -8 .* X .^ 2 ) ;
end
%
function [X,U,DX] = InitSquare(N)
% Calculate mesh size DX
DX = 2.0/N ;
N3 = floor(N/3) ;
M = N - N3 - N3 ;
% Initialise arrays
X = [-1+DX/2:DX:1-DX/2] ;
U = [zeros(1,N3) ones(1,M) zeros(1,N3) ] ;
end
%
%
% positioning of the variables
%
% U(1) U(2) U(3) U(N)
% +------+------+------+------+------+- +------+
% | | | | | | ... | |
% F(1) F(2) F(3) F(N) F(N+1)
%
% U(i) is the cell average allocated to center of the cell i.
% F(i) is the flux at the interface between cells i end cell i-1.
% Purpose: to compute intercell fluxes as left and right average: CANNOT WORK
%
function F = Centered(UL,UR,a,DT,DX)
F = (a/2) .* (UL+UR) ;
end
% Purpose: to compute intercell fluxes according to the
% Godunov first order upwind method
%
function F = Godunov(UL,UR,a,DT,DX)
% the flux at interface i is computed
if a > 0
% using the left state
F = a .* UL ;
else
% using the right state
F = a .* UR ;
end
end
%
% Purpose: to compute intercell fluxes according to the
% Toro-Billett first order CFL-2 scheme
% See Eq. 13.22, Chapter 13, Ref. 1
function [FLUX] = ToroBillet(ULL,UL,UR,URR,a,DT,DX)
CFLNUM = a*DT/DX ;
if ( abs(CFLNUM) <= 1 )
% Conventional Godunov upwind flux
FLUX = Godunov(UL,UR,a,DT,DX) ;
else
if a > 0
% Information travels from the left
cfll = ((CFLNUM - 1)/CFLNUM) * a ;
cfl = (1.0/CFLNUM) * a ;
FLUX = cfll * ULL + cfl * UL ;
else
% Information travels from the right
cfrr = ((CFLNUM + 1)/CFLNUM) * a ;
cfr = -(1.0/CFLNUM) * a ;
FLUX = cfl * UL + cfr * UR ;
end
end
end
% Purpose: to compute intercell fluxes according to the
% Lax-Friedrichs method
% See Eq. 5.77, Chapter 5, Ref. 1
function [FLUX] = LaxFriedrichs(UL,UR,a,DT,DX)
CFLNUM = a*DT/DX ;
FLUX = 0.5 .* ( a .* (UL+UR) + (DX/DT) * (UL-UR) ) ;
end
% Purpose: to compute intercell fluxes according to the
% Force method
% See Eq. 7.32, Chapter 7, Ref. 1
function [FLUX] = Force(UL,UR,a,DT,DX)
CFLNUM = a*DT/DX ;
% Compute Lax-Friedrichs flux
FluxLF = 0.5 .* ( a .* (UL+UR) + (DX/DT) * ( UL-UR ) ) ;
% Compute Richtmyer flux
FluxR = 0.5 .* a .* ( (UL + UR) + (DT/DX) .* a .* ( UL - UR ) ) ;
% Compute Force flux
FLUX = 0.5*(FluxLF + FluxR) ;
end
% Purpose: to compute intercell fluxes according to the
% Godunov first order upwind method
% See Eq. 13.73, Chapter 13, Ref. 1
function FLUX = GodunovCentered(UL,UR,a,DT,DX)
CFLNUM = a*DT/DX ;
FLUX = 0.5 .* a .* ( (1+2*CFLNUM) * UL + ( 1-2*CFLNUM) * UR ) ;
end
% Purpose: to compute intercell fluxes according to the
% Richtmyer method, or two step Lax-Wendroff method
% See Eq. 5.79, Chapter 5, Ref. 1
function FLUX = Richtmyer(UL,UR,a,DT,DX)
FLUX = 0.5 .* a .* ( (UL + UR) + (DT/DX) .* a .* ( UL - UR ) ) ;
end
% Purpose: to compute intercell fluxes according to the
% Fromm first order upwind method
% See Eq. 13.35, Chapter 13, Ref. 1
function FLUX = Fromm(ULL,UL,UR,URR,a,DT,DX)
CFLNUM = a*DT/DX ;
if ( a > 0 )
FLUX = a .* (UL + 0.25 .* (1-CFLNUM) .* (UR - ULL)) ;
else
FLUX = a .* (UR - 0.25 .* (1+CFLNUM) .* (URR - UR)) ;
end
end
% Purpose: to compute intercell fluxes according to the
% Warming-Beam method
% See Eq. 13.21, Chapter 13, Ref. 1
function FLUX = WarmingBeam(ULL,UL,UR,URR,a,DT,DX)
CFLNUM = a*DT/DX ;
if ( a > 0 )
FLUX = 0.5 .* a .* ( (3-CFLNUM) .* UL - (1-CFLNUM) .* ULL );
else
FLUX = 0.5 .* a .* ( (3+CFLNUM) .* UR - (1+CFLNUM) .* URR );
end
end
Programma driver per verificare il codice:
File: LagenExample.m:
PRB . problem = 8 ; % select Godunov first-order upwind scheme
PRB . init = 1 ; % select square wave for initial data
PRB . Ncells = 100 ; % select 100 cell inteval subdivision
PRB . CFL = 0.49 ; % advance with DT do not excede 0.9 * CFL
PRB . a = 0.25 ; % speed of the signal
PRB . StepTime = 1 ; % save the frame every 0.5 second
PRB . FinalTime = 200 ; % compute the solution op to 3 second
% call the solver
[X,UFRAMES,TFRAMES] = LagenSolver(PRB) ;
% generate movie of the solution
LagenMovie(X,UFRAMES,TFRAMES) ;
% plot the solution al frame n. 4
%[,N] = size(TFRAMES) ;
%plot( X, UFRAMES(N,:) );
Programma driver che permette di generare un filmato avi della soluzione:
File: LagenMovie.m:
function aviobj = LagenMovie(X,UFRAMES,TFRAMES)
[dummy,nframes] = size(TFRAMES) ;
aviobj = avifile('example.avi')
rect = [100 100 612 612] ;
fig = figure('position',rect) ;
set(fig,'DoubleBuffer','on');
axis manual ;
title('Lagen Movie');
for i=1:nframes
clc;
plot(X, UFRAMES(i,:),'-ob','MarkerFaceColor','r');
axis([-1 1 -0.5 1.5]);
aviobj = addframe(aviobj,getframe(fig));
end
aviobj = close(aviobj);
end
Soluzione esatta per fare confronti:
File: LagenExactSquare.m:
%
%
function [X,U] = LagenExactSquare(N,TIME,SPEEDA)
% Calculate mesh size DX
DX = 2.0/N ;
X = [-1+DX/2-TIME*SPEEDA:DX:1-DX/2-TIME*SPEEDA] ;
% put the solution in [-1..1]
U = zeros(1,N) ;
for i=1:N
while ( X(i) < -1 )
X(i) = X(i) + 2 ;
end ;
while ( X(i) > 1 )
X(i) = X(i) - 2 ;
end ;
if X(i) >= -1/3.0 && X(i) <= 1/3.0
U(i) = 1 ;
end
end
% smooth profile
X = [-1+DX/2:DX:1-DX/2] ;
end
File: LagenExactSmooth.m:
%
% Purpose: to set initial conditions for solution U and
% initialise other variables.
%
% Variables:
%
% U Array for numerical solution
%
function [X,U] = LagenExactSmooth(N,TIME,SPEEDA)
% Calculate mesh size DX
DX = 2.0/N ;
X = [-1+DX/2-TIME*SPEEDA:DX:1-DX/2-TIME*SPEEDA] ;
% put the solution in [-1..1]
for i=1:N
while ( X(i) < -1 )
X(i) = X(i) + 2 ;
end ;
while ( X(i) > 1 )
X(i) = X(i) - 2 ;
end ;
end
% smooth profile
U = exp( -8 .* X .^ 2 ) ;
X = [-1+DX/2:DX:1-DX/2] ;
end
Corso di Metodi Matematici e Calcolo per Ingegneria (AA 2006/2007)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 13:30 - 16:30 | T4 |
Martedì | 9.30 - 11.30 | T1A |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 10 - 12 | 505 |
Dispense del corso
Lucidi sulla trasformata di Laplace
versione a schermo laplace-trasformata-1x1.pdf
versione stampabile 2 lucidi per foglio laplace-trasformata-1x2.pdf
versione stampabile 4 lucidi per foglio laplace-trasformata-2x2.pdf
Soluzione di un sistema di 3 equazioni differenziali del primo ordine con Laplace esempio1.pdf
Soluzione di un sistema di 3 equazioni differenziali del secondo ordine con Laplace esempio2.pdf
Esempio di riduzione a fratti semplici esempio3.pdf
Esempio di soluzione di una ODE a coefficienti costanti esempio4
Lucidi sulla trasformata Z
versione a schermo Z-trasformata-1x1.pdf
versione stampabile 2 lucidi per foglio Z-trasformata-1x2.pdf
versione stampabile 4 lucidi per foglio Z-trasformata-2x2.pdf
Lucidi sulle serie di Fourier
versione a schermo Fourier-1x1.pdf
versione stampabile 2 lucidi per foglio Fourier-1x2.pdf
versione stampabile 4 lucidi per foglio Fourier-2x2.pdf
Lucidi sul metodo dei moltiplicatori di Lagrange
versione a schermo Minimi-1x1.pdf
versione stampabile 2 lucidi per foglio Minimi-1x2.pdf
versione stampabile 4 lucidi per foglio Minimi-2x2.pdf
I seguenti appunti sono in inglese e sovrabbondanti per il Corso ma possono comunque essere utili per la preparazione all’esame
versione a schermo slides-1D-1x1.pdf
versione stampabile 2 lucidi per foglio slides-1D-1x2.pdf
versione stampabile 4 lucidi per foglio slides-1D-2x2.pdf
versione a schermo slides-m1D-1x1.pdf
versione stampabile 2 lucidi per foglio slides-m1D-1x2.pdf
versione stampabile 4 lucidi per foglio slides-m1D-2x2.pdf
versione a schermo slides-mND-1x1.pdf
versione stampabile 2 lucidi per foglio slides-mND-1x2.pdf
versione stampabile 4 lucidi per foglio slides-mND-2x2.pdf
Minidispensa sui numeri complessi
Esami Svolti
Appello 18 gennaio 2007
- Testo dell’appello in formato pdf.
Appello 23 febbraio 2007
- Testo dell’appello (con soluzioni) in formato pdf.
Appello 18 giugno 2007
- Testo dell’appello (con soluzioni) in formato pdf.
Appello 25 luglio 2007
- Testo dell’appello (con soluzioni) in formato pdf.
Appello 7 settembre 2007
- Testo dell’appello (con soluzioni) in formato pdf.
P.h.D. Corso di Programmazione in C (AA 2006/2007)
Esercizio 1
Scrivere un programma che calcola i numeri amicabili
Sono numeri amicabili quelli per cui la somma dei divisori propri di uno è uguale all’altro e viceversa. Ad esempio 220 e 284 sono amicabili (controllate). Se un numero è amicabile di sè stesso, cioè se la somma dei suoi divisori è uguale a sè stesso, è chiamato numero perfetto.
Esercizio 2
Scrivere un programma che converte un numero un lettere (numeri minori di un miliardo). Ad esempio 12344 diventa dodicimilatrecentoqurantaquattro.
I più bravi possono cercare di scrivere un convertitore multilingua inglese/italiano o altre lingue.
Esercizio 3
Scrivere un programma che legge due polinomi (ad esempio come ordine e coefficienti) e calcola la divisione con resto
I più bravi possono cercare di leggere un polinomio come stringa tipo 1+x3+34*x4
.
Esercizio 4
Un quadrato magico
è uno schieramento di numeri interi distinti in una tabella quadrata tale che il totale di ogni riga, di ogni colonna e di entrambe le diagonali sia sempre lo stesso numero; tale intero è denominato la costante di magia o costante magica o somma magica del quadrato. Scrivere un programma C
che legge in ingresso la dimensione del quadrato e genera tutti i possibili quadrati magici di quella dimensione.
Esercizio 5
Scrivere un programma per risolvere il problema della torre di Hanoi (vedi il sito wikipedia Torre di Hanoi). I più bravi possono cercare di scrivere un programma NON ricorsivo.
Lezione del 13/3/2007
Esempi introduttivi
File: esempio1.c:
/*
I commenti sono contenuti
da / + * = inizio commento
fino a * + / = fine commento
*/
/* struttura di un programma C */
/* un programma a' una funzione col
nome fissato "main".
Restituisce un intero (int).
Il corpo del programma e' contenuto
tra { }.
Le parentesi () possono contenere
gli argomenti passati al programma
(da vedere più avanti)
*/
int
main() {
return 0 ;
/* ritorna 0 = nessun errore */
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio1.c -o esempio1
*/
File: esempio2.c:
int
main() {
int a, b, c ; /* definisco le variabili intere a, b, c */
long int d, e, f ; /* interi "lunghi" */
short int g, h ; /* interi "corti" */
unsigned int i ; /* interi senza segno */
unsigned short int j ; /* interi "corti" senza segno */
unsigned
long
int k ; /* interi "lunghi" senza segno */
/* si possono usare le forme contratte
unsigned int = unsigned
long int = long
short int = short
signed int = int
unsigned long int = unsigned long
unsigned short int = unsigned short
*/
/* operazioni sugli interi */
a = b + c ; /* somma */
a = b - c ; /* differenza */
a = b * c ; /* prodotto */
a = b / c ; /* divisione intera 10/4 ==> 2 */
a = b % c ; /* resto della divisione 20 % 3 ==> 2
infatti 20 = 3*6 + 2 */
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio2.c -o esempio2
*/
Manipolazione di bit
File: esempio3.c:
/*
uso direttiva di compilazione
#include <file>
dove <> indica di cercare il file corrispondente
nelle directory di sistema per il compilatore C
normalmente /usr/include
*/
#include <stdio.h>
/* funzione (subroutine) che converte un intero in una stringa
che rappresenta il numero in binario,
*/
void
to_binary( int aa, char str[33] ) {
int j, i = 0 ;
unsigned a = (unsigned) aa ;
/*
while ( cond ) expression ;
esegue espression finché cond e' vera
*/
/*
operatori di confronto
== uguaglianza
!= diverso
>= maggiore o uguale
<= minore o uguale
> maggiore
< minore
*/
while ( a != 0 ) {
str[i] = '0' + (a%2) ;
/* str[i] accedo all'i-esimo carattere della stringa str (a partire da 0) */
a /= 2 ; /* scorciatoia per scrivere a = a / 2 ;
in generale a OP= b ; ==> a = a OP b */
/* si può anche scrivere come a >>= 1 ; == dividere a per 2 */
++i ; /* scorciatoia per i = i+1 ; */
}
if ( i == 0 ) { str[0] = '0' ; ++i ; }
str[i] = '\0' ; /* marco il fine stringa */
/* devo rovesciare la stringa */
/* for ( INIT ; COND ; INCR ) expression ;
INIT e' eseguita una volta sola a inizio ciclo
COND viene testata ogni ciclo all'inizio, se falsa esce dal ciclo for
INCR viene eseguita alla fine di ogni ciclo
expression viene eseguita ad ogni ciclo
*/
--i ; /* per non scambiare lo 0 marcatore di fine stringa */
for ( j=0 ; j < i ; --i, ++j ) {
/* scambio str[i] con str[j] */
char bf = str[i] ;
str[i] = str[j] ;
str[j] = bf ;
}
}
int
main() {
int a = 112 ; /* definione e inizializzazione contestuale */
int b = 203 ;
int const c = 322 ; /* c non può piu essere modificato */
int d ;
char str1[33] ; /* vettore di 33 caaratteri */
char str2[33] ; /* vettore di 33 caaratteri */
char str3[33] ; /* vettore di 33 caaratteri */
/* operazioni sugli interi */
a = b + c ; /* somma */
/* print e' definita in stdio.h
print( formato, argomenti ) ;
formato = "stringa" descrizione di come stampare a terminale gli argomenti
argomenti = lista separata da "," di variabili
*/
printf("%d = %d + %d\n", a, b, c ) ;
/*
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | |
| | | | | +--+--+-- argomenti in stampa
| | | | |
| | | | +------------ carattere non stampabile (ritorno a capo + avanza linea)
| | | |
| +----+-----+--- %d formattatore = prende argomento e lo stampa come intero
|
+------ chiama la funzione printf della libreria standard
*/
a = b - c ; /* differenza */
printf("%d = %d - %d\n", a, b, c ) ;
a = b * c ; /* prodotto */
printf("%d = %d * %d\n", a, b, c ) ;
a = b / c ; /* divisione intera 10/4 ==> 2 */
printf("%d = %d / %d\n", a, b, c ) ;
a = b % c ; /* resto della divisione 20 % 3 ==> 2
infatti 20 = 3*6 + 2 */
printf("%d = %d %% %d\n", a, b, c ) ;
/*
Manipolazione di BIT!
*/
a = b << 1 ; /* shift a sinistra di 1 bit */
printf("%d = %d<<1\n", a, b) ;
to_binary(a, str1) ;
to_binary(b, str2) ;
printf("%s = %s<<1\n", str1, str2) ;
a = b << 5 ; /* shift a sinistra di 5 bit */
printf("%d = %d<<5\n", a, b) ;
to_binary(a, str1) ;
to_binary(b, str2) ;
printf("%s = %s<<5\n", str1, str2) ;
a = b >> 1 ; /* shift a destra di 1 bit */
printf("%d = %d>>1\n", a, b) ;
to_binary(a, str1) ;
to_binary(b, str2) ;
printf("%s = %s>>1\n", str1, str2) ;
a = b >> 5 ; /* shift a destra di 5 bit */
printf("%d = %d>>5\n", a, b) ;
to_binary(a, str1) ;
to_binary(b, str2) ;
printf("%s = %s>>5\n", str1, str2) ;
/* operazioni maschere bit a bit
& operazione 'and' bit a bit
| operazione 'or' bit a bit
^ operazione 'or esclusivo' bit a bit
~ operazione 'complementazione' bit a bit
*/
a = b & c ; /* and bit a bit */
to_binary(a, str1) ;
to_binary(b, str2) ;
to_binary(c, str3) ;
printf("%s = %s & %s\n", str1, str2, str3) ;
a = b | c ; /* or bit a bit */
to_binary(a, str1) ;
to_binary(b, str2) ;
to_binary(c, str3) ;
printf("%s = %s | %s\n", str1, str2, str3) ;
a = b ^ c ; /* or esclusivo bit a bit */
to_binary(a, str1) ;
to_binary(b, str2) ;
to_binary(c, str3) ;
printf("%s = %s ^ %s\n", str1, str2, str3) ;
a = ~b ; /* complemento bit a bit */
to_binary(a, str1) ;
to_binary(b, str2) ;
printf("%s = ~%s\n", str1, str2) ;
d = b & 0xFF ; /* controllo se i primi 8 bit sono assegnati */
to_binary(0xFF, str1) ;
to_binary(b, str2) ;
printf("%d = %s & %s\n", d, str1, str2) ;
d = (b<<8) & 0xFF ; /* controllo se i primi 8 bit sono assegnati */
to_binary(0xFF, str1) ;
to_binary((b<<8), str2) ;
printf("%d = %s & %s\n", d, str1, str2) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio2.c -o esempio2
*/
Il sizeof
File: esempio4.c:
/*
*/
#include <stdio.h>
int
main() {
char a ;
int b ;
short c ;
long d ;
long long e ;
float f ;
double g ;
long double h ;
printf("Stampa della occupazione in memoria dei tipi standard\n") ;
printf("sizeof(char) = %d\n", sizeof(char)) ;
printf("sizeof(int) = %d\n", sizeof(int)) ;
printf("sizeof(short) = %d\n", sizeof(short)) ;
printf("sizeof(long) = %d\n", sizeof(long)) ;
printf("sizeof(long long) = %d\n", sizeof(long long)) ;
printf("sizeof(float) = %d\n", sizeof(float)) ;
printf("sizeof(double) = %d\n", sizeof(double)) ;
printf("sizeof(long double) = %d\n", sizeof(long double)) ;
printf("sizeof(a) = %d\n", sizeof(a)) ;
printf("sizeof(b) = %d\n", sizeof(b)) ;
printf("sizeof(c) = %d\n", sizeof(c)) ;
printf("sizeof(d) = %d\n", sizeof(d)) ;
printf("sizeof(e) = %d\n", sizeof(e)) ;
printf("sizeof(f) = %d\n", sizeof(f)) ;
printf("sizeof(g) = %d\n", sizeof(g)) ;
printf("sizeof(h) = %d\n", sizeof(h)) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio2.c -o esempio2
*/
Esempi di vettori e puntatori e librerie standard:
File: esempio5.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include <stdio.h>
/* per le funzioni matematiche tipo sqrt */
#include <math.h>
/* per la routine di ordinamento qsort */
#include <stdlib.h>
/*
void
qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
*/
int
compare(const void * pa_in, const void * pb_in) {
double const * pa = pa_in ;
double const * pb = pb_in ;
if ( *pa == *pb ) return 0 ;
if ( *pa > *pb ) return 1 ;
return -1 ;
}
int
main() {
double vec[100] ; /* definisco un vettore di double di 100 elementi */
/* riempimento del vettore */
{ /* apro un blocco, posso definire variabili locali al blocco */
/* le variabili esterne tipo "vec" sono visibili nel blocco */
int i=0 ;
int j=1231242 ;
while ( i < 100 ) {
vec[i] = sqrt( fabs( (double)(j%1234) ) ) ;
j = (j*2341) % 234245 ;
++i ;
}
/* vec contiene numeri non in ordine */
}
/* stampa dei numeri */
{
int i, j ;
for ( i=0 ; i < 20 ; ++i ) {
for ( j=0 ; j < 5 ; ++j )
printf("%lf, ",vec[i*5+j]) ;
printf("\n") ;
}
}
/* ordino i numeri con qsort */
qsort(vec, 100, sizeof(vec[0]), compare ) ;
printf("\n\nNumeri Ordinati\n\n") ;
/* stampa dei numeri */
{
int i, j ;
for ( i=0 ; i < 20 ; ++i ) {
for ( j=0 ; j < 5 ; ++j )
printf("%lf, ",vec[i*5+j]) ;
printf("\n") ;
}
}
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio2.c -o esempio2
*/
File: esempio6.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include <stdio.h>
/* per le funzioni matematiche tipo sqrt */
#include <math.h>
/* per la routine di ordinamento qsort */
#include <stdlib.h>
/*
void
qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
*/
int
compare(const void * pa_in, const void * pb_in) {
double const * pa = pa_in ;
double const * pb = pb_in ;
if ( *pa == *pb ) return 0 ;
if ( *pa > *pb ) return 1 ;
return -1 ;
}
void
stampa( double vec[], int nelem ) {
int i, j ;
for ( i = 0 ; i < nelem ; ) {
for ( j = 0 ; i < nelem && j < 5 ; ++i, ++j )
printf("%lf, ", vec[i]) ;
printf("\n") ;
}
}
int
main() {
double * pvec ; /* definisco un puntatore al vettore */
/* per convenzione uso "p" davanti a una variabile puntatore
non fa parte dello standard ANSI ma delle buone abitudini
di programmazione */
int nelem = 123 ; /* definisco il numero di elementi */
/* allocazione dinamica della memoria */
pvec = malloc( nelem * sizeof(double) ) ;
printf("puntatore %lX\n",(long) pvec) ;
if ( pvec == NULL ) {
/* allocazione dinamica fallita */
printf("allocazione dinamica fallita per pvec\n") ;
exit(1) ; /* uscita pulita dal programma */
}
/* riempimento del vettore */
{ /* apro un blocco, posso definire variabili locali al blocco */
/* le variabili esterne tipo "vec" sono visibili nel blocco */
int i=0 ;
int j=1231242 ;
while ( i < nelem ) {
pvec[i] = sqrt( fabs( (double)(j%1234) ) ) ;
j = (j*2341) % 234245 ;
++i ;
}
/* vec contiene numeri non in ordine */
}
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* ordino i numeri con qsort */
qsort(pvec, nelem, sizeof(pvec[0]), compare ) ;
printf("\n\nNumeri Ordinati\n\n") ;
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* rilascio della memoria allocata */
free(pvec) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio6.c -o esempio6
*/
File: esempio7.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include <stdio.h>
/* per le funzioni matematiche tipo sqrt */
#include <math.h>
/* per la routine di ordinamento qsort */
#include <stdlib.h>
/* parametrizzo il codice */
typedef float value_type ;
/* definisco una macro */
#define VALUE_TYPE "%f"
#define CAST_VALUE_TYPE double
/*
void
qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
*/
int
compare(const void * pa_in, const void * pb_in) {
value_type const * pa = pa_in ;
value_type const * pb = pb_in ;
if ( *pa == *pb ) return 0 ;
if ( *pa > *pb ) return 1 ;
return -1 ;
}
void
stampa( value_type vec[], int nelem ) {
int i, j ;
for ( i = 0 ; i < nelem ; ) {
for ( j = 0 ; i < nelem && j < 5 ; ++i, ++j )
printf(VALUE_TYPE ", ", (CAST_VALUE_TYPE) vec[i]) ;
printf("\n") ;
}
}
int
main() {
value_type * pvec ; /* definisco un puntatore al vettore */
/* per convenzione uso "p" davanti a una variabile puntatore
non fa parte dello standard ANSI ma delle buone abitudini
di programmazione */
int nelem = 123 ; /* definisco il numero di elementi */
/* allocazione dinamica della memoria */
pvec = malloc( nelem * sizeof(value_type) ) ;
printf("puntatore %lX\n",(long) pvec) ;
if ( pvec == NULL ) {
/* allocazione dinamica fallita */
printf("allocazione dinamica fallita per pvec\n") ;
exit(1) ; /* uscita pulita dal programma */
}
/* riempimento del vettore */
{ /* apro un blocco, posso definire variabili locali al blocco */
/* le variabili esterne tipo "vec" sono visibili nel blocco */
int i=0 ;
int j=1231242 ;
while ( i < nelem ) {
pvec[i] = sqrt( fabs( (value_type)(j%1234) ) ) ;
j = (j*2341) % 234245 ;
++i ;
}
/* vec contiene numeri non in ordine */
}
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* ordino i numeri con qsort */
qsort(pvec, nelem, sizeof(pvec[0]), compare ) ;
printf("\n\nNumeri Ordinati\n\n") ;
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* rilascio della memoria allocata */
free(pvec) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio6.c -o esempio6
*/
File: esempio8.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include <stdio.h>
/* per le funzioni matematiche tipo sqrt */
#include <math.h>
/* per la routine di ordinamento qsort */
#include <stdlib.h>
struct rational {
int numer ;
int denom ;
} ;
typedef struct rational value_type ;
/*
void
qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
*/
int
compare(const void * pa_in, const void * pb_in) {
struct rational const * pa = pa_in ;
struct rational const * pb = pb_in ;
/* pa -> denom == (*pa) . denom */
int numer = pa -> numer * pb -> denom - pa -> denom * pb -> numer ;
int denom = pa -> denom * pb -> denom ;
if ( denom > 0 ) {
if ( numer > 0 ) return 1 ;
if ( numer < 0 ) return -1 ;
} else {
if ( numer < 0 ) return 1 ;
if ( numer > 0 ) return -1 ;
}
return 0 ;
}
void
stampa( struct rational vec[], int nelem ) {
int i, j ;
for ( i = 0 ; i < nelem ; ) {
for ( j = 0 ; i < nelem && j < 3 ; ++i, ++j ) {
int p = vec[i] . numer ;
int q = vec[i] . denom ;
float p_su_q = (float)p/(float)q ;
printf("(%d/%d)=%f, ", p, q, p_su_q ) ;
}
printf("\n") ;
}
}
int
main() {
value_type * pvec ; /* definisco un puntatore al vettore */
/* per convenzione uso "p" davanti a una variabile puntatore
non fa parte dello standard ANSI ma delle buone abitudini
di programmazione */
int nelem = 123 ; /* definisco il numero di elementi */
/* allocazione dinamica della memoria */
pvec = malloc( nelem * sizeof(value_type) ) ;
printf("puntatore %lX\n",(long) pvec) ;
if ( pvec == NULL ) {
/* allocazione dinamica fallita */
printf("allocazione dinamica fallita per pvec\n") ;
exit(1) ; /* uscita pulita dal programma */
}
/* riempimento del vettore */
{ /* apro un blocco, posso definire variabili locali al blocco */
/* le variabili esterne tipo "vec" sono visibili nel blocco */
int i=0 ;
int j=1231242 ;
while ( i < nelem ) {
pvec[i] . numer = j%1234 ;
pvec[i] . denom = (j+3)%234 ;
j = (j*2341) % 234245 ;
++i ;
}
/* vec contiene numeri non in ordine */
}
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* ordino i numeri con qsort */
qsort(pvec, nelem, sizeof(pvec[0]), compare ) ;
printf("\n\nNumeri Ordinati\n\n") ;
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* rilascio della memoria allocata */
free(pvec) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio6.c -o esempio6
*/
File: esempio9a.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
/*
nell'include usando le "" cerco il file nella directory
corrente o nelle directory specificate dal flag -I del compilatore
gcc -I/usr/pippo/pluto -I./libs .....
*/
#include "esempio9a.h"
int
main() {
value_type * pvec ; /* definisco un puntatore al vettore */
/* per convenzione uso "p" davanti a una variabile puntatore
non fa parte dello standard ANSI ma delle buone abitudini
di programmazione */
int nelem = 123 ; /* definisco il numero di elementi */
/* allocazione dinamica della memoria */
pvec = malloc( nelem * sizeof(value_type) ) ;
printf("puntatore %lX\n",(long) pvec) ;
if ( pvec == NULL ) {
/* allocazione dinamica fallita */
printf("allocazione dinamica fallita per pvec\n") ;
exit(1) ; /* uscita pulita dal programma */
}
/* riempimento del vettore */
{ /* apro un blocco, posso definire variabili locali al blocco */
/* le variabili esterne tipo "vec" sono visibili nel blocco */
int i=0 ;
int j=1231242 ;
while ( i < nelem ) {
pvec[i] . numer = j%1234 ;
pvec[i] . denom = (j+3)%234 ;
j = (j*2341) % 234245 ;
++i ;
}
/* vec contiene numeri non in ordine */
}
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* ordino i numeri con qsort */
qsort(pvec, nelem, sizeof(pvec[0]), compare ) ;
printf("\n\nNumeri Ordinati\n\n") ;
/* stampa dei numeri */
stampa( pvec, nelem ) ;
/* rilascio della memoria allocata */
free(pvec) ;
return 0 ;
}
/*
per compilarlo uso su macchine UNIX
> gcc esempio6.c -o esempio6
*/
File: esempio9b.c:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include "esempio9a.h"
int
compare(const void * pa_in, const void * pb_in) {
struct rational const * pa = pa_in ;
struct rational const * pb = pb_in ;
/* pa -> denom == (*pa) . denom */
int numer = pa -> numer * pb -> denom - pa -> denom * pb -> numer ;
int denom = pa -> denom * pb -> denom ;
if ( denom > 0 ) {
if ( numer > 0 ) return 1 ;
if ( numer < 0 ) return -1 ;
} else {
if ( numer < 0 ) return 1 ;
if ( numer > 0 ) return -1 ;
}
return 0 ;
}
void
stampa( struct rational vec[], int nelem ) {
int i, j ;
for ( i = 0 ; i < nelem ; ) {
for ( j = 0 ; i < nelem && j < 3 ; ++i, ++j ) {
int p = vec[i] . numer ;
int q = vec[i] . denom ;
float p_su_q = (float)p/(float)q ;
printf("(%d/%d)=%f, ", p, q, p_su_q ) ;
}
printf("\n") ;
}
}
File: esempio9a.h:
/*
* Esempio di vettori e puntatori
*
* Uso della libreria standard del C per ordinare un vettore
*
*/
#include <stdio.h>
/* per le funzioni matematiche tipo sqrt */
#include <math.h>
/* per la routine di ordinamento qsort */
#include <stdlib.h>
struct rational {
int numer ;
int denom ;
} ;
typedef struct rational value_type ;
extern void stampa ( struct rational vec[], int nelem ) ;
extern int compare ( const void * pa_in, const void * pb_in ) ;
/* in questo caso extern a' opzionale trattandosi di prototipi
di funzioni */
Lezione del 20/3/2007
Crivello di Eratostene.
File: esempio10.c:
/*
Programma che calcola i numeri primi
tra 2 e N (>2) con il metodo del crivello
di Eratostene.
*/
#include <stdio.h>
#include <stdlib.h>
int /* funzione che non restituisce 0 se tutto ok -1
se qualcosa va storto (allocazione dinamica) */
Eratostene( int const N, /* argomento non modificabile
numero massimo in cui cercare
i numeri primi */
int * p_quanti_primi, /* conterrà l'indirizzo dove
copiare il numero totale
di primi calcolati */
int ** pp_primi /* primi conterrà l'indirizzo di un
puntatore il quale a sua volta
conterrà l'indirizzo della memoria
allocata dinamicamente */
) {
/* variabili da usare nell'algoritmo */
int i, j ;
int * e_un_primo ; /* 1 = primo, 0 = non primo */
/* fase 1: allocazione dinamica del vettore di "booleani"
per l'algoritmo di Eratostene */
e_un_primo = malloc( (N+1)*sizeof(int) ) ;
if ( e_un_primo == NULL ) return -1 ;
/* fase 2: inizializzazione del vettore e_un_primo */
for ( i=0 ; i <= N ; ++i ) e_un_primo[i] = 1 ;
/* fase 3: ricerca dei numeri primi */
*p_quanti_primi = 1 ; /* 1 e 2 sappiamo gia che sono primi */
for ( i = 2 ; i <= N ; ++i ) {
if ( e_un_primo[i] == 1 ) {
/* ok, i è un numero primo */
++(*p_quanti_primi) ; /* aggiorno la conta dei primi */
/* elimino i suoi multipli
dalla tabella di numeri primi */
j = i*2 ;
while ( j <= N ) { e_un_primo[j] = 0 ; j += i ; }
}
}
/* fase 4: allocazione dinamica del vettore in uscita */
*pp_primi = malloc( (*p_quanti_primi)*sizeof(int) ) ;
if ( *pp_primi == NULL ) {
/* allocazione dinamica fallita, rilascio la memoria
allocata da e_un_primo */
free( e_un_primo ) ;
return -2 ;
}
/* fase 5: riempimento del vettore con i numeri primi */
j = 0 ;
for ( i = 1 ; i <= N ; ++i ) {
if ( e_un_primo[i] == 1 )
(*pp_primi)[j++] = i ; /* j e' incrementato DOPO il suo uso! */
/* altri modi consentiti ...
pp_primi[0][j] = i ; ++j ;
*(*pp_primi+j) = i ; ++j ;
pp_primi[0][j++] = i ;
*(*pp_primi+j++) = i ;
*/
}
/* controllo che sia andato tutto bene */
if ( j != *p_quanti_primi ) return -3 ;
/* rilascio la memoria ed esco */
free(e_un_primo) ;
return 0 ;
}
/* programma principale che richiamerà Eratostene */
int
main() {
int n_primi ; /* quanti primi ho calcolato */
int * p_primi ; /* puntatore alla zona di memoria che
conterrà i numeri primi */
int i, N, ok ;
/* stringone ottenuto con il comando figlet Eratostene */
printf(
" _____ _ _ \n"
"| ____|_ __ __ _| |_ ___ ___| |_ ___ _ __ ___ \n"
"| _| | '__/ _` | __/ _ \\/ __| __/ _ \\ '_ \\ / _ \\\n"
"| |___| | | (_| | || (_) \\__ \\ || __/ | | | __/\n"
"|_____|_| \\__,_|\\__\\___/|___/\\__\\___|_| |_|\\___|\n"
"\n"
"programma che calcola i numeri primi da 1 a N\n"
"Inserisci N=");
scanf("%d",&N) ;
ok = Eratostene( N, &n_primi, &p_primi ) ;
printf("Numeri primi tra 1 e %d\n", N) ;
for ( i=0 ; i < n_primi ; ++i ) {
printf("%d ", p_primi[i] ) ;
if ( (i%10) == 0 ) printf("\n") ;
}
printf("\n----------------------\n") ;
/* fine del programma, rilascio la memoria allocata da Eratostene */
free( p_primi ) ;
}
Crivello di Eratostene, versione con il vettore di bit
File: esempio11.c:
/*
Programma che calcola i numeri primi
tra 2 e N (>2) con il metodo del crivello
di Eratostene.
versione 2.
*/
#include <stdio.h>
#include <stdlib.h>
/* routine per la manipolazione di un vettore di bit */
typedef struct {
int nbit ;
int vec_len, bit_per_unsigned ;
unsigned * vec ;
} vettore_bit ;
int /* 0 = ok, -1 allocazione dinamica fallita */
costruisci( vettore_bit * vb, int const nbit ) {
int vec_len, bit_per_unsigned ;
vb -> nbit = nbit ; /* (*vb) . nbit = nbit ; */
/* calcolo quanti "unsigned" mi servono per contenere "nbit" bit */
vb -> bit_per_unsigned = sizeof(unsigned) * 8 ;
vb -> vec_len = (nbit + vb -> bit_per_unsigned - 1) / vb -> bit_per_unsigned ;
/* ^---- trucco per allocare i byte necessari */
/* allocazione dinamica del vettore */
vb -> vec = malloc( vb -> vec_len * sizeof(unsigned) ) ;
if ( vb -> vec == NULL ) return -1 ;
return 0 ;
}
void
distruggi( vettore_bit * vb ) {
if ( vb -> vec != NULL ) free( vb -> vec ) ;
vb -> vec = NULL ;
vb -> nbit = 0 ;
}
void
inizializza( vettore_bit * vb ) {
int i ;
/* riempie il vettore di bit con il valore 0 */
for ( i = 0 ; i < vb -> vec_len ; ++i )
vb -> vec[i] = 0 ; printf("esci inizializza\n") ;
}
int /* 0 = ok, -1 bit fuori range */
imposta_bit( vettore_bit * vb, int const nbit ) {
int i, ne, nb ;
if ( nbit > vb -> nbit || nbit < 0 ) return -1 ;
/* cerco in quale elemento del vettore vec il bit appartiene */
ne = nbit / vb -> bit_per_unsigned ;
/* cerco all'interno dell'elemento il bit di appartenenza */
nb = nbit % vb -> bit_per_unsigned ;
vb -> vec[ne] |= 1<<nb ;
}
int /* 0, 1 = valore letto, -1 bit fuori range */
leggi_bit( vettore_bit * vb, int const nbit ) {
int i, ne, nb ;
if ( nbit > vb -> nbit || nbit < 0 ) return -1 ;
/* cerco in quale elemento del vettore vec il bit appartiene */
ne = nbit / vb -> bit_per_unsigned ;
/* cerco all'interno dell'elemento il bit di appartenenza */
nb = nbit % vb -> bit_per_unsigned ;
if ( vb -> vec[ne] & 1<<nb ) return 1 ;
else return 0 ;
}
int
Eratostene( int const N,
int * p_quanti_primi,
int ** pp_primi) {
/* variabili da usare nell'algoritmo */
int i, j ;
vettore_bit e_un_primo ; /* 1 = primo, 0 = non primo */
if ( costruisci( &e_un_primo, N+1) == -1 ) return -1 ;
/* fase 2: inizializzazione del vettore e_un_primo */
inizializza( &e_un_primo ) ;
/* fase 3: ricerca dei numeri primi */
*p_quanti_primi = 1 ; /* 1 e 2 sappiamo gia che sono primi */
for ( i = 2 ; i <= N ; ++i ) {
switch ( leggi_bit( &e_un_primo, i ) ) {
case 0: /* è un primo */
++(*p_quanti_primi) ; /* aggiorno la conta dei primi */
/* elimino i suoi multipli dalla tabella di numeri primi */
j = i*2 ;
while ( j <= N ) { imposta_bit( &e_un_primo, j) ; j += i ; }
break ;
case 1: /* non è un primo */
break ;
case -1: /* errore */
return -1 ;
}
}
/* fase 4: allocazione dinamica del vettore in uscita */
*pp_primi = malloc( (*p_quanti_primi)*sizeof(int) ) ;
if ( *pp_primi == NULL ) {
/* allocazione dinamica fallita, rilascio la memoria
allocata da e_un_primo */
distruggi( &e_un_primo ) ;
return -2 ;
}
/* fase 5: riempimento del vettore con i numeri primi */
j = 0 ;
for ( i = 1 ; i <= N ; ++i ) {
switch ( leggi_bit( &e_un_primo, i ) ) {
case 0: /* è un primo */
(*pp_primi)[j++] = i ; /* j è incrementato DOPO il suo uso! */
break ;
case 1: /* non è un primo */
break ;
case -1: /* errore */
return -1 ;
}
}
/* controllo che sia andato tutto bene */
if ( j != *p_quanti_primi ) return -3 ;
/* rilascio la memoria ed esco */
distruggi(&e_un_primo) ;
return 0 ;
}
/* programma principale che richiamerà Eratostene */
int
main() {
int n_primi ; /* quanti primi ho calcolato */
int * p_primi ; /* puntatore alla zona di memoria che
conterrà i numeri primi */
int i, N, ok ;
printf(
" _____ _ _ \n"
"| ____|_ __ __ _| |_ ___ ___| |_ ___ _ __ ___ \n"
"| _| | '__/ _` | __/ _ \\/ __| __/ _ \\ '_ \\ / _ \\\n"
"| |___| | | (_| | || (_) \\__ \\ || __/ | | | __/\n"
"|_____|_| \\__,_|\\__\\___/|___/\\__\\___|_| |_|\\___|\n"
"\n"
"programma che calcola i numeri primi da 1 a N\n"
"Inserisci N=");
scanf("%d",&N) ;
ok = Eratostene( N, &n_primi, &p_primi ) ;
printf("Numeri primi tra 1 e %d\n", N) ;
for ( i=0 ; i < n_primi ; ++i ) {
printf("%d ", p_primi[i] ) ;
if ( (i%10) == 0 ) printf("\n") ;
}
printf("\n----------------------\n") ;
/* fine del programma, rilascio la memoria allocata da Eratostene */
free( p_primi ) ;
}
Soluzione numerica di un problema BVP al secondo ordine. Il sistema tridiagonale è risolto richiamando la routine LAPACK dgtsv
File: esempio12.c:
/*
Programnma che risolve con differenze finite
il problema
y'' + a(x) y' + b(x) y = c(x)
y(A) = ya
y(B) = yb
*/
#include <stdlib.h>
#include <stdio.h>
/*
prototipo della routine LAPACK
che risolve un sistema tridiagonale
*/
#define F77NAME(A) A##_
typedef int integer ;
typedef double double_precision ;
/* F77NAME(dgtsv) ==> dgtsv_ */
void F77NAME(dgtsv) ( integer const * N,
integer const * NRHS,
double_precision * DL,
double_precision * D,
double_precision * DU,
double_precision * B,
integer const * LDB,
integer * INFO );
/* definizione del problema */
double_precision
a( double_precision x )
{ return 1 ; }
double_precision
b( double_precision x )
{ return -1 ; }
double_precision
c( double_precision x )
{ return x*x ; }
/*
funzione che costruisce il sistema tridiagonale
e lo risolve con la chiamata alla routione LaPack
*/
int
bvp_solver( double_precision A, /* estremo sinistro */
double_precision B, /* estremo destro */
double_precision YA, /* BC estremo sinistro */
double_precision YB, /* BC estremo destro */
integer N, /* numero di intervalli */
double_precision **pp_y /* doppio puntatore alla soluzione */
) {
integer i, ONE=1, INFO ;
double_precision xi, h, *D, *DU, *DL, *RHS ;
/* fase 1: allocazione dinamica */
RHS = *pp_y = malloc( (N+1)* sizeof(double_precision) ) ;
if ( *pp_y == NULL ) /* controllato */ ;
D = malloc( (3*N+1)* sizeof(double_precision) ) ;
if ( D == NULL ) /* controllato */ ;
DL = D + N+1 ;
DU = DL + N ;
/* ciclo per riempire i vettori */
D[0] = 1 ; DU[0] = 0 ; RHS[0] = YA ;
D[N] = 1 ; DL[N-1] = 0 ; RHS[N] = YB ;
h = (B-A)/N ;
for ( i=1 ; i < N ; ++i ) {
xi = A + i*h ;
D[i] = -2 + h*h *b(xi) ;
DL[i-1] = 1-h*a(xi)/2 ;
DU[i] = 1+h*a(xi)/2 ;
RHS[i] = h*h*c(xi) ;
}
/* chiamata della routine lapack */
F77NAME(dgtsv) ( &N, &ONE, DL, D, DU, RHS, &N, &INFO ) ;
return INFO ;
}
int
main( int argc, char * argv[] ) {
FILE * fd ;
double_precision * p_y ;
integer i, N, ok ;
/* mi aspetto una chiamata del tipo
program N file
N = numero di intervalli
file = nome del file dove salvare il risultato
*/
printf("%d\n",argc);
if ( argc != 3 ) {
printf("comando errato\n");
exit(1) ;
}
sscanf( argv[1], "%d", &N ) ;
ok = bvp_solver( 0, 10, 1, 1, N, &p_y );
if ( ok == 0 ) {
fd = fopen( argv[2], "w+" ) ;
for ( i = 0 ; i <= N ; ++i ) {
fprintf( fd, "%lf\n", p_y[i]) ;
}
}
}
Lezione del 27/3/2007
Esempio di solutore ellittico
File: solutore-ellittico-ver1.c:
/*
* Programma che risolve con differenze finite il problema
*
* u (x,y) + u(x,y) = f(x,y) in [0,1]x[0,1]
* xx yy
*
* u(x,y) = g(x,y) su bordo di [0,1]x[0,1]
*
* Le differenze finite risultano essere
*
* | 1 |
* 1 | |
* - | 1 -4 1 | u(i,j) = f(i,j) per i,j=1..N-1
* 2 | |
* h | 1 |
*
* dove
* N = suddivisioni dell'intervallo [0,1]
* h = 1/N
* condizioni al contorno
* u(0,j) = g(0,j) bordo sinistro
* u(N,j) = g(N,j) bordo destro
* u(i,0) = g(i,0) bordo sotto
* u(i,N) = g(i,N) bordo sopra
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define F77NAME(A) A##_
typedef double value_type ; /* parametrizzo il tipo reale per i numeri */
typedef int index_type ; /* parametrizzo il tipo intero per gli indici */
typedef struct {
value_type center ;
value_type left ;
value_type right ;
value_type up ;
value_type down ;
} stencil ;
/* termine sorgente della equazione */
value_type
f(value_type const x, value_type const y)
{ return 2*exp(-y)+x*x*exp(-y) ; }
/* valore al bordo */
value_type
g(value_type const x, value_type const y)
{ return x*y+x*x*exp(-y) ; }
/* soluzione esatta per controllare il programma */
value_type
u_esatta(value_type const x, value_type const y)
{ return x*y+x*x*exp(-y) ; }
/*
Esempio di griglia 4x4 (N=3)
(0,3) - (1,3) - (2,3) - (3,3)
| | | |
(0,2) - (1,2) - (2,2) - (3,2)
| | | |
(0,1) - [(1,1)] - (2,1) - (3,1)
| | | |
(0,0) - (1,0) - (2,0) - (3,0)
Ordinamento delle equazioni:
12 -- 13 -- 14 -- 15
| | | |
8 -- 9 -- 10 -- 11
| | | |
4 -- [5] -- 6 -- 7
| | | |
0 -- 1 -- 2 -- 3
ad esempio (1,1) corrisponde a 5
se sono sul nodo (i,j) che corrisponde alla eqauzione k esima
se mi muovo a sinistra vedo l'equzione k-1 esima
se mi muovo a destra vedo l'equzione k+1 esima
se mi muovo sopra vedo l'equzione k+(N+1) esima
se mi muovo sotto vedo l'equzione k-(N+1) esima
ci sono N+1 elementi per riga.
k+(N+1)
k-1 k k+1
k-(N+1)
*/
/* dati gli indici (i,j) calcola il numero di equazione
corrispondente nella numerazione scelta */
void
map_2_to_1( index_type const N, /* suddivisioni di [0,1]x[0,1] */
index_type const i,
index_type const j,
index_type * pk ) {
*pk = i + j*(N+1) ;
}
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
void
map_1_to_2( index_type const N, /* suddivisioni di [0,1]x[0,1] */
index_type const k,
index_type * pi,
index_type * pj ) {
*pi = k % (N+1) ;
*pj = k / (N+1) ;
}
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
void
map_2_to_coord( index_type const N, /* suddivisioni di [0,1]x[0,1] */
index_type const i,
index_type const j,
value_type * pxi,
value_type * pyj ) {
*pxi = (value_type)i/N ;
*pyj = (value_type)j/N ;
}
/* dati gli indici (ki,kj) della matrice A calcola
la posizione in memoria di A(ki,kj).
Scegliamo di memorizzare gli elementi della matrice per
colonna come in FORTRAN per consistenza con le LAPACK.
Ad esempio
+ 1 2 3 +
A = | 4 5 6 |
+ 7 8 9 +
in memoria è il vettore
| 1 | -
| 4 | | prima colonna
| 7 | -
| 2 | -
| 5 | | seconda colonna
| 8 | -
| 3 | -
| 6 | | terza colonna
| 9 | -
*/
index_type
index_2_to_1( index_type const dim, /* dimensione della matrice */
index_type const i,
index_type const j ) {
return i + j*dim ;
}
void
system_build( index_type const N, /* numero di suddivisioni */
value_type (*pf)(value_type const, value_type const),
/* doppiopuntatore alla funzione termine sorgente */
value_type (*pg)(value_type const, value_type const),
/* puntatore alla funzione valore al contorno */
value_type **ppMat,
/* doppio puntatore alla matrice del sistema lineare
(allocata internamente) */
value_type **ppRHS
/* doppio puntatore al termine noto del sistema lineare
(allocato internamente) */
) {
index_type i, j, k, kcenter, kright, kleft, kup, kdown ;
index_type neq = (N+1)*(N+1) ; /* numero di equazioni del sistema lineare */
stencil st ;
value_type h = 1.0/N ; /* 1/N da 0! */
value_type xi, yj ;
/* passo 1: allocazione dionamica */
*ppMat = malloc( neq * neq * sizeof(value_type) ) ;
*ppRHS = malloc( neq * sizeof(value_type) ) ;
/* da controllare la allocazione....*/
/* passo 2: azzero gli elementi della matrice e del vettore */
for ( i=0 ; i < neq*neq ; ++i ) (*ppMat)[i] = 0 ;
for ( i=0 ; i < neq ; ++i ) (*ppRHS)[i] = 0 ;
/* passo 3: definisco lo stencil (in casi più complicati
lo stencil può essere variabile) */
st . center = -4/h/h ;
st . left = st . right = st . up = st . down = 1/h/h ;
/* passo 4: riempimento di RHS */
/* "loop" sulle celle interne */
for ( i=1 ; i < N ; ++i ) {
for ( j=1 ; j < N ; ++j ) {
map_2_to_1( N, i, j, &k ) ;
map_2_to_coord( N, i, j, &xi, &yj ) ;
(*ppRHS)[k] = (*pf)(xi,yj) ;
}
}
/* "loop" sulle celle di bordo */
for ( i=0 ; i <= N ; ++i ) {
map_2_to_1( N, i, 0, &k ) ;
map_2_to_coord( N, i, 0, &xi, &yj ) ;
(*ppRHS)[k] = (*pg)(xi,yj) ; /* bottom */
map_2_to_1( N, i, N, &k ) ;
map_2_to_coord( N, i, N, &xi, &yj ) ;
(*ppRHS)[k] = (*pg)(xi,yj) ; /* top */
}
for ( j=1 ; j < N ; ++j ) {
map_2_to_1( N, 0, j, &k ) ;
map_2_to_coord( N, 0, j, &xi, &yj ) ;
(*ppRHS)[k] = pg(xi,yj) ; /* (*pg)(xi,yj) */ /* left */
map_2_to_1( N, N, j, &k ) ;
map_2_to_coord( N, N, j, &xi, &yj ) ;
(*ppRHS)[k] = (*pg)(xi,yj) ; /* right */
}
/* passo 5: riempimento della Matrice */
/* "loop" sulle celle interne */
for ( i=1 ; i < N ; ++i ) {
for ( j=1 ; j < N ; ++j ) {
/* estraggo i numeri corrispondenti alle equazioni
dello stencil */
map_2_to_1( N, i, j, &kcenter ) ;
map_2_to_1( N, i+1, j, &kright ) ;
map_2_to_1( N, i-1, j, &kleft ) ;
map_2_to_1( N, i, j+1, &kup ) ;
map_2_to_1( N, i, j-1, &kdown ) ;
(*ppMat)[index_2_to_1(neq,kcenter,kcenter)] = st . center ;
(*ppMat)[index_2_to_1(neq,kcenter,kright)] = st . right ;
(*ppMat)[index_2_to_1(neq,kcenter,kleft)] = st . left ;
(*ppMat)[index_2_to_1(neq,kcenter,kup)] = st . up ;
(*ppMat)[index_2_to_1(neq,kcenter,kdown)] = st . down ;
}
}
/* "loop" sulle celle di bordo */
/* "loop" sulle celle di bordo */
for ( i=0 ; i <= N ; ++i ) {
map_2_to_1( N, i, 0, &k ) ;
(*ppMat)[index_2_to_1(neq,k,k)] = 1 ; /* bottom */
map_2_to_1( N, i, N, &k ) ;
(*ppMat)[index_2_to_1(neq,k,k)] = 1 ; /* top */
}
for ( j=1 ; j < N ; ++j ) {
map_2_to_1( N, 0, j, &k ) ;
(*ppMat)[index_2_to_1(neq,k,k)] = 1 ; /* left */
map_2_to_1( N, N, j, &k ) ;
(*ppMat)[index_2_to_1(neq,k,k)] = 1 ; /* right */
}
}
void
system_print( index_type const neq, /* numero di equazioni */
value_type *pMat,
/* puntatore alla matrice del sistema lineare
(allocata internamente) */
value_type *pRHS
/* puntatore al termine noto del sistema lineare
(allocato internamente) */
) {
char eq ;
index_type i, j ;
value_type val ;
static char spazi[] = " " ; /* static significa che spazi
non e` allocato sullo stack
ma in memoria */
/* spazi e' un vettore di caratteri di lunghezza non specificata.
la sua dimensione e' calcolata dal compilatore in base
alla sua inizializzazione.
Si possono inizializzare e dimensionare qualunque tipo di vettori
ad esempio
int v[] = {1,2,3,4,5} ;
double v[] = {1,2,3,4.2,5.0} ;
char *pstring[] = {"pippo","pluto","paperino"} ;
inizializzazione di un vettore di strutture
typedef struct {
double a ;
char *s ;
} a_struct ;
a_struct v[] = { {1,"pippo"}, {2,"pluto"}, {-1.0,"paperino"}} ;
*/
/* riserviamo 6 spazi per i numeri
1 spazio per la separazione */
/* stampa prima riga */
printf( "+") ;
for ( i=0 ; i < neq-1 ; ++i ) printf("%s ",spazi) ;
printf("%s+ + + +%s+\n",spazi,spazi) ;
/* stampa elementi matrice */
for ( i=0 ; i < neq ; ++i ) {
printf("|") ;
for ( j=0 ; j < neq-1 ; ++j ) {
val = pMat[index_2_to_1(neq,i,j)] ;
printf("%-6.2g ",val) ; /* - serve ad allineare a sinistra */
}
val = pMat[index_2_to_1(neq,i,neq-1)] ;
if ( i == neq/2 ) eq = '=' ;
else eq = ' ' ;
printf("%-6.2g| |x%-2d| %c |%-6.2g|\n",val,i,eq,pRHS[i]) ;
}
/* stampa ultima riga */
printf( "+") ;
for ( i=0 ; i < neq-1 ; ++i ) printf("%s ",spazi) ;
printf("%s+ + + +%s+\n",spazi,spazi) ;
}
void
pattern_print( index_type const neq, /* numero di equazioni */
value_type *pMat
/* puntatore alla matrice del sistema lineare
(allocata internamente) */
) {
index_type i, j ;
value_type val ;
/* stampa prima riga */
printf( "+") ;
for ( i=0 ; i < neq ; ++i ) printf(" ") ;
printf("+\n") ;
/* stampa elementi matrice */
for ( i=0 ; i < neq ; ++i ) {
printf("|") ;
for ( j=0 ; j < neq ; ++j ) {
val = pMat[index_2_to_1(neq,i,j)] ;
if ( val == 0 ) printf(" ") ;
else printf(" *") ;
}
printf("|\n") ;
}
/* stampa ultima riga */
printf( "+") ;
for ( i=0 ; i < neq ; ++i ) printf(" ") ;
printf("+\n") ;
}
/* interfaccia a LAPACK */
typedef int integer ;
typedef double double_precision ;
extern void F77NAME(dgesv)(integer const * N,
integer const * NRHS,
double_precision A[],
integer const * LDA,
integer IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO) ;
integer
system_solve( index_type const neq, /* numero di equaziuoni */
value_type *pMat,
/* puntatore alla matrice del sistema lineare */
value_type *pRHS
/* puntatore al termine noto del sistema lineare
conterra' in uscita la soluzione */
) {
integer * IPIV, uno=1, INFO ;
IPIV = malloc( neq * sizeof(integer) ) ;
F77NAME(dgesv)(&neq,&uno, pMat, &neq, IPIV, pRHS, &neq, &INFO );
return INFO ;
}
void
save_solution( index_type const N, /* numero di suddivisioni */
value_type *pRHS ) {
FILE * fd ;
index_type i, j, k ;
fd = fopen("OUT.txt","w+") ; /* apro il file in scrittura */
for ( i=0 ; i <= N ; ++i ) {
for ( j=0 ; j <= N ; ++j ) {
map_2_to_1( N, i, j, &k ) ;
if ( j == N ) fprintf(fd,"%g\n",pRHS[k]) ;
else fprintf(fd,"%g\t",pRHS[k]) ;
}
}
fclose(fd) ;
}
int
main() {
index_type INFO ;
index_type N = 10 ;
index_type neq = (N+1)*(N+1) ;
value_type *pMat, *pRHS, val ;
system_build( N, f, g, &pMat, &pRHS) ;
/*system_print( neq, pMat, pRHS ) ;*/
/*pattern_print( neq, pMat ) ;*/
INFO = system_solve( neq, pMat, pRHS) ;
printf( "INFO = %d\n", INFO ) ;
save_solution( N, pRHS ) ;
free( pMat ) ;
free( pRHS ) ;
}
Esempio di solutore ellittico versione 2
File: solutore-ellittico-ver2-1.c:
#include "solutore-ellittico-ver2.h"
/* termine sorgente della equazione */
value_type
f(value_type const x, value_type const y)
{ return (2+x*x)*exp(-y) ; }
/* valore al bordo */
value_type
g(value_type const x, value_type const y)
{ return x*(y+x*exp(-y)) ; }
/* soluzione esatta per controllare il programma */
value_type
u_esatta(value_type const x, value_type const y)
{ return x*(y+x*exp(-y)) ; }
int
main() {
value_type res[4] ;
index_type INFO ;
index_type NN, N = 5 ;
index_type neq ;
value_type *pMat, *pRHS, val ;
for ( NN = 0 ; NN < 4 ; ++NN, N *= 2 ) {
neq = (N+1)*(N+1) ;
system_build( N, f, g, &pMat, &pRHS) ;
INFO = system_solve( neq, pMat, pRHS) ;
printf( "INFO = %d\n", INFO ) ;
res[NN] = compare_solution( N,pRHS, u_esatta) ;
printf( "N = %d RES = %g\n", N, res[NN] ) ;
free( pMat ) ;
free( pRHS ) ;
}
printf( "ORDER1 = %g\n", log(res[0]/res[1])/log(2) ) ;
printf( "ORDER2 = %g\n", log(res[1]/res[2])/log(2) ) ;
printf( "ORDER3 = %g\n", log(res[2]/res[3])/log(2) ) ;
/*system_print( neq, pMat, pRHS ) ;*/
/*pattern_print( neq, pMat ) ;*/
//save_solution( N, pRHS ) ;
}
File: solutore-ellittico-ver2-2.c:
#include "solutore-ellittico-ver2.h"
void
system_build( index_type const N, /* numero di suddivisioni */
value_type (*pf)(value_type const, value_type const),
/* doppio puntatore alla funzione termine sorgente */
value_type (*pg)(value_type const, value_type const),
/* puntatore alla funzione valore al contorno */
value_type **ppMat,
/* doppio puntatore alla matrice del sistema lineare
(allocata internamente) */
value_type **ppRHS
/* doppio puntatore al termine noto del sistema lineare
(allocato internamente) */
) {
index_type i, j, k, kcenter, kright, kleft, kup, kdown ;
index_type neq = (N+1)*(N+1) ; /* numero di equazioni del sistema lineare */
stencil st ;
value_type h = 1.0/N ; /* 1/N da 0! */
value_type xi, yj ;
/* passo 1: allocazione dionamica */
*ppMat = malloc( neq * neq * sizeof(value_type) ) ;
*ppRHS = malloc( neq * sizeof(value_type) ) ;
/* da controllare la allocazione....*/
/* passo 2: azzero gli elementi della matrice e del vettore */
for ( i=0 ; i < neq*neq ; ++i ) (*ppMat)[i] = 0 ;
for ( i=0 ; i < neq ; ++i ) (*ppRHS)[i] = 0 ;
/* passo 3: definisco lo stencil (in casi più complicati
lo stencil può essere variabile) */
st . center = -4/h/h ;
st . left = st . right = st . up = st . down = 1/h/h ;
/* passo 4: riempimento di RHS */
/* "loop" sulle celle interne */
for ( i=1 ; i < N ; ++i ) {
for ( j=1 ; j < N ; ++j ) {
k = MAP_2_TO_1( N, i, j ) ;
MAP_2_TO_COORD( N, i, j, xi, yj ) ;
(*ppRHS)[k] = (*pf)(xi,yj) ;
}
}
/* "loop" sulle celle di bordo */
for ( i=0 ; i <= N ; ++i ) {
k = MAP_2_TO_1( N, i, 0 ) ;
MAP_2_TO_COORD( N, i, 0, xi, yj ) ;
(*ppRHS)[k] = pg(xi,yj) ; /* bottom */
k = MAP_2_TO_1( N, i, N ) ;
MAP_2_TO_COORD( N, i, N, xi, yj ) ;
(*ppRHS)[k] = pg(xi,yj) ; /* top */
}
for ( j=1 ; j < N ; ++j ) {
k = MAP_2_TO_1( N, 0, j ) ;
MAP_2_TO_COORD( N, 0, j, xi, yj ) ;
(*ppRHS)[k] = pg(xi,yj) ; /* left */
k = MAP_2_TO_1( N, N, j ) ;
MAP_2_TO_COORD( N, N, j, xi, yj ) ;
(*ppRHS)[k] = pg(xi,yj) ; /* right */
}
/* passo 5: riempimento della Matrice */
/* "loop" sulle celle interne */
for ( i=1 ; i < N ; ++i ) {
for ( j=1 ; j < N ; ++j ) {
/* estraggo i numeri corrispondenti alle equazioni
dello stencil */
kcenter = MAP_2_TO_1( N, i, j ) ;
kright = MAP_2_TO_1( N, i+1, j ) ;
kleft = MAP_2_TO_1( N, i-1, j ) ;
kup = MAP_2_TO_1( N, i, j+1 ) ;
kdown = MAP_2_TO_1( N, i, j-1 ) ;
(*ppMat)[INDEX_2_TO_1(neq,kcenter,kcenter)] = st . center ;
(*ppMat)[INDEX_2_TO_1(neq,kcenter,kright)] = st . right ;
(*ppMat)[INDEX_2_TO_1(neq,kcenter,kleft)] = st . left ;
(*ppMat)[INDEX_2_TO_1(neq,kcenter,kup)] = st . up ;
(*ppMat)[INDEX_2_TO_1(neq,kcenter,kdown)] = st . down ;
}
}
/* "loop" sulle celle di bordo */
for ( i=0 ; i <= N ; ++i ) {
k = MAP_2_TO_1( N, i, 0 ) ;
(*ppMat)[INDEX_2_TO_1(neq,k,k)] = 1 ; /* bottom */
k = MAP_2_TO_1( N, i, N ) ;
(*ppMat)[INDEX_2_TO_1(neq,k,k)] = 1 ; /* top */
}
for ( j=1 ; j < N ; ++j ) {
k = MAP_2_TO_1( N, 0, j ) ;
(*ppMat)[INDEX_2_TO_1(neq,k,k)] = 1 ; /* left */
k = MAP_2_TO_1( N, N, j ) ;
(*ppMat)[INDEX_2_TO_1(neq,k,k)] = 1 ; /* right */
}
}
void
system_print( index_type const neq, /* numero di equazioni */
value_type *pMat,
/* puntatore alla matrice del sistema lineare
(allocata internamente) */
value_type *pRHS
/* puntatore al termine noto del sistema lineare
(allocato internamente) */
) {
char eq ;
index_type i, j ;
value_type val ;
static char spazi[] = " " ; /* static significa che spazi
non e` allocato sullo stack
ma in memoria */
/* spazi e' un vettore di caratteri di lunghezza non specificata.
la sua dimensione e' calcolata dal compilatore in base
alla sua inizializzazione.
Si possono inizializzare e dimensionare qualunque tipo di vettori
ad esempio
int v[] = {1,2,3,4,5} ;
double v[] = {1,2,3,4.2,5.0} ;
char *pstring[] = {"pippo","pluto","paperino"} ;
inizializzazione di un vettore di strutture
typedef struct {
double a ;
char *s ;
} a_struct ;
a_struct v[] = { {1,"pippo"}, {2,"pluto"}, {-1.0,"paperino"}} ;
*/
/* riserviamo 6 spazi per i numeri
1 spazio per la separazione */
/* stampa prima riga */
printf( "+") ;
for ( i=0 ; i < neq-1 ; ++i ) printf("%s ",spazi) ;
printf("%s+ + + +%s+\n",spazi,spazi) ;
/* stampa elementi matrice */
for ( i=0 ; i < neq ; ++i ) {
printf("|") ;
for ( j=0 ; j < neq-1 ; ++j ) {
val = pMat[INDEX_2_TO_1(neq,i,j)] ;
printf("%-6.2g ",val) ; /* - serve ad allineare a sinistra */
}
val = pMat[INDEX_2_TO_1(neq,i,neq-1)] ;
if ( i == neq/2 ) eq = '=' ;
else eq = ' ' ;
printf("%-6.2g| |x%-2d| %c |%-6.2g|\n",val,i,eq,pRHS[i]) ;
}
/* stampa ultima riga */
printf( "+") ;
for ( i=0 ; i < neq-1 ; ++i ) printf("%s ",spazi) ;
printf("%s+ + + +%s+\n",spazi,spazi) ;
}
void
pattern_print( index_type const neq, /* numero di equazioni */
value_type *pMat
/* puntatore alla matrice del sistema lineare
(allocata internamente) */
) {
index_type i, j ;
value_type val ;
/* stampa prima riga */
printf( "+") ;
for ( i=0 ; i < neq ; ++i ) printf(" ") ;
printf("+\n") ;
/* stampa elementi matrice */
for ( i=0 ; i < neq ; ++i ) {
printf("|") ;
for ( j=0 ; j < neq ; ++j ) {
val = pMat[INDEX_2_TO_1(neq,i,j)] ;
if ( val == 0 ) printf(" ") ;
else printf(" *") ;
}
printf("|\n") ;
}
/* stampa ultima riga */
printf( "+") ;
for ( i=0 ; i < neq ; ++i ) printf(" ") ;
printf("+\n") ;
}
integer
system_solve( index_type const neq, /* numero di equaziuoni */
value_type *pMat,
/* puntatore alla matrice del sistema lineare */
value_type *pRHS
/* puntatore al termine noto del sistema lineare
conterra' in uscita la soluzione */
) {
integer * IPIV, uno=1, INFO ;
IPIV = malloc( neq * sizeof(integer) ) ;
F77NAME(dgesv)(&neq,&uno, pMat, &neq, IPIV, pRHS, &neq, &INFO );
return INFO ;
}
void
save_solution( index_type const N, /* numero di suddivisioni */
value_type const * pRHS ) {
FILE * fd ;
index_type i, j, k ;
fd = fopen("OUT.txt","w+") ; /* apro il file in scrittura */
for ( i=0 ; i <= N ; ++i ) {
for ( j=0 ; j <= N ; ++j ) {
k = MAP_2_TO_1( N, i, j ) ;
if ( j == N ) fprintf(fd,"%g\n",pRHS[k]) ;
else fprintf(fd,"%g\t",pRHS[k]) ;
}
}
fclose(fd) ;
}
value_type
compare_solution( index_type const N,
value_type const * pSOL,
value_type (*pesatta)(value_type const, value_type const) ) {
value_type xi, yj, bf ;
index_type i, j , k ;
value_type res = 0 ;
for ( i=0 ; i <= N ; ++i ) {
for ( j=0 ; j <= N ; ++j ) {
k = MAP_2_TO_1( N, i, j ) ;
MAP_2_TO_COORD( N, i, j, xi, yj ) ;
bf = fabs( pSOL[k] - pesatta(xi,yj) ) ;
if ( bf > res ) res = bf ;
}
}
return res ;
}
File: solutore-ellittico-ver2.h:
/*
* Programma che risolve con differenze finite il problema
*
* u (x,y) + u(x,y) = f(x,y) in [0,1]x[0,1]
* xx yy
*
* u(x,y) = g(x,y) su bordo di [0,1]x[0,1]
*
* Le differenze finite risultano essere
*
* | 1 |
* 1 | |
* - | 1 -4 1 | u(i,j) = f(i,j) per i,j=1..N-1
* 2 | |
* h | 1 |
*
* dove
* N = suddivisioni dell'intervallo [0,1]
* h = 1/N
* condizioni al contorno
* u(0,j) = g(0,j) bordo sinistro
* u(N,j) = g(N,j) bordo destro
* u(i,0) = g(i,0) bordo sotto
* u(i,N) = g(i,N) bordo sopra
*/
/*
Versione con matrice a BANDA per risparmiare (poca) memoria
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define F77NAME(A) A##_
typedef double value_type ; /* parametrizzo il tipo reale per i numeri */
typedef int index_type ; /* parametrizzo il tipo intero per gli indici */
typedef struct {
value_type center ;
value_type left ;
value_type right ;
value_type up ;
value_type down ;
} stencil ;
/* dati gli indici (i,j) calcola il numero di equazione
corrispondente nella numerazione scelta */
#define MAP_2_TO_1(N,i,j) ((i) + (j)*(N+1))
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
#define MAP_1_TO_2(N,k,i,j) i = (k) % (N+1) ; j = (k) / (N+1) ;
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
#define MAP_2_TO_COORD(N,i,j,xi,yj) \
xi = (value_type)(i)/(N) ; \
yj = (value_type)(j)/(N)
#define INDEX_2_TO_1(DIM,i,j) ((i) + (j)*DIM)
extern
void
system_build( index_type const N, /* numero di suddivisioni */
value_type (*pf)(value_type const, value_type const),
/* doppio puntatore alla funzione termine sorgente */
value_type (*pg)(value_type const, value_type const),
/* puntatore alla funzione valore al contorno */
value_type **ppMat,
/* doppio puntatore alla matrice del sistema lineare
(allocata internamente) */
value_type **ppRHS
/* doppio puntatore al termine noto del sistema lineare
(allocato internamente) */
) ;
extern
void
system_print( index_type const neq,
/* numero di equazioni */
value_type *pMat,
/* puntatore alla matrice del sistema lineare */
value_type *pRHS
/* puntatore al termine noto del sistema lineare */
) ;
extern
void
pattern_print( index_type const neq, /* numero di equazioni */
value_type *pMat /* puntatore alla matrice del sistema lineare */
) ;
/* interfaccia a LAPACK */
typedef int integer ;
typedef double double_precision ;
extern void F77NAME(dgesv)(integer const * N,
integer const * NRHS,
double_precision A[],
integer const * LDA,
integer IPIV[],
double_precision B[],
integer const * LDB,
integer * INFO) ;
extern
integer
system_solve( index_type const neq, /* numero di equazioni */
value_type *pMat, /* puntatore alla matrice del sistema lineare */
value_type *pRHS /* puntatore al termine noto del sistema lineare conterra' in uscita la soluzione */
) ;
extern
void
save_solution( index_type const N, value_type const * pRHS ) ;
extern
value_type
compare_solution( index_type const N,
value_type const * pSOL,
value_type (*pesatta)(value_type const, value_type const) ) ;
Lezione del 27/3/2007
Esempio di solutore ellittico
Questa implementazione costruisce il sistema lineare tramite una matrice sparsa nel formato Compressed Row. Il sistema lineare risultante è risolto tramite la libreria gratuita SUPERLU:
File: solutore-ellittico-SLU.h:
/*
* Programma che risolve con differenze finite il problema
*
* u (x,y) + u (x,y) = f(x,y) in [0,1]x[0,1]
* xx yy
*
* u(x,y) = g(x,y) su bordo di [0,1]x[0,1]
*
* Le differenze finite risultano essere
*
* | 1 |
* 1 | |
* - | 1 -4 1 | u(i,j) = f(i,j) per i,j=1..N-1
* 2 | |
* h | 1 |
*
* dove
* N = suddivisioni dell'intervallo [0,1]
* h = 1/N
* condizioni al contorno
* u(0,j) = g(0,j) bordo sinistro
* u(N,j) = g(N,j) bordo destro
* u(i,0) = g(i,0) bordo sotto
* u(i,N) = g(i,N) bordo sopra
*/
/*
* Versione con matrice sparsa e uso del pacchetto SUPERLU
* http://crd.lbl.gov/~xiaoye/SuperLU/
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef double value_type ; /* parametrizzo il tipo reale per i numeri */
typedef int index_type ; /* parametrizzo il tipo intero per gli indici */
typedef struct {
value_type center ;
value_type left ;
value_type right ;
value_type up ;
value_type down ;
} stencil ;
/* dati gli indici (i,j) calcola il numero di equazione
corrispondente nella numerazione scelta */
#define INDICES_TO_EQUATION_NUMBER(N,i,j) ((i) + (j)*(N+1))
/*
* Ad esempio nel caso 3x3 la numerazione e' seguente
*
* (0,2) -- (1,2) -- (2,2)
* | | |
* due indici (0,1) -- (1,1) -- (2,1)
* | | |
* (0,0) -- (1,0) -- (2,0)
*
* 6 -- 7 -- 8
* | | |
* numero di 3 -- 4 -- 5
* equazione | | |
* 0 -- 1 -- 2
*/
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
#define EQUATION_NUMBER_TO_INDICES(N,eq_number,i,j) \
i = (eq_number) % (N+1) ; \
j = (eq_number) / (N+1) ;
/*
* gli argomenti delle macro vanno tra parentesi peche'
*
* EQUATION_NUMBER_TO_INDICES(3,k+1,i,j)
*
* viene espanso in
*
* i = (k+1) % (3+1) ;
* j = (k+1) / (3+1) ;
*
* se omettiamo le parentesi viene espanso in
*
* i = k+1 % 3+1 ;
* j = k+1 / 3+1 ; ==> j = k+(1/3)+1
*/
/* dati il numero di equazione k calcolo gli indici (i,j)
corrispondenti nella numerazioen scelta */
#define INDICES_TO_COORD(N,i,j,xi,yj) \
xi = (value_type)(i)/(N) ; \
yj = (value_type)(j)/(N)
/*
* costruisce il sistema lineare e lo risolve chiamando SUPERLU
*/
extern
void
problem_solver( index_type const N, /* numero di suddivisioni */
value_type (*pf)(value_type const, value_type const),
/* puntatore alla funzione termine sorgente */
value_type (*pg)(value_type const, value_type const),
/* puntatore alla funzione valore al contorno */
value_type SOL[]
/* puntatore alla soluzione (allocato esternamente ad almeno (N+1)^2 elementi */
) ;
/*
* stampa la soluzione dul file file_name.
*/
extern
void
save_solution( char const file_name[], index_type const N, value_type const SOL[] ) ;
/*
* confronta la soluzione numerica con la soluzione esatta
*/
extern
value_type
compare_solution( index_type const N,
value_type const SOL[],
value_type (*pesatta)(value_type const, value_type const) ) ;
/*
INTERFACCIA CON SUPERLU
*/
#include "slu_ddefs.h"
typedef struct {
SuperMatrix * L ;
SuperMatrix * U ;
int * perm_c ;
int * perm_r ;
} factors_t ;
int dSLUFactorize( int const n,
int const nnz,
double values[],
int rowptr[],
int colidx[],
factors_t ** pLUfactors ) ;
int dSLUSolve( int const nrhs,
double b[],
int const ldb,
factors_t *LUfactors ) ;
void dSLUFree( factors_t *LUfactors ) ;
File: solutore-ellittico-SLU-1.c:
/*
* Programma che risolve con differenze finite il problema
*
* u (x,y) + u (x,y) = f(x,y) in [0,1]x[0,1]
* xx yy
*
* u(x,y) = g(x,y) su bordo di [0,1]x[0,1]
*
* Le differenze finite risultano essere
*
* | 1 |
* 1 | |
* - | 1 -4 1 | u(i,j) = f(i,j) per i,j=1..N-1
* 2 | |
* h | 1 |
*
* dove
* N = suddivisioni dell'intervallo [0,1]
* h = 1/N
* condizioni al contorno
* u(0,j) = g(0,j) bordo sinistro
* u(N,j) = g(N,j) bordo destro
* u(i,0) = g(i,0) bordo sotto
* u(i,N) = g(i,N) bordo sopra
*/
#include "solutore-ellittico-SLU.h"
/* termine sorgente della equazione */
value_type
f(value_type const x, value_type const y)
{ return (2+x*x)*exp(-y) ; }
/* valore al bordo */
value_type
g(value_type const x, value_type const y)
{ return x*(y+x*exp(-y)) ; }
/* soluzione esatta per controllare il programma */
value_type
u_esatta(value_type const x, value_type const y)
{ return x*(y+x*exp(-y)) ; }
#define N_GRID 7
int
main() {
value_type h, res[N_GRID] ;
index_type neq, NN, N = 10, NMAX=N*2*2*2*2*2*2 ;
value_type SOL[(NMAX+1)*(NMAX+1)] ;
for ( NN = 0 ; NN < N_GRID ; ++NN, N *= 2 ) {
neq = (N+1)*(N+1) ;
/* chiama il solutore per il problema ellittico */
problem_solver( N, f, g, SOL) ;
/* confronta la solzione esatta con quella numerica */
res[NN] = compare_solution( N, SOL, u_esatta ) ;
printf( "N = %d NEQ = %d RES = %g\n", N, neq, res[NN] ) ;
}
/* stimo l'ordine di convergenza del metodo */
for ( NN = 1 ; NN < N_GRID ; ++NN, N *= 2 )
printf( "ORDER%d = %g\n", NN, log(res[NN-1]/res[NN])/log(2) ) ;
/*
stimo la costante per l'ordine E(h) ~ C h^2
E(h)-E(h/2) ~ C (h^2-(h/2)^2) = C (1-1/4) h^2 = (3/4) C h^2
C = (4/3) ( E(h)-E(h/2) ) / h^2
*/
for ( NN = 1 ; NN < N_GRID ; ++NN, N *= 2 ) {
h = 1.0/N ;
printf( "C%d = %g\n", NN, (res[NN-1]-res[NN])/(h*h) ) ;
}
return 0 ;
}
File: solutore-ellittico-SLU-2.c:
#include "solutore-ellittico-SLU.h"
void
problem_solver( index_type const N, /* numero di suddivisioni */
value_type (*f)(value_type const, value_type const),
/* puntatore alla funzione termine sorgente */
value_type (*g)(value_type const, value_type const),
/* puntatore alla funzione valore al contorno */
value_type SOL[]
/* puntatore al termine noto del sistema lineare
(allocato externamente) */
) {
index_type nr ; /* indice di riga per il formato compressed row */
value_type *VALS ; /* valori matrice sparsa */
index_type *ROWINDEX, *COLS ; /* indici di riga e di colonna */
/*
* La matrice viene meorizzata nel formato "compressed coordinate"
*
* Ad esempio (gli ingici partono da 0!)
*
* + +
* | 1 0 0 |
* | 2 -1 0 |
* | 0 0 -3 |
* + +
*
* VALS = { 1, 2, -1, 3 }
* ROWS = { 0, 1, 1, 2 }
* COLS = { 0, 0, 1, 2 }
*/
factors_t *f_factors ;
index_type info, nnz, i, j, k, kright, kleft, kup, kdown ;
index_type neq = (N+1)*(N+1) ; /* numero di equazioni del sistema lineare */
stencil st ;
value_type h = 1.0/N ; /* 1/N da 0! */
value_type xi, yj ;
/* passo 1: allocazione dinamica */
VALS = malloc( 5 * neq * sizeof(value_type) ) ;
COLS = malloc( 5 * neq * sizeof(index_type) ) ;
ROWINDEX = malloc( (neq+1) * sizeof(index_type) ) ;
/* da controllare la allocazione....*/
/* passo 2: inizializzo a 0 nnz (numero elementio non zero) */
nnz = 0 ;
/* passo 3: definisco lo stencil (in casi più complicati
lo stencil può essere variabile) */
st . center = -4/h/h ;
st . left = st . right = st . up = st . down = 1/h/h ;
/* passo 4: riempimento di RHS (b di A*x=b) e della Matrice */
nr = 0 ;
for ( j=0 ; j <= N ; ++j ) {
for ( i=0 ; i <= N ; ++i ) {
ROWINDEX[nr++] = nnz ;
if ( i == 0 || i == N || j == 0 || j == N ) { /* bordo in basso a destra */
k = INDICES_TO_EQUATION_NUMBER( N, i, j ) ;
INDICES_TO_COORD( N, i, j, xi, yj ) ;
/* b(k) = g(xi,xj) */
SOL[k] = g(xi,yj) ;
/* elemento A(k,k) = 1 */
VALS[nnz] = 1 ;
COLS[nnz] = k ;
++nnz ;
} else {
k = INDICES_TO_EQUATION_NUMBER( N, i, j ) ;
INDICES_TO_COORD( N, i, j, xi, yj ) ;
SOL[k] = f(xi,yj) ;
kright = INDICES_TO_EQUATION_NUMBER( N, i+1, j ) ;
kleft = INDICES_TO_EQUATION_NUMBER( N, i-1, j ) ;
kup = INDICES_TO_EQUATION_NUMBER( N, i, j+1 ) ;
kdown = INDICES_TO_EQUATION_NUMBER( N, i, j-1 ) ;
/* elemento A(k,k) */
VALS[nnz] = st . center ;
COLS[nnz] = k ;
++nnz ;
/* elemento A(k,kright) */
VALS[nnz] = st . right ;
COLS[nnz] = kright ;
++nnz ;
/* elemento A(k,kleft) */
VALS[nnz] = st . left ;
COLS[nnz] = kleft ;
++nnz ;
/* elemento A(k,kup) */
VALS[nnz] = st . up ;
COLS[nnz] = kup ;
++nnz ;
/* elemento A(k,kdown) */
VALS[nnz] = st . down ;
COLS[nnz] = kdown ;
++nnz ;
}
}
}
ROWINDEX[nr++] = nnz ; /* marco fine elementi non zero */
/* passo 5: chiamo il solutore SUPERLU
*/
info = dSLUFactorize( neq, nnz, VALS, ROWINDEX, COLS, &f_factors ) ;
printf("Info = %d\n",info) ;
info = dSLUSolve( 1, SOL, neq, f_factors ) ;
printf("Info = %d\n",info) ;
dSLUFree( f_factors ) ;
}
void
save_solution( char const file_name[],
index_type const N, /* numero di suddivisioni */
value_type const * SOL ) {
FILE * fd ;
index_type i, j, k ;
fd = fopen(file_name,"w+") ; /* apro il file in scrittura */
for ( i=0 ; i <= N ; ++i ) {
for ( j=0 ; j <= N ; ++j ) {
k = INDICES_TO_EQUATION_NUMBER( N, i, j ) ;
if ( j == N ) fprintf(fd,"%g\n",SOL[k]) ;
else fprintf(fd,"%g\t",SOL[k]) ;
}
}
fclose(fd) ;
}
value_type
compare_solution( index_type const N,
value_type const SOL[],
value_type (*pesatta)(value_type const, value_type const) ) {
value_type xi, yj, bf ;
index_type i, j , k ;
value_type res = 0 ;
for ( i=0 ; i <= N ; ++i ) {
for ( j=0 ; j <= N ; ++j ) {
k = INDICES_TO_EQUATION_NUMBER( N, i, j ) ;
INDICES_TO_COORD( N, i, j, xi, yj ) ;
bf = fabs( SOL[k] - pesatta(xi,yj) ) ;
if ( bf > res ) res = bf ;
}
}
return res ;
}
File: solutore-ellittico-SLU-3.c:
/*
Interfaccia con SUPERLU (http://crd.lbl.gov/~xiaoye/SuperLU/)
*/
#include "solutore-ellittico-SLU.h"
/*
* Data la matrice memorizzata in Compressed Coordinate
* Calcola la fattorizzazione LU sparsa e la memorizza nella
* struttura factors_t.
*/
int
dSLUFactorize( int const n,
int const nnz,
double values[],
int rowptr[],
int colidx[],
factors_t ** f_factors ) {
SuperMatrix A, AC ;
SuperMatrix *L, *U;
int *perm_r; /* row permutations from partial pivoting */
int *perm_c; /* column permutation vector */
int *etree; /* column elimination tree */
SCformat *Lstore;
NCformat *Ustore;
int info, panel_size, permc_spec, relax;
double drop_tol = 0.0;
mem_usage_t mem_usage;
superlu_options_t options;
SuperLUStat_t stat;
/* Set the default input options. */
set_default_options(&options);
/* Initialize the statistics variables. */
StatInit(&stat);
dCreate_CompCol_Matrix(&A, n, n, nnz, values, colidx, rowptr, SLU_NC, SLU_D, SLU_GE);
L = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) );
U = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) );
if ( !(perm_r = intMalloc(n)) ) ABORT("Malloc fails for perm_r[].");
if ( !(perm_c = intMalloc(n)) ) ABORT("Malloc fails for perm_c[].");
if ( !(etree = intMalloc(n)) ) ABORT("Malloc fails for etree[].");
/*
* Get column permutation vector perm_c[], according to permc_spec:
* permc_spec = 0: natural ordering
* permc_spec = 1: minimum degree on structure of A'*A
* permc_spec = 2: minimum degree on structure of A'+A
* permc_spec = 3: approximate minimum degree for unsymmetric matrices
*/
permc_spec = options.ColPerm;
get_perm_c(permc_spec, &A, perm_c);
sp_preorder(&options, &A, perm_c, etree, &AC);
panel_size = sp_ienv(1);
relax = sp_ienv(2);
dgstrf(&options, &AC, drop_tol, relax, panel_size,
etree, NULL, 0, perm_c, perm_r, L, U, &stat, &info);
if ( info == 0 ) {
Lstore = (SCformat *) L->Store;
Ustore = (NCformat *) U->Store;
printf("No of nonzeros in factor L = %d\n", Lstore->nnz);
printf("No of nonzeros in factor U = %d\n", Ustore->nnz);
printf("No of nonzeros in L+U = %d\n", Lstore->nnz + Ustore->nnz);
dQuerySpace(L, U, &mem_usage);
printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n",
mem_usage.for_lu/1e6, mem_usage.total_needed/1e6,
mem_usage.expansions);
} else {
printf("dgstrf() error returns INFO= %d\n", info);
if ( info <= n ) { /* factorization completes */
dQuerySpace(L, U, &mem_usage);
printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n",
mem_usage.for_lu/1e6, mem_usage.total_needed/1e6,
mem_usage.expansions);
}
}
/* Save the LU factors in the factors handle */
*f_factors = (factors_t*) SUPERLU_MALLOC(sizeof(factors_t)) ;
(*f_factors) -> L = L ;
(*f_factors) -> U = U ;
(*f_factors) -> perm_c = perm_c ;
(*f_factors) -> perm_r = perm_r ;
/* Free un-wanted storage */
SUPERLU_FREE(etree);
Destroy_SuperMatrix_Store(&A);
Destroy_CompCol_Permuted(&AC);
StatFree(&stat);
return info ;
}
/*
* Data la fattorizzazione LU sparsa memorizzata nella struttura factors_t.
* calcola la soluzione dei sistemi LU x = B dove B è una matrice ldb x nrhs
* (ldb righe, nrhs colonne).
* Le soluzioni sono sovrascitte in B.
*/
int
dSLUSolve( int const nrhs, double b[], int const ldb, factors_t *LUfactors ) {
int n, info ;
SuperMatrix B;
trans_t trans;
SuperLUStat_t stat;
trans = TRANS;
/* Initialize the statistics variables. */
StatInit(&stat);
n = LUfactors -> L -> nrow ;
dCreate_Dense_Matrix(&B, n, nrhs, b, ldb, SLU_DN, SLU_D, SLU_GE);
/* Solve the system A*X=B, overwriting B with X. */
dgstrs ( trans,
LUfactors -> L,
LUfactors -> U,
LUfactors -> perm_c,
LUfactors -> perm_r,
&B, &stat, &info);
Destroy_SuperMatrix_Store(&B);
StatFree(&stat);
return info ;
}
/*
* Libera la memoria utilizzata per memorizzare la fattprizzazione LU sparsa.
*/
void
dSLUFree( factors_t *LUfactors ) {
/* Free the LU factors in the factors handle */
SUPERLU_FREE ( LUfactors -> perm_r );
SUPERLU_FREE ( LUfactors -> perm_c );
Destroy_SuperNode_Matrix ( LUfactors -> L );
Destroy_CompCol_Matrix ( LUfactors -> U );
SUPERLU_FREE ( LUfactors -> L );
SUPERLU_FREE ( LUfactors -> U );
SUPERLU_FREE ( LUfactors );
}
Primi esempi di uso della libreria pthread
File: thread-esempio1.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
sleep((rand()%3)+1) ;
printf("\n%d: Hello World!\n", threadid);
pthread_exit(NULL);
}
int
main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc, t;
for(t=0; t<NUM_THREADS; t++){
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL); /* aspetta che the thread abbiano finito */
return 0 ;
}
File: thread-esempio2.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
/* prototipo della thread */
//extern void *do_work(void *arg);
/* struttura che conterra' gli argomenti */
struct arguments {
int size ;
double *array ;
double sum ;
} ;
/* Routine della thread,fa la somma di array */
void *do_work(void *arg) {
struct arguments *argument;
int i ;
argument = (struct arguments*)arg;
argument -> sum = 0;
for ( i=0 ; i < argument -> size ; ++i )
argument -> sum += argument -> array[i];
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i;
double array[10000] ;
double a, sum ;
void *return_value;
pthread_t worker_thread;
struct arguments arg ;
arg . array = array;
arg . size = 10000 ;
for ( i=0 ; i < arg . size ; ++i )
arg . array[i] = rand() / 123.923 ;
if ( pthread_create(&worker_thread, NULL, do_work, (void *) &arg) ) {
printf("Error while creating thread\n");
exit(1);
}
printf("Valore argomento %lf\n", arg.sum ) ;
printf("Valore argomento %lf\n", arg.sum ) ;
printf("Valore argomento %lf\n", arg.sum ) ;
/* sincronizzazione, aspetto che finisca la thread */
if (pthread_join(worker_thread, &return_value)) {
printf("Error while waiting for thread\n");
exit(1);
}
printf("Valore argomento DOPO SINC %lf\n", arg.sum ) ;
printf("Valore argomento DOPO SINC %lf\n", arg.sum ) ;
pthread_exit(NULL) ;
return 0 ;
}
File: thread-esempio3.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
/* prototipo della thread */
//extern void *do_work(void *arg);
/* struttura che conterra' gli argomenti */
struct arguments {
int size ;
double *array ;
} ;
struct return_value {
double sum ;
} ;
/* Routine della thread,fa la somma di array */
void *do_work(void *arg) {
struct arguments * argument;
struct return_value * ret_value ;
ret_value = malloc( sizeof( struct return_value ) ) ;
sleep(1) ;
int i ;
argument = (struct arguments*)arg;
ret_value -> sum = 0;
for ( i=0 ; i < argument -> size ; ++i )
ret_value -> sum += argument -> array[i];
pthread_exit(ret_value) ;
}
int
main(int argc, char *argv) {
int i;
double array[100] ;
struct return_value * rval ;
pthread_t worker_thread;
struct arguments arg ;
arg . array = array;
arg . size = 100 ;
for ( i=0 ; i < arg . size ; ++i )
arg . array[i] = i ;
if ( pthread_create(&worker_thread, NULL, do_work, (void *) &arg) ) {
printf("Error while creating thread\n");
exit(1);
}
/* sincronizzazione, aspetto che finisca la thread */
if (pthread_join(worker_thread, (void**) &rval)) {
printf("Error while waiting for thread\n");
exit(1);
}
printf("Valore argomento %lf\n", rval -> sum ) ;
pthread_exit(NULL) ;
return 0 ;
}
Incremento di un contatore con due thread separate
Versione non funzionate:
File: thread-contatore.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static int counter ;
/*
Questo esempio non funziona perche' manca la sincronizzazione
*/
void *contatore(void * a) {
int i = 0 ;
for ( i = 0 ; i < 100000 ; ++i ) {
/* sezione critica!, Durante l'incremento le altre thread non
devono avere accesso a counter */
counter = counter + 1 ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
void * retv ;
pthread_t contatore_thread[2] ;
counter = 0 ;
for ( i = 0 ; i < 2 ; ++i ) {
printf("Creo contatore N.%d\n", i) ;
if ( pthread_create(&contatore_thread[i], NULL, contatore, NULL ) ) {
printf("Error while creating thread\n");
exit(1);
}
}
/* aspetto che abbiamo finito the thread */
for ( i = 0 ; i < 2 ; ++i ) {
if ( pthread_join(contatore_thread[i], &retv ) ) {
printf("Error while joining thread\n");
exit(1);
}
}
printf("contatore = %d\n", counter) ;
pthread_exit(NULL) ;
return 0 ;
}
Versione funzionate:
File: thread-contatore-ok.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex_for_counter ;
static int counter ;
/*
Questo esempio funziona perche' c'e' la sincronizzazione
*/
void *contatore(void * a) {
int i ;
for ( i = 0 ; i < 100000 ; ++i ) {
/* sezione critica!, Durante l'incremento le altre thread non
devono avere accesso a counter */
pthread_mutex_lock(&mutex_for_counter) ; /* manca controllo sulla chiamata */
counter = counter + 1 ;
pthread_mutex_unlock(&mutex_for_counter) ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
void * retv ;
pthread_t contatore_thread[10] ;
if ( pthread_mutex_init(&mutex_for_counter, NULL) ) {
/* inizializzo la variabile per il mutex */
printf("Error while creating mutex\n");
exit(1);
}
counter = 0 ;
for ( i = 0 ; i < 10 ; ++i ) {
printf("Creo contatore N.%d\n", i) ;
if ( pthread_create(&contatore_thread[i], NULL, contatore, NULL ) ) {
printf("Error while creating thread\n");
exit(1);
}
}
/* aspetto che abbiamo finito the thread */
for ( i = 0 ; i < 10 ; ++i ) {
if ( pthread_join(contatore_thread[i], &retv ) ) {
printf("Error while joining thread\n");
exit(1);
}
}
printf("contatore = %d\n", counter) ;
if ( pthread_mutex_destroy(&mutex_for_counter) ) {
/* inizializzo la variabile per il mutex */
printf("Error while destroying mutex\n");
exit(1);
}
pthread_exit(NULL) ;
return 0 ;
}
Problema dei filosofi a cena
Per una descrizione del problema di veda il link wikipedia Problema dei filosofi a cena
Le prime due versioni non funzionano ma vanno in DEADLOCK.
File: thread-filosofi.c:
/*
Versione NON funzionante del problema dei filosofi.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define N_FILOSOFI 5
typedef enum { PENSO, MANGIO, DORMO } STATO_FILOSOFO ;
typedef enum { LIBERA, INUSO } STATO_FORCHETTE ;
static STATO_FILOSOFO stato_filosofo[N_FILOSOFI] ;
static STATO_FORCHETTE stato_forchetta[N_FILOSOFI] ;
void
prende_forchetta_destra( int const n ) {
int f_destra = (n+1) % N_FILOSOFI ;
if ( stato_forchetta[f_destra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta destra\n",n) ;
while ( stato_forchetta[f_destra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_destra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta destra\n",n) ;
}
void
prende_forchetta_sinistra( int const n) {
int f_sinistra = n ;
if ( stato_forchetta[f_sinistra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta sinistra\n",n) ;
while ( stato_forchetta[f_sinistra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_sinistra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta sinistra\n",n) ;
}
void
lascia_forchetta_destra( int const n ) {
int f_destra = (n+1) % N_FILOSOFI ;
stato_forchetta[f_destra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta destra\n",n) ;
}
void
lascia_forchetta_sinistra( int const n) {
int f_sinistra = n ;
stato_forchetta[f_sinistra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta sinistra\n",n) ;
}
void *
filosofo(void *arg) {
int n = (int) arg ;
while ( 1 ) { /* ciclo infinito */
/* pensa */
stato_filosofo[n] = PENSO ;
printf("Il filosofo N.%d PENSA\n", n) ;
prende_forchetta_destra( n ) ;
prende_forchetta_sinistra( n ) ;
/* mangia */
stato_filosofo[n] = MANGIO ;
printf("Il filosofo N.%d MANGIA\n", n) ;
lascia_forchetta_destra( n ) ;
lascia_forchetta_sinistra( n ) ;
/* dorme */
stato_filosofo[n] = DORMO ;
printf("Il filosofo N.%d DORME\n", n) ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
int i ;
while ( 1 ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
printf("\nFILOSOFI: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_filosofo[i] ) {
case PENSO: printf(" P") ; break ;
case MANGIO: printf(" M") ; break ;
case DORMO: printf(" D") ; break ;
}
}
printf("\nFORCHETTE: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_forchetta[i] ) {
case LIBERA: printf(" L") ; break ;
case INUSO: printf(" U") ; break ;
}
}
printf("\n") ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
pthread_t filosofo_thread[N_FILOSOFI], monitor_thread ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
stato_filosofo[i] = DORMO ;
stato_forchetta[i] = LIBERA ;
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
printf("Creo il filosofo N.%d\n", i) ;
if ( pthread_create(&filosofo_thread[i], NULL, filosofo, (void *) i) ) {
printf("Error while creating thread\n");
exit(1);
}
}
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
printf("Error while creating thread\n");
exit(1);
}
pthread_exit(NULL) ;
return 0 ;
}
File: thread-filosofi-1.c:
/*
Versione NON funzionante del problema dei filosofi.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define N_FILOSOFI 5
pthread_mutex_t mutex_var ;
typedef enum { PENSO, MANGIO, DORMO } STATO_FILOSOFO ;
typedef enum { LIBERA, INUSO } STATO_FORCHETTE ;
static STATO_FILOSOFO stato_filosofo[N_FILOSOFI] ;
static STATO_FORCHETTE stato_forchetta[N_FILOSOFI] ;
void
prende_forchetta_destra( int const n ) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_destra = (n+1) % N_FILOSOFI ;
if ( stato_forchetta[f_destra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta destra\n",n) ;
while ( stato_forchetta[f_destra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_destra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta destra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
prende_forchetta_sinistra( int const n) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_sinistra = n ;
if ( stato_forchetta[f_sinistra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta sinistra\n",n) ;
while ( stato_forchetta[f_sinistra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_sinistra] = INUSO ; /* si accaparra la forchetta */
printf("Filosofo N.%d prende la forchetta sinistra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
lascia_forchetta_destra( int const n ) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_destra = (n+1) % N_FILOSOFI ;
stato_forchetta[f_destra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta destra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void
lascia_forchetta_sinistra( int const n) {
pthread_mutex_lock(&mutex_var) ; /* manca controllo sulla chiamata */
int f_sinistra = n ;
stato_forchetta[f_sinistra] == LIBERA ;
printf("Filosofo N.%d lascia la forchetta sinistra\n",n) ;
pthread_mutex_unlock(&mutex_var) ;
}
void *
filosofo(void *arg) {
int n = (int) arg ;
while ( 1 ) { /* ciclo infinito */
/* pensa */
stato_filosofo[n] = PENSO ;
printf("Il filosofo N.%d PENSA\n", n) ;
prende_forchetta_destra( n ) ;
prende_forchetta_sinistra( n ) ;
/* mangia */
stato_filosofo[n] = MANGIO ;
printf("Il filosofo N.%d MANGIA\n", n) ;
lascia_forchetta_destra( n ) ;
lascia_forchetta_sinistra( n ) ;
/* dorme */
stato_filosofo[n] = DORMO ;
printf("Il filosofo N.%d DORME\n", n) ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
int i ;
while ( 1 ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
printf("\nFILOSOFI: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_filosofo[i] ) {
case PENSO: printf(" P") ; break ;
case MANGIO: printf(" M") ; break ;
case DORMO: printf(" D") ; break ;
}
}
printf("\nFORCHETTE: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_forchetta[i] ) {
case LIBERA: printf(" L") ; break ;
case INUSO: printf(" U") ; break ;
}
}
printf("\n") ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
pthread_t filosofo_thread[N_FILOSOFI], monitor_thread ;
if ( pthread_mutex_init(&mutex_var, NULL) ) {
/* inizializzo la variabile per il mutex */
printf("Error while creating mutex\n");
exit(1);
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
stato_filosofo[i] = DORMO ;
stato_forchetta[i] = LIBERA ;
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
printf("Creo il filosofo N.%d\n", i) ;
if ( pthread_create(&filosofo_thread[i], NULL, filosofo, (void *) i) ) {
printf("Error while creating thread\n");
exit(1);
}
}
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
printf("Error while creating thread\n");
exit(1);
}
pthread_exit(NULL) ;
return 0 ;
}
La terza versione funziona ma non è garantito che tutti i filosofi mangino (non c’è il bilanciamento delle risorse).
File: thread-filosofi-2.c:
/*
Versione FUNZIONANTE del problema dei filosofi.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define N_FILOSOFI 5
/*
Versione funzionante del problema dei filosofi.
Per funzionare i servono due MUTEX separati, uno per prendere le forchette
ed uno per lasciare le forchette.
Usando un MUTEX solo il tentatico di prendere delle forchette da parte di un filosofo
provoca il blocco del rilascio delle forchette da parte di un altro filosofo
e quindi il DEADLOCK
*/
/* #define DEBUG */
pthread_mutex_t mutex_prende_forchette ;
pthread_mutex_t mutex_lascia_forchette ;
typedef enum { PENSO, MANGIO, DORMO } STATO_FILOSOFO ;
typedef enum { LIBERA, INUSO } STATO_FORCHETTE ;
static STATO_FILOSOFO stato_filosofo[N_FILOSOFI] ;
static STATO_FORCHETTE stato_forchetta[N_FILOSOFI] ;
void
prende_forchette( int const n ) {
pthread_mutex_lock(&mutex_prende_forchette) ; /* manca controllo sulla chiamata */
#ifdef DEBUG
printf("Filosofo N.%d cerca di prendere le forchette\n",n) ;
#endif
int f_destra = (n+1) % N_FILOSOFI ;
int f_sinistra = n ;
if ( stato_forchetta[f_destra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta destra\n",n) ;
while ( stato_forchetta[f_destra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
if ( stato_forchetta[f_sinistra] == INUSO ) {
printf("Filosofo N.%d aspetta la forchetta sinistra\n",n) ;
while ( stato_forchetta[f_sinistra] == INUSO ) ; /* aspetto che si liberi la forchetta */
}
stato_forchetta[f_destra] = INUSO ; /* si accaparra la forchetta */
stato_forchetta[f_sinistra] = INUSO ; /* si accaparra la forchetta */
#ifdef DEBUG
printf("Filosofo N.%d prende le forchette\n",n) ;
#endif
pthread_mutex_unlock(&mutex_prende_forchette) ;
}
void
lascia_forchette( int const n ) {
pthread_mutex_lock(&mutex_lascia_forchette) ; /* manca controllo sulla chiamata */
int f_destra = (n+1) % N_FILOSOFI ;
int f_sinistra = n ;
stato_forchetta[f_destra] = LIBERA ;
stato_forchetta[f_sinistra] = LIBERA ;
#ifdef DEBUG
printf("Filosofo N.%d lascia le forchette\n",n) ;
#endif
pthread_mutex_unlock(&mutex_lascia_forchette) ;
}
void *
filosofo(void *arg) {
int n = (int) arg ;
while ( 1 ) { /* ciclo infinito */
/* pensa */
stato_filosofo[n] = PENSO ;
printf("Il filosofo N.%d PENSA\n", n) ;
prende_forchette( n ) ;
/* mangia */
stato_filosofo[n] = MANGIO ;
printf("Il filosofo N.%d MANGIA\n", n) ;
sleep(1) ;
lascia_forchette( n ) ;
/* dorme */
stato_filosofo[n] = DORMO ;
printf("Il filosofo N.%d DORME\n", n) ;
//sleep(1) ;
}
pthread_exit(NULL) ;
}
void *
monitor(void *arg) {
int i ;
while ( 1 ) { /* ciclo infinito */
sleep(1) ; /* aspetta un secondo */
printf("\nFILOSOFI: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_filosofo[i] ) {
case PENSO: printf(" P") ; break ;
case MANGIO: printf(" M") ; break ;
case DORMO: printf(" D") ; break ;
}
}
printf("\nFORCHETTE: ") ;
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
switch ( stato_forchetta[i] ) {
case LIBERA: printf(" L") ; break ;
case INUSO: printf(" U") ; break ;
}
}
printf("\n") ;
}
pthread_exit(NULL) ;
}
int
main(int argc, char *argv) {
int i ;
pthread_t filosofo_thread[N_FILOSOFI], monitor_thread ;
if ( pthread_mutex_init(&mutex_prende_forchette, NULL) ) {
/* inizializzo la variabile per il mutex */
printf("Error while creating mutex\n");
exit(1);
}
if ( pthread_mutex_init(&mutex_lascia_forchette, NULL) ) {
/* inizializzo la variabile per il mutex */
printf("Error while creating mutex\n");
exit(1);
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
stato_filosofo[i] = DORMO ;
stato_forchetta[i] = LIBERA ;
}
for ( i = 0 ; i < N_FILOSOFI ; ++i ) {
printf("Creo il filosofo N.%d\n", i) ;
if ( pthread_create(&filosofo_thread[i], NULL, filosofo, (void *) i) ) {
printf("Error while creating thread\n");
exit(1);
}
}
if ( pthread_create(&monitor_thread, NULL, monitor, NULL) ) {
printf("Error while creating thread\n");
exit(1);
}
pthread_exit(NULL) ;
return 0 ;
}
Corso di Metodi Matematici e Calcolo per Ingegneria (AA 2005/2006)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 13:30 - 16:30 | P2 |
Martedì | 8.30 - 10.30 | R1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 10 - 12 | 505 |
Mercoledì | 10 - 12 | 505 |
Dispense del corso
Lucidi sulle trasformate di Laplace
- versione a schermo laplace-trasformata-1x1.pdf
- versione stampabile 2 lucidi per foglio laplace-trasformata-1x2.pdf
- versione stampabile 4 lucidi per foglio laplace-trasformata-2x2.pdf
Lucidi sulla trasformata Z
- versione a schermo Z-trasformata-1x1.pdf
- versione stampabile 2 lucidi per foglio Z-trasformata-1x2.pdf
- versione stampabile 4 lucidi per foglio Z-trasformata-2x2.pdf
Lucidi preliminari sulla trasformate di Fourier
- versione a schermo Fourier-1x1.pdf
- versione stampabile 2 lucidi per foglio Fourier-1x2.pdf
- versione stampabile 4 lucidi per foglio Fourier-2x2.pdf
Minidispensa sui numeri complessi
- pdf.
Esami Svolti
Appello 9 gennaio 2006
Appello 20 febbraio 2006
Appello 19 giugno 2006
Appello 12 luglio 2006
Appello 30 agosto 2006
P.h.D. Corso di Programmazione in C++ (AA 2005/2006)
Lezione del 10/7/2006
- Nuove funzionalita’ del C++ rispetto al C: L’overloading
File: ex001.cc:
/*
* Cosa ha in piu' in C++ a basso livello.
*
*/
/*
* Il commento su singola riga.
* dopo i caratteri //
* tutto quello che segue fino a fine riga e' ignorato
*/
// questo e' un commento
// e' simile al ! del FORTRAN 90
/*
* OVERLOADING
*
*/
// MAX versione 1 (tra interi)
// Esempio, voglio definire una funzione massimo tra due interi
int
max( int a, int b ) {
if ( a > b ) return a ;
else return b ;
}
// MAX versione 2 (tra doppia precisione)
// Se ora voglio definire le funzione massino tra "double"
// in C non posso scrivere
double
max( double a, double b ) {
if ( a > b ) return a ;
else return b ;
}
// MAX versione 3 (tra doppia interi lunghi senza segno)
// Se ora voglio definire le funzione massino tra "unsigned long long"
// in C non posso scrivere
unsigned long long
max( unsigned long long a, unsigned long long b ) {
if ( a > b ) return a ;
else return b ;
}
int
main() {
int a = 1 ; // definisco e inizializzo una variabile intera
int b = 2 ; // definisco e inizializzo una variabile intera
int c = max(a,b) ; // USO MAX VERSIONE 1
// posso definire e inizializzare variabili nuove
// in qualunque del codice (SONO C++)
double fa = 1 ; // definisco e inizializzo una variabile doppia precisione
double fb = 2 ; // definisco e inizializzo una variabile doppia precisione
double fc = max(fa,fb) ; // USO MAX VERSIONE 2
unsigned long long ulla = 1 ;
unsigned long long ullb = 2 ;
unsigned long long ullc = max(ulla,ullb) ; // USO MAX VERSIONE 3
}
/*
ASSEMBLER GENERATO DAL COMPILATORE gcc DELLA gnu (versione 4.0.1)
il comando e': gcc -fverbose-asm -S -O2 ex001.cc
-S = ferma la compilazione alla fase di generazione dell'assembler
-fverbose-asm = mette qualche commento all'assembler in modo che
sia piu' leggibile
-O2 = -O e' il livello di ottimizzazione
-O0 nessuna ottimizzazione -O3 massima ottimizzazione
.text
.align 2
.p2align 4,,15
.globl __Z3maxii
;;;; ROUTINE MAX tra interi
;;;; nei registri r3 r4 sono passati gli argomenti a e b
__Z3maxii:
LFB2:
cmpw cr7,r3,r4 ; b, tmp121, a
bgtlr cr7 ;;; se a < b ritorna dalla routine
mr r3,r4 ; a, b ;;; copia il resitro r3 (a) nel registro r4 (valore di ritorno)
blr ;;; ritorna dalla rotine
LFE2:
.align 2
.p2align 4,,15
.globl __Z3maxdd
;;;; ROUTINE MAX tra doppia precisione
;;;; nei registri f1 f2 sono passati gli argomenti a e b
;;;; fn sono i registri floating point della FPU
;;;; fsub x,y,z --> z = x-y
;;;; fneg x,y --> x = -y
;;;; fsel r,t,a,b --> se t > 0 r = a altrimenti r = b
;;;; blr --> return dalla subroutine
__Z3maxdd:
LFB3:
fsub f0,f1,f2 ; tmp123, a, b ;; f0 = f1-f2 = a-b
fsel f1,f0,f1,f2 ; tmp124, tmp123, a, b ;;; istruzione inutile ?
fneg f0,f0 ; tmp125, tmp123 ;;;; f0 = |f0| = |a-b|
fsel f1,f0,f2,f1 ; <result>, tmp125, b, tmp124
blr ;
;;;; ROUTINE MAX tra interi lunghi
;;;; nei registri (r3,r4) ed (r5,r6) sono passati gli argomenti a e b
;;;; cioe' uso una coppia di registri per ogni argomento
;;;; questo perche i registri sono di 4 byte e gli argomenti sono di 8 byte
;;;; I registri (r5,r6) contengono il valore in uscita
LFE3:
.align 2
.p2align 4,,15
.globl __Z3maxyy
__Z3maxyy:
LFB4:
cmplw cr7,r3,r5 ; b, tmp121, a ;; contronfo la parte "alta" del numero intero
bgtlr cr7
cmpw cr7,r3,r5 ; b, tmp122, a
bne cr7,L13 ;
cmplw cr7,r4,r6 ; b, tmp123, a ;; confronto la parte "bassa" del numero intero
bgtlr cr7
.p2align 4,,15
L13:
mr r3,r5 ; a, b
mr r4,r6 ; a, b
blr
LFE4:
.align 2
.p2align 4,,15
.globl _main
_main:
LFB5:
li r3,0 ; <result>,
blr ;
LFE5:
*/
File: ex002.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* OVERLOADING
*
*/
// SOMMA versione 1 (tra interi)
// Esempio, voglio definire una funzione che somma due interi
int
somma( int a, int b ) { return a+b ; }
// SOMMA versione 2 (tra interi)
// Esempio, voglio definire una funzione che somma due interi
// ma voglio restituire il risultato in un intero lungo
long long
somma( int a, int b ) { return a+b ; }
/// NON SI PUO' FARE!!!
/*
OCCHIO !!!!!!!!!!!!!
il compilatore distingue routine con lo stesso nome
e argomenti diversi.
Non c'e' traccia dell'argomento di ritorno per scelta,
infatti i meccanismi di conversione e promizione verrebbero
notevolmente complicati se questo venisse permesso.
*/
int
main() {
int a = 1 ; // definisco e inizializzo una variabile intera
int b = 2 ; // definisco e inizializzo una variabile intera
float c = somma(a,b) ; // ammesso che compili somma versione 1 e 2
// non sa se usare versione 1 o versione 2
}
- Nuove funzionalita’ del C++ rispetto al C: funzioni inline
File: ex003.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* FUNZIONI INLINE
*
*/
// FUNZIONE versione 1 (tra interi)
// Se la funzione come in questo caso e' molto semplice, il tempo
// perso a fare la chiamata e' paragonabile se non superiore
// al tempo di esecuzione della routine stessa.
extern
int
funzione( int a, int b );
// FUNZIONE versione 2 (tra interi)
// per evitare la chiamata alla funzione, uso la direttiva inline
// in questo modo la funzione somma_inline non viene "richiamata"
// ma "espansa" nel punto di chiamata
inline // dichiaro la funzione come "inline"
int
funzione_inline( int a, int b ) {
int c = a+b ;
return c*c ;
}
int
esempio(int a, int b) {
int c = funzione(a,b) ;
int d = funzione_inline(a,b) ;
int e = c-d ;
return e ;
}
int
main() {
int result = esempio( 1, 2 );
return 1 ;
}
/*
CODICE ASSEMBLER GENERATO
;;;; funzione esempio
;;;; i registri r3 ed r4 contengono gli argomenti
;;;; il risultato e' passato nel registro r3
.text
.align 2
.p2align 4,,15
.globl __Z7esempioii
__Z7esempioii:
;;;; deve costruire int c = funzione(a,b) ;
;;;;
LFB3:
mflr r0 ;,
LCFI0:
stmw r28,-16(r1) ;, ;;;; prepara lo stack per l'indirizzo di ritorno
LCFI1:
mr r28,r4 ; b, b ;;;; copia i valori dei registri r3 e r4
mr r29,r3 ; a, a ;;;; nei registri r28 e r29
stw r0,8(r1) ;,
LCFI2:
stwu r1,-80(r1) ;,,
LCFI3:
add r29,r29,r28 ; c, a, b ;;;;; queste due righe di assembler
mullw r29,r29,r29 ; tmp124, c, c ;;;;; sono l'espansione della funzione inline
bl L__Z8funzioneii$stub ; ;;;;; chiamata della funzione fuzione(r3,r4)
addi r1,r1,80 ;,,
subf r3,r29,r3 ; <result>, tmp124, ;;;; esegue r3 = c-d
lwz r0,8(r1) ;, ;;;; operazione varie da fare per il return della routine
lmw r28,-16(r1) ;,
mtlr r0 ;,
blr ;
;;;; programma PRINCIPALE
LFE3:
.align 2
.p2align 4,,15
.globl _main
_main:
LFB4:
mflr r0 ;,
LCFI4:
li r3,1 ;,
li r4,2 ;,
stw r0,8(r1) ;,
LCFI5:
stwu r1,-80(r1) ;,,
LCFI6:
bl L__Z8funzioneii$stub ;
addi r1,r1,80 ;,,
li r3,1 ; <result>,
lwz r0,8(r1) ;,
mtlr r0 ;,
blr ;
LFE4:
*/
File: ex004.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* FUNZIONI INLINE: come si sarebbe fatto in C
*
*/
// FUNZIONE versione 1 (tra interi)
// Se la funzione come in questo caso e' molto semplice, il tempo
// perso a fare la chiamata e' paragonabile se non superiore
// al tempo di esecuzione della routine stessa.
extern
int
funzione( int a, int b );
// FUNZIONE versione 2 (tra interi)
// per evitare la chiamata alla funzione, uso la direttiva inline
// in questo modo la funzione somma_inline non viene "richiamata"
// ma "espansa" nel punto di chiamata
inline // dichiaro la funzione come "inline"
int
funzione_inline( int a, int b ) {
int c = a-b ;
return c*c ;
}
/*
* Nel C non esistono le funzione inline, si usano le MACRO,
* occhio pero' che si possono fare degli errori
*/
#define FUNZIONE_INLINE(A,B) (A-B)*(A-B)
/*
* Fatta in questo modo e' sbagliata, infatti se la uso nel
* seguente modo:
*
* int c = FUNZIONE_INLINE( a-3, b+2 )
*
* espansa diventa
*
* int c = ( a-3 - b+2 )*( a-3 - b+2 );
*
* che e' diverso da
*
* int c = ( (a-3) - (b+2) )*( (a-3) - (b+2) );
*
* come uno in realta' avrebbe inteso.
*/
/* soluzione "alla C", uso delle parentesi */
#define FUNZIONE_INLINE_CORRETTA(A,B) ((A)-(B))*((A)-(B))
/*
* Fatta in questo modo e' corretta, infatti
*
* int c = FUNZIONE_INLINE( a-3, b+2 )
*
* espansa diventa
*
* int c = ( (a-3) - (b+2) )*( (a-3) - (b+2) );
*
*/
/*
* PROBLEMI E LIMITAZIONI
*
* 1) le macro non permettono la defizione di funzioni complicate
* se non con trucchi complicato e comunque solo fino ad un certo
* punto
* 2) Nelle macro non si possono definire raccoglimenti o altro, ma
* questo compito viene demandato all'ottimizzatore.
*
*/
/*
* Conclusione: quando possibile al posto delle MACRO usare le funzioni
* inline
*
*/
- Passaggio di parametri, uso delle reference
File: ex005.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* REFERENCE: ovvero puntatori "nascosti"
*
*/
/*
* Esempio:
* voglio fare una subrutine che modifica un suo argomento.
* Ad esempio voglio calcolare sqrt(aromento+2)
*/
#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,.
#include <iostream> // includo le definizioni per I/O in c++
using namespace std ;
// le definizioni dell'I/O sono contenute in un namespace di nome std.
// per estrarre tutto il contenuto del namespace std si usa l'istruzione
// scritta sopra.
// Se non uso "using namespace std" per accedere a cout dovrei usare
// l'operatore di scope :: in questo modo std::cout
void
esempio_stupido_errato( double a ) {
a = sqrt(a+2) ;
}
int
main() {
double a = 3 ;
esempio_stupido_errato( a ) ;
cout << "risultato = " << a << "\n" ;
// cout e' oggetto per I/O
// cout = character outout
// << operatore di output
// OGGETTO I/O << quello da sparare fuori
// ==> restituisce OGGETTO I/O e quindi posso usare ancora <<
//
// Di fatti una cosa del tipo
//
// cout << a << b << c ;
// si deve interpretare come
//
// ((cout << a) << b) << c ;
// o meglio
// cout << a ;
// cout << b ;
// cout << c ;
//
// ad esempio
// cout << "risultato = " << a << "\n" ;
// e' equivalente a
// cout << "risultato = " ;
// cout << a ;
// cout << "\n" ;
// posso richiamarlo con l'argomento errato
esempio_stupido_errato( 2 ) ; // promozione del 2 da intero a double
return 0 ;
}
/*
* per compilare questo esempio bisogna usare la libreria
* standard del c++ che contiene ad esempio l'I/O come segue:
*
* gcc -Wall ex005.cc -lstdc++
*/
File: ex006.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* REFERENCE: ovvero puntatori "nascosti"
*
*/
/*
* Esempio:
* voglio fare una subrutine che modifica un suo argomento.
* Ad esempio voglio calcolare sqrt(aromento+2)
*/
#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,.
#include <iostream> // includo le definizioni per I/O in c++
using namespace std ;
// le definizioni dell'I/O sono contenute in un namespace di nome std.
// per estrarre tutto il contenuto del namespace std si usa l'istruzione
// scritta sopra.
// Se non uso "using namespace std" per accedere a cout dovrei usare
// l'operatore di scope :: in questo modo std::cout
void
esempio_stupido_giusto( double * a ) { // per modificare il contenuto
// di "a" gli devo passare il suo indirizzo!
*a = sqrt(*a+2) ;
}
int
main() {
double a = 3 ;
esempio_stupido_giusto( & a ) ; // operatore & serve per estrarre l'indirizzo
cout << "risultato = " << a << "\n" ;
// cout e' oggetto per I/O
// cout = character outout
// << operatore di output
// OGGETTO I/O << quello da sparare fuori
// ==> restituisce OGGETTO I/O e quindi posso usare ancora <<
//
// Di fatti una cosa del tipo
//
// cout << a << b << c ;
// si deve interpretare come
//
// ((cout << a) << b) << c ;
// o meglio
// cout << a ;
// cout << b ;
// cout << c ;
//
// ad esempio
// cout << "risultato = " << a << "\n" ;
// e' equivalente a
// cout << "risultato = " ;
// cout << a ;
// cout << "\n" ;
return 0 ;
}
/*
* per compilare questo esempio bisogna usare la libreria
* standard del c++ che contiene ad esempio l'I/O come segue:
*
* gcc -Wall ex005.cc -lstdc++
*/
File: ex007.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* REFERENCE: ovvero puntatori "nascosti"
*
*/
/*
* Esempio:
* voglio fare una subrutine che modifica un suo argomento.
* Ad esempio voglio calcolare sqrt(aromento+2)
*/
#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,.
#include <iostream> // includo le definizioni per I/O in c++
using namespace std ;
// le definizioni dell'I/O sono contenute in un namespace di nome std.
// per estrarre tutto il contenuto del namespace std si usa l'istruzione
// scritta sopra.
// Se non uso "using namespace std" per accedere a cout dovrei usare
// l'operatore di scope :: in questo modo std::cout
void
esempio_stupido_modo_cpp( double & a ) { // per modificare il contenuto
// di "a" gli devo passare il suo indirizzo!
// non lo passo tramite un puntatore
// ma tramite un riferimento.
// La sintassi usa &
a = sqrt(a+2) ;
// Di fatto a e' un puntatore ma quando lo uso faccio
// riferimeno al suo contenuto. Di fatto e' un ALIAS (sinonimo)
// della variabile passata.
}
int
main() {
double a = 3 ;
esempio_stupido_modo_cpp( a ) ;
cout << "risultato = " << a << "\n" ;
// cout e' oggetto per I/O
// cout = character outout
// << operatore di output
// OGGETTO I/O << quello da sparare fuori
// ==> restituisce OGGETTO I/O e quindi posso usare ancora <<
//
// Di fatti una cosa del tipo
//
// cout << a << b << c ;
// si deve interpretare come
//
// ((cout << a) << b) << c ;
// o meglio
// cout << a ;
// cout << b ;
// cout << c ;
//
// ad esempio
// cout << "risultato = " << a << "\n" ;
// e' equivalente a
// cout << "risultato = " ;
// cout << a ;
// cout << "\n" ;
float b = 2 ;
esempio_stupido_modo_cpp( b ) ; // errore non esiste promozione nei riferimenti
esempio_stupido_modo_cpp( 2.0 ) ; // errore 2.0 e' una costante e non puo' essere
// modificata
return 0 ;
}
/*
* per compilare questo esempio bisogna usare la libreria
* standard del c++ che contiene ad esempio l'I/O come segue:
*
* gcc -Wall ex005.cc -lstdc++
*/
- Uso delle reference per sezionare le strutture
File: ex008.cc:
/*
* Cosa ha in piu'in C++ a basso livello.
*
*/
/*
* REFERENCE: ovvero puntatori "nascosti"
*
*/
/*
* Esempio:
* Uso delle reference per accedere a strutture complesse
*/
#include <cmath> // includo le definizioni delle funzioni matematiche sin, cos, etc,.
#include <iostream> // includo le definizioni per I/O in c++
using namespace std ;
// le definizioni dell'I/O sono contenute in un namespace di nome std.
// per estrarre tutto il contenuto del namespace std si usa l'istruzione
// scritta sopra.
// Se non uso "using namespace std" per accedere a cout dovrei usare
// l'operatore di scope :: in questo modo std::cout
// definisco una stuttura complicata
typedef struct {
double a, b, c ;
} struct1 ;
typedef struct {
struct1 sa, sb ;
int ia, ib, ic ;
} struct2 ;
typedef struct {
struct1 s1 ;
struct2 s2 ;
} struct3 ;
/*
* +-------------+
* | s1----+ |
* | | a | |
* | +-----+ |
* | | b | |
* | +-----+ |
* | | c | |
* | +-----+ |
* | s2--------+ |
* | | sa----+ | |
* | | | a | | |
* | | +-----+ | |
* | | | b | | |
* | | +-----+ | |
* | | | c | | |
* | | +-----+ | |
* | | sb----+ | |
* | | | a | | | <----
* | | +-----+ | | |
* | | | b | | | <---- nel prossimo esempio accedo a questi campi
* | | +-----+ | | |
* | | | c | | | <----
* | | +-----+ | |
* | | +-----+ | |
* | | | ia | | |
* | | +-----+ | |
* | | | ib | | |
* | | +-----+ | |
* | | | ic | | |
* | | +-----+ | |
* | +---------+ |
* +-------------+
*
* Stuttura tipo struct2
* / \
* s1 s2---------------
* / | \ / \ \ \ \
* a b c sa sb ia ib ic
* / | \ / | \
* a b c a b c
*/
void
accedi_a_sb( struct3 & s ) {
s.s2.sb.a = 1 ;
s.s2.sb.b = 2 ;
s.s2.sb.c = 3 ;
}
void
accedi_a_sb_migliorato( struct3 & s ) {
// uso un riferimento per accedere alla sottostruttura
struct1 & sb_ref = s.s2.sb ;
sb_ref.a = 1 ;
sb_ref.b = 2 ;
sb_ref.c = 3 ;
// avrei potuto usare anche un puntatore come segue
struct1 * sb_ptr = & s.s2.sb ;
(*sb_ptr).a = 1 ; // modo 1
(*sb_ptr).b = 2 ;
(*sb_ptr).c = 3 ;
sb_ptr -> a = 1 ; // con l'operatore -> e' piu leggibile
sb_ptr -> b = 2 ;
sb_ptr -> c = 3 ;
}
Lezione del 11/7/2006
- L’I/O del C++, alcuni esempi
File: ex010.cc:
/*
* Il sistema di I/O in C++
*
*/
#include <iostream> // includo le definizioni per I/O in c++
#include <iomanip> // manipolatori per la formattazione
#include <cmath> // sin, cos, tan etc
using namespace std ;
#include <stdio.h> // Input Output del C per fare dei confronti
// le definizioni dell'I/O sono contenute in un namespace di nome std.
// per estrarre tutto il contenuto del namespace std si usa l'istruzione
// scritta sopra.
// In namespace verra' descritto meglio piu' avanti
/*
con iostream di definiscono 3 oggetti
cin : oggetto per la gestione dello standard input (lettura terminale)
analogo del file descriptor (di tipo FILE *) stdin
cout : oggetto per la gestione dello standard output (scrittura su terminale)
analogo del file descriptor (di tipo FILE *) stdout
cerr : oggetto per la gestione dello standard output di errore (scrittura su terminale)
analogo del file descriptor (di tipo FILE *) stderr
La differenza tra cout e cerr e' che cerr non e' bufferizzato,
cioe' la scrittura sul file e' immediata.
*/
/*
I "COMANDI" per scrivere e leggere con questi oggetti sono
principalemente 2
operatore << che viene usato negli oggetti cout e cerr per mandare
un oggetto (int,doble,stringa etc) in uscita
operatore >> che viene usato nell oggetto cin per leggere
un oggetto (int,doble,stringa etc) da terminale
*/
int
main() {
/* esempio di stampa di una stringa */
cout << "ciao sono una stringa\n" ; // output con l'I/O del C++
printf( "ciao sono una stringa\n" ) ; // output con l'I/O del C
/* esempio di stampa di un intero con messaggio */
int i = 234 ;
cout << "i = " << i << "\n" ; // output con l'I/O del C++
// Questa linea e' equivalente
// cout << "i = " ;
// cout << i ;
// cout << "\n" ;
//
// << e' associativo a sinistra, va pensato come +,
// ad esempio a+b+c+d e' come scrivere
// (((a+b)+c)+d)
// ed e' come eseguire
// tm1 = a+b ; tmp2 = tmp1 + c ; tmp3 = tmp2 + d
//
((cout << "i = ") << i ) << "\n" ; // output con l'I/O del C++
printf( "i = %d\n", i ) ; // output con l'I/O del C
/* vantaggio dell'I/O tipo C++, se ora cambio uscita da int a double
devo cambiare il formattatore in C */
double a = 2.45 ;
cout << "a = " << a << "\n" ; // output con l'I/O del C++
printf( "a = %g\n", a ) ; // output con l'I/O del C
/* svantaggi e' piu' logorroico il modo la formattazione in C++ */
//cout . setprecision(5) ;
cout << "a = **" << setw(10) << setprecision(5) << left << a << "**\n" ; // output con l'I/O del C++
printf( "a = **%10.5f**\n", a ) ; // output con l'I/O del C
/*
Manipolatori principali
setw(size) riserva size caratteri per il prossimo output
left allinea la prossima stampa a sinistra
setprecision(digit) numero massimo di cifre (compreso il punto e il segno)
riservate per stampare un numero
dec stampa l'intero successivo in decimale
oct stampa l'intero successivo in ottale
hex stampa l'intero successivo in esadecimale
uppercase stampa in numero esadecimale in maiuscolo
*/
/* esempio stampa di pigrego a varie precisioni */
double pi = 4*atan(1.0) ;
cout << "pi(3cifre) = " << setprecision(3) << pi << "\n"
<< "pi(5cifre) = " << setprecision(5) << pi << "\n"
<< "pi(10cifre) = " << setprecision(10) << pi << "\n"
<< "pi(15cifre) = " << setprecision(15) << pi << "\n"
<< "pi(20cifre) = " << setprecision(20) << pi << "\n"
<< "pi(30cifre) = " << setprecision(30) << pi << "\n"
<< "pi(50cifre) = " << setprecision(50) << pi << "\n"
<< "pi(100cifre) = " << setprecision(100) << pi << "\n" ;
cout << "123 in varie basi: "
<< dec << 123 << " decimale\n"
<< oct << 123 << " ottale\n"
<< hex << uppercase << 123 << " esadecimale\n" << dec ;
/* esempio di lettura da terminale */
cout << "inserisci un intero: " ;
cin >> i ;
cout << "hai inserito " << i << "\n" ;
cout << "inserisci un intero e un floating point: " ;
cin >> i >> a ;
if ( !cin ) { // ! applicato all'oggetto di I/O restuisce un booleano
// true se c'e' stato un errore.
cerr << "Errore in lettura dei dati\n" ;
}
cout << "hai inserito " << i << " ed " << a << "\n" ;
}
- L’I/O del C++, scrittura su file
File: ex011.cc:
/*
* Il sistema di I/O su file in C++
* e i tipo bool aggiunti nel C++
*/
#include <iostream> // includo le definizioni per I/O in c++
#include <fstream> // includo le definizioni per I/O su FILE in c++
#include <iomanip> // manipolatori per la formattazione
#include <cmath> // sin, cos, tan etc
using namespace std ;
int
main() {
/* esempio di lettura da un file in C++ */
// ifstream e' il tipo oggetto di lettura
ifstream file ; // definisco file come oggetto (descrittore) di un file in lettura
file . open("pippo.txt") ; // apro in lettura il file pippo.txt
bool not_ok = ! file ; // bool e' il tipo booleano
// puo assumere sono due valori : true e false
// in questo caso not_ok = true se qualcosa e' andato
// storto
if ( not_ok ) {
cerr << "Errore in apertura del file pippo.txt\n" ;
}
// ! applicato all'oggetto file restituisce un booleano.
// ! opertore di negazione di un booleano scambia true <-> false
// file da solo e' oggetto di I/O NON UN BOOLEANO
// !(!file) e' un booleano che vale true se tutto va bene
cout << "INIZIO LETTURA (MODO SINGOLA STRINGA)\n" ;
while ( ! file . eof() ) {
char line[1000] ;
file >> line ; // leggo una stringa fino al primo spazio,tab o return etc,
if ( !file ) break ; // se c'e' un errore interrompo il ciclo
cout << "HO LETTO: " << line << "\n" ;
}
cout << "FINE LETTURA\n" ;
file . clear() ; // resetto tutti i flags di errore
file . seekg(ios::beg) ; // mi posisiziono all'inizio del file pippo.txt
// vanno resettati i flags altimenti non posso
// eseguire nessun comando sul file
cout << "INIZIO LETTURA (MODO SINGOLA STRINGA)\n" ;
while ( ! file . eof() ) {
char line[1000] ;
file . getline(line,1000) ; // leggo una stringa fino al primo spazio,tab o return etc,
// per un massimo di 1000 caratteri
if ( !file ) break ; // se c'e' un errore interrompo il ciclo
cout << "HO LETTO: " << line << "\n" ;
}
cout << "FINE LETTURA\n" ;
file . close() ; // chiusura del file pippo.txt
}
- Allocazione dinamica new e delete
File: ex012.cc:
/*
* Cosa ha di diverso il C++ a basso livello.
*
*/
/*
* new e delete al posto di malloc/free
*/
#include <iostream> // includo le definizioni per I/O in c++
#include <iomanip> // manipolatori per la formattazione
#include <cmath> // sin, cos, tan etc
using namespace std ;
/*
* Esempio stupido di uso di new e delete
*
* dato un vettore V di n numeri, costruisco un W
* vettore di dimensione n-1 che contiene le differenze
* successive del vettore V cioe'
*
* W[i] = V[i+1]- V[i]
*/
int
main() {
int V[] = {1,2,3,1,0,3,5,7,0}; // vettore di partenza
int * W ; // puntatore al vettore da allocare
int n = sizeof(V)/sizeof(V[0]) ; // dimensione del vettore V
W = new int [ n-1 ] ;
/* ^ ^ ^
* | | |
* | | +-- quanti elementi alloco
* | |
* | +---- tipo di elementi da allocare
* |
* |
* +---- operatore di allocazione
*
* e "equivalente" al codice C
*
* W = (int*) malloc( (n-1) * sizeof(int) );
*
* occhio che non si puo' fare la free(W) perche' il meccanismo
* di allocazione e' diverso.
*
*/
// eseguo l'algoritmo
for ( int i = 0 ; i < n-1 ; ++i ) W[i] = V[i+1] - V[i] ;
// rilascio la memoria
delete [] W ;
/* ^ ^ ^
* | | |
* | | +--- puntatore al vettore da deallocare
* | |
* | +----- [] indica che si tratta di un vettore e non di un singolo elemento
* |
* +---------- operatore di rilascio della memoria
*
* e "equivalente" al codice C se avessi alloocato W con la malloc
*
* free(W) ;
*/
/*
* SI possono allocare singoli elementi come segue
*/
double * p ;
p = new double ; // allocato spazio per un singolo numero floating point
*p = 12.23 ;
double a = 12+*p ;
cout << "a = " << a << "\n" ;
delete p ;
/* nel caso di singoli elementi si omettono le [] */
}
- Il blocco try/catch/throw
File: ex013.cc:
/*
* Cosa ha di diverso il C++ quasi a basso livello.
*
*/
/*
* blocco try/catch/throw
*/
#include <iostream> // includo le definizioni per I/O in c++
#include <iomanip> // manipolatori per la formattazione
#include <cmath> // sin, cos, tan etc
using namespace std ;
/*
* Il blocco try / catch / throw funziona in questo modo
*
try {
// codice utente
// qui posso "lanciare" una eccezzione "throw"
// se viene lanciata l'eccezzione in programma "salta" a fine blocco
}
catch ( tipo di eccessione ) {
// codice per gestire l'eccezzione
}
catch ( tipo di eccessione ) {
}
catch ( tipo di eccessione ) {
}
catch ( ... ) {
// questo blocco cattura qualunque tipo di eccezione
}
*/
#define A(I,J) A[(I)+(J)*lda]
void
fattorizzazione_LU( double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[] ) { /* vettori di interi di domensione >= N che conterra' la permutazione */
int i, j, k, imax ;
double amax, acheck ;
/* Inizializzo il vettore della permutazione */
for ( i = 0 ; i < N ; ++i ) perm[i] = i ;
for ( i = 0 ; i < N-1 ; ++i ) {
/* ricerca del pivot, cerco elemento di modulo massimo
nella colonna i-esima, cioe' A(i,i), A(i+1,i), ..., A(N-1,i) */
imax = i ;
amax = fabs( A(i,i) ) ;
for ( j=i+1 ; j < N ; j++ ) {
acheck = fabs(A(j,i));
if ( acheck > amax ) {
acheck = amax ;
imax = j ;
}
}
/* controllo che acheck > 0, se 0 la matrice e' singolare */
///////////////
/////////////// SE LA MATRICE E' SINGOLARE LANCIO UNA ECCEZIONE
///////////////
if ( amax == 0 ) throw "matrice singolare" ;
if ( imax != i ) { /* scambio la riga i con la riga imax */
/* scambio indici sul vettore della permutazione */
k = perm[i] ;
perm[i] = perm[imax] ;
perm[imax] = k ;
/* scambio delle righe nella matrice A */
for ( j=0 ; j < N ; ++j ) {
amax = A(i,j) ;
A(i,j) = A(imax,j) ;
A(imax,j) = amax ;
}
}
/* costruisco la parte della matrice Li e la applico alla matrice
LU in costruzione */
for ( k = i+1 ; k < N ; ++k ) {
amax = A(k,i) / A(i,i) ;
A(k,i) = amax ;
for ( j= i+1 ; j < N ; ++j )
A(k,j) -= amax * A(i,j) ;
}
}
if ( A(N-1,N-1) == 0 ) throw "LU eseguita ma matrice singolare" ;
}
void
stampa_L( ostream & s, // uso l'oggetto s di tipo stream per l'I/O
double A[], // matrice da fattorizzare memorizzata per colonne
int N, // dimensione della matrice da fattorizzare
int lda ) { // numero di righe usate in allocazione
for ( int i = 0 ; i < N ; ++i ) {
for ( int j = 0 ; j < i ; ++j ) {
s << setw(10) << left << A(i,j) ;
}
s << "1\n" ;
}
}
void
stampa_U( ostream & s, // uso l'oggetto s di tipo stream per l'I/O
double A[], // matrice da fattorizzare memorizzata per colonne
int N, // dimensione della matrice da fattorizzare
int lda ) { // numero di righe usate in allocazione
for ( int i = 0 ; i < N ; ++i ) {
for ( int j = 0 ; j < i ; ++j ) {
s << " " ; /* 10 spazi bianchi */
}
for ( int j = i ; j < N ; ++j ) {
s << setw(10) << left << A(i,j) ;
}
s << "\n" ; /* vado a capo a fine riga */
}
}
#undef A /* elimino la definizione di A(I,I) */
#define L(I,J) LU[(I)+(J)*lda]
#define U(I,J) LU[(I)+(J)*lda]
void
solve_LU( double LU[], /* matrice fattorizzata memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[], /* vettori di interi di domensione >= N che
conterra' la permutazione */
double b[], /* temine noto */
double x[] ) { /* soluzione */
/* applico la permutazione */
for ( int i = 0 ; i < N ; ++i ) x[perm[i]] = b[i] ;
/* Risolvo Lz = Pb */
for ( int i = 1 ; i < N ; ++i )
for ( int j = 0 ; j < i ; ++j )
x[i] -= L(i,j)*x[j];
/* Risolvo Ux = Lz */
int i=N;
do {
--i ;
for ( int j = i+1 ; j < N ; ++j )
x[i] -= U(i,j)*x[j];
x[i] /= U(i,i) ;
} while ( i > 0 ) ;
}
int
main() {
double M[] = {
4, 3, 2, 1, /* prima colonna */
1, 2, 3, 4, /* seconda colonna */
1, 0, 0, 1, /* terza colonna */
1, 0, 0, 1, /* terza colonna */
//0, 1, 2, 5 /* quarta colonna */
} ;
double b[] = { 9, 11, 16, 32 } ; /* termine noto se la solzione e' 1,2,3,4 */
double x[4] ; /* vettore che conterra' la soluzione */
int i, perm[4] ;
int dim ;
dim = 4 ;
// usi try/catch per catturare l'eventuale messaggio di errore
try {
fattorizzazione_LU( M, dim, dim, perm ) ;
}
catch ( char const msg[] ) {
cout << "ERRORE in fattorizzazione_LU:" << msg << "\n" ;
exit(1) ;
}
catch ( ... ) {
cout << "ERRORE strano fattorizzazione_LU\n" ;
exit(1) ;
}
/* stampa della matrice L ed U e la permutazione */
cout << "MATRICE L\n" ;
stampa_L( cout, M, dim, dim );
cout << "MATRICE U\n" ;
stampa_U( cout, M, dim, dim );
cout << "PERMUTAZIONE\n" ;
for ( i = 0 ; i < dim ; ++i )
cout << "perm[" << i << "]=" << perm[i] << "\n" ;
solve_LU( M, dim, dim, perm, b, x ) ;
cout << "SOLUZIONE\n" ;
for ( i = 0 ; i < dim ; ++i )
cout << "x[" << i << "]=" << x[i] << "\n" ;
return 0 ;
}
File: ex014.cc:
/*
* Cosa ha di diverso il C++ quasi a basso livello.
*
*/
/*
* blocco try/catch/throw
* stesso esempio ma con l'uso di stdexcept per la throw
*/
#include <iostream> // includo le definizioni per I/O in c++
#include <iomanip> // manipolatori per la formattazione
#include <cmath> // sin, cos, tan etc
#include <stdexcept> // definizione di oggetti standard per le eccezzioni
/*
definisce delle strutture/classi
exception
da lanciare con la throw.
Le classi sono le seguenti
logic_error
domain_error
invalid_argument
length_error
out_of_range
runtime_error
range_error
overflow_error
underflow_error
*/
using namespace std ;
/*
* Il blocco try / catch / throw funziona in questo modo
*
try {
// codice utente
// qui posso "lanciare" una eccezzione "throw"
// se viene lanciata l'eccezzione in programma "salta" a fine blocco
}
catch ( tipo di eccessione ) {
// codice per gestire l'eccezzione
}
catch ( tipo di eccessione ) {
}
catch ( tipo di eccessione ) {
}
catch ( ... ) {
// questo blocco cattura qualunque tipo di eccezione
}
*/
#define A(I,J) A[(I)+(J)*lda]
void
fattorizzazione_LU( double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[] ) { /* vettori di interi di domensione >= N che conterra' la permutazione */
int i, j, k, imax ;
double amax, acheck ;
/* Inizializzo il vettore della permutazione */
for ( i = 0 ; i < N ; ++i ) perm[i] = i ;
for ( i = 0 ; i < N-1 ; ++i ) {
/* ricerca del pivot, cerco elemento di modulo massimo
nella colonna i-esima, cioe' A(i,i), A(i+1,i), ..., A(N-1,i) */
imax = i ;
amax = fabs( A(i,i) ) ;
for ( j=i+1 ; j < N ; j++ ) {
acheck = fabs(A(j,i));
if ( acheck > amax ) {
acheck = amax ;
imax = j ;
}
}
/* controllo che acheck > 0, se 0 la matrice e' singolare */
///////////////
/////////////// SE LA MATRICE E' SINGOLARE LANCIO UNA ECCEZIONE
///////////////
if ( amax == 0 ) throw runtime_error("matrice singolare") ;
/* ^ ^
* | |
* | +-- arcgomento del costruttore
* |
* +--- costruttore dell'oggetto runtime_error
*
*/
if ( imax != i ) { /* scambio la riga i con la riga imax */
/* scambio indici sul vettore della permutazione */
k = perm[i] ;
perm[i] = perm[imax] ;
perm[imax] = k ;
/* scambio delle righe nella matrice A */
for ( j=0 ; j < N ; ++j ) {
amax = A(i,j) ;
A(i,j) = A(imax,j) ;
A(imax,j) = amax ;
}
}
/* costruisco la parte della matrice Li e la applico alla matrice
LU in costruzione */
for ( k = i+1 ; k < N ; ++k ) {
amax = A(k,i) / A(i,i) ;
A(k,i) = amax ;
for ( j= i+1 ; j < N ; ++j )
A(k,j) -= amax * A(i,j) ;
}
}
if ( A(N-1,N-1) == 0 ) throw runtime_error("LU eseguita ma matrice singolare") ;
}
void
stampa_L( ostream & s, // uso l'oggetto s di tipo stream per l'I/O
double A[], // matrice da fattorizzare memorizzata per colonne
int N, // dimensione della matrice da fattorizzare
int lda ) { // numero di righe usate in allocazione
for ( int i = 0 ; i < N ; ++i ) {
for ( int j = 0 ; j < i ; ++j ) {
s << setw(10) << left << A(i,j) ;
}
s << "1\n" ;
}
}
void
stampa_U( ostream & s, // uso l'oggetto s di tipo stream per l'I/O
double A[], // matrice da fattorizzare memorizzata per colonne
int N, // dimensione della matrice da fattorizzare
int lda ) { // numero di righe usate in allocazione
for ( int i = 0 ; i < N ; ++i ) {
for ( int j = 0 ; j < i ; ++j ) {
s << " " ; /* 10 spazi bianchi */
}
for ( int j = i ; j < N ; ++j ) {
s << setw(10) << left << A(i,j) ;
}
s << "\n" ; /* vado a capo a fine riga */
}
}
#undef A /* elimino la definizione di A(I,I) */
#define L(I,J) LU[(I)+(J)*lda]
#define U(I,J) LU[(I)+(J)*lda]
void
solve_LU( double LU[], /* matrice fattorizzata memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[], /* vettori di interi di domensione >= N che
conterra' la permutazione */
double b[], /* temine noto */
double x[] ) { /* soluzione */
/* applico la permutazione */
for ( int i = 0 ; i < N ; ++i ) x[perm[i]] = b[i] ;
/* Risolvo Lz = Pb */
for ( int i = 1 ; i < N ; ++i )
for ( int j = 0 ; j < i ; ++j )
x[i] -= L(i,j)*x[j];
/* Risolvo Ux = Lz */
int i=N;
do {
--i ;
for ( int j = i+1 ; j < N ; ++j )
x[i] -= U(i,j)*x[j];
x[i] /= U(i,i) ;
} while ( i > 0 ) ;
}
int
main() {
double M[] = {
4, 3, 2, 1, /* prima colonna */
1, 2, 3, 4, /* seconda colonna */
1, 0, 0, 1, /* terza colonna */
1, 0, 0, 1, /* terza colonna */
//0, 1, 2, 5 /* quarta colonna */
} ;
double b[] = { 9, 11, 16, 32 } ; /* termine noto se la solzione e' 1,2,3,4 */
double x[4] ; /* vettore che conterra' la soluzione */
int i, perm[4] ;
int dim ;
dim = 4 ;
// usi try/catch per catturare l'eventuale messaggio di errore
try {
fattorizzazione_LU( M, dim, dim, perm ) ;
}
catch ( runtime_error const & exc ) {
cout << "ERRORE in fattorizzazione_LU:" << exc . what() << "\n" ;
exit(1) ;
}
catch ( ... ) {
cout << "ERRORE strano fattorizzazione_LU\n" ;
exit(1) ;
}
/* stampa della matrice L ed U e la permutazione */
cout << "MATRICE L\n" ;
stampa_L( cout, M, dim, dim );
cout << "MATRICE U\n" ;
stampa_U( cout, M, dim, dim );
cout << "PERMUTAZIONE\n" ;
for ( i = 0 ; i < dim ; ++i )
cout << "perm[" << i << "]=" << perm[i] << "\n" ;
solve_LU( M, dim, dim, perm, b, x ) ;
cout << "SOLUZIONE\n" ;
for ( i = 0 ; i < dim ; ++i )
cout << "x[" << i << "]=" << x[i] << "\n" ;
return 0 ;
}
- Il namespace
File: ex015.cc:
/*
* Cosa ha di diverso il C++ quasi a basso livello.
*
*/
/*
* il namespace
*
* Il namesapce serve per evitare i conflitti di nomi.
* Ad esempio uno potrebbe usare due routione per l'ordinamento
* e chiamarla sort. Ma una implmenta in bubble sort e un'altra
* l'ordinamento shell sort.
* per evitare conlfitti invecie che moltiplicare i nomi
* si possono usare i namespace
*
*/
namespace bubble {
void
sort( int N, int v[] ) {
for ( int i = 0 ; i < N-1 ; ++i )
for ( int j = i+1 ; j < N ; ++j )
if ( v[i] > v[j] ) {
int bf = v[i] ; v[i] = v[j] ; v[j] = bf ; // scambio
}
}
}
namespace shell {
// algoritmo tipo shell
void
sort( int N, int v[] ) {
bool fine ;
int k = N ;
do {
k /= 2 ;
if ( k == 0 ) k = 1 ;
fine = true ;
for ( int i = 0 ; i < N-k ; i += k ) {
if ( v[i] > v[i+k] ) {
fine = false ;
int bf = v[i] ; v[i] = v[i+k] ; v[i+k] = bf ; // scambio
}
}
} while ( !fine || k != 1 ) ;
}
}
int
main() {
int v[] = {5,2,3, -1,3, 23,89,-23,4,-6} ;
int n = sizeof(v)/sizeof(v[0]) ;
// ordino in vettore con bubble sort
bubble::sort( n, v );
/* ^ ^ ^
* | | |
* | | +--- nome della routine di ordinamento
* | |
* | --- :: operatore di scope
* |
* +------ nome del namespace
*
*/
// ordino in vettore con shell sort
shell::sort( n, v );
/* ^ ^ ^
* | | |
* | | +--- nome della routine di ordinamento
* | |
* | --- :: operatore di scope
* |
* +------ nome del namespace
*
*/
// la potenza del namespace e' che il contenuto del
// namespace puo essere estratto tutto o in parte
using shell::sort ;
sort( n, v );
using bubble::sort ;
sort( n, v ); // a questo punto vanno in conflitto
// il compilatore non sa quale dei due
// sort utilizzare
using namespace shell ; // con questo comando estraggo TUTTO il contenuto
// del namespace (in questo caso solo sort)
}
File: ex016.cc:
/*
* Cosa ha di diverso il C++ quasi a basso livello.
*
*/
/*
* il namespace
*
* Il namesapce serve per evitare i conflitti di nomi.
* Ad esempio uno potrebbe usare due routione per l'ordinamento
* e chiamarla sort. Ma una implmenta in bubble sort e un'altra
* l'ordinamento shell sort.
* per evitare conlfitti invecie che moltiplicare i nomi
* si possono usare i namespace
*
*/
#include <iostream>
int
main() {
// cout e' "dentro" in namespace std, per accederci devo usare
// l'operatore di scope ::
std::cout << "pippo\n" ;
using std::cout ; // estraggo l'oggetto cout
cout << "pluto\n" ;
int cout = 100 ; // int non si puo definire va in conflitto con cout
}
Lezione del 12/7/2006
- Il template, motivazione ed esempi
File: ex017.cc:
/*
* Cosa ha di diverso il C++ ad alto livello
*
*/
/*
* i template, motivazioni
*
*/
#include <iostream>
/*
* Definisco 2 versioni del bubble sort,
* una per gli "int" e una per i "double"
*/
// VERSIONE 1
// algoritmo bubble sort per interi
void
sort( int const N, int V[] ) {
for ( int i = 0 ; i < N-1 ; ++i )
for ( int j = i+1 ; j < N ; ++j )
if ( V[i] > V[j] ) {
int bf = V[i] ; V[i] = V[j] ; V[j] = bf ;
}
}
// VERSIONE 2
// algoritmo bubble sort per double
void
sort( int const N, /* cambio tipo */ double V[] ) {
for ( int i = 0 ; i < N-1 ; ++i )
for ( int j = i+1 ; j < N ; ++j )
if ( V[i] > V[j] ) {
/* cambio tipo */ double bf = V[i] ; V[i] = V[j] ; V[j] = bf ;
}
}
int
main() {
int VI[] = {1,23,34,-2,4,3} ;
double VR[] = {1.3,23,34.3,-2.1,4,3} ;
int nVI = sizeof(VI)/sizeof(VI[0]) ; // totale elementi di VI
int nVR = sizeof(VR)/sizeof(VR[0]) ; // totale elementi di VR
// Sfruttando l'overloading viene richiata la routine giusta.
sort( nVI, VI ); // uso la VERSIONE 1
sort( nVR, VR ); // uso la VERSIONE 2
/*
* Anche se l'overloading permette di usare lo stesso nome
* per lo stesso algoritmo che opera su tipi diversi,
* devo comunque "riscrivere" l'algortitmo per ogni tipo
* che uso.
* Ad esempio se voglio l'algoritmo di ordinamento per i float
* o i long int devo riscrivere ancora una volta l'algoritmo.
*/
}
File: ex018.cc:
/*
* Cosa ha di diverso il C++ ad alto livello
*
*/
/*
* i template, motivazioni
*
*/
#include <iostream>
/*
* SOluzioni alla C per la proliferazione dell'algortimo
*/
// MODO C
// algoritmo bubble sort per tipi generici,
// devo passare la dimensione (in byte del tipo)
// e una routine per il confronto
void
sort( int const N, // numero di elementi di ordinare
void * V, // puntatore all'inizio del vettore
int const size_V, // dimensione in byte del singolo elemento del vettore
bool (*GT)(void const * a, void const * b)
// routine di confronto
// se l'elemento all'indirizzo puntato da a
// e' maggiore dell'elemento puntato da b
// allora ritorna "true" altrimenti "false"
) {
for ( int i = 0 ; i < N-1 ; ++i )
for ( int j = i+1 ; j < N ; ++j ) {
char * Vi = (char*)V+i*size_V ; // vado al i esimo elemento del vettore V.
// V e' puntatatore a void e quindi per lui
// non vale l'aritmetica dei puntatori.
// faccio un "cast" ad un puntatore a carattere.
// In questo modo per andare all'elemento
// i-esimo basta spostarsi di i*size_V byte
// in avanti.
char * Vj = (char*)V+j*size_V ;
if ( GT(Vi,Vj) ) { // richiamo la rotine di confronto
// scambio size_V bytes
for ( int k = 0 ; k < size_V ; ++k ) {
char bf = Vi[k] ;
Vi[k] = Vj[k] ;
Vj[k] = bf ;
}
}
}
}
// rifinitura per int e double
bool
GT_int(void const * a, void const * b) {
int const * pA = (int const *)a ;
int const * pB = (int const *)b ;
return *pA > *pB ;
}
bool
GT_double(void const * a, void const * b) {
double const * pA = (double const *)a ;
double const * pB = (double const *)b ;
return *pA > *pB ;
}
int
main() {
int VI[] = {1,23,34,-2,4,3} ;
double VR[] = {1.3,23,34.3,-2.1,4,3} ;
int nVI = sizeof(VI)/sizeof(VI[0]) ; // totale elementi di VI
int nVR = sizeof(VR)/sizeof(VR[0]) ; // totale elementi di VR
sort( nVI, VI, sizeof(int), GT_int ); // uso la VERSIONE int
sort( nVR, VR, sizeof(double), GT_double ); // uso la VERSIONE double
// Problemi:
// -- Bisogna definire le routine di confronto per ogni tipo
// -- Bisogna passare 2 parametri extra, uno per la dimensione
// in byte del tipo, e uno per il puntatore alla funzione
// di confronto.
// -- Introdurre altri parametri aumenta la possibilita di errore
// (ad esempio passo la dimensione in byte sbagliata o la
// routine di confronto sbagliata)
// -- L'uso del puntatore a funzione introduce un "overhead" e quindi
// rende il programma meno efficiente.
}
File: ex019.cc:
/*
* Cosa ha di diverso il C++ ad alto livello
*
*/
/*
* i template, motivazioni
*
*/
/*
* Definisco una versioni del bubble sort,
* con una macro
*/
#define BUBBLE_SORT(TIPO) \
void \
sort( int const N, TIPO V[] ) { \
for ( int i = 0 ; i < N-1 ; ++i ) \
for ( int j = i+1 ; j < N ; ++j ) \
if ( V[i] > V[j] ) { \
TIPO bf = V[i] ; V[i] = V[j] ; V[j] = bf ; \
} \
}
BUBBLE_SORT(int) // genero il codice bubble sort per il tipo int
BUBBLE_SORT(float)
BUBBLE_SORT(double)
BUBBLE_SORT(long int)
int
main() {
int VI[] = {1,23,34,-2,4,3} ;
double VR[] = {1.3,23,34.3,-2.1,4,3} ;
int nVI = sizeof(VI)/sizeof(VI[0]) ; // totale elementi di VI
int nVR = sizeof(VR)/sizeof(VR[0]) ; // totale elementi di VR
// Sfruttando l'overloading viene richiata la routine giusta.
sort( nVI, VI ); // uso la VERSIONE 1
sort( nVR, VR ); // uso la VERSIONE 2
/*
* Questa soluzione permette di scrivere una volta sola l'algoritmo
* ma ha alcuni problemi:
* -- Bisogna ricordardi di scrivere BUBBLE_SORT(tipo) per ogni
* tipo che ci interessa
* -- E' piuttosco scomodo scrivere algoritmi lunghi con le macro
*/
}
File: ex020.cc:
/*
* Cosa ha di diverso il C++ ad alto livello
*
*/
/*
* Soluzione con i template
*
*/
#include <iostream>
/*
* Soluzioni alla C++ per evitare la proliferazione dell'algortimo
*/
// algoritmo bubble sort
// versione generica
template <typename TIPO_GENERICO>
void
sort( int const N, TIPO_GENERICO V[] ) {
for ( int i = 0 ; i < N-1 ; ++i )
for ( int j = i+1 ; j < N ; ++j )
if ( V[i] > V[j] ) {
TIPO_GENERICO bf = V[i] ; V[i] = V[j] ; V[j] = bf ;
}
}
// di fatto ho una routine di "tipo"
// void sort( int const, T [])
int
main() {
int VI[] = {1,23,34,-2,4,3} ;
double VR[] = {1.3,23,34.3,-2.1,4,3} ;
int nVI = sizeof(VI)/sizeof(VI[0]) ; // totale elementi di VI
int nVR = sizeof(VR)/sizeof(VR[0]) ; // totale elementi di VR
sort( nVI, VI ); // cerco un matching con void sort( int const, int [])
// quindi il compilatore "espande" la defizione
// cons TIPO_GENERICO = int
sort( nVR, VR ); // cerco un matching con void sort( int const, double [])
// quindi il compilatore "espande" la defizione
// cons TIPO_GENERICO = double
// vantaggi se ora volessi ordinare un vettore di float
// basta scrivere
float VF[] = {1,23,34,-2,4,3} ;
int nVF = sizeof(VF)/sizeof(VF[0]) ; // totale elementi di VR
sort( nVF, VF );
}
File: ex021.cc:
/*
* Cosa ha di diverso il C++ ad alto livello
*
*/
#include <iostream>
#include <cmath>
/*
* Soluzioni alla C++ per evitare la proliferazione dell'algortimo
*/
// algoritmo distanza tra 2 punti
// versione generica
template <typename T>
inline
T
sqr( T const & a)
{ return a*a ; }
template <typename Tc, typename Ta, typename Tb>
Tc
dist( Ta const a[2], Tb const b[2] ) {
using std::sqrt ;
Tc res = sqrt( sqr(a[0]-b[0]) + sqr(a[1]-b[1]) );
return res ;
}
int
main() {
double a[] = {1.3,23} ;
float b[] = {34.3,-2.1,4,3} ;
// double res = dist( a, b ) ;
// scritto in questo modo il compilatore non e' in grado
// di fare in "matching" con la routine giusta.
// Infatti non controlla il tipo di ritorno.
double res1 = dist<double,double,float>( a, b ) ;
// istruisco il compilatore sul matching completo
double res2 = dist<double>( a, b ) ;
// istruisco il compilatore sul matching solo
// del primo argomento, gli altri due li deduce
double res3 = dist<double,double,double>( a, b ) ;
// non funziona perche dist( double const [2], double const [2])
// non combacia con gli argomenti double,float!.
}
- Strutture con metodi
File: ex022.cc:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
* Prima di usare i metodi vediamo come in C si
* struttura un programma per gestire ad esempio
* dei punti bidimensionali
*
*/
#include <iostream>
#include <cmath>
using namespace std ;
/* definisco la struttura punto2d */
typedef struct {
double x, y ;
} point2d ;
void
init( point2d & pnt ) {
pnt.x = pnt.y = 0 ;
}
void
set( point2d & pnt, double const x, double const y ) {
pnt.x = x ;
pnt.y = y ;
}
void
move_x( point2d & pnt, double const tx ) {
pnt.x += tx ;
}
void
move_y( point2d & pnt, double const ty ) {
pnt.y += ty ;
}
// + pnt nuova posizione
// / + pnt
// / /
// / /
// /
// + center
//
//
void
rotate( point2d & pnt, // punto da muovere
double alpha, // angolo in radianti (senso antioario)
point2d & center // centro di rotazione
) {
double dx = pnt . x - center . x ;
double dy = pnt . y - center . y ;
double dst = sqrt( dx*dx+dy*dy ) ;
double beta = atan2( dy, dx ); // dato il vettore (x,y) atan2(y,x) restituisce
// il suo angolo in radianti
pnt.x = center.x + dst * cos( alpha+beta ) ;
pnt.y = center.y + dst * sin( alpha+beta ) ;
}
void
print( point2d const & pnt, ostream & s ) {
s << "[ " << pnt . x << " , " << pnt.y << "]" ;
}
int
main() {
point2d a, b, c, d ;
set( a, 1, 2) ;
set( b, 2, .1) ;
set( c, -1, -3) ;
set( d, 0.3, 1) ;
move_x( a, 12) ;
move_y( b, -3) ;
rotate( a, 0.31, b ) ;
cout << "a = " ; print( a, cout ) ; cout << "\n" ;
cout << "b = " ; print( b, cout ) ; cout << "\n" ;
cout << "c = " ; print( c, cout ) ; cout << "\n" ;
cout << "d = " ; print( d, cout ) ; cout << "\n" ;
/*
* Anche se l'approccio e' valido si puo' fare di meglio in C++
*/
return 0 ;
}
File: ex023.cc:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
*/
#include <iostream>
#include <cmath>
using namespace std ;
/* definisco la struttura punto2d */
typedef struct point2d {
double x, y ;
/* Invecie che definire delle funzioni esterne, definisco dei
metodiinterni alla struttura */
void
init() {
x = y = 0 ;
}
void
set( double const x, double const y ) {
// this e' puntatore a se stesso cioe' la struttura stessa
// x o this -> x e' la stessa cosa a meno x non sia un argomento
// o variabile dichiarata nel metodo per cui diventa
// inaccessibile.
this -> x = x ;
this -> y = y ;
}
void
move_x( double const tx ) {
x += tx ;
}
void
move_y( double const ty ) {
y += ty ;
}
void
rotate( double alpha, // angolo in radianti (senso antioario)
struct point2d & center // centro di rotazione
) {
double dx = x - center . x ;
double dy = y - center . y ;
double dst = sqrt( dx*dx+dy*dy ) ;
double beta = atan2( dy, dx ); // dato il vettore (x,y) atan2(y,x) restituisce
// il suo angolo in radianti
x = center.x + dst * cos( alpha+beta ) ;
y = center.y + dst * sin( alpha+beta ) ;
}
void
print( ostream & s ) {
s << "[ " << x << " , " << y << "]" ;
}
} point2d ;
int
main() {
point2d a, b, c, d ;
a . set( 1, 2) ;
b . set( 2, .1) ;
c . set( -1, -3) ;
d . set( 0.3, 1) ;
a . move_x( 12) ;
b . move_y( -3) ;
a . rotate( 0.31, b ) ;
cout << "a = " ; a . print( cout ) ; cout << "\n" ;
cout << "b = " ; b . print( cout ) ; cout << "\n" ;
cout << "c = " ; c . print( cout ) ; cout << "\n" ;
cout << "d = " ; d . print( cout ) ; cout << "\n" ;
/*
* Anche se l'approccio e' valido si puo' fare di meglio in C++
*/
return 0 ;
}
- Strutture con metodi ed uso degli operatori
File: ex024.h:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
*
* Si possono anche definire gli operatori standard + - * / etc
* come operano sulla struttura
*/
#ifndef EX024_H
#define EX024_H
#include <iostream>
#include <cmath>
using namespace std ;
/* definisco la struttura punto2d */
typedef struct point2d {
double x, y ;
/* Invecie che definire delle funzioni esterne, definisco dei
metodi interni alla struttura */
// definisco solo i prototipi
void init() ;
void set( double const x, double const y ) ;
void move_x( double const tx ) ;
void move_y( double const ty ) ;
void rotate( double alpha, struct point2d & center ) ;
void print( ostream & s ) ;
} point2d ;
// voglio ora definire la somma di due punti
// point2d = point2d + point2d ;
point2d operator + ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator - ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator * ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator / ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
double operator ^ ( point2d const & a, point2d const & b ) ;
// per la stampa definisco l'operatore <<
inline
ostream &
operator << ( ostream & s, point2d const & a )
{ s << "[" << a.x << "," << a.y << "]" ; return s ; }
#endif
File: ex024a.cc:
/*
* Strutture con metodi
*/
#include "ex024.h"
// definizione dei metodi
void
point2d::init() {
x = y = 0 ;
}
void
point2d::set( double const x, double const y ) {
// this e' puntatore a se stesso cioe' la struttura stessa
// x o this -> x e' la stessa cosa a meno x non sia un argomento
// o variabile dichiarata nel metodo per cui diventa
// inaccessibile.
this -> x = x ;
this -> y = y ;
}
void
point2d::move_x( double const tx ) {
x += tx ;
}
void
point2d::move_y( double const ty ) {
y += ty ;
}
void
point2d::rotate( double alpha, // angolo in radianti (senso antioario)
point2d & center // centro di rotazione
) {
double dx = x - center . x ;
double dy = y - center . y ;
double dst = sqrt( dx*dx+dy*dy ) ;
double beta = atan2( dy, dx ); // dato il vettore (x,y) atan2(y,x) restituisce
// il suo angolo in radianti
x = center.x + dst * cos( alpha+beta ) ;
y = center.y + dst * sin( alpha+beta ) ;
}
void
point2d::print( ostream & s ) {
s << "[ " << x << " , " << y << "]" ;
}
// voglio ora definire la somma di due punti
// point2d = point2d + point2d ;
point2d
operator + ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x + b.x ;
a_plus_b.y = a.y + b.y ;
return a_plus_b ;
}
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d
operator - ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x - b.x ;
a_plus_b.y = a.y - b.y ;
return a_plus_b ;
}
point2d
operator * ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x * b.x ;
a_plus_b.y = a.y * b.y ;
return a_plus_b ;
}
point2d
operator / ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x / b.x ;
a_plus_b.y = a.y / b.y ;
return a_plus_b ;
}
double
operator ^ ( point2d const & a, point2d const & b ) {
return a.x * b.y - a.y * b.x ;
}
File: ex024b.cc:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
*
* Si possono anche definire gli operatori standard + - * / etc
* come operano sulla struttura
*/
#include "ex024.h"
int
main() {
point2d a, b, c, d ;
a . set( 1, 2) ;
b . set( 2, .1) ;
c . set( -1, -3) ;
d . set( 0.3, 1) ;
a . move_x( 12) ;
b . move_y( -3) ;
a . rotate( 0.31, b ) ;
d = a+b-c/a;
// se invecie che gli operatori avessi usato funzioni
// serebbe stato uno "statement" tipo:
// d = somma( a, differenza(b,c))
cout << "a = " ; a . print( cout ) ; cout << "\n" ;
cout << "b = " ; b . print( cout ) ; cout << "\n" ;
cout << "c = " ; c . print( cout ) ; cout << "\n" ;
cout << "d = " << d << "\n" ;
cout << "a^b = " << (a^b) << "\n" ;
/*
* Anche se l'approccio e' valido si puo' fare di meglio in C++
*/
return 0 ;
}
File: ex025.h:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
*
* Si possono anche definire gli operatori standard + - * / etc
* come operano sulla struttura
*/
#ifndef EX025_H
#define EX025_H
#include <iostream>
#include <cmath>
using namespace std ;
/* definisco la struttura punto2d */
typedef struct point2d {
double x, y ;
/* Invecie che definire delle funzioni esterne, definisco dei
metodi interni alla struttura */
// definisco solo i prototipi
void set( double const x, double const y ) ;
inline
point2d & operator += ( point2d const & b ) {
cout << "USO OPERATORE += INTERNO\n" ;
x += b.x ; y += b.y ;
return *this ;
}
} point2d ;
// voglio ora definire la somma di due punti
// point2d = point2d + point2d ;
point2d operator + ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator - ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator * ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d operator / ( point2d const & a, point2d const & b ) ;
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
double operator ^ ( point2d const & a, point2d const & b ) ;
inline
bool
operator == ( point2d const & a, point2d const & b ) {
return a.x == b.x && a.y == b.y ;
}
// gli operatori >= <= > < non hanno senso sui punti
inline
point2d & operator += ( point2d & a, point2d const & b ) {
cout << "USO OPERATORE += ESTERNO\n" ;
a.x += b.x ; a.y += b.y ;
return a ;
}
// per la stampa definisco l'operatore <<
inline
ostream &
operator << ( ostream & s, point2d const & a )
{ s << "[" << a.x << "," << a.y << "]" ; return s ; }
#endif
File: ex025a.cc:
/*
* Strutture con metodi
*/
#include "ex025.h"
// definizione dei metodi
void
point2d::set( double const x, double const y ) {
// this e' puntatore a se stesso cioe' la struttura stessa
// x o this -> x e' la stessa cosa a meno x non sia un argomento
// o variabile dichiarata nel metodo per cui diventa
// inaccessibile.
this -> x = x ;
this -> y = y ;
}
// voglio ora definire la somma di due punti
// point2d = point2d + point2d ;
point2d
operator + ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x + b.x ;
a_plus_b.y = a.y + b.y ;
return a_plus_b ;
}
// voglio ora definire la differenza di due punti
// point2d = point2d - point2d ;
point2d
operator - ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x - b.x ;
a_plus_b.y = a.y - b.y ;
return a_plus_b ;
}
point2d
operator * ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x * b.x ;
a_plus_b.y = a.y * b.y ;
return a_plus_b ;
}
point2d
operator / ( point2d const & a, point2d const & b ) {
point2d a_plus_b ;
a_plus_b.x = a.x / b.x ;
a_plus_b.y = a.y / b.y ;
return a_plus_b ;
}
double
operator ^ ( point2d const & a, point2d const & b ) {
return a.x * b.y - a.y * b.x ;
}
File: ex025b.cc:
/*
* Strutture con metodi
*/
/*
* In C++ ad una struttura si possono
* aggiungere funzioni (chiamati metodi) che
* operano sulla stessa.
*
* Si possono anche definire gli operatori standard + - * / etc
* come operano sulla struttura
*/
#include "ex025.h"
int
main() {
point2d a, b, c, d ;
a . set( 1, 2) ;
b . set( 2, .1) ;
c . set( -1, -3) ;
d . set( 0.3, 1) ;
// a += b ;
// avendo definito += sia come operatore esterno alla struttura
// che interno alla struttura, e' ambiguo
a . operator += ( b ) ; // scelgo esplicitamente l'operatore interno
a = operator += ( a, b ) ; // scelgo esplicitamente l'operatore esterno
d = a+b-c/a;
// se invecie che gli operatori avessi usato funzioni
// serebbe stato uno "statement" tipo:
// d = somma( a, differenza(b,c))
cout << "a = " << a << "\n"
<< "b = " << b << "\n"
<< "c = " << c << "\n"
<< "d = " << d << "\n"
<< "a^b = " << (a^b) << "\n" ;
/*
* Anche se l'approccio e' valido si puo' fare di meglio in C++
*/
return 0 ;
}
Lezione del 13/7/2006 e 14/7/2006
- Due classi per vettori 2D e matrici 2x2
File: Makefile:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi -O
CXX=g++
CXXFLAGS=-Wall -ansi -O
##-DDEBUG
F77=g77
FFLAGS=-O3
LIBS=-lstdc++
SRCS=prova.cc mat2.cc matvec2.cc
OBJS=$(SRCS:.cc=.o)
prova: $(OBJS)
$(CC) $(OBJS) -o prova $(LIBS)
# regola di compilazione per file tipo C
%.o: %.c
$(CC) $(CFLAGS) -c $<
# regola di compilazione per file tipo C++
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# regola di compilazione per file tipo Fortran
%.o: %.f
$(F77) $(FFLAGS) -c $<
clean:
rm $(OBJS) test
depend:
makedepend $(SRCS)
# DO NOT DELETE
prova.o: vec2.hh mat2.hh
mat2.o: mat2.hh
matvec2.o: matvec2.hh
File: vec2.hh:
/*
* Esempio di classe che implementa dei vettori con 2 componenti
*
*
*/
#ifndef VEC2_HH /* solito trucco per evitare la doppia inclusione */
#define VEC2_HH
#include <iostream>
using namespace std ;
#ifdef DEBUG
#define DEBUG_MESSAGE(A) cout << A << "\n"
#else
#define DEBUG_MESSAGE(A)
#endif
/*
* Una classe puo' essere vista come una struttura con metodi
* alla quale vengono poste alcune restrizioni e altre piccole cose.
*
*/
/* class nome_classe { definizioni e campi } ;
*
* e' simile a
*
* typedef struct { definizioni e campi } nome_classe ;
*
* ma con significative differenze
*
* 1) I campi non sono visibili all'esterno a meno che non lo
* specifichiamo (data hiding).
* 2) il typo della classe e' gia usabile all'interno
* (non occorre accedere con struct nome_classe come
* nel caso della struttura)
* 3) C'e' un importante puntatore (software) "this" che
* che punta alla istanza della classe, utile in situazioni
* particolari.
*
* In ogni punto della classe si possono inserire i seguenti
* qualificatori di visibilita':
*
* public: da qui in poi tutte le variabili e le dichiarazioni
* sono ACCESSIBILI all'esterno
*
* private: da qui in poi tutte le variabili e le dichiarazioni
* sono INACCESSIBILI all'esterno
*
* protected: (da spiegare piu' avanti)
*
* se niente e' specificato il default e' ``private:''
*/
class vec2 {
// campi (accesso privato)
double x ; // Prima coordinata del punto
double y ; // Seconda Coordinata del punto
// fino a qui la classe e' una struttura struct { double x, y ; }
public:
// costruttori (metodi con il nome della classe)
vec2() {
DEBUG_MESSAGE("passa per il costruttore vec2()");
x = y = 0 ;
} // corpo del costruttore
/*
* se in un pezzo di codice scrivo
* vec2 a, b, c ;
* dopo aver creato gli oggetti a,b,c viene chiamato
* questo metodo e di fatto vengono azzerate le coordinate x,y
* do ogni uno di questi oggetti.
*/
vec2( double const x, double const y ) {
DEBUG_MESSAGE("passa per il costruttore vec2(double const x, double const y)");
this -> x = x ; this -> y = y ;
}
/*
* se in un pezzo di codice scrivo
* vec2 a(1,2), b(3,2), c(0.1,2.0) ;
* dopo aver creato gli oggetti a,b,c viene chiamato
* questo metodo e di fatto vengono inizializzate le coordinate x,y
* do ogni uno di questi oggetti.
*/
vec2( vec2 const & a ) {
DEBUG_MESSAGE("passa per il costruttore vec2(vec2 const & a)");
this -> x = a.x ; this -> y = a.y ;
}
/*
* se in un pezzo di codice scrivo
* vec2 a(1,2) ;
* vec2 b(a) ; oppure vec2 b = a ;
* dopo aver creato l'oggetto b viene chiamato
* questo metodo che fa la copia dei valori delle
* coordinate dell'oggetto a.
*/
/*
* metodo di stampa di un vettore
*/
void
print(ostream & s) const // const indica che non modifico
// la classe
{
s << "[" << x << "," << y << "]" ;
}
// generato con il comando figlet -font mini -m 1 OPERAZIONI
// _ _ _ _ __ ___ _ ___
// / \ |_) |_ |_) /\ / | / \ |\ | |
// \_/ | |_ | \ /--\ /_ _|_ \_/ | \| _|_
// __ ___ _ ___ ___
// (_ | | | |_) | | |\ | | |
// __) |_| _|_ | |_| | \| | _|_
//
// assegnazione (operatore =) a = b ;
vec2 &
operator = (vec2 const & a) {
DEBUG_MESSAGE("passa per l'operatore vec2 = ");
x = a.x ;
y = a.y ; // assegna le coordinate di a a *this
return * this ; // ritorna un riferimento a se stesso
}
/*
// Perche' ritorno * this ?
// l'operatore = e' associativo a destra, quindi se scrivo
// a = b = c ====> a = (b=c)
// che e' come scrivere
// a . operator = ( b . operator(c) ) ;
// poiche operator = ritorna se stesso e' come fare
// b . operator = (c) ;
// a . operator = (b) ;
*/
// operatore somma +
// vec2 operator + ( vec2 const & rhs) const
// { return vec2(a.x + b.x, a.y + b.y) ; }
// dichiaro che questo operatore ha accesso agli elementi
// privati di vec2
friend vec2 operator + ( vec2 const & a, vec2 const & b ) ;
friend vec2 operator - ( vec2 const & a, vec2 const & b ) ;
friend vec2 operator * ( vec2 const & a, vec2 const & b ) ;
friend vec2 operator / ( vec2 const & a, vec2 const & b ) ;
friend double operator ^ ( vec2 const & a, vec2 const & b ) ;
// metodi vari
void
set( double const x, double const y)
{ this -> x = x ; this -> y = y ; }
// metodi vari
double const &
operator () ( int const i ) const {
switch (i) {
case 1: return x ;
case 2: return y ;
default:
cerr << "operator vec2(" << i << ") indice fuori range!\n" ;
exit(1) ;
}
}
double &
ref( int const i ) {
switch (i) {
case 1: return x ;
case 2: return y ;
default:
cerr << "vec2::ref(" << i << ") indice fuori range!\n" ;
exit(1) ;
}
}
} ; // non dimenticarsi il ; finale
inline
ostream &
operator << (ostream & s, vec2 const & a) {
a . print(s) ;
return s ;
}
// operatore somma +
inline
vec2
operator + ( vec2 const & a, vec2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore vec2 + ");
vec2 tmp ;
tmp.x = a.x + b.x ;
tmp.y = a.y + b.y ;
return tmp ;
}
// operatore somma -
inline
vec2
operator - ( vec2 const & a, vec2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore vec2 - ");
return vec2(a.x - b.x, a.y - b.y) ;
}
// operatore somma *
inline
vec2
operator * ( vec2 const & a, vec2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore vec2 * ");
return vec2(a.x * b.x, a.y * b.y) ;
}
// operatore somma /
inline
vec2
operator / ( vec2 const & a, vec2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore vec2 / ");
return vec2(a.x / b.x, a.y / b.y) ;
}
// operatore somma /
inline
double
operator ^ ( vec2 const & a, vec2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore vec2 ^ ");
return a.x * b.y - a.y * b.x ;
}
#endif
File: mat2.hh:
/*
* Esempio di classe che implementa matrici 2x2
*
*/
#ifndef MAT2_HH /* solito trucco per evitare la doppia inclusione */
#define MAT2_HH
#include <iostream>
using namespace std ;
#ifdef DEBUG
#define DEBUG_MESSAGE(A) cout << A << "\n"
#else
#define DEBUG_MESSAGE(A)
#endif
class mat2 {
// campi (accesso privato)
double M[4] ; // Matrice 2x2
public:
// costruttori (metodi con il nome della classe)
mat2();
mat2( double const s ) ;
mat2( mat2 const & a ) ;
// accesso agli elementi di A
// restituisce il riferimento all'elemento i,j
double &
ref( int const i, int const j ) {
#ifdef DEBUG
if ( i < 1 || i > 2 || j < 1 || j > 2 ) {
cerr << "in mat2 ref(" << i << "," << j << ")"
<< "\nindice fuori range!\n" ;
exit(1) ;
}
#endif
return M[(i-1)+2*(j-1)] ; // indirizzamento alla FORTRAN
}
// accesso agli elementi di A
// restituisce il riferimento all'elemento i,j
double const &
operator () ( int const i, int const j ) const {
#ifdef DEBUG
if ( i < 1 || i > 2 || j < 1 || j > 2 ) {
cerr << "in mat2(" << i << "," << j << ")"
<< "\nindice fuori range!\n" ;
exit(1) ;
}
#endif
return M[(i-1)+2*(j-1)] ; // indirizzamento alla FORTRAN
}
// accesso agli elementi di A visto come vettore
double const &
operator [] ( int const i ) const { // questo operatore puo' avere 1 solo argomento
#ifdef DEBUG
if ( i < 0 || i > 3 ) {
cerr << "in mat2 operator [] con argomento [" << i << "]"
<< "\nindice fuori range!\n" ;
exit(1) ;
}
#endif
return M[i] ; // indirizzamento alla FORTRAN
}
// questo operatore funziona in questo modo:
// mat2 a ;
// a(i,j) e' equivalente a scrivere
// a . operator () (i,j)
// che (a parte il fattio che M e' inaccessibile)
// in questo caso equivale a . M[(i-1)+2*(j-1)]
/*
* metodo di stampa di un vettore
*/
void
print(ostream & s) const // const indica che non modifico
// la classe
{
s << "[" << (*this)(1,1) << "," << (*this)(1,2)
<< ";" << (*this)(2,1) << "," << (*this)(2,2) << "]" ;
}
// generato con il comando figlet -font mini -m 1 OPERAZIONI
// _ _ _ _ __ ___ _ ___
// / \ |_) |_ |_) /\ / | / \ |\ | |
// \_/ | |_ | \ /--\ /_ _|_ \_/ | \| _|_
// __ ___ _ ___ ___
// (_ | | | |_) | | |\ | | |
// __) |_| _|_ | |_| | \| | _|_
//
// assegnazione (operatore =) a = b ;
mat2 &
operator = (mat2 const & a) {
DEBUG_MESSAGE("passa per l'operatore mat2 = ");
memcpy( this -> M, a . M, 4*sizeof(double) ) ;
return * this ; // ritorna un riferimento a se stesso
}
// dichiaro che questo operatore ha accesso agli elementi
// privati di vec2
friend mat2 operator + ( mat2 const & a, mat2 const & b ) ;
friend mat2 operator - ( mat2 const & a, mat2 const & b ) ;
friend mat2 operator * ( mat2 const & a, mat2 const & b ) ;
// metodi vari
double det() const
{ return (*this)(1,1)*(*this)(2,2) - (*this)(1,2)*(*this)(2,1) ; }
} ; // non dimenticarsi il ; finale
// costruttori (metodi con il nome della classe)
inline
mat2::mat2() {
DEBUG_MESSAGE("passa per il costruttore mat2()");
M[0] = M[1] = M[2] = M[3] = 0 ;
} // corpo del costruttore
inline
mat2::mat2( double const s ) {
DEBUG_MESSAGE("passa per il costruttore mat2(double const s)");
ref(1,1) = ref(2,2) = s ;
ref(1,2) = ref(2,1) = 0 ;
}
inline
mat2::mat2( mat2 const & a ) {
DEBUG_MESSAGE("passa per il costruttore mat2(mat2 const & a)");
// uso la funzione per copiare pezzi di memoria della libreria C
// memcpy( destinazione, sorgente, quanti byte )
memcpy( this -> M, a . M, 4*sizeof(double) ) ;
}
inline
ostream &
operator << (ostream & s, mat2 const & m) {
m . print(s) ;
return s ;
}
// operatore somma +
mat2 operator + ( mat2 const & a, mat2 const & b ) ;
// operatore somma -
mat2 operator - ( mat2 const & a, mat2 const & b ) ;
// operatore somma *
mat2 operator * ( mat2 const & a, mat2 const & b ) ;
#endif
File: mat2.cc:
/*
* Esempio di classe che implementa matrici 2x2
*
*/
#include "mat2.hh"
// operatore somma +
mat2
operator + ( mat2 const & a, mat2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore mat2 + ");
mat2 tmp ;
for ( int i = 1 ; i <= 2 ; ++i )
for ( int j = 1 ; j <= 2 ; ++j )
tmp.ref(i,j) = a(i,j) + b(i,j) ;
return tmp ;
}
// operatore somma -
mat2
operator - ( mat2 const & a, mat2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore mat2 - ");
mat2 tmp ;
for ( int i = 0 ; i < 4 ; ++i ) // usando l'operatore []
tmp.M[i] = a[i] + b[i] ; // ho un ciclo piu' efficiente
return tmp ;
}
// operatore somma *
mat2
operator * ( mat2 const & a, mat2 const & b ) {
DEBUG_MESSAGE("passa per l'operatore + ");
mat2 tmp ;
tmp.ref(1,1) = a(1,1)*b(1,1) + a(1,2) * b(2,1) ;
tmp.ref(1,2) = a(1,1)*b(1,2) + a(1,2) * b(2,2) ;
tmp.ref(2,1) = a(2,1)*b(1,1) + a(2,2) * b(2,1) ;
tmp.ref(2,2) = a(2,1)*b(1,2) + a(2,2) * b(2,2) ;
return tmp ;
}
File: matvec2.hh:
/*
* Qui raccogliamo le operazioni miste matrice vettore
*/
#ifndef MATVEC2_HH /* solito trucco per evitare la doppia inclusione */
#define MATVEC2_HH
#include "vec2.hh"
#include "mat2.hh"
vec2 operator * ( mat2 const & A, vec2 const & b ) ; // restituisce A*b
vec2 solve( mat2 const & A, vec2 const & b ) ; // restituisce x = A^-1 b
#endif
File: matvec2.cc:
/*
* Qui raccogliamo le operazioni miste matrice vettore
*/
#include "matvec2.hh"
vec2
operator * ( mat2 const & A, vec2 const & b ) {
return vec2( A(1,1) * b(1) + A(1,2) * b(2),
A(2,1) * b(1) + A(2,2) * b(2) ) ;
}
vec2
solve( mat2 const & A, vec2 const & b ) {
double det = A . det() ;
return vec2( (b(1)*A(2,2) - b(2)*A(1,2)) / det,
(A(1,1)*b(2) - A(2,1)*b(1)) / det ) ;
}
File: prova.cc:
#include "vec2.hh"
#include "mat2.hh"
#include "matvec2.hh"
int
main() {
vec2 a ; // richiama il primo costruttore
vec2 b(1,2) ; // richiama il secondo costruttore
vec2 c(b) ; // richiama il terzo costruttore
cout << "TEST COSTRUTTORI"
<< "\na = " << a
<< "\nb = " << b
<< "\nc = " << c
<< '\n' ;
a . set(3,4) ;
// test delle varie operazioni
cout << "TEST +\n"
<< a << " + " << b << " = " << a+b << '\n' ;
cout << "TEST -\n"
<< a << " - " << b << " = " << a-b << '\n' ;
cout << "TEST *\n"
<< a << " * " << b << " = " << a*b << '\n' ;
cout << "TEST /\n"
<< a << " / " << b << " = " << a/b << '\n' ;
cout << "TEST ^\n"
<< a << " ^ " << b << " = " << (a^b) << '\n' ;
// assegnazione
a = b = c ;
cout << "TEST ASSEGNAZIONE"
<< "\na = " << a
<< "\nb = " << b
<< "\nc = " << c
<< '\n' ;
mat2 A ; // richiama il primo costruttore
mat2 B(1) ; // richiama il secondo costruttore
mat2 C(B) ; // richiama il terzo costruttore
cout << "TEST COSTRUTTORI"
<< "\nA = " << A
<< "\nB = " << B
<< "\nC = " << C
<< '\n' ;
A.ref(1,2) = 2 ;
A.ref(2,2) = 3 ;
B.ref(1,2) = 1.2 ;
B.ref(2,1) = -3 ;
// test delle varie operazioni
cout << "TEST +\n"
<< A << " + " << B << " = " << A+B << '\n' ;
cout << "TEST -\n"
<< A << " - " << B << " = " << A-B << '\n' ;
cout << "TEST *\n"
<< A << " * " << B << " = " << A*B << '\n' ;
// test sistema
a = B*b ;
cout << "TEST ASSEGNAZIONE"
<< "SISTEMA " << B << " * x = " << a
<< "\nx = " << solve(B,a)
<< "\nmi aspetto = " << b
<< '\n' ;
// assegnazione
A = B = C ;
cout << "TEST ASSEGNAZIONE"
<< "\na = " << A
<< "\nb = " << B
<< "\nc = " << C
<< '\n' ;
}
- Classi e template alcuni esempi
File: ex026.cc:
/*
* Classi + Template
*
*
*/
class vec2 {
double x, y ;
/*
corpo e definizioni varie
*/
};
/*
* Problema:
* e se invecie che double voglio float ? o long double ?
*
* Soluzione:
* si possono parametrizzare le classi con l'uso dei template
*/
template <typename TYPE>
class vector2 {
TYPE x,y ;
/*
corpo e definizioni varie
*/
} ;
/*
* Per usare una particolare classe devo
* specificare il tipo
*
*/
vector2<float> a ;
vector2<double> b ;
/*
* e se volessi una classe di vettori di lunghezza fissa,
* ma non fissata a priori ?
*/
template <typename TYPE, int SIZE>
class vector {
TYPE V[SIZE] ;
/*
corpo e definizioni varie
*/
} ;
vector<float,2> aa ;
vector<double,6> bb ;
File: ex027.cc:
/*
* Classi + Template
*/
// esempio classe di vettori parametrizzata con tipo e dimensione
#include <iostream>
using namespace std ;
template <typename TYPE, int SIZE>
class vector {
TYPE V[SIZE] ;
public:
vector() ;
vector(vector<TYPE,SIZE> const & v) ;
TYPE const & operator () (int i) const ;
TYPE & ref(int i) ;
} ;
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>::vector() {
for ( int i = 0 ; i < SIZE ; ++i ) V[i] = 0 ;
}
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>::vector( vector<TYPE,SIZE> const & v ) {
for ( int i = 0 ; i < SIZE ; ++i ) V[i] = v.V[i] ;
}
template <typename TYPE, int SIZE>
TYPE const &
vector<TYPE,SIZE>::operator () ( int i ) const
{ return V[i-1] ; } // Accesso tipo FORTRAN all'elemento i-esimo
template <typename TYPE, int SIZE>
TYPE &
vector<TYPE,SIZE>::ref( int i )
{ return V[i-1] ; } // Accesso tipo FORTRAN all'elemento i-esimo
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>
operator + ( vector<TYPE,SIZE> const & a, vector<TYPE,SIZE> const & b) {
vector<TYPE,SIZE> tmp ;
for ( int i = 1 ; i <= SIZE ; ++i ) tmp.ref(i) = a(i)+b(i) ;
return tmp ;
}
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>
operator - ( vector<TYPE,SIZE> const & a, vector<TYPE,SIZE> const & b) {
vector<TYPE,SIZE> tmp ;
for ( int i = 1 ; i <= SIZE ; ++i ) tmp.ref(i) = a(i)-b(i) ;
return tmp ;
}
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>
operator * ( vector<TYPE,SIZE> const & a, vector<TYPE,SIZE> const & b) {
vector<TYPE,SIZE> tmp ;
for ( int i = 1 ; i <= SIZE ; ++i ) tmp.ref(i) = a(i)*b(i) ;
return tmp ;
}
template <typename TYPE, int SIZE>
vector<TYPE,SIZE>
operator / ( vector<TYPE,SIZE> const & a, vector<TYPE,SIZE> const & b) {
vector<TYPE,SIZE> tmp ;
for ( int i = 1 ; i <= SIZE ; ++i ) tmp.ref(i) = a(i)/b(i) ;
return tmp ;
}
template <typename TYPE, int SIZE>
ostream &
operator << ( ostream & s, vector<TYPE,SIZE> const & a ) {
s << "[ " ;
for ( int i = 1 ; i < SIZE ; ++i ) s << a(i) << "," ;
s << a(SIZE) << "]" ;
return s ;
}
int
main() {
vector<double,5> a, b, c ;
a.ref(1) = 1 ;
a.ref(2) = 2 ;
a.ref(3) = -2 ;
a.ref(4) = 3 ;
a.ref(5) = 2 ;
b.ref(1) = 1 ;
b.ref(2) = 22 ;
b.ref(3) = -2 ;
b.ref(4) = 3 ;
b.ref(5) = 4 ;
c.ref(1) = 2;
c.ref(2) = 4 ;
c.ref(3) = -2 ;
c.ref(4) = 3 ;
c.ref(5) = -1 ;
vector<double,5> d(a+b-c/a) ;
cout << "\na = " << a
<< "\nb = " << b
<< "\nc = " << c
<< "\nd = " << d
<< '\n' ;
}
P.h.D. Corso di Programmazione in C (AA 2005/2006)
Lezione del 19/6/2006
- Esempi introduttivi
File: ex001.c:
/*
questo e' un commento:
inizia con il carattere / seguito da *
finisce con il carattere * seguito da /
*/
/* commento su una singola riga */
/*
* commento con abbellimento etc etc.
*
*/
int /* valore di ritorno di tipo intero */
/* main e' il nome "ufficiale" del programma
principale, non esistono altri nomi */
main()
/* () le parentesi "contengono" gli argomenti
della funzione "main", in questo caso nessun
argomento */
{
/*************************************\
* un blocco (di istruzioni) e' *
* "qualunque" contenuta tra { e } *
\*************************************/
return 0 ; /* valore restituito dalla funzione "main" */
}
/*
il C e' un liguaggio "free form" quindi
non ci sono regole di scrittura rigide.
Ad esempio potevo scrivere tutto su una
riga:
int main() {}
per compilare il seguente programma su una
macchina UNIX con compilatore della GNU
gcc ex001.c
che genera l'eseguibile a.out
per attivare tutti i messaggi di avvertimento
(WARNING) si scrivera'
gcc -Wall ex001.c
per cambiare il nome (di default) dell'eseguibile
si scrivera'
gcc -Wall ex001.c -o ex001
in questo modo l'eseguibile generato e' ex001.
*/
File: ex002.c:
int
main()
{
/*
// le stringhe in C sono lettere spazi etc
// racchiuse tra doppi apici "
// ad esepio "io sono una stringa"
*/
/*
// per controllare il cursore esistono
// una serie di caratteri speciali.
// Sono preceduti dal carattere di "escape" \ (backslash)
//
// \a attiva il beep sul terminale
// \b sposta il cursore di uno spazio a sinistra
// \f form feed
// \n new line (passa alla riga successiva)
// \r mette il cursore a inizio riga
// \t carattere di tabulazione
// \v tabulazione verticale
// \" inserisce il carattere "
// \num num = 3 digit in ottale del carattere
// ascii corrispondente
*/
printf("ciao \"mamma\"\r") ; /* il ; separa le istruzioni */
printf("xyz\n") ;
printf("numero intero %d\n",123) ;
/* %d indica che in questo posto verra' stampato
* il valore dell'elemento successivo della lista
* degli argmenti di printf.
* In particolare d indica = decimale
*/
return 0 ;
}
File: ex003.c:
#include <stdio.h> /* da spiegare piu' avanti */
/*
* in C esistono un certo numeri di "tipi"
* numerici predefiniti:
*
* int = intero con segno, tipicamente composto
* da 2 o 4 o 8 byte. Il numero di byte e'
* quello della "parola" (word) del processore.
* Ad esempio su processori a 32 bit (4 byte)
* l'intero e' di 4 byte.
*
* float = numero floating point in singola precisione
* tipicamante 4 byte
*
* double = numero floating point in doppia precisione
* tipicamante 8 byte
*
* char = tipo carattere, un byte usato per memorizzare
* un carattere (ascii)
*
*/
/*
* A questi tipi si possono mettere dei "modificatori"
*
*
* unsigned = si applica a int e char.
* l'intero e il carattere non hanno segno
* unsigned int
* unsigned char.
* Di solito si usa la forma abbreviata
* unsigned = unsigned int
*
* short = si applica a int
* short int e' un intero che puo' usare
* meno byte di int, tipicamente 2 byte
* su un processore a 32 bit.
* Di solito si usa la forma abbreviata
* short = short int
*
* long = si applica a int e double
* long int e' un intero che puo' usare
* piu' byte di int, tipicamente 8 byte
* su un processore a 32 bit.
* long double e' una numero floating
* point di precisione quadrupla.
* Non e' implementato su tutti i compilatori.
*
*/
int
main()
{
/*
* alcuni esmopi d'uso
*/
int i, j, k ; /* definisco le variabili i,j,k
come varibili intere con segno */
short l, m ; /* definisco le variabili l,m
come varibili intere "corte" con segno */
float a, b ; /* definisco le variabili a,b
come varibili floating point
in singola precisione */
double c, d ; /* definisco le variabili c, d
come varibili floating point
in doppia precisione */
unsigned int o, p ; /* definisco le variabili o, p
come varibili intere
senza segno */
unsigned long int r, s ; /* definisco le variabili r, s
come varibili intere
senza segno "lunghe" */
/*
* sizeof(argument) : argument e' un tipo
* restituisce il numero di byte
* usato per rappresentarlo
*
*/
printf("n. byte per tipo \"char\" %ld\n", sizeof(char)) ;
printf("n. byte per tipo \"short\" %ld\n", sizeof(short)) ;
printf("n. byte per tipo \"int\" %ld\n", sizeof(int)) ;
printf("n. byte per tipo \"long\" %ld\n", sizeof(long)) ;
printf("n. byte per tipo \"float\" %ld\n", sizeof(float)) ;
printf("n. byte per tipo \"double\" %ld\n", sizeof(double)) ;
/* assegnazioni varie */
i = 11 ;
j = 23 ; k = 3434 ; /* posso scrivere piu'
instruzioni per riga */
printf("numeri in decimale i=%d j=%10d k=%-10d***\n",i,j,k) ;
/* stampo i numeri in ottale */
printf("numeri in ottale i=%o j=%10o k=%-10o***\n",i,j,k) ;
/* stampo i numeri in esadecimale */
printf("numeri in ottale i=%x j=%10x k=%-10X***\n",i,j,k) ;
/*
// Formattazione stampa interi
//
// %d intero decimale
// %ld intero long decimale
// %o intero in ottale
// %x %X intero in esadecimale
//
// %23d riservo 23 spazi per la stampa
// con allineamento a a destra
// %-12d riservo 12 spazi per la stampa
// con allineamento a sinistra
*/
l = m = -12 ; /* equivalente a scrivere
m = 12 ; l = m ; */
printf("numeri (short) l=%d m=%10d\n",l,m) ;
a = b = 1.2f ; /* f e' postfisso per indicare
la singola precisione */
printf("numeri (float) a[%%f]=%f b[%%10f]=%10f\n",a,b) ;
printf("numeri (float) a[%%10.2f]=%10.2f b[%%-10.4f]=%-10.4f\n",a,b) ;
c = 1.2 ;
d = 2 ;
printf("numeri (double) c[%%lf]=%lf d[%%10lf]=%10lf\n",c,d) ;
printf("numeri (double) c[%%10.2lf]=%10.2lf d[%%-10.4lf]=%-10.4lf\n",c,d) ;
/*
// Formattazione stampa numeri in floating point
//
// %f singola precisione
// %lf doppia precisione
// %10f riservo 10 spazi per la stampa
// %10.4f riservo 10 spazi per la stampa, 4 per la parte decimale
// %-10f riservo 10 spazi per la stampa allineato a sinista
//
// al posto di "f" posso usare "e" per formato esponenziale
// 12.34 ==> 1.234E1 E1 = 10^1
//
// al posto di "f" posso usare "g" per formato esponenziale
// quando conviene
//
*/
printf("numeri (double) c[%%lg]=%lg d[%%10lg]=%10lg\n",c,d) ;
printf("numeri (double) c[%%10.2le]=%10.2le d[%%-10.4le]=%-10.4le\n",c,d) ;
o = -1 ; /* occhio! assegno intero con segno ad un unsigned */
p = 2 ;
r = s = 12 ;
return 0 ;
}
File: ex004.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
*/
int
main()
{
int fk, fkp1, fkm1, k, n ; /* variabili usate dall'algoritmo */
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
/*
* if ( espressione logica ) istruzione ;
*
* istruzione puo' essere anche un blocco di istruzioni
* racchiuse da { }
*
*/
if ( n == 0 ) {
printf("F(0) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
if ( n == 1 ) {
printf("F(1) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
fkm1 = fk = 1 ; /* parto con k = 1 */
k = 1 ; /* intero per il ciclo */
loop_label: /* etichetta per fare dei goto */
fkp1 = fk + fkm1 ;
k = k + 1 ;
/* shift degli elementi */
fkm1 = fk ;
fk = fkp1 ;
/* controllo se ho finito il ciclo */
if ( k != n ) goto loop_label;
/* instruzione goto "salta" alla etichetta "loop_label".
* Etichetta e' una qualunue sequenza alfanumerica (senza spazi)
*
*/
printf("F(%d) = %d\n", n, fk) ; /* stampo il risultato */
return 0 ;
}
- Calcolo dei numeri di Fibonacci (varie versioni)
File: ex005a.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO:
* -- while ( ) ;
* -- do { } while ( ) ;
* -- for (;;) ;
*
* esempio con while
*
*/
int
main()
{
int fk, fkp1, fkm1, k, n ; /* variabili usate dall'algoritmo */
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
/*
* if ( espressione logica ) istruzione ;
*
* istruzione puo' essere anche un blocco di istruzioni
* racchiuse da { }
*
*/
if ( n == 0 ) {
printf("F(0) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
if ( n == 1 ) {
printf("F(1) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
/*
* calcolo numero di FIbonacci usano il while
*
* while ( test ) istruzione ;
*
* e' equivalente alle seguenti istruzioni
*
* loop_label:
* if ( not test ) goto exit_loop ;
* istruzione ;
* goto loop_label ;
* exit_loop ;
*
*/
fkm1 = fk = 1 ; /* parto con k = 1 */
k = 1 ; /* intero per il ciclo */
while ( k < n ) {
fkp1 = fk + fkm1 ;
k = k + 1 ;
/* shift degli elementi */
fkm1 = fk ;
fk = fkp1 ;
}
printf("F(%d) = %d\n", n, fk) ; /* stampo il risultato */
return 0 ;
}
File: ex005b.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO:
* -- while ( ) ;
* -- do { } while ( ) ;
* -- for (;;) ;
*
* esempio con do {} while ()
*
*/
int
main()
{
int fk, fkp1, fkm1, k, n ; /* variabili usate dall'algoritmo */
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
/*
* if ( espressione logica ) istruzione ;
*
* istruzione puo' essere anche un blocco di istruzioni
* racchiuse da { }
*
*/
if ( n == 0 ) {
printf("F(0) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
if ( n == 1 ) {
printf("F(1) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
/*
* calcolo numero di FIbonacci usano il while
*
* do { istruzione } while ( test ) ;
*
* e' equivalente alle seguenti istruzioni
*
* loop_label:
* istruzione ;
* if ( test ) goto loop_label ;
*
*/
fkm1 = fk = 1 ; /* parto con k = 1 */
k = 1 ; /* intero per il ciclo */
do {
fkp1 = fk + fkm1 ;
k = k + 1 ;
/* shift degli elementi */
fkm1 = fk ;
fk = fkp1 ;
} while ( k < n ) ;
printf("F(%d) = %d\n", n, fk) ; /* stampo il risultato */
return 0 ;
}
File: ex005c.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO:
* -- while ( ) ;
* -- do { } while ( ) ;
* -- for (;;) ;
*
* esempio con for (;;) ;
*
*/
int
main()
{
int fk, fkp1, fkm1, k, n ; /* variabili usate dall'algoritmo */
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
/*
* if ( espressione logica ) istruzione ;
*
* istruzione puo' essere anche un blocco di istruzioni
* racchiuse da { }
*
*/
if ( n == 0 ) {
printf("F(0) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
if ( n == 1 ) {
printf("F(1) = 1\n") ; /* stampo il risultato */
return 0 ; /* esco dal programma "bene" */
}
/*
* calcolo numero di FIbonacci usano il while
*
* for ( inizializzazione ; test ; incremento ) istruzione ;
*
* e' equivalente alle seguenti istruzioni
*
* inizializzazione ;
* loop_label:
* if ( not test ) goto exit_loop ;
* istruzione ;
* incremento ;
* goto loop_label ;
* exit_loop:
*
* e' equivalente anche al seguente "while loop"
*
* inizializzazione ;
* while ( test ) { instruzione ; incremento ; }
*
* OSSERVAZIONE:
*
* for ( ; test ; ) istruzione ;
* e' equivalente
* while ( test ) istruzione ;
*
*/
fkm1 = fk = 1 ; /* parto con k = 1 */
k = 1 ; /* intero per il ciclo */
for ( fkm1 = fk = 1, k=1 ; /* blocco inizializzazione
uso la virgola per separare
le instruzioni */
k < n ; /* test di fine ciclo */
++k /* incremento
++k e' equivalente a k = k+1
*/
) {
fkp1 = fk + fkm1 ;
/* shift degli elementi */
fkm1 = fk ;
fk = fkp1 ;
} ;
printf("F(%d) = %d\n", n, fk) ; /* stampo il risultato */
return 0 ;
}
File: ex005d.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO la definizione ricorsiva!
*/
int /* tipo restituito dalla funzione Fibonacci */
Fibonacci /* nome della funzione: Fibonacci */
(int n) /* argomenti della funzione:
uno solo di tipo intero */
{ /* corpo della funzione */
if ( n == 0 || n == 1 ) return 1 ;
/* || e' l'operatore di or logico,
vale "true" se almento una delle due
condizioni e' vera */
/* altri operatori sono
&& and logico
! negazione */
/* uso della definizione ricorsiva */
return Fibonacci(n-1)+Fibonacci(n-2) ;
}
int
main()
{
int n ;
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
printf("F(%d) = %d\n", n, Fibonacci(n)) ; /* stampo il risultato */
return 0 ;
}
File: ex005e.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO la definizione ricorsiva!
* e l'istruzione switch
*/
int /* tipo restituito dalla funzione Fibonacci */
Fibonacci /* nome della funzione: Fibonacci */
(int n) /* argomenti della funzione:
uno solo di tipo intero */
{ /* corpo della funzione */
switch ( n ) {
case 0:
case 1:
return 1 ;
default:
return Fibonacci(n-1)+Fibonacci(n-2) ;
}
}
int
main()
{
int n ;
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
printf("F(%d) = %d\n", n, Fibonacci(n)) ; /* stampo il risultato */
return 0 ;
}
- Esempio di funzione con compilazione separata
File: ex006a.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
* Usando la funzione "esterna" Fibonacci
*/
/* il prototipo scritto qui e' erroro prone!!!
meglio con l'include */
extern int Fibonacci(int n) ;
int
main()
{
int n ;
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
printf("F(%d) = %f\n", n, Fibonacci(n)) ; /* stampo il risultato */
return 0 ;
}
File: ex006b.c:
#include <stdio.h>
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO la definizione ricorsiva!
* e l'istruzione switch
*/
int /* tipo restituito dalla funzione Fibonacci */
Fibonacci /* nome della funzione: Fibonacci */
(int n) /* argomenti della funzione:
uno solo di tipo intero */
{ /* corpo della funzione */
switch ( n ) {
case 0:
case 1:
return 1 ;
default:
return Fibonacci(n-1)+Fibonacci(n-2) ;
}
}
/*
* Per compilarlo uso
* gcc -Wall -c ex006b.c
*
* lo swicth -c indica al compilatore che non
* deve "linkare" in un eseguibile ma produrre
* un file oggetto ex006b.o
*
* per usarlo col programma principale posso usare
* indifferentemente:
*
* gcc -Wall -c ex006a.c ## fase di compilazione
* gcc -Wall -c ex006b.c ## fase di compilazione
* gcc ex006a.o ex006b.o -o ex006 ## linking
*
* oppure
*
* gcc -Wall -c ex006b.c ## fase di compilazione
* gcc -Wall ex006a.c ex006b.o -o ex006 ## compila & linking
*
* oppure
*
* gcc -Wall ex006a.c ex006b.c -o ex006 ## compila & linking tutto in uno
*
*/
- Stesso esempio ma con file .h
File: ex007a.c:
#include <stdio.h>
#include "ex007.h"
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
* Usando la funzione "esterna" Fibonacci
*/
int
main()
{
int n ;
/* stampa sul terminale il messaggio
che richiede il rangop del numero da calcolare */
printf("Calcolo del n-esimo numero di Fibonacci\n" /* stringa su piu' righe */
"inserisci n: " ) ;
/* lettura da terminale del numero n */
scanf("%d",&n) ; /* & estrae l'indirizzo della variabile n */
printf("Hai inserito il numero n = %d\n", n) ;
printf("F(%d) = %d\n", n, Fibonacci(n)) ; /* stampo il risultato */
return 0 ;
}
File: ex007b.c:
#include <stdio.h>
/* le stringhe tra <> indicano file da cercare
nelle directory di sistema.
Tipicamente /usr/include, ma puo' cambiare
da compilatore a compilatore
*/
#include "ex007.h"
/* le stringhe tra "" indicano file da cercare
nelle directory corrente o nelle directory
indicate dagli swicth -I del compilatore.
Ad esempio
gcc .... -Imiei_iclude -I./altri_miei_iclude \
-I../ancora_altri_miei_iclude \
-I/path_assoluto/etc/
*/
/*
* esempio programma che calcola n esimo
* numero di Fibonacci.
*
* F(n) = n esimo numero di Finonacci
*
* F(0) = 1
* F(1) = 1
* F(n+1) = F(n) + F(n-1) n =1,2,3,...
*
*
* 1,1,2,3,5,8,....
*
* USANDO PERO la definizione ricorsiva!
* e l'istruzione switch
*/
int /* tipo restituito dalla funzione Fibonacci */
Fibonacci /* nome della funzione: Fibonacci */
(int n) /* argomenti della funzione:
uno solo di tipo intero */
{ /* corpo della funzione */
switch ( n ) {
case 0:
case 1:
return 1 ;
default:
return Fibonacci(n-1)+Fibonacci(n-2) ;
}
}
/*
* Per compilarlo uso
* gcc -Wall -c ex006b.c
*
* lo swicth -c indica al compilatore che non
* deve "linkare" in un eseguibile ma produrre
* un file oggetto ex006b.o
*
* per usarlo col programma principale posso usare
* indifferentemente:
*
* gcc -Wall -c ex006a.c ## fase di compilazione
* gcc -Wall -c ex006b.c ## fase di compilazione
* gcc ex006a.o ex006b.o -o ex006 ## linking
*
* oppure
*
* gcc -Wall -c ex006b.c ## fase di compilazione
* gcc -Wall ex006a.c ex006b.o -o ex006 ## compila & linking
*
* oppure
*
* gcc -Wall ex006a.c ex006b.c -o ex006 ## compila & linking tutto in uno
*
*/
File: ex007.h:
/* definizione del prototipo di Fibonacci */
extern int Fibonacci(int n) ;
Lezione del 20/6/2006
- Ricerca del massimo su un vettore
File: ex008.c:
#include <stdio.h>
/*
* Vettori e Matrici:
*
* ricerca del massimo su un vettore
*
*/
/*
* Un vettore e' dichiarato nel seguente modo:
*/
int a[100] ;
/* int = dichiarazione del tipo di vettore,
cioe' e' un vettore di interi */
/* a e' in nome del vettore */
/* [100] e' un vettore di 100 elementi indirizzati
da 0 a 99 */
/* per accedere all'iesimo elemento si scrive a[i] */
int /* ritorna la posizione dell'elemento massimo */
find_max_index( int const v[], /* vettore su cui fare la ricerca
[] indica che non conosco la dimensione
del vettore
const indica che non modifico il contenuto
del vettore all'interno della funzione
*/
int const size /* dimenzione del vettore o comunque
dimensione di lavoro o di ricerca */ ) {
int max_is = 0 ; /* dichiaro una variabile e la inizializzo contestualmente */
/* e' equivalente a scrivere int max_is ; max_is = 0 ; */
int i = 1 ;
for ( ; i < size ; ++i ) {
if ( v[i] > v[max_is] ) max_is = i ;
}
return max_is ;
}
int
main() {
/* dichiarazione con inizializzazione */
int a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
int position ;
printf("Dimensione in byte del vettore: %ld\n", sizeof(a));
printf("Dimensione in byte di un elemento del vettore: %ld\n", sizeof(a[0]));
printf("Dimensione in numero di elementi del vettore: %d\n", size);
position = find_max_index( a, size ) ;
printf("L'elemento massimo e' %d alla posizione %d\n", a[position], position);
return 0 ;
}
- Ordinamento Bubble Sort
File: ex009.c:
#include <stdio.h>
/*
* Vettori e Matrici:
*
* ordinamento bubble sort.
*
*/
int /* ritorna la posizione dell'elemento minimo */
find_min_index( int const v[], /* vettore su cui fare la ricerca
[] indica che non conosco la dimensione
del vettore
const indica che non modifico il contenuto
del vettore all'interno della funzione
*/
int const size /* dimensione del vettore o comunque
dimensione di lavoro o di ricerca */ ) {
int min_is = 0 ;
int i = 1 ;
for ( ; i < size ; ++i ) {
if ( v[i] < v[min_is] ) min_is = i ;
}
return min_is ;
}
void /* vuoto, indica che la funzione non restituisce niente!
(come SUBROUTINE in FORTRAN) */
bubble_sort( int v[], /* vettore su cui fare l'ordinamento
[] indica che non conosco la dimensione del vettore
NON USO const perche' il vettore e' modificato
dalla funzione */
int const size /* dimensione del vettore o comunque
dimensione di lavoro */ ) {
int i, pos_min ;
for ( i = 0 ; /* inizializzazione */
i < size-1 ; /* vado dal primo (0-esimo)
al penultimo (size-2 esimo)elemento */
++i /* incremento, passo all'elemento successivo */
) {
pos_min = find_min_index( v+i, /* indirizzo di v[i] */
size-i /* considero solo gli elementi necessari */
) ;
pos_min += i ; /* aggiungo i alla posizione del minimo
perche' sto considerando il sotto vettore
{v[i],v[i+1],...,v[size-1]}
*/
/* equivalente a pos_min = pos_min + i ;
si puo fare con gli operatori
+ - * /
% resto divisione ( ad esempio 7 % 3 resto divisione 7/3 vale 1
perche 7 = 2*3 + 1)
|| or
&& and
| or bit a bit
& and bit a bit
*/
/* scambio l'emento i-esimo con l'elemento pos_min-esimo */
int buffer = v[pos_min];
v[pos_min] = v[i] ;
v[i] = buffer ;
}
}
int
main() {
/* dichiarazione con inizializzazione */
int a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
int i ;
printf("Vettore non ordinato: %d",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %d",a[i]) ;
printf("\n");
bubble_sort( a, size ) ;
printf("Vettore ordinato: %d",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %d",a[i]) ;
printf("\n");
return 0 ;
}
- Ordinamento usando le librerie standard
File: ex010.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Vettori e Matrici:
*
* ordinamento quick sort usando routione
* di sistema (libreria C standard)
*
*/
/*
* routine di confronto di due numeri
* in doppia precisione
*
* la funzione deve essere del tipo:
* int (*compar)(const void *, const void *)
*/
/*
* void const * pa ;
* con questa dichiarazione pa e' un puntatore
* a senza tipo a della memoria non modifcabile
*/
int
compare_double( void const * pa, void const * pb) {
/* * (aterisco) e' un operatore di deferenziazione
cioe' vado alla locazione indicata dal puntatore
ed estraggo il contenuto */
double a = * (double*) pa ;
/* ^ ^ ^ ^
* | | | |
* | | | +--- puntatore all'elemento
* | | +--- operatore di "CAST" cioe' reinterpreta
* | | quello che sta alla sua destra nel tipo
* | | indicato in parentesi.
* | | In questo caso, "pa" passa da puntatore
* | | a void a puntatore a double
* | |
* | +--- * (asterisco) e' l'operatore di deferenziazione
* | cioe' prende il contenuto della zona di memoria
* | indirizzata dal puntatore.
* |
* +-- variabile che memorizzera una copia
* del "doble" puntato da pa
*/
double b = * (double*) pb ;
if ( a < b ) return -1 ;
if ( a > b ) return +1 ;
return 0 ;
}
int
main() {
/* dichiarazione con inizializzazione */
double a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
int i ;
printf("Vettore non ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
qsort( a, size, sizeof(a[0]),
compare_double /* compare_double e' un puntatore a funzione */
) ;
printf("Vettore ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
return 0 ;
}
File: ex011.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Vettori e Matrici:
*
* ordinamento quick sort usando routione
* di sistema (libreria C standard)
*
*/
/*
* routine di confronto di due numeri
* in doppia precisione
*
* la funzione deve essere del tipo:
* int (*compar)(const void *, const void *)
*/
/*
* void const * pa ;
* con questa dichiarazione pa e' un puntatore
* a senza tipo a della memoria non modifcabile
*/
int
compare_double( double const * pa, double const * pb) {
/* *pa e' il valore del numero "double" puntato da pa */
/* *pb e' il valore del numero "double" puntato da pb */
if ( *pa < *pb ) return -1 ;
if ( *pa > *pb ) return +1 ;
return 0 ;
}
int
main() {
/* dichiarazione con inizializzazione */
double a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
int i ;
printf("Vettore non ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
qsort( a, size, sizeof(a[0]),
(int (*) (const void *,const void *)) compare_double /* compare_double e' un puntatore a funzione */
) ;
printf("Vettore ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
return 0 ;
}
File: ex012.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Vettori e Matrici:
*
* ordinamento quick sort usando routione
* di sistema (libreria C standard)
*
*/
/*
* routine di confronto di due numeri
* in doppia precisione
*
* la funzione deve essere del tipo:
* int (*compar)(const void *, const void *)
*/
/*
* void const * pa ;
* con questa dichiarazione pa e' un puntatore
* a senza tipo a della memoria non modifcabile
*/
int
compare_double( double const * pa, double const * pb) {
/* *pa e' il valore del numero "double" puntato da pa */
/* *pb e' il valore del numero "double" puntato da pb */
if ( *pa < *pb ) return -1 ;
if ( *pa > *pb ) return +1 ;
return 0 ;
}
typedef int (*compare_fun)( void const *, void const *) ;
int
main() {
/* dichiarazione con inizializzazione */
double a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
int i ;
printf("Vettore non ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
qsort( a, size, sizeof(a[0]),
(compare_fun) compare_double /* compare_double e' un puntatore a funzione */
) ;
printf("Vettore ordinato: %lg",a[0]);
for ( i=1; i < size ; ++i )
printf( ", %lg",a[i]) ;
printf("\n");
return 0 ;
}
- Puntatori e allocazione dinamica
File: ex013.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Aritmetica dei puntatori
*
*/
int
main() {
float a[] = {1, 2, -1, -2, 3.4, 5,-7, 0 };
/* +------+
* a --> | 1.0 |
* +------+
* | 2.0 |
* +------+
* | -1.0 |
* +------+
* | -2.0 |
* +------+
* | 3.4 |
* +------+
* | 5.0 |
* +------+
* | -7.0 |
* +------+
* | 0.0 |
* +------+
*/
float *p1, *p2, *p3 ; /* definisco 3 puntatori a float */
p1 = a ; /* p1 ora punta al primo elemento */
/* +------+
* p1 = a --> | 1.0 |
* +------+
* | 2.0 |
* +------+
* | -1.0 |
* +------+
* | -2.0 |
* +------+
* | 3.4 |
* +------+
* | 5.0 |
* +------+
* | -7.0 |
* +------+
* | 0.0 |
* +------+
*/
printf("Primo elemento a[0] = %g *p1 = %g\n", a[0], *p1) ;
printf("Indirizzo elemento &a[0] = %X p1 = %X\n",
(unsigned)(&a[0]),
(unsigned)(p1)) ;
p2 = a+3 ; /* p2 ora punta al quarto elemento */
/* +------+
* p1 = a --> | 1.0 |
* +------+
* | 2.0 |
* +------+
* | -1.0 |
* +------+
* p2 --> | -2.0 |
* +------+
* | 3.4 |
* +------+
* | 5.0 |
* +------+
* | -7.0 |
* +------+
* | 0.0 |
* +------+
*/
printf("Primo elemento a[3] = %g *p2 = %g\n", a[3], *p2) ;
printf("Indirizzo elemento &a[3] = %X p2 = %X\n",
(unsigned)(&a[3]),
(unsigned)(p2)) ;
p3 = p2+2 ; /* p3 ora punta al sesto elemento */
/* +------+
* p1 = a --> | 1.0 |
* +------+
* | 2.0 |
* +------+
* | -1.0 |
* +------+
* p2 --> | -2.0 |
* +------+
* | 3.4 |
* +------+
* p3 --> | 5.0 |
* +------+
* | -7.0 |
* +------+
* | 0.0 |
* +------+
*/
printf("Primo elemento a[5] = %g *p3 = %g\n", a[5], *p3) ;
printf("Indirizzo elemento &a[5] = %X p3 = %X\n",
(unsigned)(&a[5]),
(unsigned)(p3)) ;
/* posso fare la differenza tra puntatori.
In risultato e' un intero (con segno) e
rappresenta la differenza in celle
della dimensione del tipo puntato */
printf("p2-p3= %d\n",p2-p3) ;
printf("reinterpretati come puntatori a char p2-p3= %d\n",
(char*)p2-(char*)p3) ;
printf("reinterpretati come puntatori a double p2-p3= %d\n",
(double*)p2-(double*)p3) ;
/*
* facciamo arrabbiare il sistema operativo
*
*/
printf("*p3= %g\n",*p3) ;
p3 = (float*)((char*)p2-1) ;
/* | |
* | +-- decremento il puntatore come
* | puntatore a carattere, quindi p3
* | non puntera a inizio "parola".
* +--- reinterpreto l'indirizzo come puntatore a float
* mi aspetto un errore di accesso alla memoria in
* fase di esecuzione, o un valore floating point
* sensa senso
*/
printf("*p3= %g\n",*p3) ;
p3 = (float*)((char*)p2-4) ;
printf("*p3= %g\n",*p3) ;
return 0 ;
}
File: ex014.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Aritmetica dei puntatori
*
* loop su vettore
*/
void
stampa_vec( float const a[], int const dima) {
int i ;
printf("%g",a[0]);
for ( i=1; i < dima ; ++i )
printf( ", %g",a[i]) ;
printf("\n");
}
int
main() {
float a[] = {1, 2, -1, -2, 3.4, 5,-7, 0 };
/* +------+
* a --> | 1.0 |
* +------+
* | 2.0 |
* +------+
* | -1.0 |
* +------+
* | -2.0 |
* +------+
* | 3.4 |
* +------+
* | 5.0 |
* +------+
* | -7.0 |
* +------+
* | 0.0 |
* +------+
*/
int const dima = sizeof(a)/sizeof(a[0]) ;
/* memorizzo la dimensione di a su una costante */
float *pa, *pb ; /* definisco 2 puntatori a float */
float b[dima-1] ; /* dimensione di a - 1 */
int i ;
/* voglio costruire il vettore b che contiene
* all'i-esima posizione
*
* b[i] = a[i+1]-a[i]
*
*/
/* modo triviale */
for ( i=0 ; i < dima -1 ; ++i ) b[i] = a[i+1]-a[i] ;
printf("Differenza modo 1\n") ;
stampa_vec( a, dima ) ;
/* usando i puntatori */
for ( pa = a, pb = b ; pa < a + dima - 1 ; ++pa, ++pb )
*pb = pa[1]-pa[0] ;
/* *pa e' equivalente a pa[0]
* *(pa+1) e' equivalente a pa[1]
*
* occhio che a e b pur essendo puntatori non
* sono modificabili, cioe' non posso scivere ++a
* o b = b -1 etc etc
*/
printf("Differenza modo 2\n") ;
stampa_vec( a, dima ) ;
return 0 ;
}
File: ex015.c:
#include <stdio.h>
#include <stdlib.h>
/*
* Aritmetica dei puntatori
*
* allocazione dinamica della memoria.
*
* SCOPO:
* se conosce in tempo di esecuzione la dimensione
* di un vettore conviene allocarla dinamicamente.
*
* essenzialmente bastano tre routine
*
* (void*) malloc( int numero_di_bytes )
* (void*) realloc( void *old_ptr, int numero_di_bytes )
* void free( void *ptr )
*
*/
void
stampa_vec( float const a[], int const dima) {
int i ;
printf("%g",a[0]);
for ( i=1; i < dima ; ++i )
printf( ", %g",a[i]) ;
printf("\n");
}
int
main() {
float *a, *b ;
a = malloc( 1000000000000LL * sizeof(double) ) ;
/* alloca la memoria per 10 elementi */
if ( a == NULL ) {
/* NULL di solito e' il numero 0,
se il puntatore contiene queste valore
la memoria non e' stata allocata */
/* FACCIO QUALCOSA DI ALTERNATIVO .... */
}
printf("indirizzo puntato da a = %X\n", (unsigned)a);
b = malloc( 20 * sizeof(float) ) ;
/* alloca la memoria per 10 elementi */
if ( b == NULL ) {
/* NULL di solito e' il numero 0,
se il puntatore contiene queste valore
la memoria non e' stata allocata */
/* FACCIO QUALCOSA DI ALTERNATIVO .... */
}
printf("indirizzo puntato da b = %X\n", (unsigned)b);
//printf("Differenza modo 2\n") ;
//stampa_vec( a, dima ) ;
/*
* Alla fine di tutto rilascio la memoria
*
*/
free(a) ;
free(b) ;
return 0 ;
}
File: ex016.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
* Aritmetica dei puntatori
*
* allocazione dinamica della memoria.
*
*/
/*
* Esercizio stupido.
*
* Dati due vettori a e b costruisco la matrice
* M = I + a b^T
*
* +---------+
* a = | a[0] |
* +---------+
* ....
* +---------+
* | a[n-1] |
* +---------+
*
* +---------+
* b = | b[0] |
* +---------+
* ....
* +---------+
* | b[n-1] |
* +---------+
*
* AD ESEMPIO
* + + + + + +
* | 1 | | 1 | | 2 3 3 |
* M = I + a b^T = | 1 | + | 2 | + +
* | 1 | | 1 |
* + + + +
* + +
* | 3 3 3 |
* = | 4 7 6 |
* | 2 3 4 |
* + +
*
* Una volta costruita M calcolo la norma-1
*
* n n
* || M ||_1 = max sum | Mij |
* J=1 i=1
*
* Uso per macro per usare gli indici a partire a 1.
*
*/
double /* norma risultante */
norma1_di_un_vettore( double const a[],
int const n ) {
int i ;
double res = 0 ;
for ( i = 0 ; i < n ; ++i )
res += fabsf(a[i]) ;
return res ;
}
double /* norma risultante */
routine_inutile( double const a[],
double const b[],
int const n ) {
/* uso la allocazione dinamica per questioni
didattiche.
Esercizio, riscrivere la routione SENZA
allocazione dinamica */
double * M ; /* puntatore alla matrice da allocare */
double * p ; /* puntatore genrico per fare conti */
double res ; /* memorizzo la norma 1 della matrice */
double tmp ;
int i,j ; /* interi generici per i cicli vari */
/* allocazione dinamica */
M = malloc( n*n*sizeof(double)) ;
/* Da aggiungere il controllo della allocazione dinamica */
/*
* Per la matrice M puo essere memorizzata
* per "colonne", cioe'
* M(riga,colonna) = M[riga-1+(colonna-1)*n]
* per "righe", cioe'
* M(riga,colonna) = M[colonna-1+(riga-1)*n]
*
*/
/* uso la macro per "risparmiare" le dita
uso la allocazione per colonne */
#define M(I,J) M[(I-1)+(J-1)*n]
/* NOTA: cosa fa la macro ?
*
* se ad esempio scrivo
* M(i,j+1) questo viene espanso in
* M[(i-1)+(j+1-1)*n].
* ovviamente la macro e' piu' leggibile
* ma bisogna definirne una per ogni matrice
*/
#define a(I) a[I-1]
#define b(I) b[I-1]
/* per evitare di scrivere a[i-1] b[j-1]
uso la macro per scrivere a(i) e b(i) */
/* passo 1 setto M(i,j) = a(i)*b(j) */
for ( i = 1 ; i <= n ; ++i )
for ( j = 1 ; j <= n ; ++j )
M(i,j) = a(i)*b(j) ;
/* se non avessi usato le macro
l'istruzione diventava:
M(i,j) = a(i)*b(j) ===> M[i-1+(j-1)*n] = a[i-1]*b[j+1]
oppure cambiando i cicli ad iniziale da 0
for ( i = 0 ; i < n ; ++i )
for ( j = 0 ; j < n ; ++j )
M[i+j*n] = a[i]*b[j] ;
*/
/* aggiungo la matrice identita' */
for ( i = 1 ; i <= n ; ++i )
M(i,i) += 1 ; /* e' equivalente a M(i,i) = M(i,i) + 1 ; */
/* calcolo della norma 1 */
res = 0 ;
for ( i = 1 ; i <= n ; ++i ) {
p = & M(1,i) ; /* Puntatore alla i-esima colonna */
tmp = norma1_di_un_vettore( p, n ) ;
if ( tmp > res ) res = tmp ;
}
/* libero la memoria utilizzata */
free( M ) ;
return res ; /* norma 1 di M */
}
int
main() {
/* dichiarazione con inizializzazione */
double a[] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
/* in vettore verra' dimensionato al numero di elementi
nella lista tra { }, in questo caso a 8 */
/* si poteva anche scrivere
int a[8] = { 2, 3, -1, 5, 6, 0, -3, -4 } ;
ma se tolgo un elemento avrei un elemento
non inizializzato
*/
int size = sizeof(a)/sizeof(a[0]) ;
double res ;
res = routine_inutile( a, a, size ) ;
printf("Risultato = %lg\n",res ) ;
return 0 ;
}
Lezione del 22/6/2006
- Legge da un file un elenco di nomi+matricola+voto riordina in vario modo (per nome, per voto per matricola) salva le liste ordinate su altri file
File: ex017.c:
/*
* Programma inutile che esegue i seguenti compiti:
*
* Legge da un file un elenco di nomi+matricola+voto
* riordina in vario modo (per nome, per voto per matricola)
* salva le liste ordinate su altri file
*
*/
#include <stdio.h>
#include <string.h> /* per la gestione delle stringhe e strerror */
#include <sys/errno.h> /* per leggere errno */
#include <stdlib.h> /* per la definizione di exit() */
/*
* definisco la struttura che conterra' le informazioni
* di una singola riga
*/
#define MAX_LEN 100
#define MATRICOLA_LEN 10
struct nome_della_struttura {
char cognome[MAX_LEN] ;
char nome[MAX_LEN] ;
char matricola[MATRICOLA_LEN] ;
int voto ;
} ;
/*
* La struttura matricola verra' rappresentata in memoria
* in questo modo su una macchina a 32 bit
*
* +---------------------------------+
* | cognome[0] ... cognome[3] | (singola parola di 32 bit/4 byte)
* .....
* | cognome[96]... cognome[99] |
* +---------------------------------+
* | nome[0] ... nome[3] | (singola parola di 32 bit/4 byte)
* .....
* | nome[96]... nome[99] |
* +---------------------------------+
* | matricola[0] ... matricola[3] |(singola parola di 32 bit/4 byte)
* | matricola[4] ... matricola[7] |
* | matricola[8] matricola[9] 2 byte| // 2 bite di "padding" aggiunti
* +---------------------------------+
* | voto |
* +---------------------------------+
*
* cognome usa 100 byte
* nome usa 100 byte
* matricola usa 10 byte
* voto usa 4 byte (su un processore a 32 bit)
* ----------------------
* totale 214 byte 214 / 4 = 53.25 (non divisibile x 4)
*/
/*
* definisco un vettore di 100 strutture
*/
struct nome_della_struttura a[100] ;
/*
* typedef definisce dei sinonimi
* in modo da accedere "senza" struct in fronte
*/
typedef struct nome_della_struttura tipo_struttura ;
/*
* ora "tipo_struttura" e' un nuovo tipo come int double etc
* e come tale lo possoo usare dichiarare nuove variabili etc.
*/
tipo_struttura b[100] ;
/*
* subroutine di servizio per la stampa dei record
*/
static /* e' visibile solo in questo modulo */
void /* non restituisce niente */
stampa_record( FILE * fd, /* descrittore file di uscita */
tipo_struttura const record[],
int const n_record ) {
int i ;
tipo_struttura const * ps ; /* puntatore ad un record */
for ( i = 0 ; i < n_record ; ++i ) {
ps = & record[i] ; /* modo 1: record[i] e' l'i-esimo record,
con & prendo il suo indirizzo */
ps = record + i ; /* modo 2: sfrutto l'artimetica dei puntatori,
record e' il puntatore al primo (0-esimo)
elemento record + i e' l'indirizzo
dell'i-esimo record */
fprintf(fd,
"Record n. %d\n"
" Cognome: %s\n"
" Nome: %s\n"
" Matricola: %s\n"
" Voto: %d\n",
i,
(*ps) . cognome, /* modo 1: con * accedo al record e con ``.''
seleziono il campo della una struttura.
Non posso scrivere perche'
l'operatore ``.'' ha precedenza piu' alta
dell'operatore ``*'' cioe'
*ps.cognome <--> *(ps.cognome)
e l'operatore ``.'' non e' definito sui
puntatori */
ps -> nome, /* modo 2: si usa l'operatore ``->'' come "alias"
di (* ). */
ps -> matricola,
ps -> voto) ;
}
}
/*
* FUNZIONE DI CONFRONTO RECORD per COGNOME
*/
int
compare_cognome(const void * _pa, const void * _pb) {
tipo_struttura const * pa = (tipo_struttura const *) _pa ;
tipo_struttura const * pb = (tipo_struttura const *) _pb ;
return strcmp(pa -> cognome, pb -> cognome);
}
int
compare_matricola(const void * _pa, const void * _pb) {
tipo_struttura const * pa = (tipo_struttura const *) _pa ;
tipo_struttura const * pb = (tipo_struttura const *) _pb ;
return strcmp(pa -> matricola, pb -> matricola);
}
int
compare_voto(const void * _pa, const void * _pb) {
tipo_struttura const * pa = (tipo_struttura const *) _pa ;
tipo_struttura const * pb = (tipo_struttura const *) _pb ;
if ( pa -> voto == pb -> voto ) return 0 ;
if ( pa -> voto > pb -> voto ) return +1 ;
else return -1 ;
}
int
main () {
int err_code ; /* usato per il codice di errore restituito dall I/O */
char nome_file[100] ;
FILE * descrittore_file ;
int n_record ;
tipo_struttura record[1000] ; /* max 1000 nomi da ordinare */
/*
* FILE e' un tipo definito stdio.h che contiene
* quello che serve per la gestione del file.
*/
printf("NOME FILE ?:") ;
scanf("%s",nome_file) ; /* %s e' il formato indicante una stringa
non scrivo &nome_file perche nome_file e'
gia un puntatore */
printf("Apro il file: %s\n",nome_file) ;
descrittore_file = fopen ( nome_file, "r" );
/* controllo se l'apertura del file ha avuto successo */
if ( descrittore_file == NULL ) {
perror("Ho trovato questo errore") ;
printf("Stampo l'errore in modo alternativo\n" /* stringhe concatenate dal compilatore */
"Cercando di aprire il file ``%s''\n"
"ho trovato il seguente errore: ``%s''\n",
nome_file, strerror(errno));
/*
* PROBLEMA:
* ho il testo in italiano e messaggi errore in inglese.
* per scrivere un codice in multilingua occorre usare
* le opportunita di "locale.h" (vedi manuale libc)
*/
exit(1) ; /* chiamata di sistema, uscita di brutto
ripulisce un po tutto e chiude file eventualmente
aperti */
}
/*
* apro il file 'nome_file' in lettura.
*
* i possibili modi di apertura di un file sono:
* ``r'' apro in lettura. Il puntatore e' posizionato sul primo carattere.
* ``r+'' apro in lettura e scrittura.
* Il puntatore e' posizionato sul primo carattere.
* ``w'' Apre in scrittura un nuovo file. Se il file e' gia esistente
* lo cancella.
* ``w+'' apro in lettura e scrittura. Se il file e' gia esistente
* lo cancella.
* ``a'' Apre in scrittura un file.
* Se il file non esiste ne crea uno vuoto.
* Il puntatore e' posizionato sull'ultimo carattere.
* ``a+'' Apre in lettura e scrittura un file.
* Se il file non esiste ne crea uno vuoto.
* Il puntatore e' posizionato sull'ultimo carattere.
*/
/*
* voglio saltare la prima riga che contine un commento
*/
{ /* apro nuovo blocco */
int ch ; /* posso definire nuove variabili */
while ( ( ch = fgetc(descrittore_file) ) != '\n' &&
ch != EOF ) /* messuna istruzione */ ;
}
/* ch non e' piu' visibile */
for ( n_record = 0 ; /* inizializzo n_record */
fscanf(descrittore_file, /* leggo dal file il cui descrittore e' descrittore_file */
"%s%s%s%d", /* cerco di convertire 3 stringhe e un intero */
record[n_record].cognome, /* per accedere ai campi di una struttura */
record[n_record].nome, /* si usa l'operatore ``.'' */
record[n_record].matricola, /* fscanf vuole i puntatori, quindi per le */
& record[n_record].voto /* stringhe non serve & */
) == 4 ; /* finche leggo 4 elementi continuo il ciclo */
++n_record ) {
printf("Record n. %d\n"
" Cognome: %s\n"
" Nome: %s\n"
" Matricola: %s\n"
" Voto: %d\n",
n_record,
record[n_record].cognome, /* per accedere ai campi di una struttura */
record[n_record].nome, /* si usa l'operatore ``.'' */
record[n_record].matricola,
record[n_record].voto) ;
}
/*
* Ci sono 3 descrittori file associati a tre file standard
* aperti in esecuzione del programma dal sistema operativo:
*
* FILE *stdin -- stantard input (lettura da terminale)
* FILE *stdout -- standard output (stampa su terminale)
* FILE *stderr -- standard error (stampa errori di solito su terminale)
*
* i descrittori sono riassegnabili, quindi posso cambiare
* in esecuzione l'I/O su terminale e ridirigerlo su file o altro.
*
* OCCHIO:
* print(...) e' equivalente a fprintf(stdout,...)
* scanf(...) e' equivalente a fscanf(stdin,...)
*/
/* ordina i record per cognome */
qsort( record, /* puntatore inizio vettore da ordinare */
n_record, /* intero con il numero di elementi da ordinare */
sizeof(tipo_struttura), /* intero con il numero di byte occupato
da un elemento del vettore */
compare_cognome /* puntatore a fuzione di tipo
* int (*) (void const *,void const *)
* cioe' una funzione che dati due puntatori
* generici (che punteranno a due record del vettore da ordinare)
* restituisce un intero:
* 0 se li considero uguali
* > 0 se il primo elemeno puntato lo considero maggiore
* del secondo elemento puntato.
* < 0 se il primo elemeno puntato lo considero minore
* del secondo elemento puntato.
*/
) ;
printf("Lista ordinata per COGNOME\n\n") ;
stampa_record( stdout, record, n_record ) ;
/* ordina i record per matricola */
qsort( record, n_record, sizeof(tipo_struttura), compare_matricola ) ;
printf("Lista ordinata per MATRICOLA\n\n") ;
stampa_record( stdout, record, n_record ) ;
/* ordina i record per voto */
qsort( record, n_record, sizeof(tipo_struttura), compare_voto ) ;
printf("Lista ordinata per VOTO\n\n") ;
stampa_record( stdout, record, n_record ) ;
printf("Chiudo il file: %s\n",nome_file) ;
err_code = fclose(descrittore_file) ;
/* controllo se l'apertura del file ha avuto successo */
if ( err_code != 0 ) {
perror("Ho trovato questo errore") ;
exit(1) ; /* chiamata di sistema, uscita di brutto
ripulisce un po tutto e chiude file eventualmente
aperti */
}
printf("Tutto fatto!\n") ;
return 0 ;
}
- ** Legge da un file un elenco di nomi+matricola+voto salva i record letti su una lista dinamicamente**
File: ex018.c:
/*
* Programma inutile che esegue i seguenti compiti:
*
* Legge da un file un elenco di nomi+matricola+voto
* salva i record letti su una lista dinamicamante
*
*/
#include <stdio.h>
#include <string.h> /* per la gestione delle stringhe e strerror */
#include <sys/errno.h> /* per leggere errno */
#include <stdlib.h> /* per la definizione di exit() */
/*
* definisco la struttura che conterra' le informazioni
* di una singola riga
*/
#define MAX_LEN 100
#define MATRICOLA_LEN 10
typedef struct /* non serve il nome della struttura */ {
char cognome[MAX_LEN] ;
char nome[MAX_LEN] ;
char matricola[MATRICOLA_LEN] ;
int voto ;
} tipo_struttura ;
typedef struct _elemento_lista_struttura {
tipo_struttura il_record ;
struct _elemento_lista_struttura * prossimo ;
/* puntatore a una struttura dello stesso tipo che sto
definendo */
} elemento_lista_struttura ;
/* il puntatore al primo elemento della lista e' la lista */
static elemento_lista_struttura * lista_struttura ;
static
void
Inizializza() {
lista_struttura = NULL ; /* inizializzo alla lista vuota */
}
static
void
Inserisci_in_testa_alla_lista(tipo_struttura const * record_pointer ) {
/* allocazione dinamica di un nuovo elemento della lista */
elemento_lista_struttura * nuovo_elemento ;
nuovo_elemento = malloc(sizeof(elemento_lista_struttura)) ;
/* bisogna controllare che l'allocazione vada a buon fine */
/* da fare ..... */
/* copia del record bit a bit */
memcpy( & nuovo_elemento -> il_record, /* puntatore memoria di arrivo */
record_pointer, /* puntatore memoria di partenza */
sizeof(tipo_struttura) ) ; /* quanti byte copiare */
/* inserisco in testa alla lista questo elemento */
if ( lista_struttura == NULL ) {
/* la lista e' vuota, nuovo_elemento e' la lista di un solo
elemento */
nuovo_elemento -> prossimo = NULL ;
lista_struttura = nuovo_elemento ;
} else {
/* la lista c'e' gia, aggiungo in testa alla lista */
nuovo_elemento -> prossimo = lista_struttura ;
lista_struttura = nuovo_elemento ;
}
}
static
void
Distruggi_la_lista() {
elemento_lista_struttura * prossimo ;
while ( lista_struttura != NULL ) {
prossimo = lista_struttura -> prossimo ;
/* salvo il puntatore al prossimo elemento della lista */
free( lista_struttura ) ; /* riliascio la memoria allocata */
lista_struttura = prossimo ;
/* non si puo scrivere lista_struttura = lista_struttura -> prossimo
perche' il puntatore a lista struttura e' stato rilasciato
e quindi non e' garatito che il record sia ancora in memoria */
}
}
/*
* Altre funzioni possibili da definire:
*
* Contare quanto elementi della lista ci sono
* Inserisci in coda alla lista
* Inserisci alla posizione n della lista
* Costruire una lista nell'ordine inverso
* Data lista costruire un vettore (allocato alla dimensione giusta)
* e poi riempirlo e ordinarlo.
*/
/*
* Possibili miglioramenti
* che succede con i doppi cognomi ?
* si puo' modificare il codice in modo che funzioni sempre correttamente ?
*/
static
void
Stampa_la_lista(FILE * fd) {
elemento_lista_struttura * elemento = lista_struttura ;
tipo_struttura * ps ;
int n_record = 0 ;
while ( elemento != NULL ) {
/* uso l'elemnto della lista */
ps = & elemento -> il_record ; /* estraggo il puintatore al record */
fprintf(fd,
"Record n. %d\n"
" Cognome: %s\n"
" Nome: %s\n"
" Matricola: %s\n"
" Voto: %d\n",
n_record++, /* uso il valore e solo dopo l'uso lo incremento */
ps -> cognome,
ps -> nome,
ps -> matricola,
ps -> voto) ;
/* passo al prossimo elemento della lista */
elemento = elemento -> prossimo ;
}
}
int
main () {
int err_code ; /* usato per il codice di errore restituito dall I/O */
char nome_file[100] ;
FILE * descrittore_file ;
tipo_struttura un_record ;
printf("NOME FILE ?:") ;
scanf("%s",nome_file) ;
printf("Apro il file: %s\n",nome_file) ;
descrittore_file = fopen ( nome_file, "r" );
/* controllo se l'apertura del file ha avuto successo */
if ( descrittore_file == NULL ) {
perror("Ho trovato questo errore") ;
exit(1) ;
}
Inizializza() ; /* inizializzo la lista alla lista vuota */
/*
* voglio saltare la prima riga che contine un commento
*/
{ /* apro nuovo blocco */
int ch ; /* posso definire nuove variabili */
while ( ( ch = fgetc(descrittore_file) ) != '\n' &&
ch != EOF ) /* messuna istruzione */ ;
}
/* ch non e' piu' visibile */
while ( fscanf(descrittore_file,
"%s%s%s%d",
un_record.cognome,
un_record.nome,
un_record.matricola,
& un_record.voto ) == 4 ) {
/* inserisci il record in testa alla lista */
Inserisci_in_testa_alla_lista( & un_record ) ;
/* uso & per passare il puntatore al record e non il record stesso */
}
printf("Chiudo il file: %s\n",nome_file) ;
err_code = fclose(descrittore_file) ;
/* controllo se l'apertura del file ha avuto successo */
if ( err_code != 0 ) {
perror("Ho trovato questo errore") ;
exit(1) ; /* chiamata di sistema, uscita di brutto
ripulisce un po tutto e chiude file eventualmente
aperti */
}
Stampa_la_lista ( stdout ) ;
Distruggi_la_lista() ;
printf("Tutto fatto!\n") ;
return 0 ;
}
Lezione del 23/6/2006
- Esempio di uso degli argomenti della linea di comando
File: ex019.c:
/*
* Esempio di uso degli argomenti del MAIN
*/
#include <stdio.h>
int
main(int argc, char const * argv [] ) {
/*
* argc: intero che contiene il numero di argomenti
* del comando, ad esempio invocando questo comando
* >> ex019 pippo pluto paperino
* avremo argc = 4
*/
printf( "Numero di argomenti = %d\n",argc) ;
/*
* argv: e' un vettore di puntatori.
*
* Ad esempio con la chiamata
* >> ex019 pippo pluto paperino
* il vettore di puntatori e' (Gli indirizzi sono finti)
* +------------------+
* | argv[0] = 0xF123 | --> "ex019"
* +------------------+
* | argv[1] | --> "pippo"
* +------------------+
* | argv[2] | --> "pluto"
* +------------------+
* | argv[3] = 0xFF12 | --> "paperino"
* +------------------+
*
* All'indirizzo "0xF123"
*
* +--------------+
* | "ex01" |
* +--------------+
* | "9\0" unused |
* +--------------+
*
* All'indirizzo "0xFF12"
*
* +-------------+
* | "pape" |
* +-------------+
* | "rino" |
* +-------------+
* | "\0" unused |
* +-------------+
*/
{ int i ;
for ( i = 0 ; i < argc ; ++i )
printf("Argomento n.%d = %s\n",i,argv[i]) ;
/*
* argv[i] = puntatore all'inizio della stringa che
* rappresenta l'i'esimo argomento
*/
}
return 0 ;
}
- Programma che legge un file ascii e scrive un altro file ascii con una parola per riga
File: ex020.c:
/*
* Esempio di uso degli argomenti del MAIN
*
* programma che legge un file ascii e scrive
* un altro file ascii con una parola per riga
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <string.h>
int
main(int argc, char const * argv [] ) {
int ierr ; /* per fclose */
char const * nome_file_in ;
char const * nome_file_out ;
FILE * fd_in ; /* descrittore file IN */
FILE * fd_out ; /* descrittore file OUT */
/*
* il comando deve essere
* ex020 infile outfile
*/
if ( argc != 3 ) {
printf( "Il comando %s si aspetta due argomenti\n"
"Uso: %s infile outfile\n",argv[0],argv[0]) ;
exit(1) ;
}
/*
* non sto COPIANDO le stringhe ma sto solo assegnando
* i puntatori per rendere piu'' leggibile quello che segue.
*/
nome_file_in = argv[1] ;
nome_file_out = argv[2] ;
fd_in = fopen( nome_file_in, "r" ) ;
if ( fd_in == NULL ) {
/* costruzione del messaggio di errore */
char msg[1000] ;
sprintf(msg,"Errore con il file ``%s''",nome_file_in);
perror(msg) ;
exit(1);
}
fd_out = fopen( nome_file_out, "w" ) ;
if ( fd_out == NULL ) {
/* costruzione del messaggio di errore */
printf("Errore con il file ``%s'': %s\n",nome_file_out,strerror(errno));
exit(1);
}
/*
* Ciclo di lettura e scrittura sul secondo file
*
*
*/
{ char buffer[1024] ;
while ( fscanf(fd_in,"%s",buffer) == 1 ) {
fprintf(fd_out,"%s\n",buffer) ;
}
}
/*
* chiusura dei file
*
*/
ierr = fclose(fd_out) ;
if ( ierr != 0 ) {
/* costruzione del messaggio di errore */
printf("Errore in chiusura del file ``%s'': %s\n",nome_file_out,strerror(errno));
exit(1);
}
ierr = fclose(fd_in) ;
if ( ierr != 0 ) {
/* costruzione del messaggio di errore */
printf("Errore in chiusura del file ``%s'': %s\n",nome_file_in,strerror(errno));
exit(1);
}
return 0 ;
}
- Programma che legge un file ascii e scrive un altro file ascii con una parola per riga in aggiunta le parole sono ordinate in senso crescente
File: ex021.c:
/*
* Esempio di uso degli argomenti del MAIN
*
* programma che legge un file ascii e scrive
* un altro file ascii con una parola per riga
* le parore sono ordinate in senso crescente
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <string.h>
/*
* struttura che definisce la lista delle parole
*/
typedef struct {
int occurrence ;
char * word ;
} word_element ;
static int n_word ; /* elementi di word_vector usati */
static int word_vector_reserved ; /* elementi di word_vector disponibili */
static word_element * word_vector ; /* vettore ("lista") di parole lette */
/*
* ALGORITMO
*
* Uso il vettore
*
* word_vector
*
* per tenere una "lista" ordinata delle parole
* man mano che vengono lette dal file.
* Ad ogni inserimento nella "lista" aggiorno
* occurrence della parola e la stessa e' gia presente.
*
* Se word_vector e' pieno, lo rialloco ad una dimensione
* doppia.
*
*/
int
main(int argc, char const * argv [] ) {
int i, j, k, len ;
int ierr ; /* per fclose */
char const * nome_file_in ;
char const * nome_file_out ;
FILE * fd_in ; /* descrittore file IN */
FILE * fd_out ; /* descrittore file OUT */
/*
* il comando deve essere
* ex021 infile outfile
*/
if ( argc != 3 ) {
printf( "Il comando %s si aspetta due argomenti\n"
"Uso: %s infile outfile\n",argv[0],argv[0]) ;
exit(1) ;
}
/*
* non sto COPIANDO le stringhe ma sto solo assegnando
* i puntatori per rendere piu'' leggibile quello che segue.
*/
nome_file_in = argv[1] ;
nome_file_out = argv[2] ;
fd_in = fopen( nome_file_in, "r" ) ;
if ( fd_in == NULL ) {
/* costruzione del messaggio di errore */
char msg[1000] ;
sprintf(msg,"Errore con il file ``%s''",nome_file_in);
perror(msg) ;
exit(1);
}
fd_out = fopen( nome_file_out, "w" ) ;
if ( fd_out == NULL ) {
/* costruzione del messaggio di errore */
printf("Errore con il file ``%s'': %s\n",nome_file_out,strerror(errno));
exit(1);
}
/* inizializzazione delle strutture e allocazione */
n_word = 0 ;
word_vector_reserved = 10 ;
word_vector = malloc( word_vector_reserved * sizeof(word_element)) ;
if ( word_vector == NULL ) {
perror("Non posso allocare la memoria");
exit(1);
}
/*
* Ciclo di lettura e scrittura sul secondo file
*
*
*/
{ char buffer[1024] ;
while ( fscanf(fd_in,"%s",buffer) == 1 ) {
/*
* calcolo lunghezza della stringa letta
*/
for ( len = 0 ; len < 1024 ; ++len )
if ( buffer[len] == '\0' ) break ;
/* printf("trovato %s len = %d\n",buffer,len) ; */
/*
* Devo inserire la stringa letta nel vettore word_vector
*/
if ( n_word == 0 ) {
/* printf("PRIMO INSERIMENTO\n") ; */
/* lista vuota: inseriso il primo elemento */
word_vector[0] . occurrence = 1 ;
word_vector[0] . word = malloc((len+1)*sizeof(char));
/* !- +1 per \0
* manca controllo che allocazione dinamica ha avuto
* successo
*/
strcpy(word_vector[0] . word, buffer) ;
++n_word ;
} else {
/* FASE 1: cerco la sua posizione */
k = n_word ;
do {
--k ;
/* confronto la stringa attuale con
* quella alla posizione k-esima */
i = strcmp( buffer, word_vector[k] . word ) ;
if ( i == 0 ) {
/* printf("PAROLA GIA ESISTENTE\n") ; */
/* parola e' gia esistente, aggiorno occurrence */
word_vector[k] . occurrence++ ;
goto skip_insertion ;
} else if ( i > 0 ) {
/* buffer > word_vector[k] . word
* --> vado avanti con la ricerca */
} else {
/* buffer < word_vector[k] . word
* --> buffer va inserito alla posizione k+1 */
++k ;
break ; /* interrompo il do -- while */
}
} while ( k > 0 ) ;
/* QUESTA PARTE PUO'ESSERE FATTA RICHIAMANDO bsearch */
/* FASE 2: inserisco l'elemento alla posizione k */
/* 1: controllo se ho abbastanza elementi in word_vector
*/
if ( n_word >= word_vector_reserved ) {
/* vettore pieno, devo riallocare */
word_vector_reserved *= 2 ;
printf("Riallocazione %d\n",word_vector_reserved) ;
word_vector = realloc( word_vector, word_vector_reserved * sizeof(word_element)) ;
if ( word_vector == NULL ) {
perror("Non posso allocare la memoria");
exit(1);
}
}
/*
* sposto eventualmente gli elementi del vettore
*/
for ( i = n_word ; i > k ; --i ) {
word_vector[i] . occurrence = word_vector[i-1] . occurrence ;
word_vector[i] . word = word_vector[i-1] . word ;
/*
* si puo fare anche word_vector[i] = word_vector[i-1]
*/
}
word_vector[k] . occurrence = 1 ;
word_vector[k] . word = malloc((len+1)*sizeof(char));
/* !- +1 per \0
* manca controllo che allocazione dinamica ha avuto
* successo
*/
strcpy(word_vector[k] . word, buffer) ;
++n_word ;
skip_insertion:
continue ;
}
}
}
/* stampa ordinata delle parole */
for ( k = 0 ; k < n_word ; ++k )
fprintf(fd_out, "%d %s\n",
word_vector[k] . occurrence,
word_vector[k] . word ) ;
/* usare qsort per riordinare in base alla frequenza*/
/*
* chiusura dei file
*
*/
ierr = fclose(fd_out) ;
if ( ierr != 0 ) {
/* costruzione del messaggio di errore */
printf("Errore in chiusura del file ``%s'': %s\n",nome_file_out,strerror(errno));
exit(1);
}
ierr = fclose(fd_in) ;
if ( ierr != 0 ) {
/* costruzione del messaggio di errore */
printf("Errore in chiusura del file ``%s'': %s\n",nome_file_in,strerror(errno));
exit(1);
}
return 0 ;
}
- Esempio di programma per trasformare stringhe da “uppercase” a “lowercase” e viceversa.
File: ex022.c:
/*
* Esempio senza Barbatrucco, tolower e toupper
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Dato un carattere c se e' in
*
* 'A' <= c <= 'Z'
*
* restituisce il carattere minuscolo altrimenti
* restituisce il carattere originario
*/
char
ToLower( char const c ) {
if ( c >= 'A' && c <= 'Z' )
return (c - 'A') + 'a' ;
else
return c ;
/*
* c +('a'-'A') questo funziona in ASCII
* c +('A'-'a') questo potrebbe non funzionare in toupper
*/
}
/*
* Dato un carattere c se e' in
*
* 'a' <= c <= 'z'
*
* restituisce il carattere maiuscolo altrimenti
* restituisce il carattere originario
*/
char
ToUpper( char const c ) {
if ( c >= 'a' && c <= 'z' )
return (c - 'a') + 'A' ;
else
return c ;
}
int
main(int argc, char const * argv []) {
int i ;
char lower_string[1024] ;
char upper_string[1024] ;
/*
* il comando deve essere
* ex022 stringa
*/
if ( argc != 2 ) {
printf( "Il comando %s si aspetta un argomento\n"
"Uso: %s stringa\n",argv[0],argv[0]) ;
exit(1) ;
}
/* modo becero */
for ( i=0 ;
i < strlen(argv[1]) ; /* da evitare, ad ogni iterata fa una chiamata
ad una funzione costosa */
++i ) {
lower_string[i] = ToLower(argv[1][i]) ;
upper_string[i] = ToUpper(argv[1][i]) ;
}
/* metto il carattere '\0' per marcare il fine stringa
(modo standard C di trattare le stringhe) */
lower_string[strlen(argv[1])] = '\0' ;
upper_string[strlen(argv[1])] = '\0' ;
printf("Originale: %s\n"
"In Minuscole: %s\n"
"In Maiuscole: %s\n",
argv[1], lower_string, upper_string) ;
return 0 ;
}
File: ex023.c:
/*
* Esempio di Barbatrucco, tolower e toupper
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Dato che i caratteri ascii sono "pochi" (127)
* posso usare una tabella
*/
static unsigned char ToLowerTable[256] ;
static unsigned char ToUpperTable[256] ;
static
void
Initialize() {
int c ;
for ( c=0 ; c<256 ; ++c ) {
if ( c >= 'A' && c <= 'Z' )
ToLowerTable[c] = (c - 'A') + 'a' ;
else
ToLowerTable[c] = c ;
if ( c >= 'a' && c <= 'z' )
ToUpperTable[c] = (c - 'a') + 'A' ;
else
ToUpperTable[c] = c ;
}
}
static
char
ToLower( char const c ) {
return ToLowerTable[c] ;
}
static
char
ToUpper( char const c ) {
return ToUpperTable[c] ;
}
int
main(int argc, char const * argv []) {
char lower_string[1024] ;
char upper_string[1024] ;
char const * pc ; /* puntatore a carattere generico di sola lettura */
char * pl ; /* puntatore a carattere (x lower string) */
char * pu ; /* puntatore a carattere (x upper string) */
/*
* il comando deve essere
* ex022 stringa
*/
if ( argc != 2 ) {
printf( "Il comando %s si aspetta un argomento\n"
"Uso: %s stringa\n",argv[0],argv[0]) ;
exit(1) ;
}
Initialize() ; /* inizializzo le tabelle di conversione */
pc = argv[1] ; /* pc punta all'inizio della stringa */
pl = lower_string ;
pu = upper_string ;
do {
*pl++ = ToLower(*pc) ; /* *pc = carattere all'indirizzo puntato da pc */
/* *pl = copio il carattere convertito alla locazione
puntata da pl. Con *pl++ l'operazione ++
viene eseguita DOPO l'assegnazione.
(Molto diverso da *++pl = ) */
/* MODI EQUIVALENTI:
*pl = ToLower(*pc) ; ++pl ;
pl[0] = ToLower(pc[0]) ; ++pl ; */
*pu++ = ToUpper(*pc) ;
} while ( *pc++ != '\0' ) ;
/* controllo che *pc sia il carattere di fin stringa,
dopo il confronto incremento pc al carattere successivo */
printf("Originale: %s\n"
"In Minuscole: %s\n"
"In Maiuscole: %s\n",
argv[1], lower_string, upper_string) ;
return 0 ;
}
File: ex024.c:
/*
* Esempio di Barbatrucco, tolower e toupper
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Dato che i caratteri ascii sono "pochi" (127)
* posso usare una tabella generata da TableGeneration!
*/
static unsigned char const ToLowerTable[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
static unsigned char const ToUpperTable[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
static
void
TableGeneration() {
int c,cc ;
printf("static unsigned char const ToLowerTable[256] = {");
for ( c=0 ; c<256 ; ++c ) {
if ( (c % 8) == 0 ) printf("\n") ; /* % resto della divisione intera */
if ( c >= 'A' && c <= 'Z' ) cc = (c - 'A') + 'a' ;
else cc = c ;
printf("0x%02X, ",cc) ;
/*
* FORMATTAZIONE %02X
* 0 = riempie di 0 al posto del ' ' a sinistra
* 2 = riserva 2 caratteri (almeno) per la stampa del numero
* X = stampa in esadecimale MAIUSCOLO
*/
}
printf("};\n\n"
"static unsigned char const ToUpperTable[256] = {");
for ( c=0 ; c<256 ; ++c ) {
if ( (c % 8) == 0 ) printf("\n") ; /* % resto della divisione intera */
if ( c >= 'a' && c <= 'z' ) cc = (c - 'a') + 'A' ;
else cc = c ;
printf("0x%02X, ",cc) ;
}
printf("};\n") ;
}
/* #define USA_FUNZIONI */
#ifdef USA_FUNZIONI
/* se USA_FUNZIONI e' definito espande il codice seguente fino a #else */
static
char
ToLower( char const c ) {
return ToLowerTable[c] ;
}
static
char
ToUpper( char const c ) {
return ToUpperTable[c] ;
}
#else
/* se USA_FUNZIONI NON e' definito espande il codice seguente fino a #endif */
#define ToLower(C) ToLowerTable[C]
#define ToUpper(C) ToUpperTable[C]
#endif
/*
* Con le tabelle posso usare le macro al posto
* della chiamata a funzione
*
*/
int
main(int argc, char const * argv []) {
char lower_string[1024] ;
char upper_string[1024] ;
char const * pc ; /* puntatore a carattere generico di sola lettura */
char * pl ; /* puntatore a carattere (x lower string) */
char * pu ; /* puntatore a carattere (x upper string) */
/*
* il comando deve essere
* ex022 stringa
*/
if ( argc != 2 ) {
printf( "Il comando %s si aspetta un argomento\n"
"Uso: %s stringa\n",argv[0],argv[0]) ;
exit(1) ;
}
pc = argv[1] ; /* pc punta all'inizio della stringa */
pl = lower_string ;
pu = upper_string ;
do {
*pl++ = ToLower(*pc) ; /* *pc = carattere all'indirizzo puntato da pc */
/* *pl = copio il carattere convertito alla locazione
puntata da pl. Con *pl++ l'operazione ++
viene eseguita DOPO l'assegnazione.
(Molto diverso da *++pl = ) */
/* MODI EQUIVALENTI:
*pl = ToLower(*pc) ; ++pl ;
pl[0] = ToLower(pc[0]) ; ++pl ; */
*pu++ = ToUpper(*pc) ;
} while ( *pc++ != '\0' ) ;
/* controllo che *pc sia il carattere di fin stringa,
dopo il confronto incremento pc al carattere successivo */
printf("Originale: %s\n"
"In Minuscole: %s\n"
"In Maiuscole: %s\n",
argv[1], lower_string, upper_string) ;
return 0 ;
}
Lezione del 10/7/2006
- Esempio di un programma complesso, soluzione di un sistema lineare tramite la fattorizzazione LU di una matrice quadrata
File: ex025.c:
/*
* Esempio "complesso", fattorizzazione LU di Gauss di una Matrice
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/* prototipo della funzione */
int fattorizzazione_LU( double [], int, int, int [] ) ;
#define A(I,J) A[(I)+(J)*lda]
int /* valore di ritorno se 0 = tutto ok */
/* se 1 = matrice singolare */
fattorizzazione_LU( double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[] ) { /* vettori di interi di domensione >= N che
conterra' la permutazione */
int i, j, k, imax ;
double amax, acheck ;
/* Inizializzo il vettore della permutazione */
for ( i = 0 ; i < N ; ++i ) perm[i] = i ;
for ( i = 0 ; i < N-1 ; ++i ) {
/* ricerca del pivot, cerco elemento di modulo massimo
nella colonna i-esima, cioe' A(i,i), A(i+1,i), ..., A(N-1,i) */
imax = i ;
amax = fabs( A(i,i) ) ;
for ( j=i+1 ; j < N ; j++ ) {
acheck = fabs(A(j,i));
if ( acheck > amax ) {
acheck = amax ;
imax = j ;
}
}
/* controllo che acheck > 0, se 0 la matrice e' singolare */
if ( acheck == 0 ) return 1 ;
if ( imax != i ) { /* scambio la riga i con la riga imax */
/* scambio indici sul vettore della permutazione */
k = perm[i] ;
perm[i] = perm[imax] ;
perm[imax] = k ;
/* scambio delle righe nella matrice A */
for ( j=0 ; j < N ; ++j ) {
amax = A(i,j) ;
A(i,j) = A(imax,j) ;
A(imax,j) = amax ;
}
}
/* costruisco la parte della matrice Li e la applico alla matrice
LU in costruzione */
for ( k = i+1 ; k < N ; ++k ) {
amax = A(k,i) / A(i,i) ;
A(k,i) = amax ;
for ( j= i+1 ; j < N ; ++j )
A(k,j) -= amax * A(i,j) ;
}
}
return 0 ; /* tutto ok */
}
void
stampa_L( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, "%-10lg ",A(i,j)) ;
}
fprintf( fd, "1\n") ; /* uso 10 caratteri per numero */
}
}
void
stampa_U( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, " ") ; /* 11 spazi bianchi */
}
for ( j = i ; j < N ; ++j ) {
fprintf( fd, "%-10lg ",A(i,j)) ;
}
fprintf( fd, "\n") ; /* vado a capo a fine riga */
}
}
#undef A /* elimino la definizione di A(I,I) */
#define L(I,J) LU[(I)+(J)*lda]
#define U(I,J) LU[(I)+(J)*lda]
void
solve_LU( double LU[], /* matrice fattorizzata memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[], /* vettori di interi di domensione >= N che
conterra' la permutazione */
double b[], /* temine noto */
double x[] ) { /* soluzione */
int i, j ;
/* applico la permutazione */
for ( i = 0 ; i < N ; ++i ) x[perm[i]] = b[i] ;
/* Risolvo Lz = Pb */
for ( i = 1 ; i < N ; ++i )
for ( j = 0 ; j < i ; ++j )
x[i] -= L(i,j)*x[j];
/* Risolvo Ux = Lz */
i=N;
do {
--i ;
for ( j = i+1 ; j < N ; ++j )
x[i] -= U(i,j)*x[j];
x[i] /= U(i,i) ;
} while ( i > 0 ) ;
}
int
main() {
double M[] = {
4, 3, 2, 1, /* prima colonna */
1, 2, 3, 4, /* seconda colonna */
1, 0, 0, 1, /* terza colonna */
0, 1, 2, 5 /* quarta colonna */
} ;
double b[] = { 9, 11, 16, 32 } ; /* termine noto se la solzione e' 1,2,3,4 */
double x[4] ; /* vettore che conterra' la soluzione */
int i, perm[4] ;
int iflag, dim ;
dim = 4 ;
iflag = fattorizzazione_LU( M, dim, dim, perm ) ;
printf( "Valore del flag=%d\n",iflag);
#define A(I,J) M[(I)+(J)*4]
/* stampa della matrice L ed U e la permutazione */
printf("MATRICE L\n") ;
stampa_L( stdout, M, dim, dim );
printf("MATRICE U\n") ;
stampa_U( stdout, M, dim, dim );
printf("PERMUTAZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "perm[%d]=%d\n", i, perm[i]) ;
solve_LU( M, dim, dim, perm, b, x ) ;
printf("SOLUZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "x[%d]=%lg\n", i, x[i]) ;
return 0 ;
}
- Esempio di un programma complesso, stesso problema ma soluzione cin l’uso della libreria LAPACK
File: ex026.c:
/*
* Esempio "complesso", fattorizzazione LU di Gauss di una Matrice
* Ma usando le LAPACK/BLAS
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/*
FATTORIZZAZIONE LU, PROTOTIPO FORTRAN DELLE LAPACK
NAME
DGETRF - compute an LU factorization of a general M-by-N
matrix A using partial pivoting with row interchanges
SYNOPSIS
SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO )
INTEGER INFO, LDA, M, N
INTEGER IPIV( * )
DOUBLE PRECISION A( LDA, * )
PURPOSE
DGETRF computes an LU factorization of a general M-by-N
matrix A using partial pivoting with row interchanges.
The factorization has the form
A = P * L * U
where P is a permutation matrix, L is lower triangular with
unit diagonal elements (lower trapezoidal if m > n), and U
is upper triangular (upper trapezoidal if m < n).
This is the right-looking Level 3 BLAS version of the algo-
rithm.
ARGUMENTS
M (input) INTEGER
The number of rows of the matrix A. M >= 0.
N (input) INTEGER
The number of columns of the matrix A. N >= 0.
A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
On entry, the M-by-N matrix to be factored. On
exit, the factors L and U from the factorization A =
P*L*U; the unit diagonal elements of L are not
stored.
LDA (input) INTEGER
The leading dimension of the array A. LDA >=
max(1,M).
IPIV (output) INTEGER array, dimension (min(M,N))
The pivot indices; for 1 <= i <= min(M,N), row i of
the matrix was interchanged with row IPIV(i).
INFO (output) INTEGER
= 0: successful exit
< 0: if INFO = -i, the i-th argument had an illegal
value
> 0: if INFO = i, U(i,i) is exactly zero. The fac-
torization has been completed, but the factor U is
exactly singular, and division by zero will occur if
it is used to solve a system of equations.
*/
/*
devo definire il prototipo da chiamare in C
*/
#define F77NAME(A) A##_
extern void F77NAME(dgetrf)( int * M, /* gli argomenti sono sempre passati per indirizzo */
int * N,
double * A,
int * LDA,
int * IPIV,
int * INFO ) ;
/*
NAME
DGETRS - solve a system of linear equations A * X = B or A'
* X = B with a general N-by-N matrix A using the LU factori-
zation computed by DGETRF
SYNOPSIS
SUBROUTINE DGETRS( TRANS, N, NRHS, A, LDA, IPIV, B, LDB,
INFO )
CHARACTER TRANS
INTEGER INFO, LDA, LDB, N, NRHS
INTEGER IPIV( * )
DOUBLE PRECISION A( LDA, * ), B( LDB, * )
PURPOSE
DGETRS solves a system of linear equations
A * X = B or A' * X = B with a general N-by-N matrix A
using the LU factorization computed by DGETRF.
ARGUMENTS
TRANS (input) CHARACTER*1
Specifies the form of the system of equations:
= 'N': A * X = B (No transpose)
= 'T': A'* X = B (Transpose)
= 'C': A'* X = B (Conjugate transpose = Transpose)
N (input) INTEGER
The order of the matrix A. N >= 0.
NRHS (input) INTEGER
The number of right hand sides, i.e., the number of
columns of the matrix B. NRHS >= 0.
A (input) DOUBLE PRECISION array, dimension (LDA,N)
The factors L and U from the factorization A = P*L*U
as computed by DGETRF.
LDA (input) INTEGER
The leading dimension of the array A. LDA >=
max(1,N).
IPIV (input) INTEGER array, dimension (N)
The pivot indices from DGETRF; for 1<=i<=N, row i of
the matrix was interchanged with row IPIV(i).
(LDB,NRHS)
B (input/output) DOUBLE PRECISION array, dimension
On entry, the right hand side matrix B. On exit,
the solution matrix X.
LDB (input) INTEGER
The leading dimension of the array B. LDB >=
max(1,N).
INFO (output) INTEGER
= 0: successful exit
< 0: if INFO = -i, the i-th argument had an illegal
value
*/
extern void F77NAME(dgetrs)( char * TRANS, /* gli argomenti sono sempre passati per indirizzo */
int * N,
int * NRHS,
double * A,
int * LDA,
int * IPIV,
double * B,
int * LDB,
int * INFO ) ;
#define A(I,J) A[(I)+(J)*lda]
void
stampa_L( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, "%-10lg ",A(i,j)) ;
}
fprintf( fd, "1\n") ; /* uso 10 caratteri per numero */
}
}
void
stampa_U( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, " ") ; /* 11 spazi bianchi */
}
for ( j = i ; j < N ; ++j ) {
fprintf( fd, "%-10lg ",A(i,j)) ;
}
fprintf( fd, "\n") ; /* vado a capo a fine riga */
}
}
#undef A /* elimino la definizione di A(I,I) */
int
main() {
double M[] = {
4, 3, 2, 1, /* prima colonna */
1, 2, 3, 4, /* seconda colonna */
1, 0, 0, 1, /* terza colonna */
0, 1, 2, 5 /* quarta colonna */
} ;
double b[] = { 9, 11, 16, 32 } ; /* termine noto se la solzione e' 1,2,3,4 */
double x[4] ; /* vettore che conterra' la soluzione */
int i, perm[4], one ;
int iflag, dim ;
dim = 4 ;
one = 1 ;
/* richiamo il fattorizzatore delle LAPACK */
F77NAME(dgetrf)( &dim, &dim, M, &dim, perm, &iflag );
printf( "Valore del flag=%d\n",iflag);
#define A(I,J) M[(I)+(J)*4]
/* stampa della matrice L ed U e la permutazione */
printf("MATRICE L\n") ;
stampa_L( stdout, M, dim, dim );
printf("MATRICE U\n") ;
stampa_U( stdout, M, dim, dim );
printf("PERMUTAZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "perm[%d]=%d\n", i, perm[i]) ;
for ( i = 0 ; i < dim ; ++i ) x[i] = b[i] ;
/* richiamo il solutore delle LAPACK */
F77NAME(dgetrs)( "N", &dim, &one, M, &dim, perm, x, &dim, &iflag );
printf( "Valore del flag=%d\n",iflag);
printf("SOLUZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "x[%d]=%lg\n", i, x[i]) ;
return 0 ;
}
/*
* Su una macchimna UNIX si comile con
*
* gcc -Wall ex026.c -o ex026 -llapack -lblas -lm
*
* Su un mac con i Framework
*
* gcc -Wall ex026.c -o ex026 -framework Accelerate
*
*/
Lezione del 11/7/2006
- Esempio di compilazione tramite Makefile, file del progetto
File: file.h:
/* se non e' definito FILE_H espande il blocco fino ad #endif */
#ifndef FILE_H
#define FILE_H /* definisco FILE_H cosi non includo il file una seconda volta */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/* prototipo della funzione */
extern int fattorizzazione_LU( double [], int, int, int [] ) ;
extern void stampa_L( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) ; /* numero di righe usate in allocazione */
extern void stampa_U( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) ; /* numero di righe usate in allocazione */
extern void solve_LU( double LU[], /* matrice fattorizzata memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[], /* vettori di interi di domensione >= N che
conterra' la permutazione */
double b[], /* temine noto */
double x[] ) ; /* soluzione */
static
int
max(int a, int b)
{ return a > b ? a : b ; }
/* test ? vero : falso */
#endif
File: file-vuoto.h:
File: filea.c:
#include "file.h"
#include "file.h"
#include "file-vuoto.h"
#define A(I,J) A[(I)+(J)*lda]
int /* valore di ritorno se 0 = tutto ok */
/* se 1 = matrice singolare */
fattorizzazione_LU( double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[] ) { /* vettori di interi di domensione >= N che
conterra' la permutazione */
int i, j, k, imax ;
double amax, acheck ;
/* Inizializzo il vettore della permutazione */
for ( i = 0 ; i < N ; ++i ) perm[i] = i ;
for ( i = 0 ; i < N-1 ; ++i ) {
/* ricerca del pivot, cerco elemento di modulo massimo
nella colonna i-esima, cioe' A(i,i), A(i+1,i), ..., A(N-1,i) */
imax = i ;
amax = fabs( A(i,i) ) ;
for ( j=i+1 ; j < N ; j++ ) {
acheck = fabs(A(j,i));
if ( acheck > amax ) {
amax = acheck ;
imax = j ;
}
}
/* controllo che acheck > 0, se 0 la matrice e' singolare */
if ( amax == 0 ) return 1 ;
if ( imax != i ) { /* scambio la riga i con la riga imax */
/* scambio indici sul vettore della permutazione */
k = perm[i] ;
perm[i] = perm[imax] ;
perm[imax] = k ;
/* scambio delle righe nella matrice A */
for ( j=0 ; j < N ; ++j ) {
amax = A(i,j) ;
A(i,j) = A(imax,j) ;
A(imax,j) = amax ;
}
}
/* costruisco la parte della matrice Li e la applico alla matrice
LU in costruzione */
for ( k = i+1 ; k < N ; ++k ) {
amax = A(k,i) / A(i,i) ;
A(k,i) = amax ;
for ( j= i+1 ; j < N ; ++j )
A(k,j) -= amax * A(i,j) ;
}
}
return 0 ; /* tutto ok */
}
void
stampa_L( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, "%-10lg ",A(i,j)) ;
}
fprintf( fd, "1\n") ; /* uso 10 caratteri per numero */
}
}
void
stampa_U( FILE * fd,
double A[], /* matrice da fattorizzare memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda ) { /* numero di righe usate in allocazione */
int i, j ;
for ( i = 0 ; i < N ; ++i ) {
for ( j = 0 ; j < i ; ++j ) {
fprintf( fd, " ") ; /* 10 spazi bianchi */
}
for ( j = i ; j < N ; ++j ) {
fprintf( fd, "%-9lg ",A(i,j)) ;
}
fprintf( fd, "\n") ; /* vado a capo a fine riga */
}
}
#undef A /* elimino la definizione di A(I,I) */
#define L(I,J) LU[(I)+(J)*lda]
#define U(I,J) LU[(I)+(J)*lda]
void
solve_LU( double LU[], /* matrice fattorizzata memorizzata per colonne */
int N, /* dimensione della matrice da fattorizzare */
int lda, /* numero di righe usate in allocazione */
int perm[], /* vettori di interi di domensione >= N che
conterra' la permutazione */
double b[], /* temine noto */
double x[] ) { /* soluzione */
int i, j ;
/* applico la permutazione */
for ( i = 0 ; i < N ; ++i ) x[perm[i]] = b[i] ;
/* Risolvo Lz = Pb */
for ( i = 1 ; i < N ; ++i )
for ( j = 0 ; j < i ; ++j )
x[i] -= L(i,j)*x[j];
/* Risolvo Ux = Lz */
i=N;
do {
--i ;
for ( j = i+1 ; j < N ; ++j )
x[i] -= U(i,j)*x[j];
x[i] /= U(i,i) ;
} while ( i > 0 ) ;
}
File: fileb.c:
/*
* Esempio "complesso", fattorizzazione LU di Gauss di una Matrice
*/
#include "file.h"
int
main() {
double M[] = {
4, 3, 2, 1, /* prima colonna */
1, 2, 3, 4, /* seconda colonna */
1, 0, 0, 1, /* terza colonna */
0, 1, 2, 5 /* quarta colonna */
} ;
double b[] = { 9, 11, 16, 32 } ; /* termine noto se la solzione e' 1,2,3,4 */
double x[4] ; /* vettore che conterra' la soluzione */
int i, perm[4] ;
int iflag, dim ;
dim = 4 ;
iflag = fattorizzazione_LU( M, dim, dim, perm ) ;
printf( "Valore del flag=%d\n",iflag);
#define A(I,J) M[(I)+(J)*4]
/* stampa della matrice L ed U e la permutazione */
printf("MATRICE L\n") ;
stampa_L( stdout, M, dim, dim );
printf("MATRICE U\n") ;
stampa_U( stdout, M, dim, dim );
printf("PERMUTAZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "perm[%d]=%d\n", i, perm[i]) ;
solve_LU( M, dim, dim, perm, b, x ) ;
printf("SOLUZIONE\n") ;
for ( i = 0 ; i < dim ; ++i )
printf( "x[%d]=%lg\n", i, x[i]) ;
return 0 ;
}
- Semplice esempio di Makefile
File: Makefile.vers1:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
test: filea.o fileb.o
gcc filea.o fileb.o -o test
filea.o: filea.c file.h
gcc -Wall -c filea.c
fileb.o: fileb.c file.h
gcc -Wall -c fileb.c
clear:
rm filea.o fileb.o test
- Makefile che usa alcune variabili per parametrizzare compilatore e flags
File: Makefile.vers2:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi
LIBS=-lc
OBJS=filea.o fileb.o
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
filea.o: filea.c file.h
$(CC) $(CFLAGS) -c filea.c
fileb.o: fileb.c file.h
$(CC) $(CFLAGS) -c fileb.c
clean:
rm $(OBJS) test
- Makefile che usa un pattern per la compilazione
File: Makefile.vers3:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi
LIBS=-lc
OBJS=filea.o fileb.o
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
### modo obsoleto per la generazione della regola
.c.o:
$(CC) $(CFLAGS) -c $<
clean:
rm $(OBJS) test
## elenco delle dipendenze
filea.o: filea.c file.h
fileb.o: fileb.c file.h
File: Makefile.vers4:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi -O
CXX=g++
CXXFLAGS=-Wall -ansi -O
F77=g77
FFLAGS=-O3
LIBS=-lc
OBJS=filea.o fileb.o
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
# regola di compilazione per file tipo C
%.o: %.c
$(CC) $(CFLAGS) -c $<
# regola di compilazione per file tipo C++
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# regola di compilazione per file tipo Fortran
%.o: %.f
$(F77) $(FFLAGS) -c $<
clean:
rm $(OBJS) test
## elenco delle dipendenze
filea.o: filea.c file.h
fileb.o: fileb.c file.h
- Makefile che usa mkdep per la generazione automatica delle dipendenze
File: Makefile.vers5:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi -O
CXX=g++
CXXFLAGS=-Wall -ansi -O
F77=g77
FFLAGS=-O3
LIBS=-lc
SRCS=filea.c fileb.c
OBJS=filea.o fileb.o
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
# regola di compilazione per file tipo C
%.o: %.c
$(CC) $(CFLAGS) -c $<
# regola di compilazione per file tipo C++
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# regola di compilazione per file tipo Fortran
%.o: %.f
$(F77) $(FFLAGS) -c $<
clean:
rm $(OBJS) test
depend:
mkdep $(CFLAGS) $(SRCS)
#
# Se .depend non esiste la prima volta va creato
# con touch .depend
#
include .depend
- Due esempi completi con mkdep e makedepend
File: Makefile.vers6:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi -O
CXX=g++
CXXFLAGS=-Wall -ansi -O
F77=g77
FFLAGS=-O3
LIBS=-lc
SRCS=filea.c fileb.c
OBJS=$(SRCS:.c=.o)
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
# regola di compilazione per file tipo C
%.o: %.c
$(CC) $(CFLAGS) -c $<
# regola di compilazione per file tipo C++
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# regola di compilazione per file tipo Fortran
%.o: %.f
$(F77) $(FFLAGS) -c $<
clean:
rm $(OBJS) test
depend:
mkdep $(CFLAGS) $(SRCS)
#
# Se .depend non esiste la prima volta va creato
# con touch .depend
#
include .depend
File: Makefile.vers7:
#
# oggetto: elenco file dipendenze
# (tab) comando o comandi da eseguire
#
# usando il comando
#
# gcc -MM file.c
#
# genero la linea delle dipendenze automaticamente
#
CC=gcc
CFLAGS=-Wall -ansi -O
CXX=g++
CXXFLAGS=-Wall -ansi -O
F77=g77
FFLAGS=-O3
LIBS=-lc
SRCS=filea.c fileb.c
OBJS=$(SRCS:.c=.o)
test: $(OBJS)
$(CC) $(OBJS) -o test $(LIBS)
# regola di compilazione per file tipo C
%.o: %.c
$(CC) $(CFLAGS) -c $<
# regola di compilazione per file tipo C++
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# regola di compilazione per file tipo Fortran
%.o: %.f
$(F77) $(FFLAGS) -c $<
clean:
rm $(OBJS) test
depend:
makedepend $(SRCS)
# DO NOT DELETE
filea.o: file.h /usr/include/stdio.h /usr/include/_types.h
filea.o: /usr/include/sys/_types.h /usr/include/sys/cdefs.h
filea.o: /usr/include/machine/_types.h /usr/include/ppc/_types.h
filea.o: /usr/include/string.h /usr/include/stdlib.h /usr/include/sys/wait.h
filea.o: /usr/include/sys/signal.h /usr/include/sys/appleapiopts.h
filea.o: /usr/include/machine/signal.h /usr/include/ppc/signal.h
filea.o: /usr/include/sys/resource.h /usr/include/machine/endian.h
filea.o: /usr/include/ppc/endian.h /usr/include/sys/_endian.h
filea.o: /usr/include/stdint.h /usr/include/libkern/OSByteOrder.h
filea.o: /usr/include/libkern/ppc/OSByteOrder.h /usr/include/alloca.h
filea.o: /usr/include/machine/types.h /usr/include/ppc/types.h
filea.o: /usr/include/math.h /usr/include/architecture/ppc/math.h
filea.o: file-vuoto.h
fileb.o: file.h /usr/include/stdio.h /usr/include/_types.h
fileb.o: /usr/include/sys/_types.h /usr/include/sys/cdefs.h
fileb.o: /usr/include/machine/_types.h /usr/include/ppc/_types.h
fileb.o: /usr/include/string.h /usr/include/stdlib.h /usr/include/sys/wait.h
fileb.o: /usr/include/sys/signal.h /usr/include/sys/appleapiopts.h
fileb.o: /usr/include/machine/signal.h /usr/include/ppc/signal.h
fileb.o: /usr/include/sys/resource.h /usr/include/machine/endian.h
fileb.o: /usr/include/ppc/endian.h /usr/include/sys/_endian.h
fileb.o: /usr/include/stdint.h /usr/include/libkern/OSByteOrder.h
fileb.o: /usr/include/libkern/ppc/OSByteOrder.h /usr/include/alloca.h
fileb.o: /usr/include/machine/types.h /usr/include/ppc/types.h
fileb.o: /usr/include/math.h /usr/include/architecture/ppc/math.h
- Uso del preprocessore per la compilazione condizionale
File: comp-condizionale-1.c:
/*
* esempio di compilazione condizionale
*
*/
#include <stdio.h>
#include <stdlib.h>
/*
* ci sono macro predefinite da sistema
* che possono essere usate in debugging e compilazione
* condizionale.
* le principali sono:
*
* __LINE__ = contiene la linea corrente file
* __FILE__ = contiene il nome del file corrente
*
*/
/* esempio d'uso seil test A e' falso esco con un errore */
#define DEBUG_CHECK(A) \
if ( !(A) ) { \
printf("Errore alla linea %d nel file %s\n",__LINE__,__FILE__) ; \
exit(1) ; \
}
/* \ a fine riga indica che la macro prosegue alla linea successiva */
int
main() {
DEBUG_CHECK( 1 == 2 ) ;
}
File: comp-condizionale-2.c:
/*
* esempio di compilazione condizionale
*
*/
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
/* viene espanso questo pezzo di codice se WIN32 e' definito */
/* WIN32 di solito e' definito da un compilatore installato su un
sistema windows. In questo modo si possono compilare parti
critiche "SISTEM DEPENDENT" con un unico programma
*/
#else
/* viene espanso questo pezzo di codice se WIN32 NON e' definito */
#endif
#ifndef WIN32
/* viene espanso questo pezzo di codice se WIN32 NON e' definito */
#else
/* viene espanso questo pezzo di codice se WIN32 e' definito */
#endif
/*
analogamente di puo usare
*/
#if defined(WIN32) /* e' equivalente ad #ifdef WIN32 */
/* questa forma e' piu' elastica */
#if defined(PIPPO) && defined(PLUTO)
#else
#endif
#endif
#if !defined(WIN32) /* e' equivalente ad #ifndef WIN32 */
#endif
#if 0
/* questo pezzo NON viene compilato */
#endif
#if 1
/* questo pezzo VIENE compilato */
#endif
/* esempio d'uso seil test A e' falso esco con un errore */
#define DEBUG_CHECK(A) \
if ( !(A) ) { \
printf("Errore alla linea %d nel file %s\n",__LINE__,__FILE__) ; \
exit(1) ; \
}
/* esempio di concatenazione nella macro */
#define CONCATENA(A,B) A##B
/* le macro possono definire delle costanti */
#define UNA_COSTANTE 1234
/* \ a fine riga indica che la macro prosegue alla linea successiva */
int
main() {
int abc = 2 ;
CONCATENA(ab,c) = 3 ;
DEBUG_CHECK( 1 == 2 ) ;
}
- Metodi Matematici e Calcolo per Ingegneria
- Non-linear equations and numerical optimization
- Scientific Programming in C++
Corso di Metodi Matematici e Calcolo per Ingegneria (AA 2004/2005)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 13:30 - 16:30 | Q2 |
Martedì | 8.30 - 10.30 | Q2 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Martedì | 14.30 - 16.30 | 505 |
Mercoledì | 14:30 - 16:30 | 505 |
Dispense del corso
Lucidi sulle trasformate di Laplace
- versione a schermo laplace-trasformata-1x1.pdf
- versione stampabile 2 lucidi per foglio laplace-trasformata-1x2.pdf
- versione stampabile 4 lucidi per foglio laplace-trasformata-2x2.pdf
Lucidi sulla trasformata Z
- versione a schermo Z-trasformata-1x1.pdf
- versione stampabile 2 lucidi per foglio Z-trasformata-1x2.pdf
- versione stampabile 4 lucidi per foglio Z-trasformata-2x2.pdf
Lucidi (incompleti) sul metodo di Newton e Broyden
Lucidi sul metodo del gradiente coniugato
- versione a schermo Gradiente-Coniugato-1x1.pdf
- versione stampabile 2 lucidi per foglio Gradiente-Coniugato-1x2.pdf
- versione stampabile 4 lucidi per foglio Gradiente-Coniugato-2x2.pdf
Minidispensa sui numeri complessi
- pdf.
Esami Svolti
Appello 1 febbraio 2005
Appello 25 febbraio 2005
Appello 28 giugno 2005
Appello 19 luglio 2005
Appello 3 novembre 2005
P.h.D. Course of Non-linear equations and numerical optimization (AA 2004/2005)
Lessons of 21/3/2005 and 22/3/2005
One Dimensional Non-Linear Problems
screen version slides-1D-1x1.pdf
print version 2 slides by sheet slides-1D-1x2.pdf
print version 4 slides by sheet slides-1D-2x2.pdf
Lessons of 4/4/2005 and 5/4/2005
One-Dimensional Minimization
screen version slides-m1D-1x1.pdf
print version 2 slides by sheet slides-m1D-1x2.pdf
print version 4 slides by sheet slides-m1D-2x2.pdf
Unconstrained minimization
screen version slides-mND-1x1.pdf
print version 2 slides by sheet slides-mND-1x2.pdf
print version 4 slides by sheet slides-mND-2x2.pdf
Lessons of 18/4/2005 and 19/4/2005
Conjugate Direction minimization
screen version slides-CG-1x1.pdf
print version 2 slides by sheet slides-CG-1x2.pdf
print version 4 slides by sheet slides-CG-2x2.pdf
Lessons of 2/5/2005 and 3/5/2005
Non-linear problems in N variable (preliminary draft)
screen version slides-ND-1x1.pdf
print version 2 slides by sheet slides-ND-1x2.pdf
print version 4 slides by sheet slides-ND-2x2.pdf
Quasi-Newton methods for minimization (preliminary draft)
screen version slides-mQN-1x1.pdf
print version 2 slides by sheet slides-mQN-1x2.pdf
print version 4 slides by sheet slides-mQN-2x2.pdf
Lessons of 9/5/2005 and 10/5/2005
Trust Region Method (preliminary draft)
screen version slides-TR-1x1.pdf
print version 2 slides by sheet slides-TR-1x2.pdf
print version 4 slides by sheet slides-TR-2x2.pdf
Final exam task list
The Preconditioned Conjugate Gradient method
The Fletcher Reeves and Polack Ribiere method
The Broyden method for system of nonlinear equations
The SR1 method for uncostrained optimization
The DFP and BFGS method for uncostrained optimization
The double dogleg method
The exact trust region method
The Levemberg-Marquardt method
The Sequential Quadratic Programming (SQP) method
The multidimensional Newton method and the Kantorovich proofs of its local quadratic convergence
The candidate must choose an argument and perform the following task:
Search in the literature to obtain a list of significative reference (10-20 reference)
Write a report describing the argument
Write a C++ code implementing the algorithm
The code should be commented in the report, or in alternative well documented using e.g. DOXIGEN.
P.h.D. Course of Scientific Programming in C++ (AA 2004/2005)
Bruce Eckel’s Free Electronic Books:
C++ Annotations
Lesson of 16/5/2005
File: 1.cpp:
/*
A multi line comment
start with a slash + star
end with a star + slash
*/
// single line comment
// include
#include <iostream>
/*
A program consist in a procedure named "main"
with o without arguments
*/
int // means integer is the
// return type of the routine main
main () // main is the name "fixed" of the program
// () contains eventual arguments
{ // open brace is the beginning of the body of the program
// cout = character out is the object for the output
// cout write to the standard output
std::cout << "hello world!\n" ;
// << is an operator, that in the case of the object cout means
// that the thing on the right is put in the standard output.
// the character \n is the newline. There are others special character
// \r = is the return character
// \t = is the tabulation character
// \g = the bell sound
// first possibility to avoid the use of std::
using std::cout ;
cout << "cout without std::\r"
<< "XYZ\n" ;
// use of endl
using namespace std ;
cout << "ABC" << endl ; // endl = "\n"
// but endl also empty the buffer
// endl is equivalent to the compose command
cout << "a string" << endl ;
cout << "a string" << "\n" << flush ;
return 0 ;
} // closing brace is the end of the program
File: 2.cpp:
#include <iostream>
using namespace std ;
int
main () {
int a, b ; // define the integer a and b
/*
Other numerical type
char = character (typically 8 bits)
int = integer of the size of the word of the machine
(typically 32 bits, 4 byte)
float = floting point number (normally 32, bits 4byte)
double = double precision floating point number
(typically 64 bits, 8 bytes).
Modificator
usigned
signed
[ unsigned int usigned char
signed int signed char ]
short
long
short int = small integer (typically 16 bits )
long int = large integer (typically 64 bits )
"short" is a synonimous of "short int"
"long" is a synonimous of "long int"
long double = quadruple precision floating point number
(hardware dependent)
The only sure thing anbout the size
short <= int <= long <= long long
float <= double<= long double
*/
cout << "Given me a and b " ;
// cin is the object dedicated to the input
cin >> a >> b ;
int c = a + b ;
cout << a << " + " << b << " = " << c << "\n" ;
return 0 ;
}
File: 3.cpp:
#include <iostream>
// I/O standard definitions
#include <iomanip>
// I/O manipulators
using namespace std ; // load the namespace std to ::
int
main () {
double a, b ; // define the integer a and b
cout << "Given me a and b " ;
// cin is the object dedicated to the input
cin >> a >> b ;
double c = a + b ;
// set(int n) = reserve n character for the next output
cout << setw(20) << a << " + " << b << " = " << c << "\n" ;
// other manipulators
/*
setprecision( int ) = set precision in printing number
setbase( int ) = set base to print integer 10, 8, 16
setfill( char ) = set the filling character
dec = print decimal
hex = print hexadecimal
oct = print octal
flush = flush buffer
setw(int) = reserve spaces for next output
left = align left
right = align right
scientific = print number scientific e.g. 1.234E23
floatfield = print number e.g. 123.343
*/
cout << setw(20) << setfill('*') << a << " + " << b << " = " << c << "\n" ;
cout << setprecision(10) << a << " + " << b << " = " << c << "\n" ;
cout << a << " + " << b << " = " << c << "\n" ;
cout << setbase(10) << 123 << " " << setbase(8) << 123 << "\n" ;
cout << setbase(10) << 123 << " " << setbase(16) << 123 << "\n" ;
cout << dec << 123 << " " << oct << 123 << "\n" ;
cout << dec << 123 << " " << hex << 123 << "\n" ;
return 0 ;
}
File: 4.cpp:
#include <iostream>
using namespace std ;
/*
Conditional and loop
*/
int
main () {
/*
if ( condition ) statement ;
if ( condition ) statement ;
else statement ;
*/
int a = 1 ;
int b = 2 ;
if ( a < b ) cout << "a < b is true \n" ;
else cout << "a < b is true \n" ;
if ( a < b ) {
int c = a+b ;
cout << "a < b is true \n" ;
}
else {
cout << "a < b is true \n" ;
}
/*
while ( condition ) statement ;
*/
int i = 0 ;
while ( ++i < 100 ) cout << i << endl ;
/* ++i means i = i+1 ;
there is also --i that means i = i-1
++i and i++ are different in the sense that
int j = i++ ; means that j = i next i = i+1 ;
int j = ++i ; means that i = i+1 next j = i ;
*/
/*
do {
instructions ;
} while ( condition ) ;
*/
i = 0 ;
do {
i++ ;
cout << i << ", " ;
} while ( i < 50 ) ;
cout << endl ;
/*
for ( init ; condition ; next ) statement ;
init = is a statement executed ONE time at the beginning
condition = is tested at EACH iteration
next = is a statement executed at the end of EACH iteration
*/
// int i = 1 ; is an error
int sum = 0 ;
for ( int i = 1 ; // init
i < 100 ;
i++ ) {
sum += i ; // sum = sum + i ;
}
cout << "sum = " << sum << endl ;
/*
short cut form of =
a OP= b ; means a = a OP b ;
for example
a /= b ; ==> a = a / b ;
a *= b ; ==> a = a * b ;
a |= b ; ==> a = a | b ;
*/
/*
The switch statement
switch ( int ) {
case number:
break ; // interrupt the switch,
// if not present continue to the next case.
case number:
case number:
default:
}
*/
int j = -1 ;
switch (j) {
case 7: cout << "j = 7" << endl ;
case -1: cout << "j = -1" << endl ;
case 0: cout << "j = 0" << endl ;
case 3: cout << "j = 3" << endl ;
break ;
default: cout << "j = none" << endl ;
}
return 0 ;
/*
break instruction
continue instruction
for ( ) {
...
...
if ( cond ) break ; // interrupt the loop
..
..
if ( cond ) continue ; // skip to the next iteration
..
..
}
*/
}
Lesson of 17/5/2005
File: 5.cpp:
#include <iostream>
using namespace std ;
int
main()
{
// comparison operator
double a = 1 ;
double b = 2 ;
// equality
if ( a == b ) { // = is the assign not the comparison sign
cout << "a is equal to b\n" ;
} else {
cout << "a is NOT equal to b\n" ;
}
// not equal
if ( a != b ) {
cout << "a is NOT equal to b\n" ;
} else {
cout << "a is equal to b\n" ;
}
// greater
if ( a > b ) {
cout << "a is greater than b\n" ;
} else {
cout << "a is NOT greater than b\n" ;
}
// lesser
if ( a < b ) {
cout << "a is less than b\n" ;
} else {
cout << "a is NOT less than b\n" ;
}
// greater or equal
if ( a >= b ) { // => is not a comparison operator
cout << "a is greater or equal than b\n" ;
} else {
cout << "a is NOT greater or equal than b\n" ;
}
// lesser or equal
if ( a <= b ) { // =< is not a comparison operator
cout << "a is less or equal than b\n" ;
} else {
cout << "a is NOT less or equal than b\n" ;
}
// BOOLEAN
double c = 3 ;
if ( a == b || b == c ) ; // || is the OR operator
if ( a == b && b == c ) ; // && is the AND operator
// using boolean type
bool eq = a == b ; // eq takes the values "true" or "false"
bool neq = b != c ;
if ( eq || neq ) ;
bool bc = true ;
bool ac = false ;
// loop with the use of boolean
bool cont = true ;
int i = 1 ;
while ( cont ) {
cout << i << endl ;
cont = i < 100 ;
++i ;
}
// boolean arithmetic
{
bool a, b, c, d, e ;
a = true ;
b = true ;
c = false ;
d = false ;
e = false ;
a = (b && c) || e ; // (b AND c) OR e
b = ! c ; // negation
}
return 0 ;
}
File: 6.cpp:
#include <iostream>
#include <cmath>
/*
most important include
iostream
fstream
iomanip
cmath
cstblib
from standard template library
string
vector
*/
using namespace std ;
typedef long double value_type ;
// make value_type an alias of long double
typedef int index_type ;
// make index_type an alias of int
int
main()
{
// example the use the trapezoidal rule to
// compute the integral of f(x)=1+sin(x)
// using 100 intervals
value_type a = 1 ;
value_type b = 10 ;
index_type n = 100 ;
value_type fa = (1+sin(a)) ;
value_type fb = (1+sin(b)) ;
value_type h = (b-a) / n ;
value_type res = (fa+fb)*h/2 ;
for ( index_type i = 1 ; i < n ; ++i ) {
value_type xi = a + i*h ;
value_type fi = (1+sin(xi)) ;
res += h * fi ;
}
cout << "The approximate integral is = " << res << "\n" ;
return 0 ;
}
File: 7.cpp:
#include <iostream>
#include <cmath>
using namespace std ;
typedef long double value_type ;
// make value_type an alias of long double
typedef int index_type ;
// make index_type an alias of int
// declaration of fun
value_type fun( value_type x ) ;
int
main()
{
// example the use the trapezoidal rule to
// compute the integral of f(x)=1+sin(x)
// using 100 intervals
value_type a = 1 ;
value_type b = 10 ;
index_type n = 100 ;
value_type fa = fun(a) ;
value_type fb = fun(b) ;
value_type h = (b-a) / n ;
value_type res = (fa+fb)*h/2 ;
for ( index_type i = 1 ; i < n ; ++i ) {
value_type xi = a + i*h ;
value_type fi = fun(xi) ;
res += h * fi ;
}
cout << "The approximate integral is = " << res << "\n" ;
return 0 ;
}
// definition of fun
value_type // return value of the function
fun( value_type x ) { // fun is the name of the function
return 1+sin(x); // x is one argument
}
File: 8.1.cpp:
#include <iostream>
#include <cmath>
using namespace std ;
typedef long double value_type ;
// make value_type an alias of long double
typedef int index_type ;
// make index_type an alias of int
// declaration of fun
value_type fun( value_type x ) ;
int
main()
{
// example the use the trapezoidal rule to
// compute the integral of f(x)=1+sin(x)
// using 100 intervals
value_type a = 1 ;
value_type b = 10 ;
index_type n = 100 ;
value_type fa = fun(a) ;
value_type fb = fun(b) ;
value_type h = (b-a) / n ;
value_type res = (fa+fb)*h/2 ;
for ( index_type i = 1 ; i < n ; ++i ) {
value_type xi = a + i*h ;
value_type fi = fun(xi) ;
res += h * fi ;
}
cout << "The approximate integral is = " << res << "\n" ;
return 0 ;
}
File: 8.2.cpp:
#include <iostream>
#include <cmath>
using namespace std ;
typedef long double value_type ;
// make value_type an alias of long double
typedef int index_type ;
// make index_type an alias of int
// declaration of fun
value_type fun( value_type x ) ;
// definition of fun
value_type // return value of the function
fun( value_type x ) { // fun is the name of the function
return 2+sin(x); // x is one argument
}
File: 9.1.cpp:
#include "9.h"
int
main()
{
// example the use the trapezoidal rule to
// compute the integral of f(x)=1+sin(x)
// using 100 intervals
value_type a = 1 ;
value_type b = 10 ;
index_type n = 100 ;
value_type fa = fun(a) ;
value_type fb = fun(b) ;
value_type h = (b-a) / n ;
value_type res = (fa+fb)*h/2 ;
for ( index_type i = 1 ; i < n ; ++i ) {
value_type xi = a + i*h ;
value_type fi = fun(xi) ;
res += h * fi ;
}
cout << "The approximate integral is = " << res << "\n" ;
return 0 ;
}
File: 9.2.cpp:
#include "9.h"
// definition of fun
value_type // return value of the function
fun( value_type x ) { // fun is the name of the function
return 2+sin(x); // x is one argument
}
File: 9.h:
#include <iostream>
#include <cmath>
using namespace std ;
typedef double value_type ;
// make value_type an alias of double
typedef int index_type ;
// make index_type an alias of int
// declaration of fun
value_type fun( value_type x ) ;
File: 10.1.cpp:
#include "10.h"
#include <iomanip>
value_type valabs( value_type x ) ;
int
main() {
// solving f(x) = 0 by Newton method
value_type x = 0 ;
value_type epsilon = 1E-6 ;
for ( index_type i = 1 ; i < 100 ; ++i ) {
value_type f = fun(x) ;
if ( valabs(f) < epsilon ) break ; // interrupt the loop
value_type f_1 = fun_1(x) ;
x = x - f/f_1 ;
cout << "iter = " << setw(2) << i
<< " x = " << setw(10) << x
<< " residual = " << f << "\n" ;
}
cout << "result x = " << x << "\n" ;
}
value_type
valabs( value_type x ) {
return x > 0 ? x : -x ;
}
File: 10.2.cpp:
#include "10.h"
value_type
fun(value_type x) {
return pow(x-1,2) ; // (x-1)*(x-1)
}
value_type
fun_1(value_type x) {
return 2*(x-1) ;
}
File: 10.h:
#include <iostream>
#include <cmath>
using namespace std ;
typedef double value_type ;
// make value_type an alias of double
typedef int index_type ;
// make index_type an alias of int
// declaration of fun
value_type fun( value_type x ) ;
// declaration of fun_1
value_type fun_1( value_type x ) ;
File: 11.cpp:
#include "11.h"
#include <iomanip>
// include again 11.h
#include "11.h"
value_type valabs( value_type x ) ;
int
main () {
// solving f(x) = 0 by newton method
value_type x = 0 ;
value_type epsilon = 1E-6 ;
for ( index_type i = 1 ; i < 100 ; ++i ) {
value_type f = fun(x) ;
if ( valabs( f ) < epsilon ) break ;
value_type f_1 = fun_1(x) ;
x = x - f/f_1 ;
cout << "iter = " << setw(2) << i
<< " x = " << setw(10) << x
<< " residual = " << f << "\n" ;
}
cout << " result x = " << x << "\n" ;
}
File: 11.h:
#ifndef ELEVEN_H
#define ELEVEN_H
#include <iostream>
#include <cmath>
using namespace std ;
typedef double value_type ;
// make value_type an alias of double
typedef int index_type ;
// make index_type an alias of int
inline
value_type
fun(value_type x) {
return pow(x-1,2) ; // (x-1)*(x-1)
}
inline
value_type
fun_1(value_type x) {
return 2*(x-1) ;
}
inline
value_type
valabs( value_type x ) {
return x > 0 ? x : -x ;
}
#endif
File: 12.cpp:
#include <iomanip>
#include <string>
using namespace std ;
/*
Introduction to struct
want to collect
first name
second name
age
nationality
weight
hair
driving licence
*/
typedef double value_type ;
typedef int index_type ;
struct record {
string first_name ;
string second_name ;
index_type age ;
string nationality ;
value_type weight ;
string hair_color ;
bool have_a_driving_licence ;
} ;
int
main () {
struct record a ;
a . first_name = "Pippo" ;
a . second_name = "Pluto" ;
a . age = 1204 ;
a . have_a_driving_licence = true ;
// Define and initialize
struct record b = {
"Pluto",
"Dog",
1204,
"Topolinia",
256,
"Red",
true
} ;
typedef struct record Record ;
Record c ;
}
Lesson of 18/5/2005
File: 13.cpp:
#include <iostream>
#include <iomanip>
using namespace std ;
typedef double value_type ;
typedef int index_type ;
// vec is a pointer to memory allocated
// with 100 value_type
value_type vec[100] ;
int
main() {
/*
to access the elements of vec we use
the operator [ ], and the index run
from 0 to dim-1 (here dim = 100)
*/
vec[1] ; // is the second element
vec[99] ; // is the last element
for ( index_type i = 0 ; i < 100 ; ++i )
vec[i] = i * i ;
value_type * p_vec ; // is a pointer to value_type things
p_vec = vec ; // p_vec point to the first value of
// the vector vec
// NO vec = p_vec ; vec is not assignable
p_vec = & vec[0] ; // is equivalent to p_vec = vec
cout << "& vec[0] = " << &vec[0] << " ==> "
<< (long)&vec[0]<< "\n"
<< " p_vec = " << p_vec << " ==> "
<< (long)p_vec << "\n" ;
// (long) is a "casting" operator, reinterprets
// p_vec (address) as a long integer.
cout << "vec[0] = " << vec[0] << "\n"
<< "*p_vec = " << *p_vec << "\n" ;
// * is the deference operator:
// p_vec contains the address of a value_type value
// *p_vec is the value_type value at the address p_vec
/*
pointer ca be assigned, incremented,
subtracted, ...
some example
*/
p_vec = & vec[11] ; // & estract the address from an lvalue
cout << "vec[11] = " << vec[11] << "\n"
<< "*p_vec = " << *p_vec << "\n" ;
cout << "& vec[11] = " << &vec[11] << "\n"
<< " p_vec = " << p_vec << "\n" ;
/*
Equivalent access with the * operator
*/
// vec[13] is equalent to *(vec+13)
cout << "vec[13] = " << vec[13]
<< " *(vec+13) = " << *(vec+13) << "\n" ;
//the address vec+13 is:
// the address of vec + 13 * sizeof(value_type) bytes
// assign a pointer to a translated value
p_vec = vec + 14 ;
cout << "vec[14] = " << vec[14]
<< " *p_vec = " << *p_vec << "\n" ;
/*
Operation with pointers
*/
// loop with pointers
// old loop
//for ( index_type i = 0 ; i < 100 ; ++i )
// vec[i] = 0 ;
for ( p_vec = vec ; p_vec < vec + 100 ; ++p_vec )
*p_vec = 0 ;
// another way
for ( p_vec = vec ; p_vec < vec + 100 ; )
*p_vec++ = 0 ;
// another way again
p_vec = vec ;
while ( p_vec < vec + 100 ) *p_vec++ = 0 ;
// distance between pointer
p_vec = &vec[11] ;
cout << "p_vec - vec = " << p_vec - vec << "\n" ;
cout << "(short*) p_vec - (short*) vec = "
<< (short*) p_vec - (short*) vec << "\n" ;
// the sizeof
cout << "sizeof(value_type) = " << sizeof(value_type) << "\n"
<< "sizeof(short) = " << sizeof(short) << "\n" ;
}
File: 14.cpp:
#include <iostream>
#include <iomanip>
using namespace std ;
typedef double value_type ;
typedef int index_type ;
// vec is a pointer to memory allocated
// with 100 value_type
// declare and initialize
value_type avec[10] = { 1,2,3,4,5,6,7,8,9,10 } ;
// declare and initialize, infer the size by the
// initalization list
value_type bvec[] = { 1,2,3,4,5,6,7,8,9,10 } ;
struct point {
value_type x ;
value_type y ;
value_type z ;
} ;
typedef struct point Point ;
// collapsing the previous two definition as
typedef struct {
value_type x ;
value_type y ;
value_type z ;
} point3d ;
int
main() {
value_type * cvec ;
// use dynamic allocation
cvec = new value_type [10] ;
// new is the allocator operator
// value_type is the type I am allocating
// [10] is the number of cell allocated by new
// YES cvec = bvec + 100 ;
// NO bvec = cvec + 100 ;
struct point * old_pnts ;
point3d * pnts ;
old_pnts = new struct point [100] ;
old_pnts = new Point [100] ;
pnts = new point3d [100] ;
// access to the x of the second element:
pnts[1] . x ; // first get the first element then
// access by . operator
(*(pnts+1)) . x ;
(pnts+1) -> x ;
for ( index_type i = 0 ; i < 100 ; ++i ) {
pnts[i] . x = 1 ;
pnts[i] . y = i ;
pnts[i] . z = -3 ;
// another equivalent possibility
point3d * p = pnts + i ;
p -> x = 1 ;
p -> y = i ;
p -> z = -3 ;
}
for ( index_type i = 0 ; i < 10 ; ++i )
cvec[i] = avec[i] + bvec[i] ;
// freeing memory operator is delete:
delete [] cvec ;
// delete is the deletion operator
// [] mean that I am deallocating a vector
// cvec is the idetifier of the pointer allocated
}
File: 15.cpp:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std ;
typedef double value_type ;
typedef int index_type ;
typedef struct {
value_type x, y, z ;
} point3d ;
value_type
norm( point3d const p ) { // p is passed by VALUE!
return sqrt( p.x*p.x +
p.y*p.y +
p.z*p.z ) ;
}
value_type
norm_addr( point3d const * p_addr ) { // p is passed by ADDRESS!
p_addr = p_addr + 1 ;
p_addr = p_addr - 1 ;
return sqrt( p_addr -> x * p_addr -> x +
p_addr -> y * p_addr -> y +
p_addr -> z * p_addr -> z ) ;
}
value_type
norm_addr_1( point3d const * const p_addr ) { // p is passed by ADDRESS!
// NO p_addr = p_addr + 1 ; pointer cannot be modified
// NO p_addr = p_addr - 1 ;
return sqrt( p_addr -> x * p_addr -> x +
p_addr -> y * p_addr -> y +
p_addr -> z * p_addr -> z ) ;
}
value_type
norm_addr_2( point3d * const p_addr ) { // p is passed by ADDRESS!
// NO p_addr = p_addr + 1 ; pointer cannot be modified
// NO p_addr = p_addr - 1 ;
// YES p_addr -> x = 2 ; thing pointed can be modified
return sqrt( p_addr -> x * p_addr -> x +
p_addr -> y * p_addr -> y +
p_addr -> z * p_addr -> z ) ;
}
value_type
norm_ref( point3d const & p_ref ) { // p is passed by REFERENCE!
return sqrt( p_ref . x * p_ref . x +
p_ref . y * p_ref . y +
p_ref . z * p_ref . z ) ;
}
// modification of p_ref
value_type
norm_ref_modify( point3d & p_ref ) { // p is passed by REFERENCE!
value_type res = sqrt( p_ref . x * p_ref . x +
p_ref . y * p_ref . y +
p_ref . z * p_ref . z ) ;
p_ref . z = 0 ;
return res ;
}
int
main() {
point3d pt ;
pt . x = 1 ;
pt . y = 2 ;
pt . z = 3 ;
cout << " norm_ref_modify = " << norm_ref_modify( pt ) << "\n" ;
cout << " norm = " << norm( pt ) << "\n" ;
cout << " norm_addr = " << norm_addr( & pt ) << "\n" ;
cout << " norm_ref = " << norm_ref( pt ) << "\n" ;
point3d volatile * p_pt = & pt ;
// some operation
// you cannot assume that pt is unchanged
}
Lesson of 23/5/2005
File: 16.1.cpp:
#include "16.h"
namespace newton_solver_2d {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
void
F( vec2 const & x, vec2 & Fx ) {
Fx[0] = x[0] - x[1] ;
Fx[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
// Fx[1] = pow(x[0],2) - pow(x[1],3) -2 ;
}
// JFx[row][column]
void JF( vec2 const & x, mat2 & JFx ) {
JFx[0][0] = 1 ; // DF[0]/Dx[0]
JFx[0][1] = -1 ; // DF[0]/Dx[1]
JFx[1][0] = 2*x[0] ; // DF[1]/Dx[0]
JFx[1][1] = -3*x[1]*x[1] ; // DF[1]/Dx[1]
}
/*
Small 2x2 linear solver
*/
bool
linear_solver( mat2 const & A, // coefficients matrix
vec2 const & b, // r.h.s
vec2 & x // the solution of the linear system
) {
// Using Cramer rule
value_type det = A[0][0] * A[1][1] - A[1][0] * A[0][1] ;
if ( det == 0 ) return false ;
x[0] = ( b[0] * A[1][1] - b[1] * A[0][1] ) / det ;
x[1] = ( A[0][0] * b[1] - A[1][0] * b[0] ) / det ;
return true ;
}
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec2 const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec2 & x
) {
// set x to the initial value
x[0] = x0[0] ;
x[1] = x0[1] ;
for ( index_type i = 0 ; i < n ; ++i ) {
vec2 f, h ;
mat2 jf ;
// perform a Newton step
// substep 1: compute F(x)
(*pF)(x,f) ; // shortcut borrowed for C syntax ==> pF(x,f) ;
// substep 2: compute JF(x)
(*pJF)(x,jf) ; // shortcut borrowed for C syntax ==> pJF(x,jf) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
bool ok = linear_solver(jf, f, h) ;
if ( !ok ) return false ;
// substep 4: update x
x[0] -= h[0] ;
x[1] -= h[1] ;
// check for the stopping criteria
value_type res = sqrt( h[0]*h[0]+h[1]*h[1] ) ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 16.2.cpp:
#include "16.h"
int
main() {
using newton_solver_2d::vec2 ;
using newton_solver_2d::F ;
using newton_solver_2d::JF ;
using newton_solver_2d::solver ;
using namespace std ;
vec2 x0, x ;
x0[0] = 1 ;
x0[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x[0] << ", " << x[1] << "]\n" ;
}
File: 16.h:
// standard trick for only one time inclusion
#ifndef SIXTEEN_H
#define SIXTEEN_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace newton_solver_2d {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
// define vec2 as a name for the vector with 2 components
typedef value_type vec2[2] ; // value_type a[2] ; ==> vec2 a ;
// define mat2 as a name for the matrix 2x2
typedef value_type mat2[2][2] ; // value_type a[2][2] ; ==> mat2 a ;
// an equivalent definition
// typedef vec2 mat2[2] ;
/*
now we set the definition (prototipe)
of the functions
*/
/*
This methos is not correct:
vec2
fun( vec2 x ) {
vec2 res ;
res[0] = .... ;
res[1] = .... ;
return res ;
}
return res ; // return the pointer to a temporary
*/
// prototype of the non-linear system
extern void F( vec2 const & x, vec2 & Fx ) ;
// prototype of the Jacobian of the non-linear system
extern void JF( vec2 const & x, mat2 & JFx ) ;
/*
extern = means that the bodies of the functions
are somewhere else.
*/
// prototype for the solver
extern
bool // return true = if the solution was found
solver( vec2 const & x0,
// the starting point of the Newton scheme
void (*pF) ( vec2 const & x, vec2 & Fx ),
// pF is a pointer to the function
void (*pJF) ( vec2 const & x, mat2 & JFx ),
// pF is a pointer to the jacobian function
index_type const n,
// n is the maximum number of iteration allowed
value_type const & tol,
// tolerance for the stopping critertia
vec2 & x
// x contains the computed solution
) ;
/*
A less difficult to read definition can be
obtained by splitting the prototype definition
as follows
*/
typedef void F_type ( vec2 const &, vec2 &) ;
typedef void JF_type ( vec2 const &, mat2 &) ;
extern
bool
solver( vec2 const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec2 & x
) ;
}
#endif
File: 17.1.cpp:
#include "17.h"
namespace newton_solver_2d {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec2
F( vec2 const & in ) {
vec2 Fx ;
Fx.c1 = in.c1 - in.c2 ;
Fx.c2 = in.c1*in.c1 - in.c2*in.c2*in.c2 - 2 ;
return Fx ;
}
//
mat2x2
JF( vec2 const & in ) {
mat2x2 JFx ;
JFx.A11 = 1 ; // DF[0]/Dx[0]
JFx.A12 = -1 ; // DF[0]/Dx[1]
JFx.A21 = 2*in.c1 ; // DF[1]/Dx[0]
JFx.A22 = -3*in.c2*in.c2 ; // DF[1]/Dx[1]
return JFx ;
}
/*
Small 2x2 linear solver
*/
bool
linear_solver( mat2x2 const & A, // coefficients matrix
vec2 const & b, // r.h.s
vec2 & x // the solution of the linear system
) {
// Using Cramer rule
value_type det = A.A11 * A.A22 - A.A21 * A.A12 ;
if ( det == 0 ) return false ;
x.c1 = ( b.c1 * A.A22 - b.c2 * A.A12 ) / det ;
x.c2 = ( A.A11 * b.c2 - A.A21 * b.c1 ) / det ;
return true ;
}
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec2 const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec2 & x
) {
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec2 f, h ;
mat2x2 jf ;
// perform a Newton step
// substep 1: compute F(x)
f = (*pF)(x) ; // shortcut borrowed for C syntax ==> pF(x) ;
// substep 2: compute JF(x)
jf = (*pJF)(x) ; // shortcut borrowed for C syntax ==> pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
bool ok = linear_solver(jf, f, h) ;
if ( !ok ) return false ;
// substep 4: update x
x.c1 -= h.c1 ;
x.c2 -= h.c2 ;
// check for the stopping criteria
value_type res = sqrt( h.c1*h.c1+h.c2*h.c2 ) ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 17.2.cpp:
#include "17.h"
int
main() {
using newton_solver_2d::vec2 ;
using newton_solver_2d::F ;
using newton_solver_2d::JF ;
using newton_solver_2d::solver ;
using namespace std ;
vec2 x0, x ;
x0.c1 = 1 ;
x0.c2 = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x.c1 << ", " << x.c2 << "]\n" ;
}
File: 17.h:
// standard trick for only one time inclusion
#ifndef SEVENTEEN_H
#define SEVENTEEN_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace newton_solver_2d {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
typedef struct {
value_type c1 ; // component one
value_type c2 ; // component two
} vec2 ;
typedef struct {
value_type A11 ;
value_type A12 ;
value_type A21 ;
value_type A22 ;
} mat2x2 ;
// an equivalent definition
// typedef vec2 mat2[2] ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec2 F( vec2 const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat2x2 JF( vec2 const & in ) ;
// prototype for the solver
extern
bool // return true = if the solution was found
solver( vec2 const & x0,
// the starting point of the Newton scheme
vec2 (*pF) ( vec2 const & x ),
// pF is a pointer to the function
mat2x2 (*pJF) ( vec2 const & x ),
// pF is a pointer to the jacobian function
index_type const n,
// n is the maximum number of iteration allowed
value_type const & tol,
// tolerance for the stopping critertia
vec2 & x
// x contains the computed solution
) ;
/*
A less difficult to read definition can be
obtained by splitting the prototype definition
as follows
*/
typedef vec2 F_type ( vec2 const & ) ;
typedef mat2x2 JF_type ( vec2 const & ) ;
extern
bool
solver( vec2 const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec2 & x
) ;
}
#endif
Lesson of 24/5/2005
File: 18.1.cpp:
#include "18.h"
namespace newton_solver {
/*
Small 2x2 linear solver
*/
bool
linear_solver( mat const & A, // coefficients matrix
vec const & b, // r.h.s
vec & x // the solution of the linear system
) {
// Using Cramer rule
value_type det = A.values[0][0] * A.values[1][1]
- A.values[1][0] * A.values[0][1] ;
if ( det == 0 ) return false ;
x.values[0] = ( b.values[0] * A.values[1][1]
- b.values[1] * A.values[0][1] ) / det ;
x.values[1] = ( A.values[0][0] * b.values[1]
- A.values[1][0] * b.values[0] ) / det ;
return true ;
}
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) {
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec f, h ;
mat jf ;
// perform a Newton step
// substep 1: compute F(x)
f = pF(x) ;
// substep 2: compute JF(x)
jf = pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
bool ok = linear_solver(jf, f, h) ;
if ( !ok ) return false ;
// substep 4: update x
for ( index_type i = 0 ; i < dim ; ++i )
x.values[i] -= h.values[i] ;
// check for the stopping criteria
value_type res = 0 ;
for ( index_type i = 0 ; i < dim ; ++i )
res += h.values[i]*h.values[i] ;
res = sqrt(res) ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 18.2.cpp:
#include "18.h"
namespace newton_solver {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec
F( vec const & in ) {
vec Fx ;
value_type const * x = in . values ;
Fx.values[0] = x[0] - x[1] ; // in . values[0] - in . values[1]
Fx.values[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
return Fx ;
}
//
mat
JF( vec const & in ) {
mat JFx ;
value_type const * x = in . values ;
JFx.values[0][0] = 1 ; // DF[0]/Dx[0]
JFx.values[0][1] = -1 ; // DF[0]/Dx[1]
JFx.values[1][0] = 2*x[0] ; // DF[1]/Dx[0]
JFx.values[1][1] = -3*x[1]*x[1] ; // DF[1]/Dx[1]
return JFx ;
}
}
int
main() {
using newton_solver::vec ;
using newton_solver::F ;
using newton_solver::JF ;
using newton_solver::solver ;
using namespace std ;
vec x0, x ;
x0.values[0] = 1 ;
x0.values[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x.values[0] << ", "
<< x.values[1] << "]\n" ;
}
File: 18.h:
// standard trick for only one time inclusion
#ifndef EIGHTEEN_H
#define EIGHTEEN_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace newton_solver {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
index_type const dim = 2 ;
typedef struct {
value_type values[dim] ;
} vec ;
typedef struct {
value_type values[dim][dim];
} mat ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec F( vec const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat JF( vec const & in ) ;
// prototype for the solver
typedef vec F_type ( vec const & ) ;
typedef mat JF_type ( vec const & ) ;
extern
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) ;
}
#endif
File: 19.1.cpp:
#include "19.h"
namespace newton_solver {
/*
Small 2x2 linear solver
*/
bool
linear_solver( mat const & A, // coefficients matrix
vec const & b, // r.h.s
vec & x // the solution of the linear system
) {
// Using Cramer rule
value_type det = A(0,0) * A(1,1) - A(1,0) * A(0,1) ;
if ( det == 0 ) return false ;
x[0] = ( b[0] * A(1,1) - b[1] * A(0,1) ) / det ;
x[1] = ( A(0,0) * b[1] - A(1,0) * b[0] ) / det ;
return true ;
}
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) {
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec f, h ;
mat jf ;
// perform a Newton step
// substep 1: compute F(x)
f = pF(x) ;
// substep 2: compute JF(x)
jf = pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
bool ok = linear_solver(jf, f, h) ;
if ( !ok ) return false ;
// substep 4: update x
for ( index_type i = 0 ; i < dim ; ++i )
x[i] -= h[i] ;
// check for the stopping criteria
value_type res = 0 ;
for ( index_type i = 0 ; i < dim ; ++i )
res += h[i]*h[i] ;
res = sqrt(res) ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 19.2.cpp:
#include "19.h"
namespace newton_solver {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec
F( vec const & x ) {
vec Fx ;
Fx[0] = x[0] - x[1] ; // in . values[0] - in . values[1]
Fx[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
return Fx ;
}
//
mat
JF( vec const & in ) {
mat JFx ;
value_type const * x = in . values ;
JFx(0,0) = 1 ; // DF[0]/Dx[0]
JFx(0,1) = -1 ; // DF[0]/Dx[1]
JFx(1,0) = 2*x[0] ; // DF[1]/Dx[0]
JFx(1,1) = -3*x[1]*x[1] ; // DF[1]/Dx[1]
return JFx ;
}
}
int
main() {
using newton_solver::vec ;
using newton_solver::F ;
using newton_solver::JF ;
using newton_solver::solver ;
using namespace std ;
vec x0, x ;
x0.values[0] = 1 ;
x0.values[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x.values[0] << ", "
<< x.values[1] << "]\n" ;
}
File: 19.h:
// standard trick for only one time inclusion
#ifndef NINETEEN_H
#define NINETEEN_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace newton_solver {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
index_type const dim = 2 ;
typedef struct {
value_type values[dim] ;
// declare the operator []
value_type & operator [] ( index_type i )
{ return this -> values[i] ; }
value_type const & operator [] ( index_type i )
const // this const means that this method do not
// modify the contents of the struct
{ return this -> values[i] ; }
} vec ;
typedef struct {
value_type values[dim][dim];
// declare the operator ()
value_type & operator () ( index_type i, index_type j)
{ return this -> values[i][j] ; }
value_type const & operator () ( index_type i, index_type j)
const // this const means that this method do not
// modify the contents of the struct
{ return this -> values[i][j] ; }
} mat ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec F( vec const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat JF( vec const & in ) ;
// prototype for the solver
typedef vec F_type ( vec const & ) ;
typedef mat JF_type ( vec const & ) ;
extern
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) ;
}
#endif
File: 20.1.cpp:
#include "20.h"
namespace newton_solver {
/*
Small 2x2 linear solver
*/
bool
linear_solver( mat const & A, // coefficients matrix
vec const & b, // r.h.s
vec & x // the solution of the linear system
) {
// Using Cramer rule
value_type det = A(0,0) * A(1,1) - A(1,0) * A(0,1) ;
if ( det == 0 ) return false ;
x[0] = ( b[0] * A(1,1) - b[1] * A(0,1) ) / det ;
x[1] = ( A(0,0) * b[1] - A(1,0) * b[0] ) / det ;
// b[0] is the same as:
// b . operator [] (0)
return true ;
}
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) {
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec f, h ;
mat jf ;
// perform a Newton step
// substep 1: compute F(x)
f = pF(x) ;
// substep 2: compute JF(x)
jf = pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
bool ok = linear_solver(jf, f, h) ;
if ( !ok ) return false ;
// substep 4: update x
// x = x - h ;
x -= h ;
// check for the stopping criteria
value_type res = h . norm2() ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 20.2.cpp:
#include "20.h"
namespace newton_solver {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec
F( vec const & x ) {
vec Fx ;
Fx[0] = x[0] - x[1] ; // in . values[0] - in . values[1]
Fx[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
return Fx ;
}
//
mat
JF( vec const & in ) {
mat JFx ;
value_type const * x = in . values ;
JFx(0,0) = 1 ; // DF[0]/Dx[0]
JFx(0,1) = -1 ; // DF[0]/Dx[1]
JFx(1,0) = 2*x[0] ; // DF[1]/Dx[0]
JFx(1,1) = -3*x[1]*x[1] ; // DF[1]/Dx[1]
return JFx ;
}
}
int
main() {
using newton_solver::vec ;
using newton_solver::F ;
using newton_solver::JF ;
using newton_solver::solver ;
using namespace std ;
vec x0, x ;
x0.values[0] = 1 ;
x0.values[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x.values[0] << ", "
<< x.values[1] << "]\n" ;
}
File: 20.h:
// standard trick for only one time inclusion
#ifndef TWENTIETH_H
#define TWENTIETH_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace newton_solver {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
index_type const dim = 2 ;
typedef struct vec {
value_type values[dim] ;
// declare the operator []
value_type & operator [] ( index_type i )
{ return this -> values[i] ; }
value_type const & operator [] ( index_type i )
const // this const means that this method do not
// modify the contents of the struct
{ return this -> values[i] ; }
vec const &
operator -= ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] -= a[i] ;
return * this ;
}
vec const &
operator += ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] += a[i] ;
return * this ;
}
// compute the 2 norm of the vector
value_type norm2() const {
value_type res = 0 ;
for ( index_type i = 0 ; i < dim ; ++i )
res += values[i] * values[i] ;
return sqrt(res) ;
}
} vec ;
// external operator
// add two vector
inline
vec
operator + ( vec const & a, vec const & b ) {
vec c ;
for ( index_type i = 0 ; i < dim ; ++i )
c[i] = a[i] + b[i] ;
}
// subtract two vector (definition only)
vec
operator - ( vec const & a, vec const & b ) ;
typedef struct {
value_type values[dim][dim];
// declare the operator ()
value_type & operator () ( index_type i, index_type j)
{ return this -> values[i][j] ; }
value_type const & operator () ( index_type i, index_type j)
const // this const means that this method do not
// modify the contents of the struct
{ return this -> values[i][j] ; }
} mat ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec F( vec const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat JF( vec const & in ) ;
// prototype for the solver
typedef vec F_type ( vec const & ) ;
typedef mat JF_type ( vec const & ) ;
extern
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) ;
}
#endif
File: 21.1.cpp:
#include "21.1.h"
namespace vector_matrix {
value_type & // return value
vec::operator [] // the operator [] is defined here
( index_type i ) // the argument of []
{ return this -> values[i] ; }
value_type const &
vec::operator [] ( index_type i ) const
{ return this -> values[i] ; }
vec const &
vec::operator -= ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] -= a[i] ;
return * this ;
}
vec const &
vec::operator += ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] += a[i] ;
return * this ;
}
// compute the 2 norm of the vector
value_type vec::norm2() const {
value_type res = 0 ;
for ( index_type i = 0 ; i < dim ; ++i )
res += values[i] * values[i] ;
return sqrt(res) ;
}
// external operator
// add two vector
vec
operator + ( vec const & a, vec const & b ) {
vec c ;
for ( index_type i = 0 ; i < dim ; ++i )
c[i] = a[i] + b[i] ;
return c ;
}
// subtract two vector (definition only)
vec
operator - ( vec const & a, vec const & b ) {
vec c ;
for ( index_type i = 0 ; i < dim ; ++i )
c[i] = a[i] - b[i] ;
return c ;
}
// declare the operator ()
value_type &
mat::operator () ( index_type i, index_type j)
{ return this -> values[i][j] ; }
value_type const &
mat::operator () ( index_type i, index_type j) const
{ return this -> values[i][j] ; }
/*
Small 2x2 linear solver
*/
vec
operator / ( vec const & b, mat const & A) {
vec x ;
// Using Cramer rule
value_type det = A(0,0) * A(1,1) - A(1,0) * A(0,1) ;
x[0] = ( b[0] * A(1,1) - b[1] * A(0,1) ) / det ;
x[1] = ( A(0,0) * b[1] - A(1,0) * b[0] ) / det ;
return x ;
}
}
File: 21.2.cpp:
#include "21.2.h"
namespace newton_solver {
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) {
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec f, h ;
mat jf ;
// perform a Newton step
// substep 1: compute F(x)
f = pF(x) ;
// substep 2: compute JF(x)
jf = pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
h = f / jf ;
//bool ok = linear_solver(jf, f, h) ;
//if ( !ok ) return false ;
// substep 4: update x
// x = x - h ;
x -= h ;
// check for the stopping criteria
value_type res = h . norm2() ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 21.3.cpp:
#include "21.2.h"
namespace newton_solver {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec
F( vec const & x ) {
vec Fx ;
Fx[0] = x[0] - x[1] ; // in . values[0] - in . values[1]
Fx[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
return Fx ;
}
//
mat
JF( vec const & x ) {
mat JFx ;
JFx(0,0) = 1 ; // DF[0]/Dx[0]
JFx(0,1) = -1 ; // DF[0]/Dx[1]
JFx(1,0) = 2*x[0] ; // DF[1]/Dx[0]
JFx(1,1) = -3*x[1]*x[1] ; // DF[1]/Dx[1]
return JFx ;
}
}
int
main() {
using newton_solver::vec ;
using newton_solver::F ;
using newton_solver::JF ;
using newton_solver::solver ;
using namespace std ;
vec x0, x ;
x0[0] = 1 ;
x0[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x[0] << ", "
<< x[1] << "]\n" ;
}
File: 21.1.h:
// standard trick for only one time inclusion
#ifndef TWENTIONE_ONE_H
#define TWENTIONE_ONE_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace vector_matrix {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
index_type const dim = 2 ;
class mat ; // forward declaration
class vec {
// private member of the class
value_type values[dim] ;
public: // from now the public interface
// declare the operator []
value_type & operator [] ( index_type i ) ;
value_type const & operator [] ( index_type i ) const ;
vec const & operator -= ( vec const & a );
vec const & operator += ( vec const & a );
// compute the 2 norm of the vector
value_type norm2() const ;
} ;
// external operator
// add two vector
vec operator + ( vec const & a, vec const & b ) ;
// subtract two vector (definition only)
vec operator - ( vec const & a, vec const & b ) ;
vec operator / ( vec const & b, mat const & A ) ;
class mat {
value_type values[dim][dim];
public:
// declare the operator ()
value_type & operator () ( index_type i, index_type j) ;
value_type const & operator () ( index_type i, index_type j) const ;
} ;
}
#endif
File: 21.2.h:
// standard trick for only one time inclusion
#ifndef TWENTIONE_TWO_H
#define TWENTIONE_TWO_H
#include <iostream>
#include <iomanip>
#include <cmath>
#include "21.1.h"
namespace newton_solver {
using namespace std ;
using namespace vector_matrix ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec F( vec const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat JF( vec const & in ) ;
// prototype for the solver
typedef vec F_type ( vec const & ) ;
typedef mat JF_type ( vec const & ) ;
extern
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) ;
}
#endif
File: 22.1.cpp:
#include "22.1.h"
namespace vector_matrix {
// the constructor
vec::vec( index_type dim ) {
this -> dim = dim ;
// new allocate dynamicaly the memory
// new TYPE [ SIZE ]
values = new value_type [ dim ] ;
}
// the destructor
vec::~vec() {
delete [] values ;
}
vec const & vec::operator = ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] = a[i] ;
return *this ;
}
value_type & // return value
vec::operator [] // the operator [] is defined here
( index_type i ) // the argument of []
{ return this -> values[i] ; }
value_type const &
vec::operator [] ( index_type i ) const
{ return this -> values[i] ; }
vec const &
vec::operator -= ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] -= a[i] ;
return * this ;
}
vec const &
vec::operator += ( vec const & a ) {
for ( index_type i = 0 ; i < dim ; ++i )
values[i] += a[i] ;
return * this ;
}
// compute the 2 norm of the vector
value_type vec::norm2() const {
value_type res = 0 ;
for ( index_type i = 0 ; i < dim ; ++i )
res += values[i] * values[i] ;
return sqrt(res) ;
}
// external operator
// add two vector
vec
operator + ( vec const & a, vec const & b ) {
index_type dim = a.get_dim() ;
vec c(dim) ;
for ( index_type i = 0 ; i < dim ; ++i )
c[i] = a[i] + b[i] ;
return c ;
}
// subtract two vector (definition only)
vec
operator - ( vec const & a, vec const & b ) {
index_type dim = a.get_dim() ;
vec c(dim) ;
for ( index_type i = 0 ; i < dim ; ++i )
c[i] = a[i] - b[i] ;
return c ;
}
// the constructor
mat::mat( index_type dim ) {
this -> dim = dim ;
// new allocate dynamicaly the memory
// new TYPE [ SIZE ]
values = new value_type [ dim * dim ] ;
}
// the destructor
mat::~mat() {
delete [] values ;
}
// the copy contructor
mat const & mat::operator = ( mat const & a ) {
for ( index_type i = 0 ; i < dim*dim ; ++i )
values[i] = a . values[i] ;
return *this ;
}
// declare the operator ()
value_type &
mat::operator () ( index_type i, index_type j)
{ return this -> values[i+j*dim] ; }
value_type const &
mat::operator () ( index_type i, index_type j) const
{ return this -> values[i+j*dim] ; }
/*
Small 2x2 linear solver
*/
vec
operator / ( vec const & b, mat const & A) {
vec x(2) ;
// Using Cramer rule
value_type det = A(0,0) * A(1,1) - A(1,0) * A(0,1) ;
x[0] = ( b[0] * A(1,1) - b[1] * A(0,1) ) / det ;
x[1] = ( A(0,0) * b[1] - A(1,0) * b[0] ) / det ;
return x ;
}
}
File: 22.2.cpp:
#include "22.2.h"
namespace newton_solver {
/*
Newton scheme
-1
x = x - JF(x ) F(x )
n+1 n n n
the implementation:
SOLVE: JF(x ) h = F(x )
n n
UPDATE: x = x + h
n+1 n
*/
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) {
index_type dim = x0 . get_dim();
// set x to the initial value
x = x0 ; // not reccomended
for ( index_type i = 0 ; i < n ; ++i ) {
vec f(dim), h(dim) ;
mat jf(dim) ;
// perform a Newton step
// substep 1: compute F(x)
f = pF(x) ;
// substep 2: compute JF(x)
jf = pJF(x) ;
// substep 3: compute the correction h = JF(x)^(-1)F(x)
h = f / jf ;
//bool ok = linear_solver(jf, f, h) ;
//if ( !ok ) return false ;
// substep 4: update x
// x = x - h ;
x -= h ;
// check for the stopping criteria
value_type res = h . norm2() ;
if ( res <= tol ) return true ;
}
return false ;
}
}
File: 22.3.cpp:
#include "22.2.h"
namespace newton_solver {
// F(x) = / x0 - x1 \
// | |
// \ x0**2 + x1**3 - 2 /
vec
F( vec const & x ) {
vec Fx(2) ;
Fx[0] = x[0] - x[1] ; // in . values[0] - in . values[1]
Fx[1] = x[0]*x[0] - x[1]*x[1]*x[1] - 2 ;
return Fx ;
}
//
mat
JF( vec const & x ) {
mat JFx(2) ;
JFx(0,0) = 1 ; // DF[0]/Dx[0]
JFx(0,1) = -1 ; // DF[0]/Dx[1]
JFx(1,0) = 2*x[0] ; // DF[1]/Dx[0]
JFx(1,1) = -3*x[1]*x[1] ; // DF[1]/Dx[1]
return JFx ;
}
}
int
main() {
using newton_solver::vec ;
using newton_solver::F ;
using newton_solver::JF ;
using newton_solver::solver ;
using namespace std ;
vec x0(2), x(2) ;
x0[0] = 1 ;
x0[1] = 1 ;
solver( x0, F, JF, 100, 1E-6, x ) ;
cout << "The solution is x = [ "
<< x[0] << ", "
<< x[1] << "]\n" ;
}
File: 22.1.h:
// standard trick for only one time inclusion
#ifndef TWENTITWO_ONE_H
#define TWENTITWO_ONE_H
#include <iostream>
#include <iomanip>
#include <cmath>
namespace vector_matrix {
using namespace std ;
// set the value_type to double,
// value_type is the generic name for "number"
// (non integer)type
typedef double value_type ;
// set the index_type to int,
// index_type is the generic name for "integer" type
typedef int index_type ;
class mat ; // forward declaration
class vec {
index_type dim ;
// private member of the class
value_type * values ;
vec() ;
public: // from now the public interface
// the constructor
vec( index_type dim ) ;
// the destructor
~vec() ;
index_type const & get_dim() const { return dim ; }
// the copy constructor
vec const & operator = (vec const & ) ;
// declare the operator []
value_type & operator [] ( index_type i ) ;
value_type const & operator [] ( index_type i ) const ;
vec const & operator -= ( vec const & a );
vec const & operator += ( vec const & a );
// compute the 2 norm of the vector
value_type norm2() const ;
} ;
// external operator
// add two vector
vec operator + ( vec const & a, vec const & b ) ;
// subtract two vector (definition only)
vec operator - ( vec const & a, vec const & b ) ;
vec operator / ( vec const & b, mat const & A ) ;
class mat {
index_type dim ;
// private member of the class
value_type * values ;
mat() ;
public: // from now the public interface
// the constructor
mat( index_type dim ) ;
// the destructor
~mat() ;
// the copy constructor
mat const & operator = (mat const & ) ;
// declare the operator ()
value_type & operator () ( index_type i, index_type j) ;
value_type const & operator () ( index_type i, index_type j) const ;
} ;
}
#endif
File: 22.2.h:
// standard trick for only one time inclusion
#ifndef TWENTITWO_TWO_H
#define TWENTITWO_TWO_H
#include <iostream>
#include <iomanip>
#include <cmath>
#include "22.1.h"
namespace newton_solver {
using namespace std ;
using namespace vector_matrix ;
/*
now we set the definition (prototipe)
of the functions
*/
// prototype of the non-linear system
extern vec F( vec const & in ) ;
// prototype of the Jacobian of the non-linear system
extern mat JF( vec const & in ) ;
// prototype for the solver
typedef vec F_type ( vec const & ) ;
typedef mat JF_type ( vec const & ) ;
extern
bool
solver( vec const & x0,
F_type * pF,
JF_type * pJF,
index_type const n,
value_type const & tol,
vec & x
) ;
}
#endif
Lesson of 25/5/2005
File: 24.cpp:
#include <iostream>
/*
Overloading and templates
*/
/*
compute the maximum of two numbers
*/
/* function max for double precision numbers */
// first definition
double max( double const & a, double const & b ) {
if ( a > b ) return a ;
else return b ;
}
/* function max for single precision numbers */
// second definition
float max( float const & a, float const & b ) {
if ( a > b ) return a ;
else return b ;
}
/* overloading means the same name for differents functions */
/*
The template mechanism can produce skeleton
of code that can be expanded when is needed
*/
template <typename T>
T max( T const & a, T const & b ) {
if ( a > b ) return a ;
else return b ;
}
template <typename Ta, typename Tb>
Ta max( Ta const & a, Tb const & b ) {
if ( a > b ) return a ;
else return b ;
}
int
main() {
{
double a = 1 ;
double b = 2 ;
double c = max(a,b) ;// use first definition
}
{
float a = 1 ;
float b = 2 ;
float c = max(a,b) ;// use second definition
}
{
int a = 1 ;
int b = 2 ;
int c = max(a,b) ; // use the template with T=int
}
{
int a = 1 ;
long b = 2 ;
int c = max(a,b) ; // use the template with T=int
}
}
Lesson of 30/5/2005
File: 25.cpp:
#include <iostream>
using namespace std ;
/*
Overloading and templates
*/
/*
The template mechanism can produce skeleton
of code that can be expanded when is needed
*/
template <typename T, int N>
T sum( T const v[] ) {
T res = 0 ;
for ( int i = 0 ; i < N ; ++i )
res += v[i] ;
return res ;
}
extern double b[] ; // extern double b[] ;
// somewhere there is double b[12] ;
int
main() {
double a[] = {1,2,3,4,5,6,7,8,9} ;
int const n = sizeof(a)/sizeof(a[0]); //sizeof(a)/sizeof(double) ;
cout << n << endl ;
double res = sum<double,5>(a) ;
cout << res << endl ;
res = sum<double,n>(a) ;
cout << res << endl ;
res = sum<double,n+10000>(a) ;
cout << res << endl ;
}
File: 26.cpp:
#include <iostream>
#include <string>
using namespace std ;
/*
A class can be thinked as a structure
with all the methods and data public.
*/
// this class
class A {
public:
int a, b ;
} ;
// is "nearly" equivalent to this struct
struct {
int a, b ;
} A ;
/*
One of the important feature of a class is
that we can protect some information
*/
class B {
string name ;
double x, y ;
public:
// constructor method
B(string const & _n,
double const & _x,
double const & _y)
: name(_n), x(_x), y(_y)
{ cout << "passing to the FIRST constructor for " << name << "\n" ; }
// another constructor
B(string const & _n) : name(_n), x(0), y(0)
{ cout << "passing to the SECOND constructor for " << name << "\n" ; }
// another constructor
B(string const & _n, int const _x, int const _y)
: name(_n), x(_x), y(_y)
{ cout << "passing to the THIRD constructor for " << name << "\n" ; }
// the destructor
~B() {
cout << "passing to the destructor for " << name << "\n" ;
}
} ;
B a("a",0,1) ; // call of the third constuctor
int
main() {
cout << "STARTING THE PROGRAM\n" ;
B b("b",0.0,1.0) ; // call of the first constuctor
B * pointer_to_d ;
pointer_to_d = new B("pointer",0.0,1.0) ;
cout << "INSIDE THE PROGRAM\n" ;
delete pointer_to_d ; // free memory for pointer_to_d
B c("c") ; // call of the second constuctor
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 27.cpp:
#include <iostream>
#include <string>
using namespace std ;
/*
Example of a class with many costructor
*/
template <typename T>
class vector {
public:
typedef T value_type ; // alias of T to value_type ;
private:
string the_name ;
int the_size ;
value_type * the_data ;
public:
// constructor method
vector(string const & n, int const size) : the_name(n), the_size(size) {
cout << "Building vector " << the_name << " size = " << the_size << "\n" ;
the_data = new value_type [size] ;
}
// the destructor
~vector() {
cout << "passing to the destructor for " << the_name << "\n" ;
delete [] the_data ;
}
// define the [] operator
value_type const & operator [] ( int i ) {
if ( i < 0 || i >= the_size ) {
cerr << "bad index for " << the_name << "[" << i << "]\n" ;
exit(0) ; // exit from the program
}
return the_data[i] ;
}
} ;
typedef vector<double> VECTOR ;
int
main() {
cout << "STARTING THE PROGRAM\n" ;
VECTOR v("v",100) ;
for ( int i = 0 ; i < 200 ; ++i ) {
VECTOR::value_type a ;
a = v[i] ;
}
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 28.cpp:
#include <iostream>
#include <string>
#include <sstream>
using namespace std ;
/*
Example of a class with many costructor
*/
template <typename T>
class vector {
public:
typedef T value_type ; // alias of T to value_type ;
private:
string the_name ;
int the_size ;
value_type * the_data ;
public:
// constructor method
vector(string const & n, int const size) : the_name(n), the_size(size) {
cout << "Building vector " << the_name << " size = " << the_size << "\n" ;
the_data = new value_type [size] ;
}
// the destructor
~vector() {
cout << "passing to the destructor for " << the_name << "\n" ;
delete [] the_data ;
}
// define the [] operator
value_type const & operator [] ( int i ) {
if ( i < 0 || i >= the_size ) {
// throw 1.234 ;
ostringstream the_error ;
the_error << "bad index for " << the_name << "[" << i << "]\n" ;
throw the_error.str(); // throw a string object
}
return the_data[i] ;
}
} ;
typedef vector<double> VECTOR ;
int
main() {
cout << "STARTING THE PROGRAM\n" ;
VECTOR v("v",100) ;
try {
for ( int i = 0 ; i < 200 ; ++i ) {
VECTOR::value_type a ;
a = v[i] ;
}
}
catch (int err_code) {
cerr << "found error number " << err_code << "\n" ;
}
catch (string const & err ) {
cerr << "found error : " << err << "\n" ;
}
catch (...) {
cerr << " unknown error found\n" ;
}
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 29.cpp:
#include <iostream>
#include <string>
#include <sstream>
using namespace std ;
/*
Example of an error class
*/
class error {
string the_error_message ;
int the_error_number ;
public:
error(string const & s, int n) :
the_error_message(s),
the_error_number(n) {}
void
print( ostream & stream ) const {
stream << "ERROR: " << the_error_message
<< "\nERROR number: " << the_error_number
<< "\n" ;
}
};
/*
Example of a class with many costructor
*/
template <typename T>
class vector {
public:
typedef T value_type ; // alias of T to value_type ;
private:
string the_name ;
int the_size ;
value_type * the_data ;
public:
// constructor method
vector(string const & n, int const size) : the_name(n), the_size(size) {
cout << "Building vector " << the_name << " size = " << the_size << "\n" ;
the_data = new value_type [size] ;
}
// the destructor
~vector() {
cout << "passing to the destructor for " << the_name << "\n" ;
delete [] the_data ;
}
// define the [] operator
value_type const & operator [] ( int i ) {
if ( i < 0 || i >= the_size ) {
ostringstream the_error ;
the_error << "bad index for " << the_name << "[" << i << "]\n" ;
throw error(the_error.str(),1) ; // throw a string object
}
return the_data[i] ;
}
} ;
typedef vector<double> VECTOR ;
int
main() {
cout << "STARTING THE PROGRAM\n" ;
VECTOR v("v",100) ;
try {
for ( int i = 0 ; i < 200 ; ++i ) {
VECTOR::value_type a ;
a = v[i] ;
}
}
catch (int err_code) {
cerr << "found error number " << err_code << "\n" ;
}
catch (string const & err ) {
cerr << "found error : " << err << "\n" ;
}
catch (error const & err ) {
err . print(cerr) ;
}
catch (...) {
cerr << " unknown error found\n" ;
}
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 30.cpp:
#include <iostream>
#include <string>
using namespace std ;
/*
Example of inheritance
*/
// define the base class
class Base {
string the_name ;
double x, y ;
public:
Base( string const & n ) : the_name(n), x(0), y(0) {}
Base( string const & n,
double const & _x,
double const & _y) : the_name(n), x(_x), y(_y) {}
string const & name() const { return the_name ; }
void print( ostream & stream ) const {
stream << "class: " << the_name << " " << x << " " << y << "\n" ;
}
} ;
class Derived : public Base {
public:
Derived(string const & n) : Base(n,1,1) {}
} ;
int
main() {
cout << "STARTING THE PROGRAM\n" ;
Base a("a") ;
Derived b("b") ;
a . print(cout) ;
b . print(cout) ;
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 31.cpp:
#include <iostream>
#include <string>
using namespace std ;
/*
A classical Example of inheritance
*/
// define the base class
class Object {
string the_name ;
protected:
double cx, cy ; // center of the object
double area ; // area of the object
public:
Object( string const & n ) : the_name(n) {}
string const & name() const { return the_name ; }
void print( ostream & stream ) const {
stream << "object: " << the_name
<< "\ncenter " << cx << " " << cy
<< "\narea " << area << "\n" ;
}
} ;
class Circle : public Object {
double ray ;
// here cx, cy, area are in the private part of Circle
double const PI ;
public:
Circle(double const & _cx,
double const & _cy,
double const & _ray) :
Object("circle"),
ray(_ray),
PI(3.1415)
{
// You can use the scope :: operator to access
// inherited part of the class
Object::cx = _cx ;
Object::cy = _cy ;
Object::area = 0 ;
// If there is no possibility of confusion
// you can avoid the scope operator ::
cx = _cx ;
cy = _cy ;
area = ray*ray*PI ;
}
void print( ostream & stream ) const {
Object::print(stream) ;
stream << "perimeter: " << 2*ray*PI << "\n" ;
}
} ;
class Square : public Object {
double length ;
// here cx, cy, area are in the private part of Circle
public:
Square(double const & _cx,
double const & _cy,
double const & _length) :
Object("square"),
length(_length)
{
// If there is no possibility of confusion
// you can avoid the scope operator ::
cx = _cx ;
cy = _cy ;
area = length*length ;
}
} ;
void
print( Object const & o ) {
o . print ( cout ) ;
}
int
main() {
cout << "STARTING THE PROGRAM\n" ;
Circle c(2,3,3) ;
Square q(2,3,3) ;
c . print(cout) ;
print(c) ; // loose the print of the perimeter
print(q) ;
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
File: 32.cpp:
#include <iostream>
#include <string>
using namespace std ;
/*
A classical Example of inheritance
*/
// define the base class
class Object {
string the_name ;
protected:
double cx, cy ; // center of the object
double area ; // area of the object
public:
Object( string const & n ) : the_name(n) {}
string const & name() const { return the_name ; }
virtual // declare the routine as virtual
void print( ostream & stream ) const {
stream << "object: " << the_name
<< "\ncenter " << cx << " " << cy
<< "\narea " << area << "\n" ;
}
} ;
class Circle : public Object {
double ray ;
// here cx, cy, area are in the private part of Circle
double const PI ;
public:
Circle(double const & _cx,
double const & _cy,
double const & _ray) :
Object("circle"),
ray(_ray),
PI(3.1415)
{
// You can use the scope :: operator to access
// inherited part of the class
Object::cx = _cx ;
Object::cy = _cy ;
Object::area = 0 ;
// If there is no possibility of confusion
// you can avoid the scope operator ::
cx = _cx ;
cy = _cy ;
area = ray*ray*PI ;
}
void print( ostream & stream ) const {
Object::print(stream) ;
stream << "perimeter: " << 2*ray*PI << "\n" ;
}
} ;
class Square : public Object {
double length ;
// here cx, cy, area are in the private part of Circle
public:
Square(double const & _cx,
double const & _cy,
double const & _length) :
Object("square"),
length(_length)
{
// If there is no possibility of confusion
// you can avoid the scope operator ::
cx = _cx ;
cy = _cy ;
area = length*length ;
}
} ;
void
print( Object const & o ) {
o . print ( cout ) ;
}
int
main() {
cout << "STARTING THE PROGRAM\n" ;
Circle c(2,3,3) ;
Square q(2,3,3) ;
c . print(cout) ;
print(c) ; // NOW do not loose the print of the perimeter
print(q) ;
cout << "ENDING THE PROGRAM\n" ;
return 0 ;
}
Lesson of 30/5/2005 (pomeriggio)
File: 33.cpp:
#include <iostream>
using namespace std ;
/*
A classical Example of generic programming
*/
// a simple routine that sort a vector of number
void
sort( int v[], int const dim ) {
// sorting by bubble sort
for ( int i = 0 ; i < dim-1 ; ++i )
for ( int j = i+1 ; j < dim ; ++j )
if ( v[i] > v[j] ) {
// swap the values
int k = v[i] ;
v[i] = v[j] ;
v[j] = k ;
}
}
/*
Using template we can generalize the algorithm
for any data type, other than integer
*/
template <typename T>
void
sort( T v[], int const dim ) {
// sorting by bubble sort
for ( int i = 0 ; i < dim-1 ; ++i )
for ( int j = i+1 ; j < dim ; ++j )
if ( v[i] > v[j] ) {
// swap the values
T k = v[i] ;
v[i] = v[j] ;
v[j] = k ;
}
}
/*
Sorting algorithm in the spirit of
the Standard Template Library
*/
template <typename T>
void
sort( T * begin, // pointer to the first element of the vector
T * end) { // pointer to PAST to the last element of the vector
// sorting by bubble sort
for ( T * pi = begin ; pi < end-1 ; ++pi )
for ( T * pj = pi+1 ; pj < end ; ++pj )
if ( *pi > *pj ) {
// swap the values
T buff = *pi ;
*pi = *pj ;
*pj = buff ;
}
}
int
main() {
//int v[] = {1,3,-3,2,23,123,-23,232,-3,-45,-2} ;
//int dim = sizeof(v)/sizeof(v[0]) ;
long v[] = {1,3,-3,2,23,123,-23,232,-3,-45,-2} ;
long dim = sizeof(v)/sizeof(v[0]) ;
sort(v,v+dim) ; // v = pointer to the first element
// v + dim = pointer to past to the last element
cout << v[0] ;
for ( int i = 1 ; i < dim ; ++i )
cout << ", " << v[i] ;
cout << "\n" ;
return 0 ;
}
File: 34.cpp:
#include <iostream>
// Standard template library for algorithm
#include <algorithm>
using namespace std ;
int
main() {
//int v[] = {1,3,-3,2,23,123,-23,232,-3,-45,-2} ;
//int dim = sizeof(v)/sizeof(v[0]) ;
long a[] = {1,3,-3,2,23,123,-23,232,-3,-45,-2} ;
long adim = sizeof(a)/sizeof(a[0]) ;
long b[] = {22,-34,12} ;
long bdim = sizeof(b)/sizeof(b[0]) ;
sort(a,a+adim) ; // a = pointer to the first element
// a + dim = pointer to past to the last element
sort(b,b+bdim) ; // b = pointer to the first element
// b + dim = pointer to past to the last element
for ( int i = 0 ; i < adim ; ++i )
if ( a[i] == 23 )
cout << "FOUND at rank " << i << endl ;
/*
lower_bound implements the binary search
in a sorted vector ( o vector like ).
If found return the pointer (iterator) of the found
thing. If not found return the pointer (iterator)
of past to the last element.
*/
long * res = lower_bound( a, a + adim, 1111123) ;
if ( res == a + adim || *res != 1111123 )
cout << "NOT FOUND\n" ;
else
cout << " FOUND = " << *res
<< " RANK = " << res - a
<< endl ;
cout << a[0] ;
for ( int i = 1 ; i < adim ; ++i )
cout << ", " << a[i] ;
cout << "\n" ;
/*
merge: merge two sorted vector into a
big one sorted vector
*/
long c[1000] ;
merge( a, a+adim,
b, b+bdim,
c ) ;
cout << c[0] ;
for ( int i = 1 ; i < adim+bdim ; ++i )
cout << ", " << c[i] ;
cout << "\n" ;
cout << "MAX a = " << * max_element( a, a + adim) << endl ;
c[0] = 1 ;
c[1] = 2 ;
c[2] = 3 ;
for ( int i = 0 ; i < 7 ; ++i ) {
cout << c[0] << " " << c[1] << " " << c[2] << endl ;
next_permutation( c, c+3 ) ;
}
return 0 ;
}
File: 35.cpp:
#include <iostream>
// Standard template library for algorithm
#include <algorithm>
// Standard template library for vector container
#include <vector>
using namespace std ;
int
main() {
long avec[] = {1,3,-3,2,23,123,-23,232,-3,-45,-2} ;
long adim = sizeof(avec)/sizeof(avec[0]) ;
vector<long> a ;
a . reserve( 10 ) ; // reserve memory
for ( int i = 0 ; i < adim ; ++i ) {
a . push_back(avec[i]) ;
cout << "insert " << avec[i]
<< " size = " << a . size()
<< " capacity = " << a . capacity() << endl ;
}
sort( a . begin(), a . end() ) ;
vector<long> b(3) ; // 3 is the size of the vector
b[0] = 22 ;
b[1] = -34 ;
b[2] = 12 ;
sort( b . begin(), b . end() ) ;
/*
lower_bound implements the binary search
in a sorted vector ( o vector like ).
If found return the pointer (iterator) of the found
thing. If not found return the pointer (iterator)
of past to the last element.
*/
vector<long>::iterator
res = lower_bound( a . begin(),
a . end(),
23 ) ;
if ( res == a . end() || *res != 23 )
cout << "NOT FOUND\n" ;
else
cout << " FOUND = " << *res
<< " RANK = " << res - a . begin()
<< endl ;
cout << a . front() ; // equivalent *(a.begin())
for ( vector<long>::const_iterator i = a.begin()+1 ;
i < a . end() ; ++i )
cout << ", " << *i ;
cout << "\n" ;
/*
merge: merge two sorted vector into a
big one sorted vector
*/
vector<long> c(a.size()+b.size()) ;
merge( a . begin(), a . end(),
b . begin(), b . end(),
c.begin() ) ;
cout << c . front() ;
for ( vector<long>::const_iterator i = c.begin()+1 ;
i < c . end() ; ++i )
cout << ", " << *i ;
cout << "\n" ;
cout << "MAX a = " << * max_element( a.begin(), a.end()) << endl ;
c . resize(3) ;
c[0] = 1 ;
c[1] = 2 ;
c[2] = 3 ;
for ( int i = 0 ; i < 7 ; ++i ) {
cout << c[0] << " " << c[1] << " " << c[2] << endl ;
next_permutation( c . begin(), c . end() ) ;
}
return 0 ;
}
File: 36.cpp:
#include <iostream>
// Standard template library for algorithm
#include <algorithm>
// Standard template library for associative array container
#include <map>
#include <string>
using namespace std ;
int
main() {
// example, phone book
map<string,long> phone_book ;
phone_book["mary"] = 12345 ;
phone_book["joe"] = 12334123 ;
phone_book["anna"] = 435345 ;
phone_book["philip"] = 142342 ;
phone_book["henry"] = 344443 ;
cout << phone_book["henry"] << endl ;
string key = "anna" ;
map<string,long>::iterator i = phone_book . find( key ) ;
if ( i == phone_book . end() )
cout << key << " not found\n" ;
else
cout << key << " = " << (*i) . second << " " << i -> second << "\n" ;
// print all the phone_book
for ( map<string,long>::const_iterator i = phone_book . begin() ;
i != phone_book . end() ;
++i ) {
cout << i -> first << " = " << i -> second << "\n" ;
}
return 0 ;
}
Corso di Calcolo Numerico (AA 2003/2004)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Martedì | 15:30 - 18:30 | T2 |
Mercoledì | 14.30 - 16.30 | T2 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 16.30 - 18.30 | 505 |
Giovedì | 16:30 - 18:30 | 505 |
Giovanni Zilli, Lezioni di CALCOLO NUMERICO, Imprimitur Editrice (Padova)
James F. Epperson, Introduzione all’analisi numerica, McGraw-Hill
- materiale aggiuntivo e segmenti di programmi contenuti nel libro possono essere reperiti qui
Alfio Quarteroni, Elementi di CALCOLO NUMERICO, Progetto Leonardo (Bologna)
Enrico Bertolazzi e Gianmarco Manzini, Appunti di Calcolo Numerico, pdf
Un libro On-Line in italiano di Calcolo Numerico
- Alla homepage del Prof. Giovanni Gheri del Dipartimento di Matematica Applicata U. Dini dell’Università di Pisa.
Programma svolto corso di Calcolo Numerico
AA 2003/2004 programma svolto
Sistemi lineari
Metodo di eliminazione di Gauss e decomposizione LU. Pivoting parziale e totale.
Interpolazione
Interpolazione polinomiale.
Metodo di Lagrange.
Metodo di Newton e differenze divise.
Stima dell’errore di interpolazione.
Interpolazione polinomiale a tratti.
Splines cubiche.
Minimi quadrati
Sistemi sovradeterminati e risoluzione con il metodo dei minimi quadrati. Regressione lineare e quadratica.
Zeri di funzioni
Metodo di bisezione; metodo di Newton; Metodo delle secanti. Ordine di convergenza.
Metodi iterativi per sistemi lineari
Metodi iterativi basati sullo splitting. Metodi di Jacobi, Gauss-Seidel, Matrici a diagonale dominante e teorema di Gershgorin.
Integrazione numerica
Formule di Newton-Cotes (punto medio, trapezi, Simpson). Integrazione di Gauss. Stima dell’errore.
Differenze finite
Approssimazione delle derivate prime e seconde. Derivazione delle formule con l’uso dei polinomi interpolanti. Derivazione delle formule con l’uso dello sviluppo di Taylor.
Equazioni differenziali ordinarie
Metodi di Eulero esplicito e implicito.
Metodo di Crank-Nicolson,
metodo di Heun (o Eulero migliorato),
metodo di Collatz (Eulero modificato o di Runge).
Metodi espliciti di Runge-Kutta.
Metodi multistep,
Adams-bashforth, Adams-Moulton e BDF.
Equazioni differenziali ordinarie ai valori al contorno
Richiami delle proprietà analitiche.
Metodo delle differenze centrate e metodo upwind.
Principi di massimo continui e discreti.
Esempio di instabilità.
Appello 22 giugno 2004
Appello 26 luglio 2004
Appello 25 ottobre 2004
Appello 11 gennaio 2005
Appello 25 febbraio 2005
Il formulario per lo svolgimento dell’esame
lo trovate qui
Corso di Calcolo Numerico (AA 2002/2003)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 14:30 - 17:30 | T1 |
Martedì | 10.30 - 12.30 | T3 |
Giovedì | 8:30 - 10:30 | T4 |
Giovedì | 16:30 - 18:30 | T4 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11.30 - 12.30 | 505 |
Martedì | 14:30 - 16:30 | 505 |
Testo Consigliato
Giovanni Zilli, Lezioni di CALCOLO NUMERICO, Imprimitur Editrice (Padova)
James F. Epperson, Introduzione all’analisi numerica, McGraw-Hill
- materiale aggiuntivo e segmenti di programmi contenuti nel libro possono essere reperiti qui
Alfio Quarteroni, Elementi di CALCOLO NUMERICO, Progetto Leonardo (Bologna)
Dispense del corso
Enrico Bertolazzi e Gianmarco Manzini, Appunti di Calcolo Numerico, pdf
Un libro On-Line in italiano di Calcolo Numerico
- Alla homepage del Prof. Giovanni Gheri del Dipartimento di Matematica Applicata U. Dini dell’Università di Pisa.
Programma svolto corso di Calcolo Numerico
AA 2002/2003 programma svolto
Prerequisiti
Teorema di Rolle genralizzato, Serie di Taylor, Torema della media. Norme vettoriali e matriciali.
Sistemi lineari metodi diretti
Metodo di Gauss e decomposizione LU. Numero di Condizionamento e sui significato. Pivoting e decomposizione LU con permutazioni.
Zeri di funzioni
Metodo di bisezione; metodo di Newton; Metodo delle secanti; ordine di convergenza del metodo di Newton. Metodo di Newton per funzioni in piu variabili.
Interpolazione
Interpolazione di Lagrange. Interpolazione di Newton e differenze divise. Nodi di Tchebichev. Stima dell’errore di interpolazione (con dimostrazione).
Integrazione numerica
Formule di Newton-Cotes (punto medio, trapezi, Simpson). Stima dell’errore (con dimostrazione per i Trapezi). Integrazione di Gauss con nodi di Legendre.
Minimi quadrati
Sistemi sovradeterminati e risoluzione con il metodo dei minimi quadrati. Regressione lineare e quadratica (retta per molti punti, parabola per molti punti)
Differenze finite
Approssimazione delle derivate prime e seconde. Derivazione delle formule con l’uso dei polinomi interpolanti, con l’uso dei coefficienti indeterminati e con lo sviluppo di Taylor.
Equazioni differenziali ordinarie
Metodi di Eulero in avanti (esplicito) e di Eulero all’indietro (implicito); metodo di Heun (o Eulero migliorato), metodo di Collatz (Eulero modificato o di Runge).
Metodi espliciti di Runge-Kutta Runge-Kutta del IV ordine. Cenni sui metodi multistep, Adams-bashforth Adams-Moulton.
Stabilità degli schmi numerici. Esempi con Eulero inplicito ed espliocito e regola schema multistep incondizionatamente instabile.
Equazioni differenziali ordinarie ai valori al contorno
Richiami delle psroprietà analitiche. Metodo delle differenze centrate e upwind. Principi di massimo continui e discreti.
Sistemi lineari metodi iterativi
Metodi iterativi basati sullo splitting. Condizionio necessarie e suffcienti per la convergenza degli schemi iterativi. Metodi di Jacobi e Gauss-Seidel. Matrici a diagonale dominante e teorema di Gershgorin.
Corso di Calcolo Numerico (AA 2001/2002)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 11:30 - 13:30 | BIB |
Martedì | 10.30 - 12.30 | T1 |
Mercoledì | 8:30 - 10:30 | A1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Giovedì | 11.00 - 13.00 | 505 |
Venerdì | 15:00 - 17:00 | 505 |
Testo Consigliato
Giovanni Zilli, Lezioni di CALCOLO NUMERICO, Imprimitur Editrice (Padova)
Alfio Quarteroni e Fausto Saleri, Introduzione al CALCOLO SCIENTIFICO, Esercizi e problemi risolti con MATLAB, Springer
Dispense
- Enrico Bertolazzi e Gianmarco Manzini, Appunti di Calcolo Numerico, pdf
Programma svolto corso di Calcolo Numerico
AA 2001/2002
Zeri di funzioni
Metodo di bisezione; metodo di Newton; Metodo delle secanti; ordine di convergenza del metodo di Newton.
Interpolazione
Interpolazione di Lagrange. Interpolazione di Newton e differenze divise. Stima dell’errore di interpolazione (con dimostrazione). Splines cubiche.
Integrazione numerica
Formule di Newton-Cotes (punto medio, trapezi, Simpson). Stima dell’errore (con dimostrazione per i Trapezi) e polinomi di Tchebichev. Integrazione di Gauss con nodi di Legendre.
Sistemi lineari
Metodo di Gauss e decomposizione LU. Cenni sul pivoting. Metodi iterativi basati sullo splitting. Metodi di Jacobi, Gauss-Seidel, S.O.R. Matrici a diagonale dominante e teorema di Gershgorin.
Minimi quadrati
Sistemi sovradeterminati e risoluzione con il metodo dei minimi quadrati. Regressione lineare e quadratica (retta per molti punti, parabola per molti punti)
Differenze finite
Approssimazione delle derivate prime e seconde. Derivazione delle formule con l’uso dei polinomi interpolanti. Derivazione delle formule con l’uso dei coefficienti indeterminati e sviluppo di Taylor.
Equazioni differenziali ordinarie
Metodi di Eulero in avanti (esplicito) e di Eulero all’indietro (implicito); metodo di Crank-Nicolson, metodo di Heun (o Eulero migliorato), metodo di Collatz (Eulero modificato o di Runge). Metodi espliciti di Runge-Kutta Runge-Kutta del IV ordine. Cenni sui metodi multistep, Adams-bashforth Adams-Moulton.
Equazioni differenziali ordinarie ai valori al contorno
Richiami delle proprietà analitiche. Metodo delle differenze centrate e upwind. Principi di massimo continui e discreti. Esempio di instabilità.
Esercizi in Maple
Esercitazione del 17.10.2001
Fattorizzazione LU esempio 1 matrice 3x3 senza pivoting: pdf, maple.
Fattorizzazione LU esempio 2 matrice 4x4 senza pivoting: pdf, maple.
Fattorizzazione LU esempio 3 matrice 3x3 con pivoting: pdf, maple.
Fattorizzazione LU esempio 4 matrice 4x4 con pivoting: pdf, maple.
Esercitazione del 31.10.2001
Esercitazione del 7.11.2001
Posizionamanto dei nodi e interpolazione. Parte prima: pdf, maple.
Posizionamanto dei nodi e interpolazione. Parte seconda: pdf, maple.
Esercitazione del 14.11.2001
Esercitazione del 21.11.2001
Derivazione delle formule di Gauss-Legendre per n=2 e n=3: pdf, maple.
Stima degli intervalli di integrazione per il metodo dei trapezi e di Simpson: pdf, maple.
Esercitazione del 28.11.2001
Esercitazione del 5.12.2001
Esercitazione del 12.12.2001
Esercitazione del 8.1.2002
Esercitazione del 16.1.2002
Implementazione del metodo di Runge-Kutta del quarto ordine per un sistema di due equazioni: pdf, maple.
Costruzione delle formule di Adams-Bashforth-Moulton: pdf, maple.
Costruzione delle formule di Adams-Bashforth-Moulton con differenze finite: pdf, maple.
Derivazione degli schemi di Adams-Bashforth-Moulton, una lezione on-line di Eitan Tadmor.
Corso di Geometria (AA 2000/2001)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Lunedì | 14:30 - 16:30 | T1 |
Mercoledì | 16.30 - 18.30 | T1 |
Giovedì | 14:30 - 16:30 | A1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 14.30 - 16.30 | 505 |
Giovedì | 10:30 - 12:30 | 505 |
Programma svolto Corso di Geometria
AA 2000/2001 gruppo (A-L)
Richiami sui numeri complessi
Scalari e vettori
Esempi in \(\mathbb{R}^2\), \(\mathbb{R}^3\).
Operazioni elementari (somma, moltiplicazione).
Disuguaglianza di Holder e Minkowski \((p=2)\) norma \(||\cdot||_2\).
Prodotto scalare
\[ x\cdot y = \sum_{k=1}^n x_k y_k = ||x||_2 \qquad ||y||_2 \cos\theta = \dfrac{||x+y||_2^2-||x-y||_2^2}{4} \]
Estensione al caso complesso. Uso del prodotto scalare per il calcolo degli angoli tra vettori.
Prodotto vettoriale
Uso del prodotto vettoriale per la costruzione di vettori ortogonali a piani o coppie vettori.
Matrici
Quadrate, nulla, identità, diagonali, triangolari, simmetriche hermitiane e SPD.
Rette e piani
Forma parametrica e implicita e con i vettori normali, conversione tra le varie forme, angolo tra rette, distanza punto retta punto piano.
Spazio vettoriale
Definizione, esempi \(\mathbb{R}^n\) e \(K[x]\), span, vettori linearmente dipendenti, base di vettori e coordinate. Teorema di Grassmann
\[ \mathrm{dim}(V+W)= \mathrm{dim}(V)+\mathrm{dim}(W)-\mathrm{dim}(V\cap W) \]
Mappe Lineari
Mappe lineari e matrici associate. Equivalenza della composizione di mappe e prodotto matriciale.
Definizione di range e kernel. Teorema rango nullita (dim(range)+dim(kernel)).
Metodo di Gauss
Metodo di Gauss e sue varianti. Connessione del metodo di Gauss e i cambi di coordinate. Calcolo del kernel e range di una matrice. Calcolo delll’inversa. Calcolo del rango di una matrice.
Determinanti
Determinante definizione assiomatica. Sviluppo di Laplace del determinante. Calcolo del determinante col metodo di Gauss. Derivazione della regola di Cramer.
Autovalori e autovettori
Autovalori e autovettori di una trasformazione lineare. Molteplicità algebrica e geometrica. Trasformazioni di similitudine e invarianza del polinomio caratteristico. Calcolo degli autovettori e diagonalizzazione di una matrice.
Testo Consigliato
M. Grieco, B. Zucchetti, Algebra Lineare e Geometria Analitica, La Goliardica Pavese
Tom M. Apostol, Calcolo, Volume secondo, Geometria, Bollati Boringhieri
Dispense
Esami di Geometria
- 7 febbraio 2001
- Non disponibili
- 27 febbraio 2001
- 22 giugno 2001
- 10 luglio 2001
- 26 settembre 2001
Esercizi in Maple
Rette parametriche, proiezione di un punto su una retta: MAPLE, PDF
Piano per tre punti e proiezione di un punto su un piano: MAPLE, PDF
Calcolo della matrice dell’operatore lineare derivata: MAPLE, PDF
Risoluzione di un sistema 3x4 con il metodo di Gauss: MAPLE, PDF
Risoluzione di un sistema 4x4 con il metodo di Gauss: MAPLE, PDF
Calcolo del determinante con lo sviluppo di Laplace: MAPLE, PDF
Esercizi per l’esame in Maple
Data una conica della forma \(a x^2 + b x y + c y^2 + d x + e y + f = 0\) determinare il tipo di conica e trovare la trasformazione del tipo \[ \begin{cases} x = x' \cos\theta + y'\sin\theta+t_x & \\ y = -x' \sin\theta + y'\cos\theta+t_y & \end{cases} \] porta la conica alla forma canonica.
(livello di difficoltà 4)
Date due rette \(r\) e \(s\) scritte come intersezione di due piani:
\[ r = \begin{cases} a_1x+b_1y+c_1z+d_1=0 & \\ a_2x+b_2y+c_2z+d_2=0 & \end{cases} \]
\[ s = \begin{cases} a_3x+b_3y+c_3z+d_3=0 & \\ a_4x+b_4y+c_4z+d_4=0 & \end{cases} \]
determinare se le rette sono:
coincidenti;
parallele;
intersecanti;
sghembe;
\(r\) o \(s\) non rappresenta una retta.
(livello di difficolà 2)
Scrivere una procedura Maple del tipo:
> inverti := proc (A) > ... return IA; > end proc;
che data la matrice
A
restituisce la sua inversaIA
calcolandola col metodo di Gauss senza fare uso delle primitive mapleLinearSolve
neA^(-1)
.(livello di difficoltà 3)
Data la lista di vettori \([v_1,v_2,\ldots,v_n]\) scrivere una procedura maple
> gs := proc ( lista ) > .. return nuovalista; > end proc;
che stabilisce:
se i vettori sono tra loro linearmente indipendenti
calcola la matrice triangolare inferiore \(T\) e i vettori \(w_k\) cosi definiti
\[ w_k + \sum_{i=1}^{k-1} T_{k,i}w_i=v_k \]
in modo tale che siano tra loro ortogonali cioè
\[ w_k\cdot w_j = \begin{cases} 0 & k\neq j \\ 1 & k=j \end{cases} \]
(livello di difficoltà 3)
Data la lista di punti: \([ [x_1,y_1],[x_2,y_2],\ldots,[x_n,y_n]]\) che definiscono i contorni di un poligono presi in senso antiorario e un punto pnt = \([x,y]\) scrivere una procedura Maple:
> interno := proc ( pnt, lista ) > ...; > end proc;
che stabilisce se il punto è interno, esterno o sul bordo del poligono.
(livello di difficoltà 4)
Data la lista di punti: \([ [x_1,y_1],[x_2,y_2],\ldots,[x_n,y_n]]\) che definiscono i contorni di un poligono presi in senso antiorario e la retta \(r = [x_k,y_k]+t[v_x,v_y]\) scrivere una procedura Maple:
> interno := proc ( t, lista ) > ...; > return slst; > end proc;
che restituisce la lista sei segmenti intersezione della retta con il poligono.
(livello di difficoltà 4)
Sia data la lista di coppie di vettori: \([ [a_1,b_1],[a_2,b_2],\ldots,[a_n,b_n]]\) che definiscono la trasformazione di coordinate della mappa \(L\) come segue
\[ Aa_k = b_k, \qquad k=1,2,\ldots,n \]
dove \(A\) è la matrice associata alla mappa lineare \(L\). Scrivere una procedura Maple:
> interno := proc ( lista ) > ...; > return A; > end proc;
che (se i dati sono sufficienti e consistenti) restituisce tale matrice.
(livello di difficoltà 5)
Corso di Calcolo Numerico (AA 2000/2001)
Orario delle lezioni
GIORNO | ORA | AULA |
---|---|---|
Martedì | 9:30 - 11:30 | A1 |
Mercoledì | 10.30 - 11.30 | T1 |
Venerdì | 10:30 - 13:30 | T1 |
Orario di ricevimento
GIORNO | ORA | AULA |
---|---|---|
Mercoledì | 14.30 - 16.30 | 505 |
Giovedì | 10:30 - 12:30 | 505 |
Testo Consigliato
Giovanni Zilli, Lezioni di CALCOLO NUMERICO, Imprimitur Editrice (Padova)
Alfio Quarteroni, Elementi di CALCOLO NUMERICO, Progetto Leonardo (Bologna)
Dispense
- Enrico Bertolazzi e Gianmarco Manzini, Appunti di Calcolo Numerico, pdf
Programma svolto corso di Calcolo Numerico
AA 2000/2001 gruppo (A-L)
Rappresentazione dei numeri sul calcolatore
Cenni sulle basi binarie esadecimali e numeri floating point.
Zeri di funzioni
Metodo dicotomico (o bisezione), metodo delle corde e secanti, metodo di Newton. Convergenza del metodo di Newton e delle Secanti. Calcolo della radice quadrata e cubica.
Sistemi lineari (metodi diretti)
Richiami di algebra lineare e teorema di Cramer. Metodo di eliminazione di Gauss. Calcolo della decomposizione LU, dei determinanti. Connessione del metodo di Gauss e matrici di Frobenius e a Blocchi.
Sistemi lineari (metodi iterativi)
Metodi iterativi generali casi particolari: metodo di Jacobi, Gauss Seidel e SOR. Formulazione matriciale e per coordinate. Studio della convergenza. Metodi per matrici SPD: metodi di Richardson metodo del gradiente (steepest descent) e gradiente coniugato.
Interpolazione
Interpolazione polinomiale in generale e determinante di Vandermonte. Interpolazione di Lagrange, interpolazione di Newton e differenze divise. Stima dell’errore di interpolazione.
Minimi quadrati
Approssimazione ai minimi quadrati lineari e parabolici.
Derivazione numerica
Formule per le derivate prime e seconde e stima degli errori. Approssimazione delle derivate tramite polinomi interpolatori e tramite lo sviluppo di Taylor.
Integrazione numerica
Formula midpoint dei trapezi e di Simpson. Stima dell’errore per il metodo dei trapezi e di Simpson. Estrapolazione di Romberg. Formule Gaussiane.
Equazioni differenziali ordinarie (ai valori iniziali)
Metodo di Eulero esplicito e convergenza. Metodi di Heun e Collatz. Metodi di Runge Kutta. Metodi predictor corrector di Adams-Bashford Adams-Moulton.
Equazioni differenziali ordinarie (ai valori al contorno)
Richiami delle proprietà analitiche. Metodo delle differenze centrate e upwind. Principi di massimo continui e discreti. Esempio di instabilità.
Esercizi in Maple
Lezione n.1
Lezione n.2
Lezione n.3
Lezione n.4
Lezione n.5
Esempio di sistema di equazioni ordinarie ai valori iniziali. Aprossimazione della soluzione con Eulero: pdf, maple
Esempio di sistema di equazioni ordinarie ai valori iniziali. Approssimazione della soluzione con Eulero Implicito: pdf, maple
Esempio di sistema di equazioni ordinarie ai valori iniziali. Approssimazione della soluzione con Heun. pdf, maple
Esempio di sistema di equazioni ordinarie ai valori iniziali. Approssimazione della soluzione con Collatz: pdf, maple
Esempio di sistema di equazioni ordinarie ai valori iniziali. Approssimazione della soluzione con Eulero modificato: pdf, maple
Lezione n.6
Uso di Runge-Kutta al 4 ordine e un metodo multistep: pdf, maple
Approssimazione di una equazione ai valori al contorno con le differenze centrate: pdf, maple
Approssimazione di un equazione ai valori al contorno col metodo upwind: pdf, maple
Lezione n.7
Approssimazione della soluzione di un sistema lineare col metodo di Jacobi: pdf, maple
Approssimazione della soluzione di un sistema lineare col metodo di Gauss-Seidel: pdf, maple
Approssimazione della soluzione di un sistema lineare col metodo SOR: pdf, maple
Approssimazione del raggio spettrale della matrice di iterazione del metodo SOR: pdf, maple