diff --git a/source/Dive_into_Functions.rst b/source/Dive_into_Functions.rst
index 417f5a428bd6ea6ec74f47fbd436d5cb420d86c6..427a4877e8c51595f85ea6bef6a510f829d48fb6 100644
--- a/source/Dive_into_Functions.rst
+++ b/source/Dive_into_Functions.rst
@@ -513,3 +513,12 @@ Second implementation
    :language: python
 
 :download:`matrix2.py <_static/code/matrix2.py>` .
+
+
+Thirs implementation
+
+.. literalinclude:: _static/code/matrix3.py
+   :linenos:
+   :language: python
+
+:download:`matrix3.py <_static/code/matrix3.py>` .
diff --git a/source/_static/code/matrix3.py b/source/_static/code/matrix3.py
new file mode 100644
index 0000000000000000000000000000000000000000..bae22e6b4857ad48581ab65dd96fa11028e96bc0
--- /dev/null
+++ b/source/_static/code/matrix3.py
@@ -0,0 +1,272 @@
+"""
+Implementation of simple matrix
+"""
+
+
+def create(nb_rows, nb_cols, val=None):
+    """
+    :param nb_rows: the number of rows
+    :type nb_rows: int
+    :param nb_cols: the number of columns
+    :type nb_cols: int
+    :param val: the default value to fill the matrix
+    :type val: any (None by default)
+    :return: matrix of nb_rows x nb_cols
+    :rtype: matrix
+    """
+    matrix = {}
+    for i in range(nb_rows):
+        for j in range(nb_cols):
+            matrix[(i, j)] = val
+    return matrix
+
+
+import sys
+major, minor = sys.version_info[:2]
+if major < 3 or (major == 3 and minor < 7):
+    raise NotImplementedError(
+        "Implementation missing for this Python version:"
+        "{}.{}".format(major, minor))
+else:
+    def size(matrix):
+        """
+        :param matrix: the matrix of which we want the size
+        :type matrix: matrix
+        :return: the size of matrix (number of rows, number of cols)
+        :rtype: typle of 2 int
+        """
+        # Not robust, and needs a Python version where dicts preserve
+        # key insertion order.
+        # Only works because matrix was created
+        # using a dict where the last inserted key corresponded
+        # to the the last row and last column
+        (last_row, last_col) = list(matrix.keys())[-1]
+        return (last_row + 1, last_col + 1)
+
+
+def _check_bounds(matrix, row, col):
+    """
+    Check whether row and col are compatible with the matrix size.
+
+    :param matrix: the matrix to check
+    :type matrix: matrix
+    :param row: the index of row to check
+    :type row: int
+    :param col: the index of column to check
+    :type col: int
+    :raise: IndexError if row or col are out of matrix bounds
+    """
+    (nb_rows, nb_cols) = size(matrix)
+    if (row < 0 or row >= nb_rows) or (col < 0 or col >= nb_cols):
+        raise IndexError("matrix index out of range")
+
+
+def get_cell(matrix, row, col):
+    """
+    :param matrix: the matrix
+    :type matrix: matrix
+    :param row: the row number
+    :type row: int
+    :param col: the column number
+    :type col: int
+    :return: the content of cell corresponding to row x col
+    :rtype: any
+    """
+    _check_bounds(matrix, row, col)
+    return matrix[(row, col)]
+
+
+def set_cell(matrix, row, col, val):
+    """
+    Set the value val in cell specified by row x col.
+
+    :param matrix: the matrix to modify
+    :type matrix: matrix
+    :param row: the row number of cell to set
+    :type row: int
+    :param col: the column number of cell to set
+    :type col: int
+    :param val: the value to set in cell
+    :type val: int
+    """
+    _check_bounds(matrix, row, col)
+    matrix[(row, col)] = val
+
+
+def mult(matrix, val):
+    """
+    :param matrix: the matrix
+    :type matrix: matrix
+    :param val: the value to mult the matrix with
+    :type val: int
+    :return: a new matrix corresponding the scalar product of matrix * val
+    :rtype: matrix
+    """
+    new_matrix = []
+    for (coords, value) in matrix.items():
+        new_matrix[coords] = value * val
+    return new_matrix
+
+
+def mult_inplace(matrix, val):
+    """
+    Compute the scalar product of a matrix and a value
+    do this operation in place
+
+    :param matrix: the matrix
+    :type matrix: matrix
+    :param val: the value to mult the matrix with
+    :type val: int
+    """
+    for (coords, value) in matrix.items():
+        matrix[coords] = value * val
+
+
+def get_row(matrix, row):
+    """
+    :param matrix: the matrix
+    :type matrix: matrix
+    :param row: row number
+    :type row: int
+    :return: the row of matrix corresponding to row
+    :rtype: list
+    """
+    _check_bounds(matrix, row, 0)
+    _, nb_cols = size(matrix)
+    row_values = []
+    for col in range(nb_cols):
+        row_values.append(get_cell(matrix, row, col))
+    return row_values
+
+
+def set_row(matrix, row, val):
+    """
+    set all cells of row row with val
+
+    :param matrix: the matrix to modify
+    :type matrix: matrix
+    :param row: the row number
+    :type row: int
+    :param val: the value to put in cells
+    :type val: any
+    """
+    _check_bounds(matrix, row, 0)
+    _, nb_cols = size(matrix)
+    for col in range(nb_cols):
+        set_cell(matrix, row, col, val)
+
+
+def get_col(matrix, col):
+    """
+    :param matrix: the matrix
+    :type matrix: matrix
+    :param col: the column number
+    :type col: int
+    :return: the column corresponding to col of matrix
+            a shallow copy of the col
+    :rtype: list
+    """
+    _check_bounds(matrix, 0, col)
+    nb_rows, _ = size(matrix)
+    col_values = []
+    for row in range(nb_rows):
+        col_values.append(get_cell(matrix, row, col))
+    return col_values
+
+
+def set_col(matrix, col, val):
+    """
+    set all cells of col col with val
+
+    :param matrix: the matrix to modify
+    :type matrix: matrix
+    :param col: the column number
+    :type col: int
+    :param val: the value to put in cells
+    :type val: any
+    """
+    _check_bounds(matrix, 0, col)
+    nb_rows, _ = size(matrix)
+    for row in range(nb_rows):
+        set_cell(matrix, row, col, val)
+
+
+def replace_col(matrix, col, col_values):
+    """
+    replace column col with col_values
+
+    :param matrix: the matrix to modify
+    :type matrix: matrix
+    :param col: the column number to replace
+    :type col: int
+    :param col_values: the list of values to use as replacement of column
+    :type col_values: list
+    """
+    nb_rows, nb_cols = size(matrix)
+    if len(col_values) != nb_rows:
+        raise RuntimeError(
+            f"the size of col_values {len(col_values)} does not fit "
+            f"matrix size {nb_rows} x {nb_cols}")
+    _check_bounds(matrix, 0, col)
+    for row in range(nb_rows):
+        set_cell(matrix, col, row, col_values[row])
+
+
+def replace_row(matrix, row, row_values):
+    """
+    replace row row with row_values
+
+    :param matrix: the matrix to modify
+    :type matrix: matrix
+    :param row: the column number
+    :type row: int
+    :param row: the list of value to use as replacement of row
+    :type row: list
+    """
+    nb_rows, nb_cols = size(matrix)
+    if len(row_values) != nb_cols:
+        raise RuntimeError(
+            f"the size of row_values {len(row_values)} does not fit "
+            f"matrix size {nb_rows} x {nb_cols}")
+    _check_bounds(matrix, row, 0)
+    for col in range(nb_cols):
+        set_cell(matrix, col, row, row_values[col])
+
+
+def to_str(matrix):
+    """
+    :param matrix: the matrix to represent as string
+    :type matrix: matrix
+    :return: a string representation of the matrix
+    :rtype: str
+    """
+    lines = []
+    nb_rows, nb_cols = size(matrix)
+    for row in range(nb_rows):
+        lines.append("\t".join([
+            str(val) for val in get_row(matrix, row)]))
+    return "\n".join(lines)
+
+
+if __name__ == '__main__':
+    m = create(5, 3)
+    print(m)
+    print(to_str(m))
+    set_cell(m, 0, 0, 1)
+    print(m)
+    print(to_str(m))
+    set_cell(m, 0, 2, 2)
+    print(m)
+    print(to_str(m))
+    set_cell(m, 4, 0, 12)
+    print(m)
+    print(to_str(m))
+    set_cell(m, 4, 2, 15)
+    print(m)
+    print(to_str(m))
+    print("get row 0",  get_row(m, 0))
+    print("get col 0", get_col(m, 0))
+
+    m2 = create(3, 2, 4)
+    mult_inplace(m2, 2)
+    print(to_str(m2))