De kolommen van een reële N×N-matrix A kunnen geïnterpreteerd worden als vectoren in een N-dimensionale ruimte. Deze vectoren zijn niet noodzakelijk orthonormaal (d.w.z. onderling loodrecht en met lengte 1). Het Gram-Schmidt algoritme construeert uitgaande van de kolommen van A een reeks van N vectoren, allen lineaire combinaties van de kolommen van A die wel orthonormaal zijn.

Noem xi de vector die geassocieerd is met de i-de kolom van A. In een eerste stap zoeken we N vectoren yi die onderling loodrecht zijn, namelijk:
y0=x0
en voor 0<i<N:
yi=xij=0i1xiyjyjyjyj
In deze uitdrukking staat ab voor het scalair product van de vectoren a en b.
In een laatste stap, normeren we de vectoren yi, namelijk
zi=yi||yi|| met ||a|| de klassieke norm van de vector a, gedefinieerd als de vierkantswortel uit de som van de kwadraten van de componenten van a.

Schrijf de functie orthonormaal() met als enig argument een NumPy-tabel, met N rijen en N kolommen, en N>0. Het resultaat van de functie is een NumPy-tabel, eveneens bestaande uit N rijen en N kolommen, waarvan de kolommen de vectoren zi voorstellen, verkregen via de hierboven beschreven aanpak. Je mag aannemen dat de originele tabel niet-singulier is.

Voorbeeld

a = [[1.0, 2.0, 3.0],[4.0, 5.0, 6.0], [9.0, 8.0, 4.0]]
orthonormaal(np.array(a)) = 
[[ 0.10101525  0.61796622 -0.77968819]
 [ 0.40406102  0.69066813  0.59976014]
 [ 0.90913729 -0.37562653 -0.17992804]]