Pivot de gauss avec numpy#

Links: notebook, html, python, slides, GitHub

Etape par étape, le pivote de Gauss implémenté en python puis avec numpy.

from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline

Python#

import numpy
def pivot_gauss(m):
    n = m.copy()
    for i in range(1, m.shape[0]):
        j0 = i
        while j0 < m.shape[0] and m[j0, i-1] == 0:
            j0 += 1
        for j in range(j0, m.shape[0]):
            coef = - m[j, i-1] / m[i-1, i-1]
            for k in range(i-1, m.shape[1]):
                m[j, k] += coef * m[i-1, k]
    return m


m = numpy.random.rand(4, 4)
piv = pivot_gauss(m)
piv * (numpy.abs(piv) > 1e-10)
array([[0.55773852, 0.26401337, 0.36548134, 0.12568338],
       [0.        , 0.84501794, 0.3183026 , 0.11992052],
       [0.        , 0.        , 0.26876495, 0.1272863 ],
       [0.        , 0.        , 0.        , 0.3082964 ]])

* (numpy.abs(piv) > 1e-10) sert à simplifier l’affichage des valeurs quasi nulles.

Numpy 1#

def pivot_gauss2(m):
    n = m.copy()
    for i in range(1, m.shape[0]):
        j0 = i
        while j0 < m.shape[0] and m[j0, i-1] == 0:
            j0 += 1
        for j in range(j0, m.shape[0]):
            coef = - m[j, i-1] / m[i-1, i-1]
            m[j, i-1:] += m[i-1, i-1:] * coef
    return m


piv = pivot_gauss2(m)
piv * (numpy.abs(piv) > 1e-10)
array([[0.55773852, 0.26401337, 0.36548134, 0.12568338],
       [0.        , 0.84501794, 0.3183026 , 0.11992052],
       [0.        , 0.        , 0.26876495, 0.1272863 ],
       [0.        , 0.        , 0.        , 0.3082964 ]])

Numpy 2#

def pivot_gauss3(m):
    n = m.copy()
    for i in range(1, m.shape[0]):
        j0 = i
        while j0 < m.shape[0] and m[j0, i-1] == 0:
            j0 += 1
        coef = - m[j0:, i-1] / m[i-1, i-1]
        m[j0:, i-1:] += coef.reshape((-1, 1)) * m[i-1, i-1:].reshape((1, -1))
    return m


piv = pivot_gauss3(m)
piv * (numpy.abs(piv) > 1e-10)
array([[0.55773852, 0.26401337, 0.36548134, 0.12568338],
       [0.        , 0.84501794, 0.3183026 , 0.11992052],
       [0.        , 0.        , 0.26876495, 0.1272863 ],
       [0.        , 0.        , 0.        , 0.3082964 ]])

Vitesse#

from cpyquickhelper.numbers import measure_time
from tqdm import tqdm
import pandas

data = []
for n in tqdm([10, 20, 30, 40, 50, 60, 70, 80, 100]):
    m = numpy.random.rand(n, n)
    if n < 50:
        res = measure_time(lambda: pivot_gauss(m), number=10, repeat=10)
        res.update(dict(name="python", n=n))
        data.append(res)
    res = measure_time(lambda: pivot_gauss2(m), number=10, repeat=10)
    res.update(dict(name="numpy1", n=n))
    data.append(res)
    res = measure_time(lambda: pivot_gauss3(m), number=10, repeat=10)
    res.update(dict(name="numpy2", n=n))
    data.append(res)

df = pandas.DataFrame(data)
df
100%|██████████| 9/9 [00:04<00:00,  1.82it/s]
average deviation min_exec max_exec repeat number ttime context_size name n
0 0.000674 0.000213 0.000374 0.001088 10 10 0.006741 64 python 10
1 0.000454 0.000127 0.000256 0.000562 10 10 0.004544 64 numpy1 10
2 0.001363 0.000390 0.000780 0.001894 10 10 0.013629 64 numpy2 10
3 0.001038 0.000959 0.000658 0.003908 10 10 0.010384 64 python 20
4 0.000841 0.000280 0.000656 0.001640 10 10 0.008413 64 numpy1 20
5 0.001814 0.000280 0.001621 0.002472 10 10 0.018138 64 numpy2 20
6 0.013065 0.009250 0.007522 0.033579 10 10 0.130650 64 python 30
7 0.003207 0.000164 0.002992 0.003397 10 10 0.032071 64 numpy1 30
8 0.002815 0.000030 0.002782 0.002874 10 10 0.028153 64 numpy2 30
9 0.053362 0.020418 0.040569 0.099695 10 10 0.533620 64 python 40
10 0.012710 0.001281 0.011835 0.015254 10 10 0.127104 64 numpy1 40
11 0.005585 0.000941 0.004866 0.007821 10 10 0.055855 64 numpy2 40
12 0.024682 0.005618 0.019726 0.036658 10 10 0.246824 64 numpy1 50
13 0.007721 0.000831 0.007127 0.010041 10 10 0.077207 64 numpy2 50
14 0.038531 0.006086 0.032592 0.053980 10 10 0.385306 64 numpy1 60
15 0.009483 0.000068 0.009380 0.009618 10 10 0.094831 64 numpy2 60
16 0.042429 0.008567 0.035483 0.063337 10 10 0.424291 64 numpy1 70
17 0.011983 0.000712 0.011418 0.013913 10 10 0.119831 64 numpy2 70
18 0.084926 0.009155 0.076947 0.106115 10 10 0.849257 64 numpy1 80
19 0.015445 0.000432 0.014988 0.016419 10 10 0.154452 64 numpy2 80
20 0.137455 0.007508 0.122579 0.148460 10 10 1.374552 64 numpy1 100
21 0.025048 0.000231 0.024841 0.025697 10 10 0.250484 64 numpy2 100
piv = df.pivot(index="n", columns="name", values="average")
piv
name numpy1 numpy2 python
n
10 0.000454 0.001363 0.000674
20 0.000841 0.001814 0.001038
30 0.003207 0.002815 0.013065
40 0.012710 0.005585 0.053362
50 0.024682 0.007721 NaN
60 0.038531 0.009483 NaN
70 0.042429 0.011983 NaN
80 0.084926 0.015445 NaN
100 0.137455 0.025048 NaN
piv.plot(title="pivot de gauss");
../_images/pivot_gauss_14_0.png