diff --git a/linear_algebra/basic_operations/doc.txt b/linear_algebra/basic_operations/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f585bf653f76a9550102a1b6181cc99a649f4cab
--- /dev/null
+++ b/linear_algebra/basic_operations/doc.txt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de> 
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup basic_operations BASIC_OPERATIONS
+ * @ingroup  linear_algebra 
+ *
+ * @brief    Matrix basic operations
+ *
+ * @details  This module provides functions to perform basic matrix operations such as
+ *           matrix addition, multiplication, or transposition.
+ * 
+ * @author   Zakaria Kasmi
+ *
+ */
diff --git a/linear_algebra/basic_operations/include/matrix.h b/linear_algebra/basic_operations/include/matrix.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb2ae7cf33ba46a59cdd6c498f7863fae9d8bb79
--- /dev/null
+++ b/linear_algebra/basic_operations/include/matrix.h
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     basic_operations
+ * @{
+ *
+ * @file
+ * @brief       Matrix computations.
+ *
+ * @details     Matrix computations include operations such as addition,
+ *              subtraction, and transposition.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef MATRIX_H_
+#define MATRIX_H_
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/*!
+   \def matrix_t
+   @brief Define the data type of the matrix elements
+   @details The user can choose between a double or floating point arithmetic.
+ */
+//#define matrix_t float
+#ifndef matrix_t
+#define matrix_t double
+#endif
+
+/*!
+   \def MACHEPS
+   The upper bound on the relative error due to rounding in floating point arithmetic.
+ */
+#ifndef MACHEPS
+#define MACHEPS  2E-16
+#endif
+
+/*!
+   \def M_PI
+   Pi, the ratio of a circle's circumference to its diameter.
+ */
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+/**
+ * A structure to define the row and column number of a matrix.
+ */
+typedef struct {
+    uint8_t row_num;    /**< the row number */
+    uint8_t col_num;    /**< the column number */
+
+} matrix_dim_t;
+
+/**
+ * @brief   Initialize all the elements of the matrix with a specified value.
+ *
+ * @param[in]  m               row number of the matrix.
+ * @param[in]  n               column number of the matrix.
+ * @param[out] matrix[][]      pointer to the matrix.
+ * @param[in]  value           value to be set.
+ *
+ */
+void matrix_init(uint8_t m, uint8_t n, matrix_t matrix[m][n], matrix_t value);
+
+/**
+ * @brief   Clear all the elements of the vector.
+ *
+ * @param[in]  m               row number of the matrix.
+ * @param[in]  n               column number of the matrix.
+ * @param[out] matrix[][]      pointer to the matrix.
+ *
+ */
+void matrix_clear(uint8_t m, uint8_t n, matrix_t matrix[m][n]);
+
+/**
+ * @brief    Computes the transpose of a matrix.
+ *
+ * @param[in] m                 row number of the matrix.
+ * @param[in] n                 column number of the matrix.
+ * @param[in]  src_matrix[][]   pointer to the matrix to transpose.
+ * @param[out] dest_matrix[][]  pointer to the destination matrix.
+ *
+ */
+void matrix_transpose(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                      matrix_t dest_matrix[n][m]);
+
+/**
+ * @brief   Computes the in-place transpose of a matrix.
+ *          Transpose the matrix without auxiliary memory.
+ *
+ * @note    This function is limited to square matrices.
+ *
+ * @param[in] m               row and column number of the matrix.
+ * @param[in,out] matrix[][]  pointer to the matrix to transpose.
+ *
+ */
+void matrix_in_place_transpose(uint8_t m, matrix_t matrix[][m]);
+
+/**
+ * @brief   Copy the elements of a matrix to another matrix.
+ *
+ * @param[in] m                     row number of the matrix to copy.
+ * @param[in] n                     column number of the matrix to copy.
+ * @param[in] src_matrix[][]        pointer to the source matrix
+ * @param[out] dest_matrix[][]      pointer to the destination matrix.
+ *
+ */
+void matrix_copy(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                 matrix_t dest_matrix[m][n]);
+/**
+ * @brief   Copy a part of a matrix to another matrix or sub-matrix.
+ *          A part of the source matrix can be copied in a sub-part of
+ *          the destination matrix (sub-matrix). The source and destination
+ *          sub-matrices are limited by the row and column indices.
+ *
+ * @param[in] m                 row number of the source matrix.
+ * @param[in] n                 column number of the source matrix.
+ * @param[in] src_matrix[][]    pointer to the source matrix.
+ * @param[in] start_row_ind     the start index of the rows of the source sub-matrix.
+ * @param[in] end_row_ind       the end index of the rows of the source sub-matrix.
+ * @param[in] start_col_ind     the start index of the columns of the source sub-matrix.
+ * @param[in] end_col_ind       the end index of the columns of the source sub-matrix.
+ * @param[in] dest_row_num      the row number of the destination sub-matrix.
+ * @param[in] dest_col_num      the column number of the destination sub-matrix.
+ * @param[out] dest_matrix[][]  pointer to the destination (sub)-matrix.
+ *
+ */
+void matrix_part_copy(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                      uint8_t start_row_ind, uint8_t end_row_ind,
+                      uint8_t start_col_ind, uint8_t end_col_ind,
+                      uint8_t dest_row_num, uint8_t dest_col_num,
+                      matrix_t dest_matrix[][dest_col_num]);
+
+/**
+ * @brief   Compute the rank of a matrix.
+ *          The SVD must be previously invoked to get the singular values of
+ *          the matrix.
+ *
+ * @note    This function should be invoked after the call of the @ref svd method.
+ *
+ * @param[in] m                   row number of the source matrix.
+ * @param[in] n                   column number of the source matrix.
+ * @param[in] singl_values_arr[]  array containing the singular values of the
+ *                                matrix.
+ * @param[in] length              length of the singular values array.
+ *
+ * @return    the rank of the matrix.
+ *
+ */
+uint8_t matrix_get_rank(uint8_t m, uint8_t n, matrix_t singl_values_arr[],
+                        uint8_t length);
+
+/**
+ * @brief   Compute the addition of two matrices.
+ *          Add matrix B to matrix A and return the result in A_plus_B matrix.
+ *
+ * @param[in] m               row number of the matrix to add.
+ * @param[in] n               column number of the matrix to add.
+ * @param[in] A[][]           pointer to the first matrix.
+ * @param[in] B[][]           pointer to the second matrix.
+ * @param[out] A_plus_B[][]   pointer to the destination matrix.
+ *
+ */
+void matrix_add(uint8_t m, uint8_t n, matrix_t A[m][n], matrix_t B[m][n],
+                matrix_t A_plus_B[m][n]);
+
+/**
+ * @brief   Add a number to diagonal elements of a matrix.
+ *
+ * @param[in]     n            column number of the matrix.
+ * @param[in,out] A[][]        pointer to the matrix.
+ * @param[in]     diag_el_num  number of diagonal elements to overwrite.
+ * @param[in]     value        the value to add to the diagonal elements.
+ *
+ */
+void matrix_add_to_diag(uint8_t n, matrix_t A[][n], uint8_t diag_el_num,
+                        matrix_t value);
+
+/**
+ * @brief   Compute the subtraction of two matrices.
+ *          Subtract matrix B from matrix A and return the result in
+ *          A_minus_B matrix.
+ *
+ * @param[in] m               row number of the matrix to add.
+ * @param[in] n               column number of the matrix to add.
+ * @param[in] A[][]           pointer to the first matrix.
+ * @param[in] B[][]           pointer to the second matrix.
+ * @param[out] A_minus_B[][]  pointer to the destination matrix.
+ *
+ */
+void matrix_sub(uint8_t m, uint8_t n, matrix_t A[m][n], matrix_t B[m][n],
+                matrix_t A_minus_B[m][n]);
+
+/**
+ * @brief   Compute the multiplication of two matrices.
+ *
+ * @param[in]  a_line_num       row number of the first matrix.
+ * @param[in]  a_col_num        column number of the first matrix.
+ * @param[in]  a_matrix[][]     pointer to the first matrix.
+ * @param[in]  b_line_num       row number of the second matrix.
+ * @param[in]  b_col_num        column number of the second matrix.
+ * @param[in]  b_matrix[][]     pointer to the second matrix.
+ * @param[out] dest_matrix[][]  pointer to the destination matrix.
+ *
+ */
+void matrix_mul(uint8_t a_line_num, uint8_t a_col_num,
+                matrix_t a_matrix[a_line_num][a_col_num],
+                uint8_t b_line_num, uint8_t b_col_num,
+                matrix_t b_matrix[b_line_num][b_col_num],
+                matrix_t dest_matrix[a_line_num][b_col_num]);
+
+/**
+ * @brief   Compute the partial multiplication of two matrices.
+ *
+ * @details Enables the calculation of matrix product of parts of two matrices.
+ *
+ * @param[in]  a_col_num_max     column number of the first matrix.
+ * @param[in]  a_matrix[][]      pointer to the first matrix.
+ * @param[in]  b_col_num_max     column number of the second matrix.
+ * @param[in]  b_matrix[][]      pointer to the second matrix.
+ * @param[in]  a_start_row_ind   row begin of the first, partial matrix.
+ * @param[in]  a_end_row_ind     row end of the first, partial matrix.
+ * @param[in]  a_start_col_ind   column begin of the first, partial matrix.
+ * @param[in]  a_end_col_ind     column end of the first, partial matrix.
+ * @param[in]  b_start_row_ind   row begin of the second, partial matrix.
+ * @param[in]  b_end_row_ind     row end of the second, partial matrix.
+ * @param[in]  b_start_col_ind   column begin of the second, partial matrix.
+ * @param[in]  b_end_col_ind     column end of the second, partial matrix.
+ * @param[in]  dest_col_size     column size of the destination matrix.
+ * @param[out] dest_matrix[][]   pointer to the destination matrix.
+ */
+void matrix_part_mul(uint8_t a_col_num_max, matrix_t a_matrix[][a_col_num_max],
+                     uint8_t b_col_num_max, matrix_t b_matrix[][b_col_num_max],
+                     uint8_t a_start_row_ind, uint8_t a_end_row_ind,
+                     uint8_t a_start_col_ind, uint8_t a_end_col_ind,
+                     uint8_t b_start_row_ind, uint8_t b_end_row_ind,
+                     uint8_t b_start_col_ind, uint8_t b_end_col_ind,
+                     uint8_t dest_col_size,
+                     matrix_t dest_matrix[][dest_col_size]);
+
+/**
+ * @brief   Compute the multiplication of a matrix with a column vector.
+ *          Return Am,n * Vn,1 = Bm,1, where the A is a (mxn)-matrix, V is a
+ *          n-dimensional column vector, and the result is a m-dimensional
+ *          column vector.
+ *
+ * @param[in]  m              row number of the matrix to multiply.
+ * @param[in]  n              column number of the matrix to multiply.
+ * @param[in]  matrix[][]     pointer to the matrix.
+ * @param[in]  vec            pointer to the n-dimensional column vector.
+ * @param[out] dst_arr        pointer to the destination m-dimensional column
+ *                            vector.
+ *
+ */
+void matrix_mul_vec(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                    matrix_t vec[n], matrix_t dst_arr[m]);
+
+//A'(n,m)*b(m,1) = c(n,1)
+/**
+ * @brief   Compute the multiplication of transposed matrix with column vector.
+ * @details Transpose A and return A'n,m * Vm,1 = Bn,1, where A is a
+ *          (mxn)-matrix, V is a m-dimensional column vector, and the result is
+ *          a n-dimensional column vector.
+ *
+ * @param[in]  m              row number of the matrix to transpose and multiply.
+ * @param[in]  n              column number of the matrix to transpose and multiply.
+ * @param[in]  A[][]          pointer to the matrix.
+ * @param[in]  b_size         size of the column vector.
+ * @param[in]  b_vec[]        pointer to the column vector of m-dimension.
+ * @param[out] c_vec[]        pointer to the destination, column vector of n-dimension.
+ *
+ */
+void matrix_trans_mul_vec(uint8_t m, uint8_t n, matrix_t A[m][n],
+                          uint8_t b_size, matrix_t b_vec[m], matrix_t c_vec[n]);
+
+
+/**
+ * @brief   Compute the multiplication of a column and row vector.
+ *          Return Cm,1 * R1,n = Mm,n, where C is a m-dimensional column vector,
+ *          R is a n-dimensional row vector, and the result is a (mxn)-matrix.
+ *
+ * @param[in]  m                row number of the column vector.
+ * @param[in]  col_vec[]        pointer to the column vector.
+ * @param[in]  n                column number of the row vector.
+ * @param[in]  row_vec[]        pointer to the row vector.
+ * @param[in]  max_n            column number of the result matrix.
+ * @param[out] res_mat[][]      pointer to the (mxn) result matrix.
+ *
+ */
+void matrix_mul_col_vec_row_vec(uint8_t m, matrix_t col_vec[m], uint8_t n,
+                                matrix_t row_vec[n], uint8_t max_n,
+                                matrix_t res_mat[][max_n]);
+
+
+/**
+ * @brief   Compute the multiplication of row vector and a matrix.
+ *          Return R1,m * Am,n = R1,n, where R is a m-dimensional row vector,
+ *          A is a (mxn)-matrix, and the result is a row vector of n-dimension.
+ *
+ * @param[in]  m              size of the row vector and row number of the
+ *                            matrix.
+ * @param[in]  n              column number of the matrix.
+ * @param[in]  vec[]          pointer to the row vector.
+ * @param[in]  matrix[][]     pointer to the matrix.
+ * @param[out] dst_arr        pointer to the destination row vector of
+ *                            n-dimension.
+ *
+ */
+void matrix_vec_mul_matr(uint8_t m, uint8_t n, matrix_t vec[m],
+                         matrix_t matrix[m][n], matrix_t dst_arr[n]);
+
+
+/**
+ * @brief   Compute the multiplication of a scalar with row vector and a matrix.
+ *          Return scal*R1,m * Am,n = R1,n, where scal is a scalar, R is a
+ *          m-dimensional row vector, A is a (mxn)-matrix, and the result is a
+ *          row vector of n-dimension.
+ *
+ * @param[in]  m              size of the row vector and row number of the
+ *                            matrix.
+ * @param[in]  n              column number of the matrix.
+ * @param[in]  scalar         scalar value.
+ * @param[in]  vec[]          pointer to the row vector.
+ * @param[in]  matrix[][]     pointer to the matrix.
+ * @param[out] dst_arr        pointer to the destination row vector of
+ *                            n-dimension.
+ *
+ */
+void matrix_mul_scalar_vec_matr(uint8_t m, uint8_t n, matrix_t scalar,
+                                matrix_t vec[m], matrix_t matrix[m][n],
+                                matrix_t dst_arr[n]);
+
+
+/**
+ * @brief   Compute the multiplication of the transpose of a matrix with itself.
+ *          Transpose the matrix A and multiply it with the matrix A: A'*A.
+ *
+ * @param[in]  m              row number of the matrix.
+ * @param[in]  n              column number of the matrix.
+ * @param[in]  A[][]          pointer to the matrix.
+ * @param[out] AT_mul_A[][]   pointer to the destination matrix (A'*A).
+ *
+ */
+void matrix_trans_mul_itself(uint8_t m, uint8_t n, matrix_t A[m][n],
+                             matrix_t AT_mul_A[n][n]);
+
+/**
+ * @brief   Set all the diagonal elements of a matrix with a specified value.
+ *
+ * @param[in]     m                 row number of the matrix.
+ * @param[in]     n                 column number of the matrix.
+ * @param[in]     value             value to be set.
+ * @param[in,out] diag_matrix[][]   pointer to the matrix.
+ *
+ */
+void matrix_set_diag_elements(uint8_t m, uint8_t n, matrix_t value,
+                              matrix_t diag_matrix[m][n]);
+
+/**
+ * @brief   Set all the diagonal elements of a matrix with values that are saved
+ *          in a vector.
+ *
+ * @param[in]     m                 row number of the matrix.
+ * @param[in]     n                 column number of the matrix.
+ * @param[in,out] diag_matrix[][]   pointer to the matrix.
+ * @param[in]     length            size of the vector.
+ * @param[in]     vec               pointer to the vector containing diagonal
+ *                                  elements.
+ *
+ */
+void matrix_get_diag_mat_new(uint8_t m, uint8_t n, matrix_t diag_matrix[m][n],
+                             uint8_t length, matrix_t vec[]);
+
+/**
+ * @brief   Create a diagonal matrix with a specified value.
+ *
+ * @param[in]     m                 row number of the matrix.
+ * @param[in]     n                 column number of the matrix.
+ * @param[in]     value             value of the diagonal elements.
+ * @param[in,out] diag_matrix[][]   pointer to the diagonal matrix.
+ *
+ */
+void matrix_get_diag_mat(uint8_t m, uint8_t n, matrix_t value,
+                         matrix_t diag_matrix[m][n]);
+
+/**
+ * @brief   Multiply all elements of a matrix with a specified value.
+ *
+ * @param[in]     m                 row number of the matrix.
+ * @param[in]     n                 column number of the matrix.
+ * @param[in]     mat_src           pointer to the source matrix.
+ * @param[in]     value             multiplication factor.
+ * @param[out]    mat_dest[][]      pointer to the destination matrix.
+ *
+ */
+void matrix_mul_scalar(uint8_t m, uint8_t n, matrix_t mat_src[m][n],
+                       matrix_t value, matrix_t mat_dest[m][n]);
+
+/**
+ * @brief   Get a column of a matrix.
+ *
+ * @param[in]   m             row number of the matrix.
+ * @param[in]   n             column number of the matrix.
+ * @param[in]   matrix[][]    pointer to the matrix.
+ * @param[in]   col_num       number of the requested column.
+ * @param[out]  col_vec[]     pointer to the column vector.
+ *
+ */
+void matrix_get_column_vec(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                           uint8_t col_num, matrix_t col_vec[m]);
+
+/**
+ * @brief   Get a part of a column of a matrix.
+ *
+ * @param[in]   max_m             row number of the matrix.
+ * @param[in]   max_n             column number of the matrix.
+ * @param[in]   matrix[][]        pointer to the matrix.
+ * @param[in]   col_num           number of the requested column.
+ * @param[in]   offset            points to the start position of the column vector.
+ * @param[out]  col_vec[]         pointer to the column vector.
+ *
+ */
+void matrix_get_part_column_vec(uint8_t max_m, uint8_t max_n,
+                                matrix_t matrix[max_m][max_n], uint8_t col_num,
+                                uint8_t offset,
+                                matrix_t col_vec[max_m - offset]);
+
+/**
+ * @brief   Get the largest element of a column vector in a matrix.
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] matrix[][]      pointer to the matrix.
+ * @param[in] col_num         column number.
+ *
+ * @return    the largest element of a column.
+ *
+ */
+matrix_t matrix_get_max_elem_in_column(uint8_t m, uint8_t n,
+                                       matrix_t matrix[m][n], uint8_t col_num);
+
+/**
+ * @brief   Get the maximum absolute value of a column vector in a matrix.
+ *
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] matrix[][]      pointer to the matrix.
+ * @param[in] col_num         column number.
+ *
+ * @return    the maximum absolute value of a column.
+ *
+ */
+matrix_t matrix_get_abs_max_elem_in_column(uint8_t m, uint8_t n,
+                                           matrix_t matrix[m][n],
+                                           uint8_t col_num);
+
+/**
+ * @brief   Get the largest element of a column vector in a sub-matrix.
+ *
+ * @param[in] max_m           total row number of the matrix.
+ * @param[in] max_n           total column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ * @param[in] row_num         row number of the sub-matrix.
+ * @param[in] col_num         column number of the sub-matrix.
+ *
+ * @return    the largest element of a partial column.
+ *
+ */
+matrix_t matrix_get_max_elem_in_part_column(uint8_t max_m, uint8_t max_n,
+                                            matrix_t matrix[max_m][max_n],
+                                            uint8_t row_num, uint8_t col_num);
+
+/**
+ * @brief   Get the maximum absolute value of a column vector in a sub-matrix.
+ *
+ * @param[in] max_m           total row number of the matrix.
+ * @param[in] max_n           total column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ * @param[in] row_num         row number of the sub-matrix.
+ * @param[in] col_num         column number of the sub-matrix.
+ *
+ * @return    the maximum absolute value of a partial column.
+ *
+ */
+matrix_t matrix_get_abs_max_elem_in_part_column(uint8_t max_m, uint8_t max_n,
+                                                matrix_t matrix[max_m][max_n],
+                                                uint8_t row_num,
+                                                uint8_t col_num);
+
+/**
+ * @brief   Get the maximum absolute value and its position in a column vector in a sub-matrix.
+ *
+ * @param[in]  max_m            total row number of the matrix.
+ * @param[in]  max_n            total column number of the matrix.
+ * @param[in]  matrix[][]       pointer to the entire matrix.
+ * @param[in]  row_num          row number of the sub-matrix.
+ * @param[in]  col_num          column number of the sub-matrix.
+ * @param[out] index            pointer to the variable holding the position of the maximum absolute
+ *                              value in the column vector of the sub-matrix.
+ *
+ * @return    the maximum absolute value of a partial column.
+ *
+ */
+matrix_t matrix_get_abs_max_elem_and_index_in_part_column(uint8_t max_m,
+                                                          uint8_t max_n,
+                                                          matrix_t matrix[max_m][max_n],
+                                                          uint8_t row_num, uint8_t col_num,
+                                                          uint8_t *index);
+/**
+ * @brief    Swaps two rows of a matrix.
+ * @details  Swaps the rows i and j of a matrix.
+ *
+ * @param[in]  n                column number of the matrix.
+ * @param[in]  matrix[][]       pointer to the matrix.
+ * @param[in]  i                the i-the row of the matrix.
+ * @param[in]  j                the j-the row of the matrix.
+ *
+ */
+void matrix_swap_rows(uint8_t n, matrix_t matrix[][n], uint8_t i, uint8_t j);
+
+/**
+ * @brief    Swaps two rows of a sub-matrix.
+ * @details  Swaps the rows i and j of a part of a matrix.
+ *
+ * @param[in]  n                column number of the entire matrix.
+ * @param[in, out]  matrix[][]  pointer to the entire matrix.
+ * @param[in]  i                the i-the row of the sub-matrix.
+ * @param[in]  j                the j-the row of the sub-matrix.
+ * @param[in]  col_begin        the column begin of the sub-matrix.
+ * @param[in]  col_end          the column end of the sub-matrix.
+ *
+ */
+void matrix_part_swap_rows(uint8_t n, matrix_t matrix[][n], uint8_t i,
+                           uint8_t j, uint8_t col_begin,
+                           uint8_t col_end);
+/**
+ * @brief   Get the 2-norm of a matrix that is equal to the largest singular value.
+ *
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] A[][]           pointer to the matrix.
+ *
+ * @return     the 2-norm of a matrix.
+ *
+ */
+double matrix_get_two_norm(uint8_t m, uint8_t n, matrix_t A[][n]);
+
+/**
+ * @brief   Get the Frobenius norm of a matrix.
+ *
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] A[][]           pointer to the matrix.
+ *
+ * @return     the Frobenius norm a matrix.
+ *
+ */
+double matrix_get_frob_norm(uint8_t m, uint8_t n, matrix_t A[][n]);
+
+/**
+ * @brief    Computes the inverse an upper triangular matrix.
+ *
+ * @param[in]     m           row number of the matrix.
+ * @param[in]     n           column number of the matrix.
+ * @param[in]     U[][]       pointer to the upper triangular matrix.
+ * @param[out]    inv_U[][]   pointer to the inverse matrix.
+ *
+ */
+void matrix_get_inv_upp_triang(uint8_t m, uint8_t n, matrix_t U[][n],
+                               matrix_t inv_U[][m]);
+/**
+ * @brief    Computes the inverse a lower triangular matrix.
+ *
+ * @param[in]     m           row number of the matrix.
+ * @param[in]     n           column number of the matrix.
+ * @param[in]     L[][]       pointer to the matrix.
+ * @param[out]    inv_L[][]   pointer to the inverse matrix.
+ *
+ */
+void matrix_get_inv_low_triang(uint8_t m, uint8_t n, matrix_t L[][n],
+                               matrix_t inv_L[][m]);
+/**
+ * @brief    Gets the upper triangular part of a matrix.
+ *
+ * @param[in]     m             row number of the matrix.
+ * @param[in]     n             column number of the matrix.
+ * @param[in]     A[][]         pointer to the matrix.
+ * @param[out]    tr_up_A[][]   pointer to the upper triangular part of the matrix.
+ *
+ */
+void matrix_get_upp_triang(uint8_t m, uint8_t n, matrix_t A[][n],
+                           matrix_t tr_up_A[][n]);
+/**
+ * @brief    Gets the lower triangular part of a matrix.
+ *
+ * @param[in]     m              row number of the matrix.
+ * @param[in]     n              column number of the matrix.
+ * @param[in]     A[][]          pointer to the matrix.
+ * @param[out]    tr_low_A[][]   pointer to the lower triangular part of the matrix.
+ *
+ */
+void matrix_get_low_triang(uint8_t m, uint8_t n, matrix_t A[][n],
+                           matrix_t tr_low_A[][n]);
+
+/**
+ * @brief   Display the values of the matrix elements.
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ *
+ */
+void matrix_print(uint8_t m, uint8_t n, matrix_t matrix[m][n]);
+
+/**
+ * @brief   Display the values of the sub-matrix elements.
+ *
+ * @param[in] m               total row number of the matrix.
+ * @param[in] n               total column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ * @param[in] start_row_ind   start row number of the sub-matrix.
+ * @param[in] end_row_ind     end row number of the sub-matrix.
+ * @param[in] start_col_ind   start column number of the sub-matrix.
+ * @param[in] end_col_ind     end column number of the sub-matrix.
+ *
+ */
+void matrix_part_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                       uint8_t start_row_ind, uint8_t end_row_ind,
+                       uint8_t start_col_ind, uint8_t end_col_ind);
+
+/**
+ * @brief   Display the values of the matrix elements.
+ *          This function allows the user to determine the precision as well as
+ *          the with of the numbers to display.
+ *
+ * @note    This function is more memory-consuming than @ref matrix_print.
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ * @param[in] before_dec      the number of digits to be printed before the
+ *                            decimal point.
+ * @param[in] after_dec       the number of digits to be printed after the
+ *                            decimal point.
+ *
+ */
+void matrix_flex_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                       uint8_t before_dec, uint8_t after_dec);
+
+
+/**
+ * @brief   Display the values of the sub-matrix elements.
+ *          This function allows the user to determine the precision as well as
+ *          the with of the numbers to display.
+ *
+ * @note    This function is more memory-consuming than @ref matrix_part_print.
+ *
+ * @param[in] m               total row number of the matrix.
+ * @param[in] n               total column number of the matrix.
+ * @param[in] matrix[][]      pointer to the entire matrix.
+ * @param[in] start_row_ind   start row number of the sub-matrix.
+ * @param[in] end_row_ind     end row number of the sub-matrix.
+ * @param[in] start_col_ind   start column number of the sub-matrix.
+ * @param[in] end_col_ind     end column number of the sub-matrix.
+ * @param[in] before_dot      the number of digits to be printed before the
+ *                            decimal point.
+ * @param[in] after_dot       the number of digits to be printed after the
+ *                            decimal point.
+ *
+ */
+void matrix_flex_part_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                            uint8_t start_row_ind, uint8_t end_row_ind,
+                            uint8_t start_col_ind, uint8_t end_col_ind,
+                            uint8_t before_dot, uint8_t after_dot);
+
+
+/**
+ * @brief     Compute the multiplication of a scalar with row vector and a
+ *            sub-matrix.
+ * @details   Return scal*R1,m * Am,n = R1,n, where scal is a scalar, R is a
+ *            m-dimensional row vector, A is a (mxn)-matrix, and the result is a
+ *            row vector of n-dimension.
+ *
+ * @param[in]  max_m          size of the row vector and row number of the
+ *                            matrix.
+ * @param[in]  max_n          column number of the matrix.
+ * @param[in]  scalar         scalar value.
+ * @param[in]  vec[]          pointer to the row vector.
+ * @param[in]  matrix[][]     pointer to the matrix.
+ * @param[in] begin_row       start row number of the sub-matrix.
+ * @param[in] begin_column    start column number of the sub-matrix.
+ * @param[out] dst_arr        pointer to the destination row vector of n-dimension.
+ *
+ */
+void matrix_part_mul_scalar_vec_matr(uint8_t max_m, uint8_t max_n,
+                                     matrix_t scalar, matrix_t vec[max_m],
+                                     matrix_t matrix[max_m][max_n],
+                                     uint8_t begin_row, uint8_t begin_column,
+                                     matrix_t dst_arr[max_n - begin_row]);
+
+/**
+ * @brief   Get the value of a matrix at the position (i,j).
+ *
+ *
+ * @param[in] m               row number of the matrix.
+ * @param[in] n               column number of the matrix.
+ * @param[in] matrix[][]      pointer to the matrix.
+ * @param[in] i               row number.
+ * @param[in] j               column number.
+ *
+ * @return     the value of the matrix at the row i and column j.
+ *
+ */
+matrix_t matrix_read(uint8_t m, uint8_t n, matrix_t matrix[m][n], uint8_t i,
+                     uint8_t j);
+/**
+ * @brief   Write a value in a matrix at the position (i,j).
+ *
+ *
+ * @param[in]      m               row number of the matrix.
+ * @param[in]      n               column number of the matrix.
+ * @param[out]     matrix[][]      pointer to the matrix.
+ * @param[in] i                    row number.
+ * @param[in] j                    column number.
+ * @param[in] val                  value to write in the matrix.
+ *
+ */
+void matrix_write(uint8_t m, uint8_t n, matrix_t matrix[m][n], uint8_t i,
+                  uint8_t j, matrix_t val);
+
+#endif /* MATRIX_H_ */
diff --git a/linear_algebra/basic_operations/include/vector.h b/linear_algebra/basic_operations/include/vector.h
new file mode 100644
index 0000000000000000000000000000000000000000..64b1295cf574b99d22cddda3991b51b14f468c13
--- /dev/null
+++ b/linear_algebra/basic_operations/include/vector.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     basic_operations
+ * @{
+ *
+ * @file
+ * @brief       Vector computations.
+ * @details     Vector computations include operations such as addition,
+ *              subtraction, and inner product (dot product).
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef VECTOR_H_
+#define VECTOR_H_
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/** @brief   Define the data type of the vector elements */
+//#define vector_t float
+#ifndef vector_t
+#define vector_t double
+#endif
+
+/**
+ * @brief   Clear all the elements of the vector.
+ *
+ * @param[in] size            size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ */
+void vector_clear(uint8_t size, vector_t arr[]);
+
+/**
+ * @brief   Copy the elements of the source vector to the destination vector.
+ *
+ * @param[in] size            number of elements to copy.
+ * @param[in] src_arr[]       pointer to the source vector.
+ * @param[in] dest_arr[]      pointer to the destination vector.
+ *
+ */
+void vector_copy(uint8_t size, vector_t src_arr[], vector_t dest_arr[]);
+
+/**
+ * @brief   Clear all the elements of the vector.
+ *
+ * @param[in] size            size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ */
+void vector_clear(uint8_t size, vector_t arr[]);
+
+/**
+ * @brief   Compute the 2-norm norm of a vector.
+ *
+ * @param[in] length          size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ * @return    the 2-norm of the vector.
+ *
+ */
+vector_t vector_get_norm2(uint8_t length, vector_t arr[]);
+
+/**
+ * @brief   Compute the squared 2-norm norm of a vector .
+ *
+ * @param[in] length          size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ * @return    the squared 2-norm of the vector.
+ *
+ */
+vector_t vector_get_square_norm2(uint8_t length, vector_t arr[]);
+
+/**
+ * @brief   Compute the sum of the elements of a vector.
+ *
+ * @param[in] length          size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ * @return    the sum of the elements of the vector.
+ *
+ */
+vector_t vector_get_sum(uint8_t length, vector_t arr[]);
+
+/**
+ * @brief   Compute the average or mean value of a vector.
+ *
+ * @param[in] length          size of the vector.
+ * @param[in] arr[]           pointer to the vector.
+ *
+ * @return    the mean value of the vector.
+ *
+ */
+vector_t vector_get_mean_value(uint8_t length, vector_t arr[]);
+
+/**
+ * @brief   Compute the subtraction of two vectors.
+ *          Substact b_vec from a_vec and return the result in a_minus_b.
+ *
+ * @param[in]  size           number of elements to subtract.
+ * @param[in]  a_vec[]        pointer to the first vector.
+ * @param[in]  b_vec[]        pointer to the second vector.
+ * @param[out] a_minus_b[]    pointer to the destination vector.
+ *
+ */
+void vector_sub(uint8_t size, vector_t a_vec[], vector_t b_vec[],
+                vector_t a_minus_b[]);
+
+/**
+ * @brief   Compute the addition of two vectors.
+ *          Add b_vec to a_vec and return the result in a_plus_b.
+ *
+ * @param[in]  size           number of elements to subtract.
+ * @param[in]  a_vec[]        pointer to the first vector.
+ * @param[in]  b_vec[]        pointer to the second vector.
+ * @param[out] a_plus_b_vec[]     pointer to the destination vector.
+ *
+ */
+void vector_add(uint8_t size, vector_t a_vec[size], vector_t b_vec[size],
+                vector_t a_plus_b_vec[size]);
+/**
+ * @brief   Compute the multiplication of two vectors.
+ *          Multiple vectors a_vec and b_vec element by element and return
+ *          the result in a_mul_b.
+ *
+ * @param[in]  size           number of elements to multiply.
+ * @param[in]  a_vec[]        pointer to the first vector.
+ * @param[in]  b_vec[]        pointer to the second vector.
+ * @param[out] a_mul_b_vec[]  pointer to the destination vector.
+ *
+ */
+void vector_mul(uint8_t size, vector_t a_vec[size], vector_t b_vec[size],
+                vector_t a_mul_b_vec[size]);
+
+/**
+ * @brief   Compute the square of a vector.
+ *          Square the elements of vector vec and return the result in
+ *          square_vec.
+ *
+ * @param[in]  n              number of elements to square.
+ * @param[in]  vec[]          pointer to the source vector.
+ * @param[out] square_vec[]   pointer to the destination vector.
+ *
+ */
+void vector_square(uint8_t n, vector_t vec[n], vector_t square_vec[n]);
+
+/**
+ * @brief   Compute the product of a vector with a real number.
+ *          Multiple the elements of a vector with a scalar and return the
+ *          result in the vector itself.
+ *
+ * @param[in]       size      number of elements to multiply with a scalar.
+ * @param[in, out]  a_vec[]   pointer to the source/destination vector.
+ * @param[in]       scl       a scalar.
+ *
+ */
+void vector_in_place_scalar_mul(uint8_t size, vector_t a_vec[size],
+                                vector_t scl);
+
+/**
+ * @brief   Compute the product of a vector with a real number.
+ *          Multiple the elements of a vector with a scalar and return the
+ *          result in other vector.
+ *
+ * @param[in]       size          number of elements to multiply with a scalar.
+ * @param[in]       src_vec[]     pointer to the source vector.
+ * @param[in]       scl           a scalar.
+ * @param[out]      dest_vec      pointer to the destination vector.
+ *
+ */
+void vector_scalar_mul(uint8_t size, vector_t src_vec[size], vector_t scl,
+                       vector_t dest_vec[]);
+
+/**
+ * @brief   Compute the division of a vector with a real number.
+ *          Divide the elements of a vector with a scalar and return the
+ *          result in the vector itself.
+ *
+ * @param[in]       size      number of elements to divide with a scalar.
+ * @param[in, out]  a_vec[]   pointer to the source/destination vector.
+ * @param[in]       scl       a scalar.
+ *
+ */
+void vector_scalar_div(uint8_t size, vector_t a_vec[size], vector_t scl);
+
+//Euclidean distance: d = sum((x-y).^2).^0.5
+
+/**
+ * @brief   Compute the Euclidean distance between two vectors.
+ *
+ * @param[in] length          size of the vector.
+ * @param[in] vec1[]          pointer to the first vector.
+ * @param[in] vec2[]          pointer to the second vector.
+ *
+ * @return    the Euclidean distance.
+ *
+ */
+vector_t vector_get_euclidean_distance(uint8_t length, vector_t vec1[],
+                                       vector_t vec2[]);
+/**
+ * @brief   Compute the dot product of two vectors.
+ *
+ * @param[in] n               size of the vectors.
+ * @param[in] vec1[]          pointer to the first vector.
+ * @param[in] vec2[]          pointer to the second vector.
+ *
+ * @return    the scalar product of two vectors.
+ *
+ */
+vector_t vector_get_scalar_product(uint8_t n, vector_t vec1[n],
+                                   vector_t vec2[n]);
+
+/**
+ * @brief   Determine the equality of two vectors.
+ *
+ * @param[in] length       size of the vector.
+ * @param[in] vec_1[]      pointer to the first vector.
+ * @param[in] vec_2[]      pointer to the second vector.
+ *
+ * @return true, if the two vectors are equal.
+ * @return false, if not.
+ *
+ */
+bool vector_is_equal(uint16_t length, vector_t vec_1[], vector_t vec_2[]);
+
+/**
+ * @brief   Determine the equality of two vectors of type uint32_t.
+ *
+ * @param[in] length           size of the vector.
+ * @param[in] vec_1[]          pointer to the first vector.
+ * @param[in] vec_2[]          pointer to the second vector.
+ *
+ * @return true, if the two vectors are equal.
+ * @return false, if not.
+ *
+ */
+bool vector_uint32_is_equal(uint32_t length, uint32_t vec_1[], uint32_t vec_2[]);
+
+/**
+ * @brief   Determine the index of the vector elements before sorting.
+ *          Determine the index of the elements of a sorted vector. These
+ *          indices correspond to the positions of the elements in the unsorted
+ *          vector.
+ *
+ * @param[in]  k                  size of the unsorted vector.
+ * @param[in]  n                  size of the sorted vector.
+ * @param[in]  unsorted_vector[]  pointer to the unsorted vector.
+ * @param[in]  sorted_vector[]    pointer to the sorted vector.
+ * @param[out] index_vector[]     pointer to the index vector.
+ *
+ */
+void vector_get_index_vector(uint8_t k, uint8_t n, vector_t unsorted_vector[n],
+                             vector_t sorted_vector[n], uint8_t index_vector[n]);
+
+/**
+ * @brief   Compute the maximal value and its index of a vector.
+ *
+ *
+ * @param[in]  length  vector size.
+ * @param[in]  vec[]   pointer to the vector.
+ * @param[in]  index   pointer to the index.
+ *
+ * @return     the maximal value of the vector.
+ *
+ */
+vector_t vector_get_max_and_index(uint8_t length, vector_t vec[],
+                                  uint8_t *index);
+
+/**
+ * @brief   Compute the residual of two vectors.
+ *
+ *
+ * @param[in]  length       vector size.
+ * @param[in]  a_vec[]      pointer to the first vector.
+ * @param[in]  b_vec[]      pointer to the second vector.
+ *
+ * @return     the residual of the two vectors.
+ *
+ */
+vector_t vector_get_residual(uint8_t length, vector_t a_vec[], vector_t b_vec[]);
+
+/**
+ * @brief   Get the elements of the vector by an index vector.
+ *
+ * @param[in]  src_vec[]    pointer to source vector.
+ * @param[in]  k            size of the index vector.
+ * @param[in]  index_vec[]  pointer to the index vector.
+ * @param[out] dst_vec[]    pointer to the destination vector
+ *
+ */
+void vector_get_elements(vector_t src_vec[], uint8_t k, uint8_t index_vec[],
+                         vector_t dst_vec[]);
+
+/**
+ * @brief   Display the values of the vector's elements.
+ *
+ * @param[in] length  size of the vector to display.
+ * @param[in] arr     pointer to the vector.
+ *
+ */
+void vector_print(uint32_t length, vector_t arr[]);
+
+/**
+ * @brief   Display the values of the vector's elements of type uint8_t.
+ *
+ * @param[in] length          size of the vector to display.
+ * @param[in] arr             pointer to the vector.
+ *
+ */
+void vector_print_u8_array(uint32_t length, uint8_t arr[]);
+
+/**
+ * @brief   Display the values of the vector's elements.
+ *          This function allows the user to determine the precision as well as
+ *          the with of the numbers to display.
+ *
+ * @param[in] length          size of the vector to display.
+ * @param[in] arr             pointer to the vector.
+ * @param[in] before_dot      the number of digits to be printed before the
+ *                            decimal point.
+ * @param[in] after_dot       the number of digits to be printed after the
+ *                            decimal point.
+ *
+ */
+void vector_flex_print(uint32_t length, vector_t arr[], uint8_t before_dot,
+                       uint8_t after_dot);
+
+#endif /* VECTOR_H_ */
diff --git a/linear_algebra/basic_operations/matrix.c b/linear_algebra/basic_operations/matrix.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9475df58bc540b5cb012312306545f4fa6eb9fb
--- /dev/null
+++ b/linear_algebra/basic_operations/matrix.c
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Matrix computations.
+ *
+ * @details     Matrix computations include operations such as addition,
+ *              subtraction, and transposition.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <float.h>
+
+#include "matrix.h"
+#include "utils.h"
+#include "svd.h"
+
+static int32_t max(int32_t a, int32_t b)
+{
+    if (a > b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+void matrix_clear(uint8_t m, uint8_t n, matrix_t matrix[m][n])
+{
+    memset(matrix, 0, sizeof(matrix[0][0]) * m * n);
+}
+
+void matrix_init(uint8_t m, uint8_t n, matrix_t matrix[m][n], matrix_t value)
+{
+    memset(matrix, value, sizeof(matrix[0][0]) * m * n);
+}
+
+void matrix_transpose(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                      matrix_t dest_matrix[n][m])
+{
+    int i, j;
+
+    for (i = 0; i < m; i++) {
+        for (j = 0; j < n; j++) {
+            dest_matrix[j][i] = src_matrix[i][j];
+        }
+    }
+}
+
+
+void matrix_in_place_transpose(uint8_t m, matrix_t matrix[][m])
+{
+    uint8_t i, j;
+    matrix_t tmp;
+
+    for (i = 0; i < m; i++) {
+        for (j = i + 1; j < m; j++) {
+            tmp = matrix[i][j];
+            matrix[i][j] = matrix[j][i];
+            matrix[j][i] = tmp;
+        }
+    }
+}
+
+void matrix_copy(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                 matrix_t dest_matrix[m][n])
+{
+    memcpy(dest_matrix, src_matrix, sizeof(matrix_t) * m * n);
+}
+
+void matrix_part_copy(uint8_t m, uint8_t n, matrix_t src_matrix[m][n],
+                      uint8_t start_row_ind, uint8_t end_row_ind,
+                      uint8_t start_col_ind, uint8_t end_col_ind,
+                      uint8_t dest_row_num, uint8_t dest_col_num,
+                      matrix_t dest_matrix[][dest_col_num])
+{
+    int16_t i, j;
+
+    if ((end_row_ind > start_row_ind) && (end_col_ind > start_col_ind)) {
+        for (i = start_row_ind;
+             (i <= end_row_ind)
+             && ((i - start_row_ind)
+                 < dest_row_num);
+             i++) {
+            for (j = start_col_ind;
+                 (j <= end_col_ind)
+                 && ((j - start_col_ind)
+                     < dest_col_num);
+                 j++) {
+                dest_matrix[i - start_row_ind][j - start_col_ind] =
+                    src_matrix[i][j];
+            }
+        }
+    }
+    else {
+        //copy one element
+        if ((start_row_ind == end_row_ind)
+            && (start_col_ind == end_col_ind)) {
+
+            dest_matrix[start_row_ind][start_row_ind] =
+                src_matrix[start_row_ind][start_row_ind];
+        }
+        //copy a row vector of the matrix
+        else if (start_row_ind == end_row_ind) {
+            i = 0;
+            for (j = start_col_ind; j <= end_col_ind; j++) {
+                dest_matrix[start_row_ind][i++] =
+                    src_matrix[start_row_ind][j];
+            }
+        }
+        //copy a column vector of the matrix
+        else if (start_col_ind == end_col_ind) {
+            j = 0;
+            for (i = start_row_ind; i <= end_row_ind; i++) {
+                dest_matrix[j++][start_col_ind] =
+                    src_matrix[i][start_col_ind];
+            }
+        }
+    }
+}
+
+
+void matrix_print(uint8_t m, uint8_t n, matrix_t matrix[m][n])
+{
+    int i, j;
+
+    puts("{");
+    for (i = 0; i < m; i++) {
+        printf("{");
+        for (j = 0; j < n; j++) {
+            printf("%7.4f", matrix[i][j]);
+            if (j < n - 1) {
+                printf(", ");
+            }
+        }
+        printf("}");
+        if (i < m - 1) {
+            printf(", ");
+        }
+        puts("");
+    }
+    printf("}");
+}
+
+
+void matrix_part_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                       uint8_t start_row_ind, uint8_t end_row_ind,
+                       uint8_t start_col_ind, uint8_t end_col_ind)
+{
+    int16_t i, j;
+
+    if ((end_row_ind > start_row_ind) && (end_col_ind > start_col_ind)) {
+        puts("{");
+        for (i = start_row_ind; i <= end_row_ind; i++) {
+            printf("{");
+            for (j = start_col_ind; j <= end_col_ind; j++) {
+                printf("%7.4f", matrix[i][j]);
+                if (j < end_col_ind) {
+                    printf(", ");
+                }
+            }
+            printf("}");
+            if (i < end_row_ind) {
+                printf(", ");
+            }
+            puts("");
+        }
+        printf("}");
+    }
+    else {
+        //print only one element of the matrix
+        if ((start_row_ind == end_row_ind)
+            & (start_col_ind == end_col_ind)) {
+
+            printf("{%3.4f}", matrix[start_row_ind][start_col_ind]);
+        }
+        // print row vector of the matrix
+        else if (start_row_ind == end_row_ind) {
+            printf("{");
+            for (j = start_col_ind; j <= end_col_ind; j++) {
+                printf("%3.4f", matrix[start_row_ind][j]);
+                if (j < end_col_ind) {
+                    printf(", ");
+                }
+            }
+            printf("}");
+        }
+        // print column vector of the matrix
+        else if (start_col_ind == end_col_ind) {
+            puts("{");
+            for (i = start_row_ind; i <= end_row_ind; i++) {
+                printf("%3.4f", matrix[i][start_col_ind]);
+                if (i < end_row_ind) {
+                    printf(",\n");
+                }
+            }
+            printf("}");
+        }
+    }
+}
+
+void matrix_flex_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                       uint8_t before_dot, uint8_t after_dot)
+{
+    uint16_t i, j;
+    char format_str_buff[13];
+
+    sprintf(format_str_buff, "%%%u.%uf", before_dot, after_dot);
+
+    puts("{");
+    for (i = 0; i < m; i++) {
+        printf("%11s", "{");
+        for (j = 0; j < n; j++) {
+            utils_printf(format_str_buff, matrix[i][j]);
+            if (j < n - 1) {
+                printf(", ");
+            }
+        }
+        printf("}");
+        if (i < m - 1) {
+            printf(", ");
+        }
+        puts("");
+    }
+    printf("%7s\n", "};");
+}
+
+
+void matrix_flex_part_print(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                            uint8_t start_row_ind, uint8_t end_row_ind,
+                            uint8_t start_col_ind, uint8_t end_col_ind,
+                            uint8_t before_dot, uint8_t after_dot)
+{
+    int16_t i, j;
+    char format_str_buff[13];
+
+    sprintf(format_str_buff, "%%%u.%uf", before_dot, after_dot);
+
+    if ((end_row_ind > start_row_ind) && (end_col_ind > start_col_ind)) {
+        puts("{");
+        for (i = start_row_ind; i <= end_row_ind; i++) {
+            printf("%11s", "{");
+            for (j = start_col_ind; j <= end_col_ind; j++) {
+                utils_printf(format_str_buff, matrix[i][j]);
+                if (j < end_col_ind) {
+                    printf(", ");
+                }
+            }
+            printf("}");
+            if (i < end_row_ind) {
+                printf(", ");
+            }
+            puts("");
+        }
+        printf("%11s\n", "};");
+    }
+    else {
+        //print only one element of the matrix
+        if ((start_row_ind == end_row_ind)
+            & (start_col_ind == end_col_ind)) {
+            printf("{");
+            utils_printf(format_str_buff,
+                         matrix[start_row_ind][start_col_ind]);
+            printf("}");
+        }
+        // print row vector of the matrix
+        else if (start_row_ind == end_row_ind) {
+            printf("{");
+            for (j = start_col_ind; j <= end_col_ind; j++) {
+                utils_printf(format_str_buff,
+                             matrix[start_row_ind][j]);
+                if (j < end_col_ind) {
+                    printf(", ");
+                }
+            }
+            printf("}");
+        }
+        // print column vector of the matrix
+        else if (start_col_ind == end_col_ind) {
+            puts("{");
+            for (i = start_row_ind; i <= end_row_ind; i++) {
+                utils_printf(format_str_buff,
+                             matrix[i][start_col_ind]);
+                if (i < end_row_ind) {
+                    printf(",\n");
+                }
+            }
+            printf("}");
+        }
+    }
+}
+
+
+uint8_t matrix_get_rank(uint8_t m, uint8_t n, matrix_t singl_values_arr[],
+                        uint8_t length)
+{
+    uint8_t rank = 0;
+    int i;
+    double eps = pow(2.0, -52.0);
+    double tol = max(m, n) * singl_values_arr[0] * eps;
+
+    for (i = 0; i < length; i++) {
+        if (singl_values_arr[i] > tol) {
+            rank++;
+        }
+    }
+
+    return rank;
+}
+
+void matrix_sub(uint8_t m, uint8_t n, matrix_t A[m][n], matrix_t B[m][n],
+                matrix_t A_minus_B[m][n])
+{
+    uint8_t i, j;
+
+    for (i = 0; i < m; i++) {
+        for (j = 0; j < n; j++) {
+            A_minus_B[i][j] = A[i][j] - B[i][j];
+        }
+    }
+}
+
+void matrix_add(uint8_t m, uint8_t n, matrix_t A[m][n], matrix_t B[m][n],
+                matrix_t A_plus_B[m][n])
+{
+    uint8_t i, j;
+
+    for (i = 0; i < m; i++) {
+        for (j = 0; j < n; j++) {
+            A_plus_B[i][j] = A[i][j] + B[i][j];
+        }
+    }
+}
+
+void matrix_add_to_diag(uint8_t n, matrix_t A[][n], uint8_t diag_el_num,
+                        matrix_t value)
+{
+    uint8_t i;
+
+    for (i = 0; i < diag_el_num; i++) {
+        A[i][i] += value;
+    }
+}
+
+void matrix_mul(uint8_t a_line_num, uint8_t a_col_num,
+                matrix_t a_matrix[a_line_num][a_col_num],
+                uint8_t b_line_num, uint8_t b_col_num,
+                matrix_t b_matrix[b_line_num][b_col_num],
+                matrix_t dest_matrix[a_line_num][b_col_num])
+{
+
+    int i, j, k;
+
+    if (a_col_num != b_line_num) {
+        puts(
+            "the first matrix column number must be equal with the line number"
+            " of the second matrix !!!");
+    }
+    else {
+
+        for (i = 0; i < a_line_num; i++) {
+            for (j = 0; j < b_col_num; j++) {
+                dest_matrix[i][j] = 0;
+                for (k = 0; k < b_line_num; k++) {
+                    dest_matrix[i][j] += a_matrix[i][k]
+                                         * b_matrix[k][j];
+                }
+            }
+        }
+    }
+}
+
+void matrix_part_mul(uint8_t a_col_num_max, matrix_t a_matrix[][a_col_num_max],
+                     uint8_t b_col_num_max, matrix_t b_matrix[][b_col_num_max],
+                     uint8_t a_start_row_ind, uint8_t a_end_row_ind,
+                     uint8_t a_start_col_ind, uint8_t a_end_col_ind,
+                     uint8_t b_start_row_ind, uint8_t b_end_row_ind,
+                     uint8_t b_start_col_ind, uint8_t b_end_col_ind,
+                     uint8_t dest_col_size,
+                     matrix_t dest_matrix[][dest_col_size])
+{
+    uint8_t a_line_num;
+    uint8_t b_col_num;
+    uint8_t b_line_num;
+
+    if ((a_end_col_ind - a_start_col_ind)
+        != (b_end_row_ind - b_start_row_ind)) {
+        puts(
+            "the first matrix column number must be equal with the line number"
+            " of the second matrix !!!");
+    }
+    else {
+
+        a_line_num = a_end_row_ind - a_start_row_ind + 1;
+        b_line_num = b_end_row_ind - b_start_row_ind + 1;
+        b_col_num = b_end_col_ind - b_start_col_ind + 1;
+
+        for (uint8_t i = 0; i < a_line_num; i++) {
+            for (uint8_t j = 0; j < b_col_num; j++) {
+                dest_matrix[i][j] = 0;
+                for (uint8_t k = 0; k < b_line_num; k++) {
+                    dest_matrix[i][j] +=
+                        a_matrix[i
+                                 + a_start_row_ind][k
+                                                    + a_start_col_ind]
+                        * b_matrix[k
+                                   + b_start_row_ind][j
+                                                      + b_start_col_ind];
+                }
+            }
+        }
+    }
+}
+
+
+void matrix_mul_vec(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                    matrix_t vec[n], matrix_t dst_arr[m])
+{
+
+    uint8_t i, j;
+
+    if (vec != dst_arr) {
+        memset(dst_arr, 0, m * sizeof(matrix_t));
+    }
+
+    for (i = 0; i < m; i++) {
+        for (j = 0; j < n; j++) {
+            dst_arr[i] += matrix[i][j] * vec[j];
+        }
+    }
+}
+
+
+void matrix_vec_mul_matr(uint8_t m, uint8_t n, matrix_t vec[m],
+                         matrix_t matrix[m][n], matrix_t dst_arr[n])
+{
+    uint8_t i, j;
+
+    //Make sense ?
+    if (vec != dst_arr) {
+        memset(dst_arr, 0, n * sizeof(matrix_t));
+    }
+
+    for (i = 0; i < n; i++) {       //column
+        for (j = 0; j < m; j++) {   //rows
+            dst_arr[i] += vec[j] * matrix[j][i];
+        }
+    }
+}
+
+
+void matrix_mul_scalar_vec_matr(uint8_t m, uint8_t n, matrix_t scalar,
+                                matrix_t vec[m], matrix_t matrix[m][n],
+                                matrix_t dst_arr[n])
+{
+    uint8_t i, j;
+
+    //Make sense ?
+    if (vec != dst_arr) {
+        memset(dst_arr, 0, n * sizeof(matrix_t));
+    }
+
+    for (i = 0; i < n; i++) {       //column
+        for (j = 0; j < m; j++) {   //rows
+            dst_arr[i] += scalar * vec[j] * matrix[j][i];
+        }
+    }
+}
+
+
+void matrix_part_mul_scalar_vec_matr(uint8_t max_m, uint8_t max_n,
+                                     matrix_t scalar, matrix_t vec[max_m],
+                                     matrix_t matrix[max_m][max_n],
+                                     uint8_t begin_row, uint8_t begin_column,
+                                     matrix_t dst_arr[max_n - begin_row])
+{
+    int16_t i, j;
+
+    if (vec != dst_arr) {
+        memset(dst_arr, 0, (max_n - begin_row) * sizeof(matrix_t));
+    }
+
+    for (i = begin_column; i < max_n; i++) {    //column
+        for (j = begin_row; j < max_m; j++) {   //rows
+            dst_arr[i - begin_column] += scalar * vec[j - begin_row]
+                                         * matrix[j][i];
+
+        }
+    }
+}
+
+
+void matrix_trans_mul_vec(uint8_t m, uint8_t n, matrix_t A[m][n],
+                          uint8_t b_size, matrix_t b_vec[m], matrix_t c_vec[n])
+{
+    uint8_t i, j;
+
+    if (m != b_size) {
+        puts(
+            "The vector size should be equal the raw number of the matrix !!!");
+    }
+    else {
+        for (j = 0; j < n; j++) {
+            c_vec[j] = 0;
+            for (i = 0; i < m; i++) {
+                c_vec[j] += A[i][j] * b_vec[i];
+            }
+        }
+    }
+}
+
+
+void matrix_mul_col_vec_row_vec(uint8_t m, matrix_t col_vec[m], uint8_t n,
+                                matrix_t row_vec[n], uint8_t max_n,
+                                matrix_t res_mat[][max_n])
+{
+    uint8_t i, j;
+
+    for (i = 0; i < m; i++) {
+        for (j = 0; j < n; j++) {
+            res_mat[i][j] = col_vec[i] * row_vec[j];
+        }
+    }
+}
+
+
+void matrix_trans_mul_itself(uint8_t m, uint8_t n, matrix_t A[m][n],
+                             matrix_t AT_mul_A[n][n])
+{
+    uint8_t i, j, k;
+    matrix_t column_vec[m];
+    matrix_t tmp_col_vec[m];
+
+    for (i = 0; i < n; i++) {
+        matrix_get_column_vec(m, n, A, i, column_vec);
+        for (j = 0; j < n; j++) {
+            matrix_get_column_vec(m, n, A, j, tmp_col_vec);
+            AT_mul_A[i][j] = 0;
+            for (k = 0; k < m; k++) {
+                AT_mul_A[i][j] += column_vec[k]
+                                  * tmp_col_vec[k];
+            }
+        }
+    }
+}
+
+void matrix_set_diag_elements(uint8_t m, uint8_t n, matrix_t value,
+                              matrix_t diag_matrix[m][n])
+{
+    uint8_t max = 0;
+
+    if (m < n) {
+        max = m;
+    }
+    else {
+        max = n;
+    }
+    for (uint8_t i = 0; i < max; i++) {
+        diag_matrix[i][i] = value;
+    }
+}
+
+void matrix_get_diag_mat_new(uint8_t m, uint8_t n, matrix_t diag_matrix[m][n],
+                             uint8_t length, matrix_t vec[])
+{
+    uint8_t i;
+
+    matrix_clear(m, n, diag_matrix);
+
+    for (i = 0; i < length; i++) {
+        diag_matrix[i][i] = vec[i];
+    }
+}
+
+
+void matrix_get_diag_mat(uint8_t m, uint8_t n, matrix_t value,
+                         matrix_t diag_matrix[m][n])
+{
+    matrix_clear(m, n, diag_matrix);
+    matrix_set_diag_elements(m, n, value, diag_matrix);
+}
+
+
+void matrix_mul_scalar(uint8_t m, uint8_t n, matrix_t mat_src[m][n],
+                       matrix_t value, matrix_t mat_dest[m][n])
+{
+    for (int i = 0; i < m; i++) {
+        for (int j = 0; j < n; j++) {
+            mat_dest[i][j] = value * mat_src[i][j];
+        }
+    }
+}
+
+void matrix_get_column_vec(uint8_t m, uint8_t n, matrix_t matrix[m][n],
+                           uint8_t col_num, matrix_t col_vec[m])
+{
+    uint8_t i;
+
+    for (i = 0; i < m; i++) {
+        col_vec[i] = matrix[i][col_num];
+    }
+}
+
+
+void matrix_get_part_column_vec(uint8_t max_m, uint8_t max_n,
+                                matrix_t matrix[max_m][max_n], uint8_t col_num,
+                                uint8_t offset,
+                                matrix_t col_vec[max_m - offset])
+{
+    uint8_t i;
+
+    for (i = offset; i < max_m; i++) {
+        col_vec[i - offset] = matrix[i][col_num];
+    }
+}
+
+matrix_t matrix_get_max_elem_in_column(uint8_t m, uint8_t n,
+                                       matrix_t matrix[m][n], uint8_t col_num)
+{
+    matrix_t elem_max;
+    uint8_t i;
+
+    elem_max = matrix[0][col_num];
+    for (i = 1; i < m; i++) {
+        if (matrix[i][col_num] > elem_max) {
+            elem_max = matrix[i][col_num];
+        }
+    }
+
+    return elem_max;
+}
+
+matrix_t matrix_get_abs_max_elem_in_column(uint8_t m, uint8_t n,
+                                           matrix_t matrix[m][n],
+                                           uint8_t col_num)
+{
+    matrix_t abs_max_elem;
+    uint8_t i;
+
+    abs_max_elem = fabs(matrix[0][col_num]);
+    for (i = 1; i < m; i++) {
+        if (fabs(matrix[i][col_num]) > abs_max_elem) {
+            abs_max_elem = fabs(matrix[i][col_num]);
+        }
+    }
+
+    return abs_max_elem;
+}
+
+matrix_t matrix_get_max_elem_in_part_column(uint8_t max_m, uint8_t max_n,
+                                            matrix_t matrix[max_m][max_n],
+                                            uint8_t row_num, uint8_t col_num)
+{
+    matrix_t max_elem;
+    uint8_t i;
+
+    max_elem = matrix[row_num][col_num];
+    for (i = row_num + 1; i < max_m; i++) {
+        if (matrix[i][col_num] > max_elem) {
+            max_elem = matrix[i][col_num];
+        }
+    }
+
+    return max_elem;
+}
+
+matrix_t matrix_get_abs_max_elem_in_part_column(uint8_t max_m, uint8_t max_n,
+                                                matrix_t matrix[max_m][max_n],
+                                                uint8_t row_num,
+                                                uint8_t col_num)
+{
+    matrix_t abs_max_elem;
+    uint8_t i;
+
+    abs_max_elem = fabs(matrix[row_num][col_num]);
+    for (i = row_num + 1; i < max_m; i++) {
+        if (fabs(matrix[i][col_num]) > abs_max_elem) {
+            abs_max_elem = fabs(matrix[i][col_num]);
+        }
+    }
+
+    return abs_max_elem;
+}
+
+matrix_t matrix_get_abs_max_elem_and_index_in_part_column(uint8_t max_m,
+                                                          uint8_t max_n,
+                                                          matrix_t matrix[max_m][max_n],
+                                                          uint8_t row_num, uint8_t col_num,
+                                                          uint8_t *index)
+{
+    matrix_t abs_max_elem;
+    uint8_t i;
+
+    abs_max_elem = fabs(matrix[row_num][col_num]);
+    *index = row_num;
+    for (i = row_num + 1; i < max_m; i++) {
+        if (fabs(matrix[i][col_num]) > abs_max_elem) {
+            abs_max_elem = fabs(matrix[i][col_num]);
+            *index = i;
+        }
+
+    }
+
+    return abs_max_elem;
+}
+
+void matrix_swap_rows(uint8_t n, matrix_t matrix[][n], uint8_t i, uint8_t j)
+{
+    matrix_t tmp;
+
+    for (uint8_t k = 0; k < n; k++) {
+        tmp = matrix[i][k];
+        matrix[i][k] = matrix[j][k];
+        matrix[j][k] = tmp;
+    }
+}
+
+void matrix_part_swap_rows(uint8_t n, matrix_t matrix[][n], uint8_t i,
+                           uint8_t j, uint8_t col_begin,
+                           uint8_t col_end)
+{
+    matrix_t tmp;
+
+    if (col_begin <= col_end) {
+        for (uint8_t k = col_begin; k < (col_end + 1); k++) {
+            tmp = matrix[i][k];
+            matrix[i][k] = matrix[j][k];
+            matrix[j][k] = tmp;
+        }
+    }
+
+}
+
+double matrix_get_two_norm(uint8_t m, uint8_t n, matrix_t A[][n])
+{
+    double two_norm = 0.0;
+    matrix_dim_t dim;
+    matrix_t copy_A[m][n];
+
+    svd_get_U_dim(m, n, &dim);
+    matrix_t U[dim.row_num][dim.col_num];
+    matrix_t S[n][n];
+    matrix_t V[n][n];
+    uint8_t s_length = svd_get_single_values_num(m, n);
+    matrix_t s[s_length];
+
+    matrix_copy(m, n, A, copy_A);
+    svd(m, n, copy_A, dim.row_num, dim.col_num, U, S, V, s_length, s);
+    printf("U1 = ");
+    matrix_print(dim.row_num, dim.col_num, U);
+    puts("");
+    printf("S1 = ");
+    matrix_print(n, n, S);
+    puts("");
+    printf("V1 = ");
+    matrix_print(n, n, V);
+    puts("");
+
+    two_norm = S[0][0];
+
+    return two_norm;
+}
+
+double matrix_get_frob_norm(uint8_t m, uint8_t n, matrix_t A[][n])
+{
+    double frob_norm = 0.0;
+
+    for (uint8_t i = 0; i < m; i++) {
+        for (uint8_t j = 0; j < n; j++) {
+            frob_norm += pow(A[i][j], 2);
+        }
+    }
+
+    return sqrt(frob_norm);
+}
+
+void matrix_get_inv_upp_triang(uint8_t m, uint8_t n, matrix_t U[][n],
+                               matrix_t inv_U[][m])
+{
+    //Zero out the inv_U matrix
+    matrix_clear(n, m, inv_U);
+    for (uint8_t i = 0; i < n; i++) {
+        if (U[i][i] != 0) {
+            inv_U[i][i] = 1 / U[i][i];
+        }
+        else {
+            inv_U[i][i] = FLT_MAX;
+        }
+        for (uint8_t j = 0; j <= (i - 1); j++) {
+            matrix_t u = 0.0;
+            for (uint8_t k = j; k <= (i - 1); k++) {
+                u = u + U[k][i] * inv_U[j][k];
+            }
+            inv_U[j][i] = -u * inv_U[i][i];
+        }
+    }
+}
+
+void matrix_get_inv_low_triang(uint8_t m, uint8_t n, matrix_t L[][n],
+                               matrix_t inv_L[][m])
+{
+    //Zero out the inv_L matrix
+    matrix_clear(n, m, inv_L);
+    for (uint8_t i = 0; i < n; i++) {
+        if ((i <= m) & (i <= n)) {
+            if (L[i][i] != 0) {
+                inv_L[i][i] = 1 / L[i][i];
+            }
+            else {
+                inv_L[i][i] = FLT_MAX;
+            }
+            for (uint8_t j = 0; j <= (i - 1); j++) {
+                matrix_t l = 0.0;
+                for (uint8_t k = j; k <= (i - 1); k++) {
+                    l = l + L[i][k] * inv_L[k][j];
+                }
+                inv_L[i][j] = -l * inv_L[i][i];
+            }
+        } //if
+    } //for
+}
+
+void matrix_get_upp_triang(uint8_t m, uint8_t n, matrix_t A[][n],
+                           matrix_t tr_up_A[][n])
+{
+    // Same matrix
+    if ((&A[0][0]) == (&tr_up_A[0][0])) {
+        for (uint8_t i = 1; i < m; i++) {
+            for (uint8_t j = 0; (j < i) && (j < n); j++) {
+                A[i][j] = 0;
+            }
+        }
+
+    }
+    else {
+        for (uint8_t i = 0; i < m; i++) {
+            for (uint8_t j = 0; j < n; j++) {
+                if (i <= j) {
+                    tr_up_A[i][j] = A[i][j];
+                }
+                else {
+                    tr_up_A[i][j] = 0;
+                }
+            }
+        }
+    }
+
+}
+
+void matrix_get_low_triang(uint8_t m, uint8_t n, matrix_t A[][n],
+                           matrix_t tr_low_A[][n])
+{
+
+    if ((&A[0][0]) == (&tr_low_A[0][0])) {
+        // Same matrix
+        for (uint8_t i = 0; i < m; i++) {
+            for (uint8_t j = i + 1; (j > i) && (j < n); j++) {
+                A[i][j] = 0;
+            }
+        }
+
+    }
+    else {
+        for (uint8_t i = 0; i < m; i++) {
+            for (uint8_t j = 0; j < n; j++) {
+                if (i >= j) {
+                    tr_low_A[i][j] = A[i][j];
+                }
+                else {
+                    tr_low_A[i][j] = 0;
+                }
+            }
+        }
+    }
+}
+
+matrix_t matrix_read(uint8_t m, uint8_t n, matrix_t matrix[m][n], uint8_t i,
+                     uint8_t j)
+{
+    return matrix[i][j];
+}
+
+void matrix_write(uint8_t m, uint8_t n, matrix_t matrix[m][n], uint8_t i,
+                  uint8_t j, matrix_t val)
+{
+    matrix[i][j] = val;
+}
diff --git a/linear_algebra/basic_operations/vector.c b/linear_algebra/basic_operations/vector.c
new file mode 100644
index 0000000000000000000000000000000000000000..b586c3a9f3c44f167495d86003185bc1a440ba4c
--- /dev/null
+++ b/linear_algebra/basic_operations/vector.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Vector computations.
+ *              Vector computations include operations such as addition,
+ *              subtraction, and inner product (dot product).
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdbool.h>
+
+#include "vector.h"
+#include "utils.h"
+
+void vector_clear(uint8_t n, vector_t arr[])
+{
+    memset(arr, 0, sizeof(vector_t) * n);
+}
+
+void vector_copy(uint8_t size, vector_t src_arr[], vector_t dest_arr[])
+{
+    memcpy(dest_arr, src_arr, size * sizeof(vector_t));
+}
+
+vector_t vector_get_norm2(uint8_t length, vector_t arr[])
+{
+    vector_t square_norm = 0.0;
+    uint8_t i = 0;
+
+    for (; i < length; i++) {
+        square_norm += arr[i] * arr[i];
+    }
+
+    return sqrt(square_norm);
+}
+
+vector_t vector_get_square_norm2(uint8_t length, vector_t arr[])
+{
+    vector_t square_norm = 0.0;
+    uint8_t i = 0;
+
+    for (; i < length; i++) {
+        square_norm += arr[i] * arr[i];
+    }
+
+    return square_norm;
+}
+
+vector_t vector_get_sum(uint8_t length, vector_t arr[])
+{
+    vector_t sum = 0.0;
+    uint8_t i;
+
+    for (i = 0; i < length; i++) {
+        sum += arr[i];
+    }
+
+    return sum;
+}
+
+vector_t vector_get_mean_value(uint8_t length, vector_t arr[])
+{
+    vector_t mean = 0.0;
+    uint8_t i;
+
+    for (i = 0; i < length; i++) {
+        mean += arr[i];
+    }
+
+    if (length != 0) {
+        mean /= length;
+    }
+
+    return mean;
+}
+
+void vector_sub(uint8_t size, vector_t a_vec[], vector_t b_vec[],
+                vector_t a_minus_b[])
+{
+    uint8_t i;
+
+    for (i = 0; i < size; i++) {
+        a_minus_b[i] = a_vec[i] - b_vec[i];
+    }
+}
+
+void vector_add(uint8_t size, vector_t a_vec[size], vector_t b_vec[size],
+                vector_t a_plus_b_vec[size])
+{
+    uint8_t i;
+
+    for (i = 0; i < size; i++) {
+        a_plus_b_vec[i] = a_vec[i] + b_vec[i];
+    }
+}
+
+void vector_mul(uint8_t size, vector_t a_vec[size], vector_t b_vec[size],
+                vector_t a_mul_b_vec[size])
+{
+    uint8_t i;
+
+    for (i = 0; i < size; i++) {
+        a_mul_b_vec[i] = a_vec[i] * b_vec[i];
+    }
+}
+
+void vector_square(uint8_t n, vector_t vec[n], vector_t square_vec[n])
+{
+    for (int i = 0; i < n; i++) {
+        square_vec[i] = vec[i] * vec[i];
+    }
+}
+
+void vector_in_place_scalar_mul(uint8_t size, vector_t a_vec[size],
+                                vector_t scl)
+{
+    uint8_t i;
+
+    for (i = 0; i < size; i++) {
+        a_vec[i] = scl * a_vec[i];
+    }
+}
+
+void vector_scalar_mul(uint8_t size, vector_t src_vec[size], vector_t scl,
+                       vector_t dest_vec[])
+{
+    uint8_t i;
+
+    for (i = 0; i < size; i++) {
+        dest_vec[i] = scl * src_vec[i];
+    }
+}
+
+void vector_scalar_div(uint8_t size, vector_t a_vec[size], vector_t scl)
+{
+    uint8_t i;
+
+    if (scl != 0) {
+        for (i = 0; i < size; i++) {
+            a_vec[i] = a_vec[i] / scl;
+        }
+    }
+}
+
+//Euclidean distance: d = sum((x-y).^2).^0.5
+vector_t vector_get_euclidean_distance(uint8_t length, vector_t vec1[],
+                                       vector_t vec2[])
+{
+    vector_t d = 0.0;
+    vector_t diff_vec[length];
+
+    vector_sub(length, vec1, vec2, diff_vec);
+    d = vector_get_norm2(length, diff_vec);
+
+    return d;
+}
+
+vector_t vector_get_max_and_index(uint8_t length, vector_t vec[],
+                                  uint8_t *index)
+{
+    vector_t max = vec[0];
+
+    *index = 0;
+    for (uint8_t i = 1; i < length; i++) {
+        if (vec[i] > max) {
+            max = vec[i];
+            *index = *index + 1;
+        }
+    }
+    return max;
+}
+
+vector_t vector_get_scalar_product(uint8_t n, vector_t vec1[n],
+                                   vector_t vec2[n])
+{
+    vector_t r = 0;
+
+    for (int i = 0; i < n; i++) {
+        r = r + (vec1[i] * vec2[i]);
+    }
+
+    return r;
+}
+
+bool vector_is_equal(uint16_t length, vector_t vec_1[], vector_t vec_2[])
+{
+
+    for (uint16_t i = 0; i < length; i++) {
+        if (vec_1[i] != vec_2[i]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void vector_get_index_vector(uint8_t k, uint8_t n, vector_t unsorted_vector[n],
+                             vector_t sorted_vector[n], uint8_t index_vector[n])
+{
+
+    for (int i = 0; i < k; i++) {
+        for (int j = 0; j < n; j++) {
+            if (unsorted_vector[j] == sorted_vector[i]) {
+                index_vector[i] = j;
+            }
+        }
+    }
+}
+
+vector_t vector_get_residual(uint8_t length, vector_t a_vec[], vector_t b_vec[])
+{
+    vector_t diff_vec[length];
+
+    vector_sub(length, a_vec, b_vec, diff_vec);
+    return vector_get_norm2(length, diff_vec);
+}
+
+void vector_get_elements(vector_t src_vec[], uint8_t k, uint8_t index_vec[],
+                         vector_t dst_vec[])
+{
+    for (uint8_t i = 0; i < k; i++) {
+        dst_vec[i] = src_vec[index_vec[i]];
+    }
+}
+
+bool vector_uint32_is_equal(uint32_t length, uint32_t vec_1[], uint32_t vec_2[])
+{
+
+    for (uint32_t i = 0; i < length; i++) {
+        if (vec_1[i] != vec_2[i]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void vector_print(uint32_t length, vector_t arr[])
+{
+    uint16_t i;
+
+    printf("{");
+    for (i = 0; i < length; i++) {
+        printf("%5.4f", arr[i]);
+        if (i < length - 1) {
+            printf(", ");
+        }
+    }
+    printf("}");
+}
+
+void vector_print_u8_array(uint32_t length, uint8_t arr[])
+{
+    uint32_t i;
+
+    printf("{");
+    for (i = 0; i < length; i++) {
+        printf("%u", arr[i]);
+        if (i < length - 1) {
+            printf(", ");
+        }
+    }
+    printf("}");
+}
+
+// This function is more memory-consuming than vector_print
+void vector_flex_print(uint32_t length, vector_t arr[], uint8_t before_dot,
+                       uint8_t after_dot)
+{
+    uint32_t i;
+    char format_str_buff[13];
+
+    sprintf(format_str_buff, "%%%u.%uf", before_dot, after_dot);
+    printf("{");
+    for (i = 0; i < length; i++) {
+        //printf(format_str_buff, arr[i]);
+        utils_printf(format_str_buff, arr[i]);
+        if (i < length - 1) {
+            printf(", ");
+        }
+    }
+    printf("}");
+    //puts("");
+}
diff --git a/linear_algebra/doc.txt b/linear_algebra/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..91081ada6318963d5b3cd4222db5c63f294372aa
--- /dev/null
+++ b/linear_algebra/doc.txt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    linear_algebra LINEAR_ALGEBRA
+ *
+ * @brief       Linear algebra operations
+ *
+ * @details  The linear algebra module contains functions that are specific to vector and 
+ *           matrix operations, and other algebraic operations. This module is composed of 
+ *           five submodules: basic_operation, matrix_decompositions, pseudo_inverse, 
+ *           solve_linear_equations, and utilities submodules.
+ * 
+ * @author Zakaria Kasmi
+ *
+ */
diff --git a/linear_algebra/matrix_decompositions/doc.txt b/linear_algebra/matrix_decompositions/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d8bee1408e32a491747feca02e5e99404dfe23f2
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/doc.txt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de> 
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup  matrix_decompositions MATRIX_DECOMPOSITIONS
+ * @ingroup   linear_algebra
+ *
+ * @brief    Matrix decomposition algorithms.
+ *
+ * @details  This module provides algorithms of matrix decomposition such as
+ *           Householder, Givens, or Golub-Kahan-Reinsch algorithms.
+ *
+ * @author   Zakaria Kasmi
+ */
diff --git a/linear_algebra/matrix_decompositions/include/lu_decomp.h b/linear_algebra/matrix_decompositions/include/lu_decomp.h
new file mode 100644
index 0000000000000000000000000000000000000000..59f955c7f8b3b49c8762813f022a4bf4ff2d662d
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/include/lu_decomp.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     matrix_decompositions
+ * @{
+ *
+ * @file
+ * @brief       Computes the LU decomposition of the matrix.
+ * @details     Computes the permutation matrix P such that: A = P'*L*U, where L is a lower
+ *              triangular matrix and U is an upper triangular matrix. It implements the Gaussian
+ *              Elimination (GE) with pivoting algorithm.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+#ifndef LU_DECOMP_H_
+#define LU_DECOMP_H_
+
+#include "matrix.h"
+
+/**
+ * @brief   Computes the LU decomposition of the matrix.
+ * @details Computes the permutation matrix P such that: A = P'*L*U, where L is a lower triangular
+ *          matrix and U is an upper triangular matrix. It implements the Gaussian Elimination with
+ *          pivoting algorithm.
+ *
+ * @note    Matrix U is stored in the matrix A.
+ *
+ * @param[in] n               column number of the matrix.
+ * @param[in,out] A[][]       pointer to the matrices A and U.
+ * @param[out]    L[][]       pointer to the L matrix.
+ * @param[out]    P[][]       pointer to the P matrix.
+ *
+ * @return    the number of changes by computing the LU decomposition.
+ */
+uint8_t lu_decomp(uint8_t n, matrix_t A[][n], matrix_t L[][n], matrix_t P[][n]);
+
+#endif /*LU_DECOMP_H_ */
diff --git a/linear_algebra/matrix_decompositions/include/qr_common.h b/linear_algebra/matrix_decompositions/include/qr_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..3edc335d75739849846ff5351d21baddafa239d4
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/include/qr_common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     matrix_decompositions
+ * @{
+ *
+ * @file
+ * @brief       Common definitions and implementations for the QR-decomposition.
+ *              Provide necessary methods to construct Q- and R- matrices using.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef QR_COMMON_H_
+#define QR_COMMON_H_
+
+#include <inttypes.h>
+#include "matrix.h"
+
+/**
+ * Possible algorithms to compute the QR-decomposition of a matrix.
+ */
+enum QR_ALGORITHM {
+    QR_Householder, QR_Givens
+};
+
+/**
+ * @brief   Implements the backward substitution algorithm.
+ *
+ * @param[in]   m               row number of the matrix.
+ * @param[in]   n               column number of the matrix.
+ * @param[in]   U[][]           pointer to the matrix U.
+ * @param[in]   b[]             pointer to the vector b.
+ * @param[out]  x_sol[]         pointer to the solution of the substitution algorithm.
+ *
+ */
+void qr_common_backward_subst(uint8_t m, uint8_t n, matrix_t U[][n],
+                              matrix_t b[m], matrix_t x_sol[m]);
+/**
+ * @brief   Compute the reduced form of the QR-decomposition algorithm.
+ *
+ * @param[in]   m               row number of the matrix.
+ * @param[in]   n               column number of the matrix.
+ * @param[in]   Q[][]           pointer to the matrix Q.
+ * @param[in]   R[][]           pointer to the matrix R.
+ * @param[out]  red_Q[][]       pointer to the reduced matrix Q.
+ * @param[out]  red_R[][]       pointer to the reduced matrix R.
+ *
+ */
+void qr_common_get_reduced_QR(uint8_t m, uint8_t n, matrix_t Q[m][m],
+                              matrix_t R[m][n], matrix_t red_Q[m][n], matrix_t red_R[n][n]);
+
+#endif /* QR_COMMON_H_ */
diff --git a/linear_algebra/matrix_decompositions/include/qr_givens.h b/linear_algebra/matrix_decompositions/include/qr_givens.h
new file mode 100644
index 0000000000000000000000000000000000000000..1708c332f3bfda8d1aaf6d3678008b1508ae4173
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/include/qr_givens.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     matrix_decompositions
+ * @{
+ *
+ * @file
+ * @brief       Givens algorithm for the QR-decomposition.
+ *              Provide necessary methods to construct Q- and R- matrices using
+ *              Givens rotations. A = QR, where Q is an (m \f$\times\f$ n)-matrix with
+ *              orthonormal columns and R is an (n \f$\times\f$ n) upper triangular matrix.
+ *
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef QR_GIVENS_H_
+#define QR_GIVENS_H_
+
+#include <inttypes.h>
+
+#include "matrix.h"
+
+/**
+ * @brief    Computes the QR decomposition of the matrix A by using the Givens
+ *           algorithm.
+ * @details  Gets a QR decomposition of an m-by-n matrix A such that A = Q*R.
+ *           The compact as well as the full decomposition of the matrix can be computed.
+ *
+ * @note    R is stored in the matrix A.
+ *
+ * @param[in] m                   row number of the matrix.
+ * @param[in] n                   column number of the matrix.
+ * @param[in,out] A[][]           pointer to the matrices A and R.
+ * @param[in]     q_col_num       column number of the matrix Q.
+ * @param[out]    Q[][]           pointer to the Q matrix.
+ * @param[in] reduced             computes the compact form of the QR decomposition if true,
+ *                                otherwise the full version.
+ *
+ * @return  1, if computing the QR decomposition is successful.
+ * @return -1, if computing the QR decomposition is not successful.
+ *
+ */
+int8_t qr_givens_decomp(uint8_t m, uint8_t n, matrix_t A[][n],
+                             uint8_t q_col_num, matrix_t Q[][q_col_num],
+                             bool reduced);
+
+/**
+ * @brief   Compute the Givens parameters.
+ *          The computation of the parameters c, s, t, and r can have problems with
+ *          overflow or underflow, therefore this algorithm employs a
+ *          normalization procedure.
+ *          The Givens parameters c, s, t and r are saved in a vector.
+ *
+ * @param[in]  xjj            value at the diagonal j of the matrix.
+ * @param[in]  xij            value at the index j of a column vector i.
+ * @param[out] c_s_t_r_vec[]  pointer to the vector holding the c, s, t and r parameters.
+ *
+ */
+void qr_givens_get_params(matrix_t xjj, matrix_t xij, matrix_t c_s_t_r_vec[]);
+
+#endif /* QR_GIVENS_H_ */
diff --git a/linear_algebra/matrix_decompositions/include/qr_householder.h b/linear_algebra/matrix_decompositions/include/qr_householder.h
new file mode 100644
index 0000000000000000000000000000000000000000..97e9707586aa9850beae315f831bf9ec4cd7043e
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/include/qr_householder.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     matrix_decompositions
+ * @{
+ *
+ * @file
+ * @brief       Householder algorithm for the QR-decomposition.
+ * @details     Provide necessary methods to construct Q- and R- matrices using
+ *              Householder reflections. A = QR, where Q is an (m \f$\times\f$ n)-matrix with
+ *              orthonormal columns and R is an (n \f$\times\f$ n) upper triangular matrix.
+ *
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+#ifndef QR_HOUSEHOLDER_H_
+#define QR_HOUSEHOLDER_H_
+
+#include <inttypes.h>
+
+#include "matrix.h"
+
+/**
+ * @brief   Computes the QR decomposition of the matrix A by using the
+ *          Householder algorithm.
+ * @note    R is stored in the matrix A.
+ *
+ * @param[in]     m               row number of the matrix to decompose in QR.
+ * @param[in]     n               column number of the matrix to decompose in QR.
+ * @param[in,out] A[][]           pointer to the matrices A and R.
+ * @param[in]     q_col_num       column number of the matrix Q.
+ * @param[in,out] Q[][]           pointer to the matrix Q.
+ * @param[in]     reduced         computes the compact form of the QR decomposition if true,
+ *                                otherwise the full version.
+ *
+ * @return  1, if computing the QR decomposition is successful.
+ * @return -1, if computing the QR decomposition is not successful.
+ *
+ */
+int8_t qr_householder_decomp(uint8_t m, uint8_t n, matrix_t A[][n],
+                                  uint8_t q_col_num, matrix_t Q[][q_col_num],
+                                  bool reduced);
+#endif /* QR_HOUSEHOLDER_H_ */
diff --git a/linear_algebra/matrix_decompositions/include/svd.h b/linear_algebra/matrix_decompositions/include/svd.h
new file mode 100644
index 0000000000000000000000000000000000000000..109bdce87e6e691b1be9ff052856beb3597db695
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/include/svd.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     matrix_decompositions
+ * @{
+ *
+ * @file
+ * @brief       Algorithm for the Singular Value Decomposition (SVD).
+ * @details     Provide necessary methods to compute the compact SVD of
+ *              a matrix. A = U*S*V, where U is a (m x l) orthogonal matrix,
+ *              S is a (l x l) diagonal matrix, V is a (l x n) orthogonal
+ *              matrix, and l = min(m,n). The SVD is computed by using the
+ *              Golub--Kahan--Reinsch algorithm that works in two phases:
+ *              bidiagonalization and a reduction to the diagonal form phase.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef SVD_H_
+#define SVD_H_
+
+#include "matrix.h"
+
+/* Define the cases of the Golub-Reinsch Algorithm */
+
+/**
+ * The case of computing negligible values.
+ */
+#define SVD_COMPUTE_NEGLIGIBLE_VALUES     1
+
+/**
+ * The case of splitting at negligible values.
+ */
+#define SVD_SPLIT_AT_NEGLIGIBLE_VALUES    2
+
+/**
+ * The case of the QR-step.
+ */
+#define SVD_QR_STEP 3
+
+/**
+ * The case of the order of absolute singular values.
+ */
+#define SVD_ORDER_ABSOLUTE_SING_VALUES    4
+
+/**
+ * @brief     Compute the Singular-Value Decomposition (SVD) of a matrix.
+ *
+ * @details   Matrix A is transformed to A = U*S*V, where U and V are unitary
+ *            matrices, and S is a diagonal matrix.
+ *
+ *
+ * @param[in]       m                    row number of the matrix A.
+ * @param[in]       n                    column number of the matrix A.
+ * @param[in, out]  A[][]                pointer to the matrix A.
+ * @param[in]       u_m                  row number of the matrix U.
+ * @param[in]       u_n                  column number of the matrix U.
+ * @param[in, out]  U[][]                pointer to the matrix U.
+ * @param[in, out]  S[][]                pointer to the matrix S.
+ * @param[in, out]  V[][]                pointer to the matrix V.
+ * @param[in]       sing_vec_length      length of the singular vector.
+ * @param[in, out]  singl_values_vec[]   pointer to the vector saving the singular values.
+ *
+ */
+void svd(uint8_t m, uint8_t n, matrix_t A[m][n],
+         uint8_t u_m, uint8_t u_n, matrix_t U[u_m][u_n],
+         matrix_t S[u_n][n], matrix_t V[n][n],
+         uint8_t sing_vec_length, matrix_t singl_values_vec[]);
+
+/**
+ * @brief     Calculate the dimension of the matrix U.
+ *
+ * @param[in]       m         row number of the matrix to decompose.
+ * @param[in]       n         column number of the matrix to decompose.
+ * @param[out]      u_dim     pointer to the dimension struct.
+ *
+ */
+void svd_get_U_dim(uint8_t m, uint8_t n, matrix_dim_t *u_dim);
+
+/**
+ * @brief     Calculate the dimension of the matrix S.
+ *
+ * @param[in]       m         row number of the matrix to decompose.
+ * @param[in]       n         column number of the matrix to decompose.
+ * @param[out]      s_dim     pointer to the dimension struct.
+ *
+ */
+void svd_get_S_dim(uint8_t m, uint8_t n, matrix_dim_t *s_dim);
+
+/**
+ * @brief     Calculate the dimension of the matrix V.
+ *
+ * @param[in]       m         row number of the matrix to decompose.
+ * @param[in]       n         column number of the matrix to decompose.
+ * @param[out]      v_dim     pointer to the dimension struct.
+ *
+ */
+void svd_get_V_dim(uint8_t m, uint8_t n, matrix_dim_t *v_dim);
+
+/**
+ * @brief     Calculate the number of the singular values.
+ *
+ * @param[in]       m         row number of the matrix to decompose.
+ * @param[in]       n         column number of the matrix to decompose.
+ *
+ * @return    the number of the singular values.
+ *
+ */
+uint8_t svd_get_single_values_num(uint8_t m, uint8_t n);
+
+/**
+ * @brief     Compute the reciprocal singular values.
+ *
+ * @details   This method is based on the singular values.
+ *
+ * @param[in]  m                        row number of the matrix to transform in SVD.
+ * @param[in]  n                        column number of the matrix to transform in SVD.
+ * @param[in]  length                   length of the array of single values.
+ * @param[in]  singl_values_arr         pointer to the array of single values.
+ * @param[out] recip_singl_values_arr   pointer to the array of the reciprocal
+ *                                      singular values.
+ *
+ */
+void svd_get_reciproc_singular_values(uint8_t m, uint8_t n, uint8_t length,
+                                      matrix_t singl_values_arr[],
+                                      matrix_t recip_singl_values_arr[]
+                                      );
+/**
+ * @brief     Compute and print the SVD of a matrix.
+ *
+ *
+ * @param[in]  m                        row number of the matrix to transform in SVD.
+ * @param[in]  n                        column number of the matrix to transform in SVD.
+ * @param[in]  matrix_arr[][]           pointer to the matrix.
+ * @param[in]  i                        label.
+ *
+ */
+void svd_compute_print_U_S_V_s(uint8_t m, uint8_t n, matrix_t matrix_arr[m][n],
+                               uint8_t i);
+
+#endif /* SVD_H_ */
diff --git a/linear_algebra/matrix_decompositions/lu_decomp.c b/linear_algebra/matrix_decompositions/lu_decomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..9be7fc7580348c0cfcb94db6cbdd27ad7be32b39
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/lu_decomp.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Computes the LU decomposition of the matrix.
+ * @details     Computes the permutation matrix P such that: A = P'*L*U, where L is a lower
+ *              triangular matrix and U is an upper triangular matrix. It implements the Gaussian
+ *              Elimination (GE) with pivoting algorithm.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <float.h>
+#include <stdio.h>
+
+#include "matrix.h"
+#include "vector.h"
+
+// U will be saved in A
+uint8_t lu_decomp(uint8_t n, matrix_t A[][n], matrix_t L[][n], matrix_t P[][n])
+{
+    matrix_t abs_max_col_elem;
+    uint8_t k;
+    uint8_t pivot_index;
+    uint8_t changes;
+    matrix_t multipliers_vec[n - 1];
+
+    matrix_get_diag_mat(n, n, 1, L);
+    matrix_get_diag_mat(n, n, 1, P);
+    changes = 0;
+    for (uint8_t i = 0; i < n - 1; i++) {
+        abs_max_col_elem =
+            matrix_get_abs_max_elem_and_index_in_part_column(
+                n, n, A, i, i, &k);
+        if (abs_max_col_elem <= FLT_EPSILON) {
+            continue;
+        }
+
+        pivot_index = k;
+
+        if (pivot_index != i) {
+            //Swap the rows at the position i and pivot_index of the matrix A(i, i:n)
+            matrix_part_swap_rows(n, A, i, k, i, n - 1);
+
+            //Swap the matrix P at the rows i and pivot_index
+            matrix_swap_rows(n, P, i, k);
+
+            //Swap the rows of L in columns 0 through i-1. //FIXED
+            if (i >= 1) {
+
+                matrix_part_swap_rows(n, L, i, k, 0, i - 1);
+            }
+            changes++;
+        } //if
+
+        for (uint8_t j = i + 1; j < n; j++) {
+            //compute multipliers
+            multipliers_vec[j - 1] = A[j][i] / A[i][i];
+            //update the matrix A
+            for (uint8_t l = i + 1; l < n; l++) {
+                A[j][l] = A[j][l]
+                          - multipliers_vec[j - 1]
+                          * A[i][l];
+            }
+            //zero out the elements of column i, from row i+1 to n-1.
+            A[j][i] = 0;
+            // Set the matrix L with the multipliers
+            L[j][i] = multipliers_vec[j - 1];
+        }
+
+    }   //for
+
+    return changes;
+}
diff --git a/linear_algebra/matrix_decompositions/qr_common.c b/linear_algebra/matrix_decompositions/qr_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..27091fa79ea1480411389e9f2d58e81312d1e937
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/qr_common.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Common definitions and implementations for the QR-decomposition.
+ *              Provide necessary methods to construct Q- and R- matrices using.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "matrix.h"
+
+void qr_common_backward_subst(uint8_t m, uint8_t n, matrix_t U[][n],
+                              matrix_t b[m], matrix_t x_sol[m])
+{
+    int8_t i;
+    uint8_t j;
+    matrix_t sum;
+
+    if (m != n) {
+        puts("The matrix should be square !!!");
+        return;
+    }
+
+    //clear x_sol
+    memset(x_sol, 0, sizeof(matrix_t) * m);
+
+    if (U[m - 1][m - 1] != 0) {
+        x_sol[m - 1] = b[m - 1] / U[m - 1][m - 1];
+    }
+
+    for (i = m - 2; i >= 0; i--) {
+        sum = 0.0;
+        for (j = i + 1; j < m; j++) {
+            sum += U[i][j] * x_sol[j];
+        }
+
+        if (U[i][i] != 0) {
+            x_sol[i] = (b[i] - sum) / U[i][i];
+        }
+    }
+}
+
+void qr_common_get_reduced_QR(uint8_t m, uint8_t n, matrix_t Q[m][m],
+                              matrix_t R[m][n], matrix_t reduc_Q[m][n],
+                              matrix_t reduc_R[n][n])
+{
+    if (m >= n) {
+        matrix_part_copy(m, m, Q, 0, m - 1, 0, n - 1, m, n, reduc_Q);
+        matrix_part_copy(m, n, R, 0, n - 1, 0, n - 1, n, n, reduc_R);
+    }
+    else {
+        puts(
+            "The row number of A should be greater than the column number of A");
+    }
+}
diff --git a/linear_algebra/matrix_decompositions/qr_givens.c b/linear_algebra/matrix_decompositions/qr_givens.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff9d30a64a871a09c9734a97887da60a4cae15e8
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/qr_givens.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Givens algorithm for the QR-decomposition.
+ *              Provide necessary methods to construct Q- and R- matrices using
+ *              Givens rotations. A = QR, where Q is an (m \f$\times \f$ n)-matrix with
+ *              orthonormal columns and R is an (n \f$\times\f$ n) upper triangular matrix.
+ *
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "matrix.h"
+#include "qr_givens.h"
+
+/*R will be stored in A */
+int8_t qr_givens_decomp(uint8_t m, uint8_t n, matrix_t A[][n],
+                        uint8_t q_col_num,
+                        matrix_t Q[][q_col_num], bool reduced)
+{
+    if (m < n) {
+        puts("A has more columns than rows");
+        return -1;
+    }
+
+    for (uint8_t j = 0; j < n; j++) {
+        for (uint8_t i = j + 1; i < m; i++) {
+            matrix_t c_s_t_r_vec[4];
+            qr_givens_get_params(A[j][j], A[i][j], c_s_t_r_vec);
+            A[i][j] = c_s_t_r_vec[2];   //A[i][j] = t
+            A[j][j] = c_s_t_r_vec[3];   //A[j][j] = r
+            if (j < n) {
+                for (uint8_t k = j + 1; k < n; k++) {
+                    matrix_t c, s;
+                    c = c_s_t_r_vec[0];
+                    s = c_s_t_r_vec[1];
+                    matrix_t tmp = A[j][k];
+                    A[j][k] = c * A[j][k] + s * A[i][k];
+                    A[i][k] = -s * tmp + c * A[i][k];
+                }
+            }
+
+        }
+    }
+
+    uint8_t max_m;
+    if (reduced) {
+        max_m = n;
+    }
+    else {
+        max_m = m;
+    }
+
+    if (!reduced) {
+        matrix_clear(m, max_m, Q);
+    }
+
+    matrix_part_copy(m, n, A, 0, m - 1, 0, n - 1, m, max_m, Q);
+
+    // Build R
+    matrix_get_upp_triang(m, n, A, A);
+
+    // Build Q
+    for (int16_t j = max_m - 1; j >= 0; j--) {
+        // Zero out column j from row 0 up to row j
+        for (uint8_t k = 0; k <= j; k++) {
+            Q[k][j] = 0;
+        }
+        Q[j][j] = 1;
+
+        for (int16_t i = m - 1; i >= j + 1; i--) {
+            matrix_t t = Q[i][j];
+            Q[i][j] = 0;
+            matrix_t c = 1 / sqrt(1 + t * t);
+            matrix_t s;
+            if (c != 0) {
+                s = c * t;
+            }
+            else {
+                s = 1;
+            }
+
+            for (uint8_t k = j; k < max_m; k++) {
+                matrix_t tmp = Q[j][k];
+                Q[j][k] = c * Q[j][k] - s * Q[i][k];
+                Q[i][k] = s * tmp + c * Q[i][k];
+            }
+        } //for
+    }
+
+    return 1;
+}
+
+void qr_givens_get_params(matrix_t xjj, matrix_t xij, matrix_t c_s_t_r_vec[])
+{
+    if (xjj != 0) {
+        matrix_t u;
+
+        c_s_t_r_vec[2] = xij / xjj;                         //t = xij/xjj
+        u = sqrt(1 + c_s_t_r_vec[2] * c_s_t_r_vec[2]);      //u = sqrt(1 + t*t)
+        c_s_t_r_vec[0] = 1 / u;                             //c = 1/u
+        c_s_t_r_vec[1] = c_s_t_r_vec[0] * c_s_t_r_vec[2];   //s = c*t
+        c_s_t_r_vec[3] = u * xjj;                           //r = u*xjj
+    }
+    else {
+        c_s_t_r_vec[0] = 0;         //c = 0
+        c_s_t_r_vec[1] = 1;         //s = 1
+        c_s_t_r_vec[2] = FLT_MAX;   //t = infinity
+        c_s_t_r_vec[3] = xij;       //r = xij
+    }
+}
diff --git a/linear_algebra/matrix_decompositions/qr_householder.c b/linear_algebra/matrix_decompositions/qr_householder.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0da7346dc42f3785762bb5cb25061bd60294e0d
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/qr_householder.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Householder algorithm for the QR-decomposition.
+ * @details     Provide necessary methods to construct Q- and R- matrices using
+ *              Householder reflections. A = QR, where Q is an (m \f$\times\f$ n)-matrix with
+ *              orthonormal columns and R is an (n \f$\times\f$ n) upper triangular matrix.
+ *
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <math.h>
+
+#include "matrix.h"
+#include "utils.h"
+
+/*R will be stored in A */
+int8_t qr_householder_decomp(uint8_t m, uint8_t n, matrix_t A[][n],
+                             uint8_t q_col_num,
+                             matrix_t Q[][q_col_num], bool reduced)
+{
+    if (m < n) {
+        puts("A has more columns than rows");
+        return -1;
+    }
+    matrix_t diag_R_vec[n];
+
+    for (uint8_t k = 0; k < n; k++) {
+        //compute the two-norm of the k-th column of the matrix A
+        double norm_2 = 0.0;
+        for (uint8_t i = k; i < m; i++) {
+            norm_2 = utils_get_save_square_root(norm_2, A[i][k]);
+
+        }
+
+        if (norm_2 != 0.0) {
+            // Form k-th Householder vector.
+            if (A[k][k] < 0) {
+                norm_2 = -norm_2;
+            }
+            for (int i = k; i < m; i++) {
+                A[i][k] /= norm_2;
+            }
+
+            A[k][k] += 1.0;
+
+            // Apply the Householder transformation to the rest columns of the matrix.
+            for (uint8_t j = k + 1; j < n; j++) {
+                double sigma = 0.0;
+                for (uint8_t i = k; i < m; i++) {
+                    sigma += A[i][k] * A[i][j];
+                }
+                sigma = -sigma / A[k][k];
+                for (uint8_t i = k; i < m; i++) {
+                    A[i][j] += sigma * A[i][k];
+                }
+            }
+
+        } // if
+
+        diag_R_vec[k] = -norm_2;
+
+    } //for
+
+    // Build Q
+    uint8_t max_n, max_m;
+    if (!reduced) {
+        max_n = m;
+        max_m = m;
+    }
+    else {
+        max_n = n;
+        max_m = n;
+    }
+
+    for (int k = max_n - 1; k >= 0; k--) {
+        for (int i = 0; i < m; i++) {
+            Q[i][k] = 0.0;
+        } // clear matrix Q
+        Q[k][k] = 1.0;
+        for (int j = k; j < max_n; j++) {
+            if (k < n) {
+                if (A[k][k] != 0) {
+                    double s = 0.0;
+                    for (int i = k; i < m; i++) {
+                        s += A[i][k] * Q[i][j];
+                    }
+                    s = -s / A[k][k];
+                    for (int i = k; i < m; i++) {
+                        Q[i][j] += s * A[i][k];
+                    }
+                } //if
+            } //if
+        }
+    }
+
+    // Build R
+    for (int i = 0; i < max_m; i++) {
+        for (int j = 0; j < n; j++) {
+            if (i == j) {
+                A[i][j] = diag_R_vec[i];
+            }
+            else if (i > j) {
+                A[i][j] = 0;
+            }
+        }
+    }
+
+    return 1;
+}
diff --git a/linear_algebra/matrix_decompositions/svd.c b/linear_algebra/matrix_decompositions/svd.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9ed22f568e1d0f5408fbddf7ef5c89363fcd3ea
--- /dev/null
+++ b/linear_algebra/matrix_decompositions/svd.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Algorithm for the Singular Value Decomposition (SVD).
+ *              Provide necessary methods to compute the compact SVD of
+ *              a matrix. A = U*S*V, where U is a (m x l) orthogonal matrix,
+ *              S is a (l x l) diagonal matrix, V is a (l x n) orthogonal
+ *              matrix, and l = min(m,n). The SVD is computed by using the
+ *              Golub--Kahan--Reinsch algorithm that works in two phases:
+ *              bidiagonalization and a reduction to the diagonal form phase.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "svd.h"
+#include "matrix.h"
+#include "vector.h"
+
+static void svd_bidiagonal_trans_and_store_diag_elem(uint8_t m, uint8_t n,
+                                                     matrix_t A[m][n],
+                                                     uint8_t u_m, uint8_t u_n,
+                                                     matrix_t U0[u_m][u_n],
+                                                     matrix_t V0[n][n],
+                                                     matrix_t sup_diag_elem_vec[],
+                                                     matrix_t diag_elem_vec[]
+                                                     );
+
+static void svd_setup_bi_diagonal_matrix(uint8_t m, uint8_t n, matrix_t A[m][n],
+                                         uint8_t u_n, matrix_t U1[m][u_n],
+                                         matrix_t V1[n][n],
+                                         matrix_t sup_diag_elem_vec[],
+                                         matrix_t diag_elem_vec[]
+                                         );
+
+static void svd_compute_singular_values_U_V(uint8_t m, uint8_t n, uint8_t u_n,
+                                            matrix_t U[m][u_n],
+                                            matrix_t V[n][n],
+                                            matrix_t sup_diag_elem_vec[],
+                                            matrix_t diag_elem_vec[]);
+
+static void svd_generate_S(uint8_t m, uint8_t n, matrix_t S[n][n],
+                           uint8_t sing_vec_length, matrix_t singl_values_vec[]);
+
+static int32_t min(int32_t a, int32_t b)
+{
+    if (a < b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+static int32_t max(int32_t a, int32_t b)
+{
+    if (a > b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+static matrix_t get_abs_max(matrix_t arr[], uint8_t length)
+{
+    uint8_t i;
+    matrix_t max = fabs(arr[0]);
+
+    for (i = 1; i < length; i++) {
+        if (fabs(arr[i]) > max) {
+            max = fabs(arr[i]);
+        }
+    }
+
+    return max;
+}
+
+void svd_get_U_dim(uint8_t m, uint8_t n, matrix_dim_t *u_dim)
+{
+    u_dim->row_num = m;
+    u_dim->col_num = min(m, n);
+}
+
+void svd_get_S_dim(uint8_t m, uint8_t n, matrix_dim_t *s_dim)
+{
+    s_dim->row_num = min(m, n);
+    s_dim->col_num = n;
+}
+
+void svd_get_V_dim(uint8_t m, uint8_t n, matrix_dim_t *v_dim)
+{
+    v_dim->row_num = m;
+    v_dim->col_num = n;
+}
+
+uint8_t svd_get_single_values_num(uint8_t m, uint8_t n)
+{
+    return min(m + 1, n);
+}
+
+void svd(uint8_t m, uint8_t n, matrix_t A[m][n],
+         uint8_t u_m, uint8_t u_n, matrix_t U[u_m][u_n],
+         matrix_t S[u_n][n], matrix_t V[n][n],
+         uint8_t sing_vec_length, matrix_t singl_values_vec[])
+{
+
+    int8_t u_n_min = min(m, n);
+    matrix_t sup_diag_elem_vec[n];
+
+    matrix_clear(m, u_n_min, U);
+    matrix_clear(n, n, S);
+    matrix_clear(n, n, V);
+    memset(singl_values_vec, 0, sizeof(matrix_t) * sing_vec_length);
+
+    svd_bidiagonal_trans_and_store_diag_elem(m, n, A, u_m, u_n, U, V,
+                                             sup_diag_elem_vec, singl_values_vec);
+
+    svd_setup_bi_diagonal_matrix(m, n, A, u_n, U, V, sup_diag_elem_vec,
+                                 singl_values_vec);
+
+    svd_compute_singular_values_U_V(m, n, u_n, U, V, sup_diag_elem_vec,
+                                    singl_values_vec);
+
+    svd_generate_S(u_n, n, S, sing_vec_length, singl_values_vec);
+}
+
+/**
+ * @brief     Reduce the matrix A to a bi-diagonal form.
+ *
+ * @details   The bi-diagonal transformation is placed in the U0 and V0 matrices
+ *            for a subsequent back multiplication. The super-diagonal and the
+ *            diagonal elements are saved in the sup_diag_elem_vec and
+ *            diag_elem_vec vectors.
+ *
+ * @param[in]       m                       row number of the matrix A.
+ * @param[in]       n                       column number of the matrix A.
+ * @param[in, out]  A[][n]                  pointer to the matrix A.
+ * @param[in]       u_m                     row number of the matrix U0.
+ * @param[in]       u_n                     column number of the matrix U0.
+ * @param[out]      U0[][u_n]               pointer to the matrix U0.
+ * @param[out]      V0[][u_n]               pointer to the matrix V0.
+ * @param[out]      sup_diag_elem_vec[]     pointer to the vector saving the
+ *                                          super-diagonal elements.
+ * @param[out]      diag_elem_vec[]         pointer to the vector saving the
+ *                                          diagonal elements.
+ *
+ */
+static void svd_bidiagonal_trans_and_store_diag_elem(uint8_t m, uint8_t n,
+                                                     matrix_t A[m][n],
+                                                     uint8_t u_m, uint8_t u_n,
+                                                     matrix_t U0[u_m][u_n],
+                                                     matrix_t V0[n][n],
+                                                     matrix_t sup_diag_elem_vec[],
+                                                     matrix_t diag_elem_vec[])
+{
+    int col_trans_num = min(m - 1, n);
+    int row_trans_num = max(0, min(n - 2, m));
+    int upper_lim = max(col_trans_num, row_trans_num);
+
+    for (int index = 0; index < upper_lim; index++) {
+        if (index < col_trans_num) {
+            diag_elem_vec[index] = 0;
+            for (int row_num = index; row_num < m; row_num++) {
+                diag_elem_vec[index] = hypot(
+                    diag_elem_vec[index],
+                    A[row_num][index]);
+            }
+            if (diag_elem_vec[index] != 0.0) {
+                if (A[index][index] < 0.0) {
+                    diag_elem_vec[index] =
+                        -diag_elem_vec[index];
+                }
+                for (int row_num = index; row_num < m;
+                     row_num++) {
+                    A[row_num][index] /=
+                        diag_elem_vec[index];
+                }
+                A[index][index] += 1.0;
+            }
+            diag_elem_vec[index] = -diag_elem_vec[index];
+        }
+        for (int col_num = index + 1; col_num < n; col_num++) {
+            if ((index < col_trans_num)
+                & (diag_elem_vec[index] != 0.0)) {
+
+                /* Transformation */
+                matrix_t transf_val = 0;
+                for (int i = index; i < m; i++) {
+                    transf_val += A[i][index]
+                                  * A[i][col_num];
+                }
+                transf_val = -transf_val / A[index][index];
+                for (int i = index; i < m; i++) {
+                    A[i][col_num] += transf_val
+                                     * A[i][index];
+                }
+            }
+            sup_diag_elem_vec[col_num] = A[index][col_num];
+        }
+        if (index < col_trans_num) {
+
+            /* Place a part of the bi-diagonal transformation in U0 */
+            for (int row_num = index; row_num < m; row_num++) {
+                U0[row_num][index] = A[row_num][index];
+            }
+        }
+        if (index < row_trans_num) {
+            sup_diag_elem_vec[index] = 0;
+            for (int i = index + 1; i < n; i++) {
+                sup_diag_elem_vec[index] = hypot(
+                    sup_diag_elem_vec[index],
+                    sup_diag_elem_vec[i]);
+            }
+            if (sup_diag_elem_vec[index] != 0.0) {
+                if (sup_diag_elem_vec[index + 1] < 0.0) {
+                    sup_diag_elem_vec[index] =
+                        -sup_diag_elem_vec[index];
+                }
+                for (int i = index + 1; i < n; i++) {
+                    sup_diag_elem_vec[i] /=
+                        sup_diag_elem_vec[index];
+                }
+                sup_diag_elem_vec[index + 1] += 1.0;
+            }
+            sup_diag_elem_vec[index] = -sup_diag_elem_vec[index];
+            if ((index + 1 < m)
+                & (sup_diag_elem_vec[index] != 0.0)) {
+                matrix_t transf_vec[m];
+
+                /* Compute the transformation vector */
+                for (int i = index + 1; i < m; i++) {
+                    transf_vec[i] = 0.0;
+                }
+                for (int j = index + 1; j < n; j++) {
+                    for (int i = index + 1; i < m; i++) {
+                        transf_vec[i] +=
+                            sup_diag_elem_vec[j]
+                            * A[i][j];
+                    }
+                }
+
+                /* Reduce the matrix */
+                for (int col_num = index + 1; col_num < n;
+                     col_num++) {
+                    matrix_t t =
+                        -sup_diag_elem_vec[col_num]
+                        / sup_diag_elem_vec[index
+                                            + 1];
+                    for (int row_num = index + 1;
+                         row_num < m;
+                         row_num++) {
+                        A[row_num][col_num] +=
+                            t
+                            * transf_vec[row_num];
+                    }
+                }
+            }
+
+            /* Place a part of the bi-diagonal transformation in V0 */
+            for (int row_num = index + 1; row_num < n; row_num++) {
+                V0[row_num][index] = sup_diag_elem_vec[row_num];
+            }
+        }
+    }
+}
+
+/**
+ * @brief     Setup the final bi-diagonal transformation of the matrix.
+ *
+ * @details   The final transformation is placed in the U1 and V1 matrices.
+ *            The final transformation is based on the reduced bi-diagonal
+ *            matrix computed in a previous step.
+ *
+ * @param[in]       m                       row number of the matrix A.
+ * @param[in]       n                       column number of the matrix A.
+ * @param[in]       A[][n]                  pointer to the matrix A.
+ * @param[in]       u_n                     column number of the matrix U1.
+ * @param[out]      U1[][u_n]               pointer to the matrix U1.
+ * @param[out]      V1[][n]                 pointer to the matrix V1.
+ * @param[in,out]   sup_diag_elem_vec[]     pointer to the vector saving the
+ *                                          super-diagonal elements.
+ * @param[in,out]   diag_elem_vec[]         pointer to the vector saving the
+ *                                          diagonal elements.
+ *
+ */
+static void svd_setup_bi_diagonal_matrix(uint8_t m, uint8_t n, matrix_t A[m][n],
+                                         uint8_t u_n, matrix_t U1[m][u_n],
+                                         matrix_t V1[n][n],
+                                         matrix_t sup_diag_elem_vec[],
+                                         matrix_t diag_elem_vec[])
+{
+
+    int col_trans_num = min(m - 1, n);
+    int row_trans_num = max(0, min(n - 2, m));
+    int8_t upp_col_num = min(m, n);
+    int p_index = min(n, m + 1);
+
+    if (col_trans_num < n) {
+        diag_elem_vec[col_trans_num] = A[col_trans_num][col_trans_num];
+    }
+    if (m < p_index) {
+        diag_elem_vec[p_index - 1] = 0.0;
+    }
+    if (row_trans_num + 1 < p_index) {
+        sup_diag_elem_vec[row_trans_num] =
+            A[row_trans_num][p_index - 1];
+    }
+    sup_diag_elem_vec[p_index - 1] = 0.0;
+
+    /* Generate the matrix U1 */
+    for (int j = col_trans_num; j < upp_col_num; j++) {
+        for (int i = 0; i < m; i++) {
+            U1[i][j] = 0.0;
+        }
+        U1[j][j] = 1.0;
+    }
+    for (int k = col_trans_num - 1; k >= 0; k--) {
+        if (diag_elem_vec[k] != 0.0) {
+            for (int j = k + 1; j < upp_col_num; j++) {
+                matrix_t factor_t = 0;
+                for (int i = k; i < m; i++) {
+                    factor_t += U1[i][k] * U1[i][j];
+                }
+                factor_t = -factor_t / U1[k][k];
+                for (int i = k; i < m; i++) {
+                    U1[i][j] += factor_t * U1[i][k];
+                }
+            }
+            for (int i = k; i < m; i++) {
+                U1[i][k] = -U1[i][k];
+            }
+            U1[k][k] += 1.0;
+            for (int i = 0; i < k - 1; i++) {
+                U1[i][k] = 0.0;
+            }
+        }
+        else {
+            for (int i = 0; i < m; i++) {
+                U1[i][k] = 0.0;
+            }
+            U1[k][k] = 1.0;
+        }
+    }
+
+    /* Generate the matrix V1 */
+    for (int k = n - 1; k >= 0; k--) {
+        if ((k < row_trans_num) & (sup_diag_elem_vec[k] != 0.0)) {
+            for (int j = k + 1; j < n; j++) {
+                matrix_t t = 0;
+                for (int i = k + 1; i < n; i++) {
+                    t += V1[i][k] * V1[i][j];
+                }
+                t = -t / V1[k + 1][k];
+                for (int i = k + 1; i < n; i++) {
+                    V1[i][j] += t * V1[i][k];
+                }
+            }
+        }
+        for (int i = 0; i < n; i++) {
+            V1[i][k] = 0.0;
+        }
+        V1[k][k] = 1.0;
+    }
+}
+
+/**
+ * @brief     Compute the singular values and the matrices U and V.
+ *
+ * @details   The computed bi-diagonal matrix in the first phase is reduced to
+ *            a diagonal form. In the bi-diagonal procedure, we distinguish
+ *            between the splitting, the cancellation and the negligibility
+ *            steps. The singular values will be stored in the vector of
+ *            diagonal elements.
+ *
+ *
+ * @param[in]       m                       row number of the matrix U.
+ * @param[in]       n                       row and column number of the matrix
+ *                                          V.
+ * @param[in]       u_n                     column number of the matrix U.
+ * @param[in,out]   U[][u_n]                pointer to the matrix U.
+ * @param[in,out]   V[][n]                  pointer to the matrix V.
+ * @param[in,out]   sup_diag_elem_vec[]     pointer to the vector saving the
+ *                                          super-diagonal elements.
+ * @param[in,out]   diag_elem_vec[]         pointer to the vector saving the
+ *                                          diagonal and singular elements.
+ *
+ */
+static void svd_compute_singular_values_U_V(uint8_t m, uint8_t n, uint8_t u_n,
+                                            matrix_t U[m][u_n],
+                                            matrix_t V[n][n],
+                                            matrix_t sup_diag_elem_vec[],
+                                            matrix_t diag_elem_vec[])
+{
+    int p_index = min(n, m + 1);
+    int max_k = p_index - 1;
+    int iter_num = 0;
+    matrix_t eps = pow(2.0, -52.0);
+    matrix_t tol = pow(2.0, -966.0);
+
+    while (p_index > 0) {
+        int k_index, case_num;
+
+        for (k_index = p_index - 2; k_index >= -1; k_index--) {
+            if (k_index == -1) {
+                break;
+            }
+            if (fabs(sup_diag_elem_vec[k_index])
+                <=
+                tol
+                + eps
+                * (fabs(
+                       diag_elem_vec[k_index])
+                   + fabs(
+                       diag_elem_vec[k_index
+                                     + 1]))) {
+                sup_diag_elem_vec[k_index] = 0.0;
+                break;
+            }
+        }
+        if (k_index == p_index - 2) {
+            case_num = SVD_ORDER_ABSOLUTE_SING_VALUES; //4
+        }
+        else {
+            int ks_index;
+            for (ks_index = p_index - 1; ks_index >= k_index;
+                 ks_index--) {
+                if (ks_index == k_index) {
+                    break;
+                }
+                matrix_t t =
+                    (ks_index != p_index ?
+                     fabs(
+                         sup_diag_elem_vec[ks_index]) :
+                     0.)
+                    +
+                    (ks_index
+                     != k_index
+                     + 1 ?
+                     fabs(
+                         sup_diag_elem_vec[ks_index
+                                           - 1]) :
+                     0.);
+                if (fabs(diag_elem_vec[ks_index])
+                    <= tol + eps * t) {
+                    diag_elem_vec[ks_index] = 0.0;
+                    break;
+                }
+            }
+            if (ks_index == k_index) {
+                case_num = SVD_QR_STEP; //3
+            }
+            else if (ks_index == p_index - 1) {
+                case_num = SVD_COMPUTE_NEGLIGIBLE_VALUES; //1
+            }
+            else {
+                case_num = SVD_SPLIT_AT_NEGLIGIBLE_VALUES;  //2
+                k_index = ks_index;
+            }
+        }
+        k_index++;
+
+        switch (case_num) {
+
+            /* Compute negligible values */
+            case SVD_COMPUTE_NEGLIGIBLE_VALUES: {
+                matrix_t f_val = sup_diag_elem_vec[p_index - 2];
+                sup_diag_elem_vec[p_index - 2] = 0.0;
+                for (int j = p_index - 2; j >= k_index; j--) {
+                    matrix_t t_val = hypot(diag_elem_vec[j], f_val);
+                    matrix_t split_cs_fac = diag_elem_vec[j]
+                                            / t_val;
+                    matrix_t split_sn_fac = f_val / t_val;
+                    diag_elem_vec[j] = t_val;
+                    if (j != k_index) {
+                        f_val = -split_sn_fac
+                                * sup_diag_elem_vec[j
+                                                    - 1];
+                        sup_diag_elem_vec[j - 1] = split_cs_fac
+                                                   * sup_diag_elem_vec[j
+                                                                       - 1];
+                    }
+                    /* Compute the V matrix */
+                    for (int i = 0; i < n; i++) {
+                        t_val =
+                            split_cs_fac * V[i][j]
+                            + split_sn_fac
+                            * V[i][p_index
+                                   - 1];
+                        V[i][p_index - 1] =
+                            -split_sn_fac * V[i][j]
+                            + split_cs_fac
+                            * V[i][p_index
+                                   - 1];
+                        V[i][j] = t_val;
+                    }
+                }
+            }
+            break;
+
+            /* Split at negligible values sup_diag_elem_vec(k) */
+            case SVD_SPLIT_AT_NEGLIGIBLE_VALUES: {
+                matrix_t f_val = sup_diag_elem_vec[k_index - 1];
+                sup_diag_elem_vec[k_index - 1] = 0.0;
+                for (int j = k_index; j < p_index; j++) {
+                    matrix_t t_val = hypot(diag_elem_vec[j], f_val);
+                    matrix_t split_cs_fac = diag_elem_vec[j]
+                                            / t_val;
+                    matrix_t split_sn_fac = f_val / t_val;
+                    diag_elem_vec[j] = t_val;
+                    f_val = -split_sn_fac * sup_diag_elem_vec[j];
+                    sup_diag_elem_vec[j] = split_cs_fac
+                                           * sup_diag_elem_vec[j];
+
+                    /* Compute the U matrix */
+                    for (int i = 0; i < m; i++) {
+                        t_val =
+                            split_cs_fac * U[i][j]
+                            + split_sn_fac
+                            * U[i][k_index
+                                   - 1];
+                        U[i][k_index - 1] =
+                            -split_sn_fac * U[i][j]
+                            + split_cs_fac
+                            * U[i][k_index
+                                   - 1];
+                        U[i][j] = t_val;
+                    }
+                }
+            }
+            break;
+
+            /* The QR Step */
+            case SVD_QR_STEP: {
+
+                matrix_t buff[5] = { diag_elem_vec[p_index - 1],
+                                     diag_elem_vec[p_index - 2],
+                                     sup_diag_elem_vec[p_index - 2],
+                                     diag_elem_vec[k_index],
+                                     sup_diag_elem_vec[k_index] };
+                matrix_t scale = get_abs_max(buff, 5);
+
+                matrix_t p_diag_elem = diag_elem_vec[p_index - 1]
+                                       / scale;
+                matrix_t p_minus_diag_elem = diag_elem_vec[p_index - 2]
+                                             / scale;
+                matrix_t p_minus_sup_diag_elem =
+                    sup_diag_elem_vec[p_index - 2] / scale;
+                matrix_t k_diag_elem = diag_elem_vec[k_index] / scale;
+                matrix_t k_sup_diag_elem = sup_diag_elem_vec[k_index]
+                                           / scale;
+                matrix_t d_val = ((p_minus_diag_elem + p_diag_elem)
+                                  * (p_minus_diag_elem - p_diag_elem)
+                                  + p_minus_sup_diag_elem
+                                  * p_minus_sup_diag_elem)
+                                 / 2.0;
+                matrix_t e_val = (p_diag_elem * p_minus_sup_diag_elem)
+                                 * (p_diag_elem * p_minus_sup_diag_elem);
+                matrix_t wilkinson_shift = 0.0;
+                if ((d_val != 0.0) | (e_val != 0.0)) {
+                    wilkinson_shift = sqrt(d_val * d_val + e_val);
+                    if (d_val < 0.0) {
+                        wilkinson_shift = -wilkinson_shift;
+                    }
+                    wilkinson_shift = e_val
+                                      / (d_val + wilkinson_shift);
+                }
+                matrix_t f_val = (k_diag_elem + p_diag_elem)
+                                 * (k_diag_elem - p_diag_elem)
+                                 + wilkinson_shift;
+                matrix_t g_val = k_diag_elem * k_sup_diag_elem;
+
+                for (int j = k_index; j < p_index - 1; j++) {
+                    matrix_t t = hypot(f_val, g_val);
+                    matrix_t split_cs_fac = f_val / t;
+                    matrix_t split_sn_fac = g_val / t;
+                    if (j != k_index) {
+                        sup_diag_elem_vec[j - 1] = t;
+                    }
+                    f_val =
+                        split_cs_fac * diag_elem_vec[j]
+                        + split_sn_fac
+                        * sup_diag_elem_vec[j];
+                    sup_diag_elem_vec[j] =
+                        split_cs_fac
+                        * sup_diag_elem_vec[j]
+                        - split_sn_fac
+                        * diag_elem_vec[j];
+                    g_val = split_sn_fac * diag_elem_vec[j + 1];
+                    diag_elem_vec[j + 1] = split_cs_fac
+                                           * diag_elem_vec[j + 1];
+
+                    /* Compute the V matrix */
+                    for (int i = 0; i < n; i++) {
+                        t =
+                            split_cs_fac * V[i][j]
+                            + split_sn_fac
+                            * V[i][j
+                                   + 1];
+                        V[i][j + 1] =
+                            -split_sn_fac * V[i][j]
+                            + split_cs_fac
+                            * V[i][j
+                                   + 1];
+                        V[i][j] = t;
+                    }
+
+                    t = hypot(f_val, g_val);
+                    split_cs_fac = f_val / t;
+                    split_sn_fac = g_val / t;
+                    diag_elem_vec[j] = t;
+                    f_val =
+                        split_cs_fac
+                        * sup_diag_elem_vec[j]
+                        + split_sn_fac
+                        * diag_elem_vec[j
+                                        + 1];
+                    diag_elem_vec[j + 1] =
+                        -split_sn_fac
+                        * sup_diag_elem_vec[j]
+                        + split_cs_fac
+                        * diag_elem_vec[j
+                                        + 1];
+                    g_val = split_sn_fac * sup_diag_elem_vec[j + 1];
+                    sup_diag_elem_vec[j + 1] = split_cs_fac
+                                               * sup_diag_elem_vec[j + 1];
+                    if (j < m - 1) {
+                        for (int i = 0; i < m; i++) {
+                            t =
+                                split_cs_fac
+                                * U[i][j]
+                                + split_sn_fac
+                                * U[i][j
+                                       + 1];
+                            U[i][j + 1] =
+                                -split_sn_fac
+                                * U[i][j]
+                                + split_cs_fac
+                                * U[i][j
+                                       + 1];
+                            U[i][j] = t;
+                        }
+                    }
+                }
+                sup_diag_elem_vec[p_index - 2] = f_val;
+                iter_num++;
+            }
+            break;
+
+            /* Order the absolute singular values */
+            case SVD_ORDER_ABSOLUTE_SING_VALUES: {
+
+                if (diag_elem_vec[k_index] <= 0.0) {
+                    diag_elem_vec[k_index] =
+                        (diag_elem_vec[k_index] < 0.0 ?
+                         -diag_elem_vec[k_index] :
+                         0.0);
+
+                    for (int i = 0; i < n; i++) {
+                        V[i][k_index] = -V[i][k_index];
+                    }
+                }
+
+                while (k_index < max_k) {
+                    if (diag_elem_vec[k_index]
+                        >= diag_elem_vec[k_index + 1]) {
+                        break;
+                    }
+                    matrix_t k_diag_elem = diag_elem_vec[k_index];
+                    diag_elem_vec[k_index] = diag_elem_vec[k_index
+                                                           + 1];
+                    diag_elem_vec[k_index + 1] = k_diag_elem;
+                    if (k_index < n - 1) {
+                        for (int i = 0; i < n; i++) {
+                            k_diag_elem = V[i][k_index + 1];
+                            V[i][k_index + 1] =
+                                V[i][k_index];
+                            V[i][k_index] = k_diag_elem;
+                        }
+                    }
+                    if (k_index < m - 1) {
+                        for (int i = 0; i < m; i++) {
+                            k_diag_elem = U[i][k_index + 1];
+                            U[i][k_index + 1] =
+                                U[i][k_index];
+                            U[i][k_index] = k_diag_elem;
+                        }
+                    }
+                    k_index++;
+                }
+                iter_num = 0;
+                p_index--;
+            }
+            break;
+        }
+    }
+}
+
+/**
+ * @brief     Compute the rectangular diagonal matrix S.
+ *
+ * @details   The calculation of the matrix S is based on the three previous
+ *            steps: the bi-diagonal reduction, the final bi-diagonal
+ *            transformation, and the computation of the singular values.
+ *
+ * @param[in] m                   row number of the matrix to transform in SVD.
+ * @param[in] n                   row and column number of the matrix S.
+ * @param[in] S[][n]              pointer to the matrix S.
+ * @param[in] sing_vec_length     length of the vector saving the singular
+ *                                values.
+ * @param[in] singl_values_vec[]  pointer to the vector saving the singular
+ *                                elements.
+ *
+ */
+static void svd_generate_S(uint8_t m, uint8_t n, matrix_t S[n][n],
+                           uint8_t sing_vec_length, matrix_t singl_values_vec[])
+{
+    uint8_t i;
+
+    for (i = 0; i < m; i++) {
+        for (uint8_t j = 0; j < n; j++) {
+            S[i][j] = 0.0;
+        }
+        if (i < sing_vec_length) {
+            S[i][i] = singl_values_vec[i];
+        }
+    }
+}
+
+void svd_get_reciproc_singular_values(uint8_t m, uint8_t n, uint8_t length,
+                                      matrix_t singl_values_arr[],
+                                      matrix_t recip_singl_values_arr[]
+                                      )
+{
+    uint8_t i;
+    matrix_t eps = pow(2.0, -52.0);
+    matrix_t tol = max(m, n) * singl_values_arr[0] * eps;
+
+    for (i = 0; i < length; i++) {
+        if (fabs(singl_values_arr[i]) >= tol) {
+            recip_singl_values_arr[i] = 1.0 / singl_values_arr[i];
+        }
+        else {
+            recip_singl_values_arr[i] = 0;
+        }
+    }
+}
+
+void svd_compute_print_U_S_V_s(uint8_t m, uint8_t n, matrix_t matrix_arr[m][n],
+                               uint8_t i)
+{
+    printf(
+        "########################## Test %d ##########################\n",
+        i);
+    matrix_dim_t u_dim;
+    svd_get_U_dim(m, n, &u_dim);
+    matrix_t U[u_dim.row_num][u_dim.col_num];
+    matrix_t S[u_dim.col_num][n];
+    matrix_t V[n][n];
+    uint8_t s_length = svd_get_single_values_num(m, n);
+
+    printf("matrix%d =\n", i);
+    matrix_print(m, n, matrix_arr);
+    puts("");
+    matrix_t s[s_length];
+    svd(m, n, matrix_arr, u_dim.row_num, u_dim.col_num, U, S, V, s_length,
+        s);
+
+    printf("U%d =\n", i);
+    matrix_print(u_dim.row_num, u_dim.col_num, U);
+    puts("");
+
+    printf("S%d =\n", i);
+    matrix_print(u_dim.col_num, n, S);
+    puts("");
+
+    printf("V%d =\n", i);
+    matrix_print(n, n, V);
+    puts("");
+
+    printf("s%d = ", i);
+    printf("{");
+    for (uint8_t i = 0; i < s_length; i++) {
+        printf("%5.4f ", s[i]);
+        if (i < s_length - 1) {
+            printf(", ");
+        }
+    }
+    printf("}");
+
+    puts("");
+}
diff --git a/linear_algebra/pseudo_inverse/doc.txt b/linear_algebra/pseudo_inverse/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c95aa897927459dec98fd27f9905f9d2e7351c7b
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/doc.txt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de> 
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    pseudo_inverse PSEUDO_INVERSE
+ * @ingroup     linear_algebra
+ *
+ * @brief       Algorithms to calculate the pseudo-inverse of a matrix.
+ *
+ * @details     The pseudo-inverse matrix can be computed using QR-decomposition or SVD algorithms.
+ *               
+ * @author      Zakaria Kasmi
+ *
+ */
diff --git a/linear_algebra/pseudo_inverse/include/moore_penrose_pseudo_inverse.h b/linear_algebra/pseudo_inverse/include/moore_penrose_pseudo_inverse.h
new file mode 100644
index 0000000000000000000000000000000000000000..a53da965169b9ec30173224f26ef89007a620aa4
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/include/moore_penrose_pseudo_inverse.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     pseudo_inverse
+ * @{
+ *
+ * @file
+ * @brief       Moore--Penrose algorithm to compute the pseudo-inverse of a matrix.
+ *
+ * @details     The computation of the pseudo-inverse is based on the
+ *              Singular Value Decomposition (SVD).
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef MOORE_PENROSE_PSEUDO_INVERSE_H_
+#define MOORE_PENROSE_PSEUDO_INVERSE_H_
+
+/**
+ * The maximal row number allowed.
+ */
+#define MAX_ROW_NUM 23
+
+/**
+ * The maximal column number allowed.
+ */
+#define MAX_COL_NUM 23
+
+/* define error numbers */
+/**
+ * The Moore--Penrose inverse is successfully completed.
+ */
+#define MOORE_PENROSE_PSEUDO_COMP_SUCCESS                   1
+
+/**
+ * The maximal row number allowed is exceeded.
+ */
+#define MOORE_PENROSE_PSEUDO_MAX_ALLOW_ROW_COL_EXCEEED     -1
+
+/**
+ * The transposed matrix should be delivered.
+ */
+#define MOORE_PENROSE_PSEUDO_GIVE_MATRIX_TRANSPOSE         -2
+
+/**
+ * Invalid rank value of a matrix.
+ */
+#define MOORE_PENROSE_INVALID_RANK_VALUE                   -3
+
+#include "matrix.h"
+
+/**
+ * @brief   Calculate the Moore--Penrose inverse of a rectangular matrix.
+ *          The computation of the Moore--Penrose inverse is based on the
+ *          Golub--Kahan--Reinsch SVD algorithm.
+ *
+ * @param[in]   m           row number of the matrix to inverse.
+ * @param[in]   n           column number of the matrix to inverse.
+ * @param[in]   A[][]       pointer to the matrix A.
+ * @param[out]  pinv_A[][]  pointer to the pseudo-inverse matrix.
+ *
+ * @return  1, if the computation of the Moore-Penrose inverse is successful.
+ * @return -1, if the maximal, allowed column or row number is exceeded.
+ * @return -2, if the matrix is underdetermined (m<n).
+ * @return -3, if the rank of the matrix is equal to 0.
+ *
+ */
+int8_t moore_penrose_get_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                              matrix_t pinv_A[n][m]);
+
+/**
+ * @brief     Compute and print the Moore--Penrose inverse of a matrix.
+ *
+ *
+ * @param[in]  m                  row number of the matrix.
+ * @param[in]  n                  column number of the matrix.
+ * @param[in]  matrix[][]         pointer to the matrix.
+ * @param[in]  i                  label.
+ *
+ */
+void moore_penrose_pinv_compute_print(uint8_t m, uint8_t n,
+                                      matrix_t matrix[m][n], uint8_t i);
+
+#endif /* MOORE_PENROSE_PSEUDO_INVERSE_H_ */
diff --git a/linear_algebra/pseudo_inverse/include/pseudo_inverse.h b/linear_algebra/pseudo_inverse/include/pseudo_inverse.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa9f3d7fc5b2ce73b2ecbcba794a64c3f78520d8
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/include/pseudo_inverse.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     pseudo_inverse
+ * @{
+ *
+ * @file
+ * @brief       Compute the pseudo-inverse of a matrix.
+ *
+ * @details     The pseudo-inverse matrix can be computed using the Singular Value Decomposition
+ *             (SVD), Householder, or Givens algorithms.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+#ifndef PSEUDO_INVERSE_H_
+#define PSEUDO_INVERSE_H_
+
+/**
+ * Possible algorithms to compute the pseudo-inverse matrix.
+ */
+enum ALGORITHM {
+    Moore_Penrose,  /**< Moore--Penrose algorithm */
+    Householder,    /**< Householder algorithm */
+    Givens,         /**< Givens algorithm */
+    Gauss           /**< Gaussian elimination with pivoting algorithm */
+};
+
+#endif /* PSEUDO_INVERSE_H_ */
diff --git a/linear_algebra/pseudo_inverse/include/qr_pseudo_inverse.h b/linear_algebra/pseudo_inverse/include/qr_pseudo_inverse.h
new file mode 100644
index 0000000000000000000000000000000000000000..b04af0cc04c826752621c29b17f072e162a4ff39
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/include/qr_pseudo_inverse.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     pseudo_inverse
+ * @{
+ *
+ * @file
+ * @brief       QR decomposition algorithms to compute the pseudo-inverse of a matrix.
+ *
+ * @details     The computation of the pseudo-inverse is implemented using the Householder or
+ *              the Givens algorithms.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef QR_GET_PINV_H_
+#define QR_GET_PINV_H_
+
+#include <inttypes.h>
+
+#include "matrix.h"
+#include "qr_common.h"
+
+/**
+ * @brief    Calculate the pseudo inverse of a rectangular matrix using the QR decomposition.
+ * @details  The computation of the pseudo inverse is based on the Householder or Givens
+ *           algorithm.
+ *
+ * @param[in]   m           row number of the matrix to inverse.
+ * @param[in]   n           column number of the matrix to inverse.
+ * @param[in]   A[][]       pointer to the matrix A.
+ * @param[out]  pinv_A[][]  pointer to the pseudo-inverse matrix.
+ * @param[in]   algo        choice between the Householder or Givens algorithms.
+ *
+ * @return  1, if computing the pseudo-inverse matrix is successful.
+ * @return -1, if computing the pseudo-inverse matrix is not successful.
+ *
+ */
+int8_t qr_get_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                   matrix_t pinv_A[n][m], enum QR_ALGORITHM algo);
+
+#endif /* QR_GET_PINV_H_ */
diff --git a/linear_algebra/pseudo_inverse/moore_penrose_pseudo_inverse.c b/linear_algebra/pseudo_inverse/moore_penrose_pseudo_inverse.c
new file mode 100644
index 0000000000000000000000000000000000000000..13ea72050932c3902267f86819bb4f7e830e8897
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/moore_penrose_pseudo_inverse.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Moore--Penrose algorithm to compute the pseudo-inverse of a
+ *              rectangular matrix.
+ * @details     The computation of the pseudo-inverse is based on the
+ *              Singular Value Decomposition (SVD).
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "moore_penrose_pseudo_inverse.h"
+#include "matrix.h"
+#include "svd.h"
+
+static int32_t min(int32_t a, int32_t b);
+static int8_t moore_penrose_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                                 uint8_t u_m, uint8_t u_n, matrix_t U[u_m][u_n],
+                                 matrix_t S[u_n][n], matrix_t V[n][n],
+                                 uint8_t s_length, matrix_t s[],
+                                 matrix_t pinv_A[n][m]);
+
+int8_t moore_penrose_get_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                              matrix_t pinv_A[n][m])
+{
+    matrix_dim_t udim;
+    int8_t answer = 0;
+
+    if (m < n) { /*
+                  * first compute the pseudo inverse of the transposed of the
+                  * matrix A, than transpose the computed pseudo inverse.
+                  */
+        uint8_t trans_m = n;
+        uint8_t trans_n = m;
+        matrix_t trans_A[n][m];
+        matrix_t trans_A_pinv[trans_n][trans_m];
+
+        matrix_transpose(m, n, A, trans_A);
+        svd_get_U_dim(trans_m, trans_n, &udim);
+        matrix_t U[udim.row_num][udim.col_num];
+
+        matrix_t S[udim.col_num][trans_n];
+        matrix_t V[trans_n][trans_n];
+        uint8_t s_length = svd_get_single_values_num(trans_m, trans_n);
+        matrix_t s[s_length];
+
+        answer = moore_penrose_pinv(trans_m, trans_n, trans_A,
+                                    udim.row_num, udim.col_num, U, S, V,
+                                    s_length, s, trans_A_pinv);
+        matrix_transpose(trans_n, trans_m, trans_A_pinv, pinv_A);
+
+        return answer;
+    }
+    else { /* compute the pseudo inverse */
+        svd_get_U_dim(m, n, &udim);
+        matrix_t U[udim.row_num][udim.col_num];
+        matrix_t S[udim.col_num][n];
+        matrix_t V[n][n];
+        uint8_t s_length = svd_get_single_values_num(m, n);
+        matrix_t s[s_length];
+        answer = moore_penrose_pinv(m, n, A,
+                                    udim.row_num, udim.col_num, U, S, V,
+                                    s_length, s, pinv_A);
+
+        return answer;
+    }
+
+}
+
+/**
+ * @brief     Calculate the Moore--Penrose inverse of a (m x n) matrix with (m>n).
+ * @details   To compute the pseudo-inverse of a matrix with (m<n), the
+ *            transposed of the matrix must be delivered.
+ *
+ * @param[in]   m           row number of the matrix to inverse.
+ * @param[in]   n           column number of the matrix to inverse.
+ * @param[in]   A[][n]      pointer to the matrix A.
+ * @param[out]  pinv_A[][m] pointer to the pseudo-inverse matrix.
+ *
+ * @return  1, if the computation of the Moore-Penrose inverse is successful.
+ * @return -1, if the maximal, allowed column or row number is exceeded.
+ * @return -2, if the matrix is underdetermined (m<n).
+ * @return -3, if the rank of the matrix is equal to 0.
+ *
+ */
+static int8_t moore_penrose_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                                 uint8_t u_m, uint8_t u_n, matrix_t U[u_m][u_n],
+                                 matrix_t S[u_n][n], matrix_t V[n][n],
+                                 uint8_t s_length, matrix_t s[],
+                                 matrix_t pinv_A[n][m])
+{
+
+    matrix_dim_t u_dim;
+    matrix_t rec_s[s_length];
+
+    uint8_t i, j, k, col_min;
+
+    if ((m > MAX_ROW_NUM) | (n > MAX_COL_NUM)) {
+
+        printf(
+            "The maximal, allowed number of the rows and columns is %d\n",
+            MAX_ROW_NUM);
+        return MOORE_PENROSE_PSEUDO_MAX_ALLOW_ROW_COL_EXCEEED;
+    }
+
+    if (m < n) {
+
+        puts("Please, give the transposed matrix");
+        return MOORE_PENROSE_PSEUDO_GIVE_MATRIX_TRANSPOSE;
+    }
+    else {
+        svd_get_U_dim(m, n, &u_dim);
+        s_length = svd_get_single_values_num(m, n);
+
+        svd(m, n, A, u_dim.row_num, u_dim.col_num, U, S, V, s_length,
+            s);
+    }
+
+    if (matrix_get_rank(m, n, s, s_length) < 1) {
+        puts("The minimum rank-value of a matrix is one");
+        return MOORE_PENROSE_INVALID_RANK_VALUE;
+    }
+
+    svd_get_reciproc_singular_values(m, n, s_length, s, rec_s);
+
+    col_min = min(n, u_dim.col_num);
+
+    matrix_clear(n, m, pinv_A);
+
+    for (i = 0; i < n; i++) {
+        for (j = 0; j < u_dim.row_num; j++) {
+            for (k = 0; k < col_min; k++) {
+                pinv_A[i][j] += V[i][k] * rec_s[k] * U[j][k];
+
+            }
+        }
+    }
+
+    return MOORE_PENROSE_PSEUDO_COMP_SUCCESS;
+}
+
+static int32_t min(int32_t a, int32_t b)
+{
+    if (a < b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+void moore_penrose_pinv_compute_print(uint8_t m, uint8_t n,
+                                      matrix_t matrix[m][n], uint8_t i)
+{
+    matrix_t pinv_mat[n][m];
+
+    moore_penrose_get_pinv(m, n, matrix, pinv_mat);
+    printf("pinv%d = ", i);
+    matrix_flex_print(n, m, pinv_mat, 11, 7);
+    puts("");
+}
diff --git a/linear_algebra/pseudo_inverse/qr_pseudo_inverse.c b/linear_algebra/pseudo_inverse/qr_pseudo_inverse.c
new file mode 100644
index 0000000000000000000000000000000000000000..cbb06419cb0377dde2b2f17f4c2f2cc92c360869
--- /dev/null
+++ b/linear_algebra/pseudo_inverse/qr_pseudo_inverse.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       QR decomposition algorithms to compute the pseudo-inverse of a matrix.
+ *
+ * @details     The computation of the pseudo-inverse is implemented using the Householder or
+ *              the Givens algorithms.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+
+#include "matrix.h"
+#include "qr_common.h"
+#include "qr_givens.h"
+#include "qr_householder.h"
+#include "pseudo_inverse.h"
+
+int8_t qr_get_pinv(uint8_t m, uint8_t n, matrix_t A[m][n],
+                   matrix_t pinv_A[n][m], enum QR_ALGORITHM algo)
+{
+    int8_t status;
+
+    switch (algo) {
+        case QR_Householder:
+        {
+            puts("Householder !!!!");
+            matrix_t Q[m][m];
+            matrix_t R[m][n];
+            matrix_copy(m, n, A, R);
+            status = qr_householder_decomp(m, n, R, m, Q, false);
+            matrix_t inv_R[n][m];
+            matrix_get_inv_upp_triang(m, n, R, inv_R);
+
+            // A+ = R^-1*Q'
+            matrix_in_place_transpose(m, Q);
+            matrix_mul(n, m, inv_R, m, m, Q, pinv_A);
+
+            break;
+        }
+
+        case QR_Givens:
+        {
+            puts("Givens !!!");
+
+            matrix_t Q[m][m];
+            matrix_t R[m][n];
+            matrix_copy(m, n, A, R);
+            status = qr_givens_decomp(m, n, R, m, Q, false);
+            matrix_t inv_R[n][m];
+            matrix_get_inv_upp_triang(m, n, R, inv_R);
+
+            // A+ = R^-1*Q'
+            matrix_in_place_transpose(m, Q);
+            matrix_mul(n, m, inv_R, m, m, Q, pinv_A);
+
+            break;
+        }
+
+        default:
+        {
+            matrix_t Q[m][m];
+            matrix_t R[m][n];
+            matrix_copy(m, n, A, R);
+            status = qr_householder_decomp(m, n, R, m, Q, false);
+            matrix_t inv_R[n][m];
+            matrix_get_inv_upp_triang(m, n, R, inv_R);
+
+            // A+ = R^-1*Q'
+            matrix_in_place_transpose(m, Q);
+            matrix_mul(n, m, inv_R, m, m, Q, pinv_A);
+
+        }
+    }
+
+    return status;
+}
diff --git a/linear_algebra/solve_linear_equations/doc.txt b/linear_algebra/solve_linear_equations/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..83fdda83ced14816bfd8f9cc75a69f3b89ee35ef
--- /dev/null
+++ b/linear_algebra/solve_linear_equations/doc.txt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de> 
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    solve_linear_equations SOLVE_LINEAR_EQUATIONS
+ * @ingroup     linear_algebra
+ *
+ * @brief       Enables to solve systems of linear equations Ax = b for x.
+ *
+ * @details     The user can select various algorithm such as the Moore--Penrose
+ *              inverse, the Givens or the Householder algorithm for the
+ *              QR-decomposition to solve the systems of linear equations.
+ *               
+ * @author      Zakaria Kasmi
+ */
diff --git a/linear_algebra/solve_linear_equations/include/solve.h b/linear_algebra/solve_linear_equations/include/solve.h
new file mode 100644
index 0000000000000000000000000000000000000000..ece6ed3bba7815a45aa7880f7ee96beadee7267c
--- /dev/null
+++ b/linear_algebra/solve_linear_equations/include/solve.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     solve_linear_equations
+ * @{
+ *
+ * @file
+ * @brief       Enables to solve systems of linear equations Ax = b for x.
+ * @details     The user can select various algorithm such as the Moore--Penrose
+ *              inverse, the Givens or the Householder algorithm for the QR-decomposition.
+ *              The user can also choose the Gaussian Elimination with pivoting algorithm to solve
+ *              the systems of linear equations.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef SOLVE_H_
+#define SOLVE_H_
+
+#include "matrix.h"
+#include "pseudo_inverse.h"
+
+/**
+ * @brief   Solve an (m \f$\times\f$ n) linear system Ax = b by using the Moore--Penrose,
+ *          Householder, or the Givens algorithm.
+ *
+ * @param[in]  m              row number of the matrix A.
+ * @param[in]  n              column number of the matrix A.
+ * @param[in]  A[][]          pointer to the matrix A.
+ * @param[in]  b[]            pointer to the vector b.
+ * @param[out] x_sol[]        pointer to the solution vector.
+ * @param[in]  algo           specifies the algorithm to use (e.g. the Householder method).
+ *
+ * @return  1, if solving the linear equation system is successful.
+ * @return -1, if solving the linear equation system is not successful.
+ *
+ */
+int8_t solve(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+             matrix_t x_sol[n], enum ALGORITHM algo);
+
+/**
+ * @brief   Solve an (m \f$\times\f$ n) linear system Ax = b, using the Householder
+ *          algorithm.
+ *
+ * @param[in]  m              row number of the matrix A.
+ * @param[in]  n              column number of the matrix A.
+ * @param[in]  A[][]          pointer to the matrix A.
+ * @param[in]  b[]            pointer to the vector b.
+ * @param[out] x_sol[]        pointer to the solution vector.
+ *
+ * @return  1, if solving the linear equation system is successful.
+ * @return -1, if solving the linear equation system is not successful.
+ *
+ */
+int8_t solve_householder(uint8_t m, uint8_t n, matrix_t A[][n],
+                              matrix_t b[m],
+                              matrix_t x_sol[n]);
+
+/**
+ * @brief   Solve an (m \f$\times\f$ n) linear system Ax = b, using the Givens algorithm.
+ *
+ * @param[in]  m              row number of the matrix A.
+ * @param[in]  n              column number of the matrix A.
+ * @param[in]  A[][]          pointer to the matrix A.
+ * @param[in]  b[]            pointer to the vector b.
+ * @param[out] x_sol[]        pointer to the solution vector.
+ *
+ * @return  1, if solving the linear equation system is successful.
+ * @return -1, if solving the linear equation system is not successful.
+ * @return -1, if the linear system is not solvable.
+ *
+ */
+int8_t solve_givens(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+                         matrix_t x_sol[n]);
+
+/**
+ * @brief   Solve an (m \f$\times\f$ n) linear system Ax = b, using the Gaussian Elimination with
+ *          pivoting algorithm.
+ *
+ * @param[in]  m              row number of the matrix A.
+ * @param[in]  n              column number of the matrix A.
+ * @param[in]  A[][]          pointer to the matrix A.
+ * @param[in]  b[]            pointer to the vector b.
+ * @param[out] x_sol[]        pointer to the solution vector.
+ *
+ * @return  1, if solving the linear equation system is successful.
+ * @return -1, if solving the linear equation system is not successful.
+ * @return -2, if the linear system is not solvable.
+ *
+ */
+int8_t solve_lu_decomp(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+                       matrix_t x_sol[n]);
+#endif /* SOLVE_H_ */
diff --git a/linear_algebra/solve_linear_equations/solve.c b/linear_algebra/solve_linear_equations/solve.c
new file mode 100644
index 0000000000000000000000000000000000000000..44976490c243498187cdae8353a80096c2a6a318
--- /dev/null
+++ b/linear_algebra/solve_linear_equations/solve.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ *
+ * @{
+ *
+ * @file
+ * @brief       Enables to solve systems of linear equations Ax = b for x.
+ * @details     The user can select various algorithm such as the Moore--Penrose
+ *              inverse, the Givens or the Householder algorithm for the
+ *              QR-decomposition to solve the systems of linear equations.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+
+#include "solve.h"
+#include "matrix.h"
+#include "qr_givens.h"
+#include "qr_common.h"
+#include "lu_decomp.h"
+#include "qr_householder.h"
+#include "moore_penrose_pseudo_inverse.h"
+
+int8_t solve(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+             matrix_t x_sol[n], enum ALGORITHM algo)
+{
+    int8_t status;
+
+    switch (algo) {
+        case Moore_Penrose:
+        {
+            //puts("Moore Penrose !!!!");
+            matrix_t pinv_A[n][m];
+            status = moore_penrose_get_pinv(m, n, A, pinv_A);
+            matrix_mul_vec(n, m, pinv_A, b, x_sol);
+            break;
+        }
+        case Householder:
+            //puts("Householder !!!!");
+            status = solve_householder(m, n, A, b, x_sol);
+            break;
+
+        case Givens:
+            //puts("Givens !!!");
+            status = solve_givens(m, n, A, b, x_sol);
+            break;
+
+        case Gauss:
+            //puts("Gauss !!!");
+            status = solve_lu_decomp(m, n, A, b, x_sol);
+            break;
+
+        default:
+        {
+            //puts("Default: Moore Penrose");
+            matrix_t pinv_A[n][m];
+            status = moore_penrose_get_pinv(m, n, A, pinv_A);
+            matrix_mul_vec(n, m, pinv_A, b, x_sol);
+        }
+
+    }
+
+    return status;
+}
+
+int8_t solve_householder(uint8_t m, uint8_t n, matrix_t A[][n],
+                         matrix_t b[m],
+                         matrix_t x_sol[n])
+{
+
+    matrix_t Q[m][n];
+    matrix_t qt_b[n];
+
+    if (m >= n) {
+        int8_t status;
+        status = qr_householder_decomp(m, n, A, n, Q, true);
+
+        /* qt_b = Q'*b --> Rx = Q'b (R is stored in A) */
+        matrix_trans_mul_vec(m, n, Q, m, b, qt_b);
+        qr_common_backward_subst(n, n, A, qt_b, x_sol);
+
+        return status;
+    }
+    else {
+        puts("[solve_householder]: The equation is not solvable !!!");
+
+        return -2;
+    }
+}
+
+int8_t solve_givens(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+                    matrix_t x_sol[n])
+{
+    matrix_t Q[m][n];
+    matrix_t qt_b[n];
+
+    if (m >= n) {
+        int8_t status;
+        status = qr_givens_decomp(m, n, A, n, Q, true);
+
+        /* qt_b = Q'*b --> Rx = Q'b (R is stored in A) */
+        matrix_trans_mul_vec(m, n, Q, m, b, qt_b);
+        qr_common_backward_subst(n, n, A, qt_b, x_sol);
+
+        return status;
+    }
+    else {
+        puts("[solve_givens]: The equation is not solvable !!!");
+        return -2;
+    }
+}
+
+int8_t solve_lu_decomp(uint8_t m, uint8_t n, matrix_t A[][n], matrix_t b[m],
+                       matrix_t x_sol[n])
+{
+
+    if (m == n) {
+        //puts("solve_lu_decomp !!!");
+        matrix_t L[m][m];
+        matrix_t P[m][m];
+        lu_decomp(m, A, L, P);
+
+        /* lu_b = inv(L)*P*b */
+        matrix_t inv_L[m][m];
+        matrix_get_inv_low_triang(m, m, L, inv_L);
+        matrix_t tmp[m][m];
+        matrix_mul(m, m, inv_L, m, m, P, tmp);
+        matrix_t lu_b[m];
+        matrix_mul_vec(m, m, tmp, b, lu_b);
+
+        /* U*x =  inv(L)*P*b = lu_b*/
+        qr_common_backward_subst(n, n, A, lu_b, x_sol);
+        return 1;
+    }
+
+    else {
+        puts(
+            "[solve_lu_decomp]: Only quadratic linear equation systems are supported !!!");
+        return -1;
+    }
+}
diff --git a/linear_algebra/utilities/combinatorics.c b/linear_algebra/utilities/combinatorics.c
new file mode 100644
index 0000000000000000000000000000000000000000..214322b97ee6df205b0dc6f9a442b7273dee8ae4
--- /dev/null
+++ b/linear_algebra/utilities/combinatorics.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ *
+ * @{
+ *
+ * @file
+ * @brief       Calculate possible \f$ \binom{n}{k} combinations \f$ without repetition in ascending
+ *              order.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "combinatorics.h"
+#include "vector.h"
+
+uint8_t combinatorics_init(uint8_t n, uint8_t k, uint8_t comb_arr[])
+{
+    if (k > n) {
+        return (COMBI_ERROR);
+    }
+
+    if (k == 0) {
+        return (COMBI_EMPTY);
+    }
+
+
+    // Initialization of the combinatoric array with k-values.
+    for (uint32_t i = 0; i < k; i++) {
+        comb_arr[i] = i;
+    }
+
+    return (COMBI_SUCCESS);
+}
+
+uint8_t combinatorics_get_next_without_rep(uint8_t n, uint8_t k,
+                                           uint8_t comb_arr[])
+{
+
+    if (comb_arr[k - 1] < n - 1) {
+        comb_arr[k - 1] = comb_arr[k - 1] +1;
+        return (COMBI_SUCCESS);
+    }
+
+    int32_t i;
+    for (i = k - 2; i >= 0; i--) {
+        if (comb_arr[i] < n - k + i) {
+            break;
+        }
+    }
+
+    //Break, if comb_arr[0] == n - k
+    if (i < 0) {
+        return (COMBI_END);
+    }
+
+    comb_arr[i] = comb_arr[i] + 1;
+
+    while (i < k - 1) {
+        comb_arr[i + 1] = comb_arr[i] + 1;
+        i++;
+    }
+
+    return (COMBI_SUCCESS);
+}
diff --git a/linear_algebra/utilities/doc.txt b/linear_algebra/utilities/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7754019330097308ed27ab6e8fa2bfa32bba0b1d
--- /dev/null
+++ b/linear_algebra/utilities/doc.txt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de> 
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup utilities UTILITIES
+ * @ingroup  linear_algebra 
+ *
+ * @brief       Utilities for linear algebra.
+ * @details     Utility-functions are needed by linear algebra-module as well as
+ *              other modules such as the position algorithm-module.
+ * 
+ * @author      Zakaria Kasmi
+ *
+ */
diff --git a/linear_algebra/utilities/include/combinatorics.h b/linear_algebra/utilities/include/combinatorics.h
new file mode 100644
index 0000000000000000000000000000000000000000..0a3ec4a9c896e44136ebb6f4218e3c17c59c43bd
--- /dev/null
+++ b/linear_algebra/utilities/include/combinatorics.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utilities
+ * @{
+ *
+ * @file
+ * @brief       Calculate possible \f$ \binom{n}{k} combinations \f$ without repetition in ascending
+ *              order.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef COMBINATORICS_H_
+#define COMBINATORICS_H_
+
+#include<stdint.h>
+
+/**
+ * Case of an error.
+ */
+#define COMBI_ERROR    -1
+
+/**
+ * Case of an empty combination set.
+ */
+#define COMBI_EMPTY     0
+
+/**
+ * Case of successfully calculated combination set.
+ */
+#define COMBI_SUCCESS   1
+
+/**
+ * Case of completion of calculating combination sets.
+ */
+#define COMBI_END       2
+
+
+/**
+ * @brief   Initialize the combinations generator.
+ *
+ * @param[in]  n           size of the set.
+ * @param[in]  k           size of the sub-set.
+ * @param[out] comb_arr[]  pointer to the combination set.
+ *
+ * return @ref COMBI_ERROR,   if k > n.
+ * return @ref COMBI_EMPTY,   if k =0.
+ * return @ref COMBI_SUCCESS, if successful.
+ *
+ */
+uint8_t combinatorics_init(uint8_t n, uint8_t k, uint8_t comb_arr[]);
+
+/**
+ * @brief   Generate the next combination.
+ *
+ * @param[in]      n           size of the set.
+ * @param[in]      k           size of the sub-set.
+ * @param[in, out] comb_arr[]  pointer to the combination set.
+ *
+ * return @ref COMBI_END,     if the last combination is generated.
+ * return @ref COMBI_SUCCESS, if successful.
+ *
+ */
+uint8_t combinatorics_get_next_without_rep(uint8_t n, uint8_t k, uint8_t comb_arr[]);
+
+
+#endif /*COMBINATORICS_H_ */
diff --git a/linear_algebra/utilities/include/norm_dist_rnd_generator.h b/linear_algebra/utilities/include/norm_dist_rnd_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..369c1a6e578f8f059942c90e1f9c6c330009103a
--- /dev/null
+++ b/linear_algebra/utilities/include/norm_dist_rnd_generator.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utilities
+ * @{
+ *
+ * @file
+ * @brief       Generating normally distributed random numbers.
+ * @details     The generation of normally distributed random numbers is implemented by using
+ *              the Box--Muller method.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+// COMBINATORICS_H_
+
+#ifndef NORM_DIST_RND_GENERATOR_H_
+#define NORM_DIST_RND_GENERATOR_H_
+
+/*!
+   \def PI
+   Pi, the ratio of a circle's circumference to its diameter.
+ */
+#define PI   3.14159265
+
+double get_norm_distr_rand_num(double mean, double std_dev);
+double get_rand_num(int seed);
+
+
+#endif /* NORM_DIST_RND_GENERATOR_H_ */
diff --git a/linear_algebra/utilities/include/shell_sort.h b/linear_algebra/utilities/include/shell_sort.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e0df2c8b3f20ba70ea25e63684a7af9c60db7f1
--- /dev/null
+++ b/linear_algebra/utilities/include/shell_sort.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utilities
+ * @{
+ *
+ * @file
+ * @brief       Implement the Shell sort algorithm.
+ * @details     The Shell sort algorithm is more convenient for devices with limited storage
+ *              capacity.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef SHELL_SORT_H_
+#define SHELL_SORT_H_
+
+#include <stdint.h>
+#include "vector.h"
+
+/**
+ * @brief   Sort a data set of integers by using the Shell sort algorithm.
+ *
+ * @param[in]   array[]         pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ */
+void int_shell_sort(int *array, int length);
+
+/**
+ * @brief   Sort a data set of type utils_t by using the Shell sort algorithm.
+ *
+ * @param[in]   arr[]           pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ */
+void shell_sort(vector_t *arr, uint8_t length);
+
+
+#endif /* SHELL_SORT_H_ */
diff --git a/linear_algebra/utilities/include/shell_sort.h.bak b/linear_algebra/utilities/include/shell_sort.h.bak
new file mode 100644
index 0000000000000000000000000000000000000000..cf241333ed0cb14f3d7b3704fb6dd51ac2c26bc9
--- /dev/null
+++ b/linear_algebra/utilities/include/shell_sort.h.bak
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utils
+ * @{
+ *
+ * @file
+ * @brief       Implement the Shell sort algorithm.
+ * @details     The Shell sort algorithm is more convenient for devices with limited storage
+ *              capacity.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef SHELL_SORT_H_
+#define SHELL_SORT_H_
+
+#include <stdint.h>
+#include "vector.h"
+
+/**
+ * @brief   Sort a data set of integers by using the Shell sort algorithm.
+ *
+ * @param[in]   array[]         pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ */
+void int_shell_sort(int* array, int length);
+
+/**
+ * @brief   Sort a data set of type utils_t by using the Shell sort algorithm.
+ *
+ * @param[in]   arr[]           pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ */
+void shell_sort(vector_t* arr, uint8_t length);
+
+/**
+ * @brief   Sort a data set of type utils_t by using the Shell sort algorithm.
+ *
+ * @param[in]   arr[]           pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ */
+void double_shell_sort(vector_t* arr, uint8_t length);
+
+
+
+
+
+#endif /* SHELL_SORT_H_ */
diff --git a/linear_algebra/utilities/include/utils.h b/linear_algebra/utilities/include/utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d6b25535096e14ebb603cd4d1b8dd01387c2a00
--- /dev/null
+++ b/linear_algebra/utilities/include/utils.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utilities
+ * @{
+ *
+ * @file
+ * @brief       Utilities for linear algebra.
+ * @details     Utility-functions are needed by linear algebra-module as well as
+ *              other modules such as the position algorithm-module.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef UTILS_H_
+#define UTILS_H_
+
+#include <inttypes.h>
+#include "vector.h"
+
+/** @brief   Define the pi-constant */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/**
+ * @brief   Convert the angle from degrees to radians.
+ *
+ * @param[in] deg_angle     angle in degrees.
+ *
+ * @return                  angle in radians.
+ *
+ */
+double utils_to_radian(double deg_angle);
+
+/**
+ * @brief   Compute the sine of a variable in degrees.
+ *          Calculate the sine of the variable deg_angle, which is expressed
+ *          in degrees.
+ *
+ * @param[in] deg_angle     angle in degrees.
+ *
+ * @return                  sine value.
+ *
+ */
+double utils_sind(double deg_angle);
+
+/**
+ * @brief   Interchange the values of two variables of type uint8_t.
+ *
+ * @param[in] *a     pointer to first variable.
+ * @param[in] *b     pointer to second variable.
+ *
+ */
+void utils_swap(uint8_t *a, uint8_t *b);
+
+/**
+ * @brief    Returns the greater of two real numbers.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the greater of a and b.
+ *
+ */
+double utils_max(double a, double b);
+
+/**
+ * @brief    Returns the smaller of two real numbers.
+ *
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the smaller of a and b.
+ *
+ */
+double utils_min(double a, double b);
+
+/**
+ * @brief    Returns the greater of two numbers from type uint8_t.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the greater of a and b.
+ *
+ */
+uint8_t utils_u8_max(uint8_t a, uint8_t b);
+
+/**
+ * @brief    Returns the smaller of two numbers from type uint8_t.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the smaller of a and b.
+ *
+ */
+uint8_t utils_u8_min(uint8_t a, uint8_t b);
+
+// Enables to use variable format string as well as argument lists
+// Fixing error: format not a string literal.
+
+/**
+ * @brief   Print by using variable format string as well as argument lists.
+ *          This function enables to print data by using a variable format
+ *          string as well as argument list. Furthermore, it avoids the error:
+ *          "format not a string literal", if printf is used.
+ *
+ * @param[in] *format_str     format string.
+ * @param[in] ...             argument list.
+ *
+ */
+void utils_printf(char *format_str, ...);
+
+/**
+ * @brief   Compute the mean value of a data set.
+ *
+ * @param[in] arr_size        size of the data set.
+ * @param[in] in_arr[]        pointer to the data set.
+ *
+ * @return    the mean value of the data set.
+ *
+ */
+double utils_mean(uint8_t arr_size, vector_t in_arr[]);
+
+/**
+ * @brief   Compute the moving average of a data set.
+ *
+ * @param[in]   arr_size        size of the data set.
+ * @param[in]   in_arr[]        pointer to the data set.
+ * @param[in]   window_size     window size.
+ * @param[out]  out_arr         pointer to the values of the moving average.
+ *
+ */
+void utils_moving_average(uint8_t arr_size, vector_t in_arr[],
+                          uint8_t window_size,
+                          vector_t out_arr[]);
+
+/**
+ * @brief   Compute the median of a finite array of numbers.
+ *
+ * @param[in]   arr[]           pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ * @return    the median value of the data set.
+ *
+ */
+double utils_get_median(vector_t arr[], uint8_t length);
+
+/**
+ * @brief   Compute the square root without under/overflow.
+ *
+ * @param[in]   x      first value.
+ * @param[in]   y      second value.
+ *
+ * @return    save square root.
+ *
+ */
+double utils_get_save_square_root(double x, double y);
+
+#endif /* UTILS_H_ */
diff --git a/linear_algebra/utilities/include/utils.h.bak b/linear_algebra/utilities/include/utils.h.bak
new file mode 100644
index 0000000000000000000000000000000000000000..4316862c16abaaee8717f2fdb3800d83c2dcfac3
--- /dev/null
+++ b/linear_algebra/utilities/include/utils.h.bak
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     utils
+ * @{
+ *
+ * @file
+ * @brief       Utilities for linear algebra.
+ * @details     Utility-functions are needed by linear algebra-module as well as
+ *              other modules such as the position algorithm-module.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#ifndef UTILS_H_
+#define UTILS_H_
+
+#include <inttypes.h>
+
+/** @brief   Define the data type */
+#define utils_t double
+
+#ifndef utils_t
+#define utils_t double
+#endif
+
+/** @brief   Define the pi-constant */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/**
+ * @brief   Convert the angle from degrees to radians.
+ *
+ * @param[in] deg_angle     angle in degrees.
+ *
+ * @return                  angle in radians.
+ *
+ */
+double utils_to_radian(double deg_angle);
+
+/**
+ * @brief   Compute the sine of a variable in degrees.
+ *          Calculate the sine of the variable deg_angle, which is expressed
+ *          in degrees.
+ *
+ * @param[in] deg_angle     angle in degrees.
+ *
+ * @return                  sine value.
+ *
+ */
+double utils_sind(double deg_angle);
+
+/**
+ * @brief   Interchange the values of two variables of type uint8_t.
+ *
+ * @param[in] *a     pointer to first variable.
+ * @param[in] *b     pointer to second variable.
+ *
+ */
+void utils_swap(uint8_t *a, uint8_t *b);
+
+/**
+ * @brief    Returns the greater of two real numbers.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the greater of a and b.
+ *
+ */
+double utils_max(double a, double b);
+
+/**
+ * @brief    Returns the smaller of two real numbers.
+ *
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the smaller of a and b.
+ *
+ */
+double utils_min(double a, double b);
+
+/**
+ * @brief    Returns the greater of two numbers from type uint8_t.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the greater of a and b.
+ *
+ */
+uint8_t utils_u8_max(uint8_t a, uint8_t b);
+
+/**
+ * @brief    Returns the smaller of two numbers from type uint8_t.
+ *
+ * @param[in] a     the first value to compare.
+ * @param[in] b     the second value to compare.
+ *
+ * @return          the smaller of a and b.
+ *
+ */
+uint8_t utils_u8_min(uint8_t a, uint8_t b);
+
+// Enables to use variable format string as well as argument lists
+// Fixing error: format not a string literal.
+
+/**
+ * @brief   Print by using variable format string as well as argument lists.
+ *          This function enables to print data by using a variable format
+ *          string as well as argument list. Furthermore, it avoids the error:
+ *          "format not a string literal", if printf is used.
+ *
+ * @param[in] *format_str     format string.
+ * @param[in] ...             argument list.
+ *
+ */
+void utils_printf(char *format_str, ...);
+
+/**
+ * @brief   Compute the mean value of a data set.
+ *
+ * @param[in] arr_size        size of the data set.
+ * @param[in] in_arr[]        pointer to the data set.
+ *
+ * @return    the mean value of the data set.
+ *
+ */
+double utils_mean(uint8_t arr_size, double in_arr[]);
+
+/**
+ * @brief   Compute the moving average of a data set.
+ *
+ * @param[in]   arr_size        size of the data set.
+ * @param[in]   in_arr[]        pointer to the data set.
+ * @param[in]   window_size     window size.
+ * @param[out]  out_arr         pointer to the values of the moving average.
+ *
+ */
+void utils_moving_average(uint8_t arr_size, double in_arr[], uint8_t window_size, double out_arr[]);
+
+
+/**
+ * @brief   Compute the median of a finite array of numbers.
+ *
+ * @param[in]   arr[]           pointer to the data set.
+ * @param[in]   length          size of the data set.
+ *
+ * @return    the median value of the data set.
+ *
+ */
+double utils_get_median(double arr[], uint8_t length);
+
+/**
+ * @brief   Compute the square root without under/overflow.
+ *
+ * @param[in]   x      first value.
+ * @param[in]   y      second value.
+ *
+ * @return    save square root.
+ *
+ */
+double utils_get_save_square_root(double x, double y);
+
+#endif /* UTILS_H_ */
diff --git a/linear_algebra/utilities/norm_dist_rnd_generator.c b/linear_algebra/utilities/norm_dist_rnd_generator.c
new file mode 100644
index 0000000000000000000000000000000000000000..d7766a767b4cc7ff59b673c81f9b811af5b36592
--- /dev/null
+++ b/linear_algebra/utilities/norm_dist_rnd_generator.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ *
+ * @{
+ *
+ * @file
+ * @brief       Generating normally distributed random numbers.
+ * @details     The generation of normally distributed random numbers is implemented by using
+ *              the Box--Muller method.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "norm_dist_rnd_generator.h"
+
+
+
+/**
+ * @brief   Get a normally distributed random number by applying the Box--Muller method.
+ *
+ * @param[in] mean_val      mean value.
+ * @param[in] std_dev_val   standard deviation.
+ *
+ * @return                  normally distributed random number.
+ *
+ */
+double get_norm_distr_rand_num(double mean_val, double std_dev_val)
+{
+    double u, r, theta;
+    double x;
+    double adj_norm_rv;
+
+    // Generate a random value of u
+    u = 0.0;
+    while (u == 0.0) {
+        u = get_rand_num(0);
+    }
+
+    r = sqrt(-2.0 * log(u));
+
+    // Generate a random value of theta
+    theta = 0.0;
+    while (theta == 0.0) {
+        theta = 2.0 * PI * get_rand_num(0);
+    }
+
+    x = r * cos(theta);
+
+    adj_norm_rv = (x * std_dev_val) + mean_val;
+
+    return (adj_norm_rv);
+}
+
+/**
+ * @brief    Generate uniform (0.0, 1.0) random numbers by using the Linear Congruential
+ *           Generator (LGC) algorithm.
+ *
+ * @note     The LGC is implemented based on the following book:
+ *            R. Jain, "The Art of Computer Systems Performance Analysis,"
+ *            John Wiley & Sons, 1991.
+ *
+ * @param[in] initial_seed_val  initial seed value.
+ *
+ * @return    random number between 0.0 and 1.0.
+ *
+ */
+double get_rand_num(int initial_seed_val)
+{
+    const long a = 16807;
+    const long m = 2147483647;
+    const long q = 127773;
+    const long r = 2836;
+    static long x;
+    long x_div_q;
+    long x_mod_q;
+    long new_x;
+
+    // Setting of the seed value
+    if (initial_seed_val > 0) {
+        x = initial_seed_val;
+        return (0.0);
+    }
+
+    x_div_q = x / q;
+    x_mod_q = x % q;
+    new_x = (a * x_mod_q) - (r * x_div_q);
+    if (new_x > 0) {
+        x = new_x;
+    }
+    else {
+        x = new_x + m;
+    }
+
+    return ((double)x / m);
+}
diff --git a/linear_algebra/utilities/shell_sort.c b/linear_algebra/utilities/shell_sort.c
new file mode 100644
index 0000000000000000000000000000000000000000..c64d662f49680cc28134c3b9f405e15311e88b29
--- /dev/null
+++ b/linear_algebra/utilities/shell_sort.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Implement the Shell sort algorithm.
+ * @details     The Shell sort algorithm is more convenient for devices with limited storage
+ *              capacity.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include "utils.h"
+#include "vector.h"
+
+/* Shell Sort Program */
+void int_shell_sort(int *array, int length)
+{
+    int n = length;
+    int i, j, gap, temp;
+
+    for (gap = n / 2; gap > 0; gap /= 2) {
+        for (i = gap; i < n; i++) {
+            temp = array[i];
+            for (j = i; j >= gap; j -= gap) {
+                if (temp < array[j - gap]) {
+                    array[j] = array[j - gap];
+                }
+                else {
+                    break;
+                }
+            }
+            array[j] = temp;
+        }
+    }
+}
+
+void shell_sort(vector_t *arr, uint8_t length)
+{
+    int32_t j, k;
+    vector_t temp;
+
+    for (int32_t i = length / 2; i > 0; i = i / 2) {
+        for (j = i; j < length; j++) {
+            temp = arr[j];
+            for (k = j - 1; k >= 0 && arr[k] > temp; k--) {
+                arr[k + 1] = arr[k];
+            }
+            arr[k + 1] = temp;
+        }
+    }
+}
diff --git a/linear_algebra/utilities/utils.c b/linear_algebra/utilities/utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0f6673eda562d584af06ee21adf30c9e2b98516
--- /dev/null
+++ b/linear_algebra/utilities/utils.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2020 Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *               2020 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @{
+ *
+ * @file
+ * @brief       Utilities for linear algebra.
+ *              Utility-functions are needed by the linear algebra-module as
+ *              well as other modules such as the position algorithm-module.
+ *
+ * @author      Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "utils.h"
+#include "shell_sort.h"
+
+// from degree to radian
+double utils_to_radian(double deg_angle)
+{
+    double radians_angle = deg_angle * M_PI / 180.0;
+
+    return radians_angle;
+}
+
+//Sine of argument in degrees
+double utils_sind(double deg_angle)
+{
+    double radians_angle = deg_angle * M_PI / 180.0;
+
+    return sin(radians_angle);
+}
+
+void utils_swap(uint8_t *a, uint8_t *b)
+{
+    uint8_t tmp;
+
+    tmp = *a;
+    *a = *b;
+    *b = tmp;
+}
+
+double utils_max(double a, double b)
+{
+    if (a < b) {
+        return b;
+    }
+    else {
+        return a;
+    }
+}
+
+double utils_min(double a, double b)
+{
+    if (a < b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+uint8_t utils_u8_max(uint8_t a, uint8_t b)
+{
+    if (a < b) {
+        return b;
+    }
+    else {
+        return a;
+    }
+}
+
+uint8_t utils_u8_min(uint8_t a, uint8_t b)
+{
+    if (a < b) {
+        return a;
+    }
+    else {
+        return b;
+    }
+}
+
+// Enables to use variable format strings as well as argument lists
+void utils_printf(char *format_str, ...)
+{
+    va_list args;
+
+    va_start(args, format_str);
+    vprintf(format_str, args);
+    va_end(args);
+}
+
+double utils_mean(uint8_t arr_size, vector_t in_arr[])
+{
+    double mean = 0.0;
+
+    if (arr_size <= 0) {
+        puts("Not valid input array size !!!");
+        return mean;
+    }
+
+    for (uint8_t i = 0; i < arr_size; i++) {
+        mean += in_arr[i];
+    }
+
+    return mean / arr_size;
+}
+
+void utils_moving_average(uint8_t arr_size, vector_t in_arr[],
+                          uint8_t window_size,
+                          vector_t out_arr[])
+{
+    double sum = 0.0;
+    double trail_value = 0;
+    uint8_t pos = 0;
+
+    if (arr_size <= 0) {
+        puts("Not valid input array size !!!");
+        return;
+    }
+
+    if (window_size <= 0) {
+        puts("Not valid window size !!!");
+        return;
+    }
+
+    for (uint8_t i = 0; i < arr_size; i++) {
+        sum = sum - trail_value + in_arr[i];
+        out_arr[i] = sum / window_size;
+
+        pos++;
+        if (pos >= window_size) {
+
+            trail_value = in_arr[pos - window_size];
+
+        }
+    }
+}
+
+double utils_get_median(vector_t arr[], uint8_t length)
+{
+    int middle = length / 2;
+
+    shell_sort(arr, length);
+
+    if (length % 2 == 1) {
+        return arr[middle];
+    }
+    else {
+        return (arr[middle - 1] + arr[middle]) / 2.0;
+    }
+
+}
+
+/** sqrt(a^2 + b^2) without under/overflow. **/
+double utils_get_save_square_root(double x, double y)
+{
+    double sqr_root;
+
+    if (fabs(x) > fabs(y)) {
+        sqr_root = y / x;
+        sqr_root = fabs(x) * sqrt(1 + sqr_root * sqr_root);
+    }
+    else if (y != 0) {
+        sqr_root = x / y;
+        sqr_root = fabs(y) * sqrt(1 + sqr_root * sqr_root);
+    }
+    else {
+        sqr_root = 0.0;
+    }
+
+    return sqr_root;
+}