{"id":18015564,"url":"https://github.com/nomemory/neat-matrix-library","last_synced_at":"2025-06-22T04:38:15.135Z","repository":{"id":40299311,"uuid":"327015433","full_name":"nomemory/neat-matrix-library","owner":"nomemory","description":"nml is a \"simple\" matrix/numerical analysis library written in pure C. The scope of the library is to highlight various algorithm implementations related to matrices. Code readability was a major concern.","archived":false,"fork":false,"pushed_at":"2024-06-17T08:04:11.000Z","size":2503,"stargazers_count":94,"open_issues_count":3,"forks_count":20,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-04T09:36:03.257Z","etag":null,"topics":["ansi-c","c","gauss-elimination","gauss-jordan","linear-algebra","linear-algebra-library","linear-algorithms","lu-decomposition","matrix","neat","nml","reduced-row-echelon-form","row-echelon-form"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nomemory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-05T13:59:12.000Z","updated_at":"2025-03-30T12:50:02.000Z","dependencies_parsed_at":"2024-10-30T04:24:35.942Z","dependency_job_id":null,"html_url":"https://github.com/nomemory/neat-matrix-library","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nomemory/neat-matrix-library","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-matrix-library","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-matrix-library/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-matrix-library/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-matrix-library/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nomemory","download_url":"https://codeload.github.com/nomemory/neat-matrix-library/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-matrix-library/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261237812,"owners_count":23128844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansi-c","c","gauss-elimination","gauss-jordan","linear-algebra","linear-algebra-library","linear-algorithms","lu-decomposition","matrix","neat","nml","reduced-row-echelon-form","row-echelon-form"],"created_at":"2024-10-30T04:14:25.416Z","updated_at":"2025-06-22T04:38:10.116Z","avatar_url":"https://github.com/nomemory.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"```\n .----------------.  .----------------.  .----------------. \n| .--------------. || .--------------. || .--------------. |\n| | ____  _____  | || | ____    ____ | || |   _____      | |\n| ||_   \\|_   _| | || ||_   \\  /   _|| || |  |_   _|     | |\n| |  |   \\ | |   | || |  |   \\/   |  | || |    | |       | |\n| |  | |\\ \\| |   | || |  | |\\  /| |  | || |    | |   _   | |\n| | _| |_\\   |_  | || | _| |_\\/_| |_ | || |   _| |__/ |  | |\n| ||_____|\\____| | || ||_____||_____|| || |  |________|  | |\n| |              | || |              | || |              | |\n| '--------------' || '--------------' || '--------------' |      Neat Matrix Library\n '----------------'  '----------------'  '----------------'       \n```\n\n**nml** is a simple [matrix](https://en.wikipedia.org/wiki/Matrix_(mathematics)) and [linear algebra](https://en.wikipedia.org/wiki/Linear_algebra) library written in standard C. \n\nCode should be portable and there are no dependencies. \n\nFor a detailed explanation of the library code please check this [blog post](https://www.andreinc.net/2021/01/20/writing-your-own-linear-algebra-matrix-library-in-c).\n\nIt currently supports:\n* Basic Matrix Operations (row swaps, colum swaps, multiplication, addition, etc.)\n* [LU Decomposition](https://en.wikipedia.org/wiki/LU_decomposition);\n* Inverse(A);\n* Determinant(A) \n* Solving [linear systems of equations](https://en.wikipedia.org/wiki/System_of_linear_equations);\n* [Row Echelon Form](https://en.wikipedia.org/wiki/Gaussian_elimination);\n* Reduced Row Echelon Form ([Gauss-Jordan](https://brilliant.org/wiki/gaussian-elimination/));\n* [QR decomposition](https://en.wikipedia.org/wiki/QR_decomposition)\n\nThe library is still under development, but a few thousands test cases are already implemented, covering the most complex algorithms (REF, RREF, LUP, QR, DET, INV, BACKWARD SUBSTITION, FORWARD SUBSTITION, etc.)\n\nTable of Contents\n=================\n\n   * [Compile / Run Examples](#compile--run-examples)\n      * [Building the library](#building-the-library)\n      * [Building the examples](#building-the-examples)\n      * [Running the tests](#running-the-tests)\n      * [Cleaning](#cleaning)\n   * [How to use the library](#how-to-use-the-library)\n      * [Creating matrices](#creating-matrices)\n         * [Creating a new Matrix](#creating-a-new-matrix)\n         * [Creating a marray from an array (double[N])](#creating-a-marray-from-an-array-doublen)\n         * [Creating a Matrix from an external file](#creating-a-matrix-from-an-external-file)\n         * [Creating a matrix from user input](#creating-a-matrix-from-user-input)\n         * [Creating randomized matrices](#creating-randomized-matrices)\n      * [Check if two matrices are equal](#check-if-two-matrices-are-equal)\n      * [Accesing and modifying matrix elements](#accesing-and-modifying-matrix-elements)\n         * [Select rows and columns](#select-rows-and-columns)\n         * [Set all elements to a value](#set-all-elements-to-a-value)\n         * [Set the first diagonal to a value](#set-the-first-diagonal-to-a-value)\n         * [Scalar multiply the matrix](#scalar-multiply-the-matrix)\n         * [Multiply rows](#multiply-rows)\n         * [Add rows](#add-rows)\n      * [Modifying the matrix structure](#modifying-the-matrix-structure)\n         * [Remove rows and columns](#remove-rows-and-columns)\n         * [Swap rows and columns](#swap-rows-and-columns)\n         * [Concatenate matrices](#concatenate-matrices)\n      * [Matrices operations](#matrices-operations)\n         * [Add and subtract matrices](#add-and-subtract-matrices)\n         * [Multiply matrices (dot)](#multiply-matrices-dot)\n      * [Transpose matrices](#transpose-matrices)\n      * [Calculate trace](#calculate-trace)\n      * [Row Echelon](#row-echelon)\n         * [Calculate Row Echelon Form using Gaussian Elimination](#calculate-row-echelon-form-using-gaussian-elimination)\n         * [Calculate Reduced Row Echelon Form using Gauss-Jordan](#calculate-reduced-row-echelon-form-using-gauss-jordan)\n      * [LU(P) Decomposition](#lup-decomposition)\n      * [Matrix inverse](#matrix-inverse)\n      * [Matrix determinant](#matrix-determinant)\n      * [Solve linear systems of equations](#solve-linear-systems-of-equations)\n      \n# Compile / Run Examples\n\nThe build file for the library it's called `nml.sh`. \nIt's actually a `bash` script (not a `makefile`!).\n\n## Building the library\n\n```bash\n./nml.sh clean build\n```\n\nThis will compile the library, create a `dist` folder where you will find `*.a` static library file and the header files.\n\n`gcc` and `ar` should be available in `$PATH`.\n\nIf you want to use the `clang` compiler instead of `gcc` you need to manually edit the `./nml.sh` file, changing the variable `CC` from `gcc` to `clang`. \nNothing else should be changed.\n\n```bash\n# COMPILING RELATED\nCC=clang #\u003c----------------- here\nCCFLAGS=\"-Wall -c\"\nCCFLAGS_EXAMPLES=\"-Wall\"\n```\n\n## Building the examples\n\nExamples can be found in the [`./examples` folder](https://github.com/nomemory/neat-matrix-library/tree/main/examples).\n\nTo build the code examples:\n\n```bash\n./nml.sh clean examples\n```\n\n1. This will create an `examples/lib` folder where the `libnml.a` and the header files will be copied;\n2. The `examples/*.c` will be compiled with the latest version of `libnml`;\n3. For each `examples/*.c` an executable (`*.ex`) will be created.\n\nTo run an example:\n\n```bash\n# ./nml.sh clean examples \u0026\u0026 ./examples/\u003cexample name\u003e.ex\n./nml.sh clean examples \u0026\u0026 ./examples/playground.ex\n```\n\n## Running the tests \n\nTo run the tests \n\n```bash\n./nml.sh clean test\n```\n\n1. This will create a `test/lib` folder where the `libnml.a` and the header files will be copied;\n2. Each test `tests/*.c` will be compiled with the latest version of `libnml`;\n3. For each test `tests/*/c` an executable (`*.ex`) will be created.\n\nThe test data was generated using [sympy](https://docs.sympy.org/). \nIn the `tests/generators/` folder you can find the python3 (`.py`) scripts used to generate the data.\n\n## Cleaning\n\n```bash\n./nml.sh clean\n```\n\nThis will clean everything (`*.o`,`*.ex`,`*.a`) and will leave the library folder in a clean state.\n\n# How to use the library\n\nA few examples can be found in the [`./examples` folder](https://github.com/nomemory/neat-matrix-library/tree/main/examples) folder.\n\n## Creating matrices\n\nAll the methods are interacting with the `nml_mat` struct:\n\n```c\ntypedef struct nml_mat_s {\n  unsigned int num_rows;\n  unsigned int num_cols;\n  double **data;\n  int is_square;\n} nml_mat;\n```\n\nTo interact the elements of the matrix:\n\n```c\nnml_mat *m = ...\nm-\u003edata[i][j] = ...\n```\n\n### Creating a new Matrix\n\nThe methods for a creating a new matrix are:\n* `nml_mat *nml_mat_new(unsigned int num_rows, unsigned int num_cols)`\n  - Creates a `num_rows * num_cols` matrix of zeroes. \n* `nml_mat *nml_mat_sqr(unsigned int size)`\n  - Creates a square `size * size` matrix  of zeroes.\n* `nml_mat *nml_mat_eye(unsigned int size)`\n  - Creates an identity `size * size` matrix.\n* `nml_mat *nml_mat_cp(nml_mat *m)`\n  - Returns a new identitcal copy of matrix `m`.\n  \nEverytime we create a matrix, we dynamically allocate memory. \nTo free the memory please use: `nml_mat_free(nml_mat *m)`.  \n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n\n  nml_mat* m, *mx;\n\n  printf(\"\\nCreating an empty matrix with 2x3\\n\");\n  m = nml_mat_new(2,3);\n  nml_mat_print(m);\n  nml_mat_free(m);\n\n  printf(\"\\nCreating a square matrix 5x5 \\n\");\n  m = nml_mat_sqr(5);\n  nml_mat_print(m);\n  nml_mat_free(m);\n\n  printf(\"\\nCreating an ID 7x7 Matrix and copying it into another matrix:\\n\");\n  m = nml_mat_eye(7);\n  mx = nml_mat_cp(m);\n  nml_mat_print(m);\n  nml_mat_print(mx);\n  nml_mat_free(m);\n  nml_mat_free(mx);\n\n  return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/creating_a_matrix.ex\n```\n\n### Creating a marray from an array (`double[N]`)\n\nAn array can be used as the \"data source\" for the Matrix by using:\n* `nml_mat *nml_mat_from(unsigned int num_rows, unsigned int num_cols, unsigned int n_vals, double *vals)`\n  - `num_rows` and `num_cols` represent the dimensions of the matrix;\n  - `n_vals` how many values to read from the `vals` source. If `n_vals` is smaller than the product `num_cols * num_rows`, `0.0` will be used as the default value;\n  - `vals` the array containing double values. \n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) { \n    double array[6] = { \n        1.0, 0.2, 3.0, 4.0, 5.0, 3.1 \n    };\n    nml_mat* my;\n    \n    // 3 rows, 2 columns\n    // read exactly 6 numbers from array[6]\n    my = nml_mat_from(3, 2, 6, array);\n    nml_mat_print(my);\n    nml_mat_free(my);\n\n    // 4 rows, 2 columns\n    // read exactly 3 numbers from array[6]\n    my = nml_mat_from(4, 2, 3, array);\n    nml_mat_print(my);\n    nml_mat_free(my);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/creating_a_matrix_from_an_array.ex\n```\n\n### Creating a Matrix from an external file\n\nThe two methods that can be used to create a matrix from a file on disk are:\n* `nml_mat *nml_mat_fromfile(const char *file)` \n  * Create a matrix from the `file` path. If the file cannot be opened a `NULL` matrix will be returned. \n* `nml_mat *nml_mat_fromfilef(FILE *f)` \n  * Creates a matrix from am already opened stream `f`. Does not automatically close the stream (`FILE`). \n\nIn the file, the matrix has the following format:\n\n```\n4 5\n0.0     1.0     2.0     5.0     3.0\n3.0     8.0     9.0     1.0     4.0\n2.0     3.0     7.0     1.0     1.0\n0.0     0.0     4.0     3.0     8.0\n```\n\nOn the first line `4` represents the number of rows and `5` represents the number of columns of the Matrix\nThen next lines contain the matrix elements: `4 * 5 = 20` numbers.\n\nExample code:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    const char *f = \"examples/data/matrix1.data\";\n    nml_mat *from_file = nml_mat_fromfile(f);\n    nml_mat_print(from_file);\n    nml_mat_free(from_file);\n\n    // Or if the file is already opened\n\n    FILE *m_file = fopen(\"examples/data/matrix2.data\", \"r\");\n    nml_mat *from_file2 = nml_mat_fromfilef(m_file);\n    nml_mat_print(from_file2);\n    nml_mat_free(from_file2);\n    fclose(m_file);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/creating_a_matrix_from_file.ex\n```\n\n### Creating a matrix from user input\n\nThe `nml_mat *nml_mat_fromfilef(FILE *f)` can be called, with `f=stdin`.\n\nCode example:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *from_file2 = nml_mat_fromfilef(stdin);\n    nml_mat_print(from_file2);\n    nml_mat_free(from_file2);\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/creating_a_matrix_from_user_input.ex\n```\n\n### Creating randomized matrices\n\nCreating a randomized matrix can be done with the following two methods:\n* `nml_mat *nml_mat_rnd(unsigned int num_rows, unsigned int num_cols, double min, double max)`\n  - Creates a randomized matrix of size `num_rows * num_cols`;\n  - The random values are between `min` and `max`;\n* `nml_mat *nml_mat_sqr_rnd(unsigned int size, double min, double max)`\n  - Creates a randomized matrix of size `size * size`;\n  - The random values are between `min` and `max`;\n  \n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003ctime.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n  srand(time(NULL)); // Should be called once per program\n  nml_mat *m = nml_mat_rnd(5, 5, -10.0, 10.0);\n  nml_mat_print(m);\n  nml_mat_free(m);\n  return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/create_randomized_matrix.ex\n```\n\n## Check if two matrices are equal\n\nThere are two \"equality\" methods for matrices:\n\n* `int nml_mat_eqdim(nml_mat *m1, nml_mat *m2)`\n  - Tests if two matrices have the same dimension.\n  \n* `int nml_mat_eq(nml_mat *m1, nml_mat *m2, double tolerance)`\n  - Test if two matrices are equal:\n    - They have the same dimensions\n    - The elements are equal or close of being equal.\n  - If you want the elements to be \"exactly\" eqaul, `tolerance=0.0`\n\n\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003ctime.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n    srand(time(NULL));\n    nml_mat *m1 = nml_mat_rnd(2, 3, 1.0, 10.0);\n    nml_mat *m2 = nml_mat_rnd(2, 3, 1.0, 10.0);\n\n    if (nml_mat_eq(m1, m2, 0.001)) {\n        printf(\"Wow, what were the oddss..\\n\");\n    } else {\n        printf(\"It's ok, nobody is that lucky!\\n\");\n    }\n    if (nml_mat_eqdim(m1, m2)) {\n        printf(\"At least we know they both have the same number of rows and columns.\\n\");\n    }\n\n    nml_mat_free(m1);\n    nml_mat_free(m2);\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/matrix_equality.ex\n```\n\n## Accesing and modifying matrix elements\n\n### Select rows and columns\n\nTwo methods can be used to select rows and columns from a source matrix (`nml_mat*`):\n\n* `nml_mat *nml_mat_col_get(nml_mat *m, unsigned int col)`\n* `nml_mat *nml_mat_row_get(nml_mat *m, unsigned int row)`\n\nThe following code extracts every column of a given random matrix into a temporary column matrix (`nml_mat*`):\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003ctime.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n  printf(\"\\nExtract all matrix columns from a Matrix as matrices\\n\");\n  srand(time(NULL));\n  nml_mat *m = nml_mat_rnd(5, 5, -10.0, 10.0);\n  nml_mat *col;\n  nml_mat_print(m);\n  int i = 0;\n  for(i = 0; i \u003c m-\u003enum_cols; i++) {\n    col = nml_mat_col_get(m, i);\n    nml_mat_print(col);\n    nml_mat_free(col);\n  }\n  nml_mat_free(m);\n  return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/select_columns.ex\n```\n\n### Set all elements to a value\n\nUse: `void nml_mat_all_set(nml_mat *matrix, double value)`\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cmath.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    // Creates a matrix of zeros of size = 5\n    nml_mat *pi_mat = nml_mat_sqr(5);\n\n    // Sets all elements to PI\n    nml_mat_all_set(pi_mat, M_PI);\n\n    nml_mat_print(pi_mat);\n    nml_mat_free(pi_mat);\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/set_all_elements.ex\n```\n\n### Set the first diagonal to a value\n\nUse: `int nml_mat_diag_set(nml_mat *matrix, double value)`\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cmath.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    // Creates a matrix of zeros of size = 5\n    nml_mat *pi_mat = nml_mat_sqr(5);\n\n    // Sets the first diagonal to PI\n    nml_mat_diag_set(pi_mat, M_PI);\n\n    nml_mat_print(pi_mat);\n    nml_mat_free(pi_mat);\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/set_diagonal_elements.ex\n```\n\n### Scalar multiply the matrix\n\nUse:\n* `nml_mat *nml_mat_smult(nml_mat *m, double num)`\n   - Multiplies all elements of matrix `m` with `num`. A new matrix is returned.\n* `int nml_mat_smult_r(nml_mat *m, double num)`\n   - Multiplies all elements of matrix `m` with `num`. All changes are done on matrix `m`.\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m = nml_mat_eye(5);\n\n    // Multiply all elements of m with 2.0\n    // and return a new matrix\n\n    nml_mat *new_m = nml_mat_smult(m, 2.0);\n\n    if (!(nml_mat_eq(m, new_m, 0.0))) {\n        printf(\"It's normal to see this message.\\n\");\n    }\n\n    // Multiply all elements of m with 2.0\n    // m is modified, no new matrix is created\n    nml_mat_smult_r(m, 2.0);\n\n    if (nml_mat_eq(m, new_m, 0.0)) {\n        printf(\"It's even more normal to see this message.\\n\");\n    }\n\n    nml_mat_free(m);\n    nml_mat_free(new_m);\n    \n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/scalar_multiply.ex\n```\n\n### Multiply rows\n\nUse:\n\n* `nml_mat *nml_mat_row_mult(nml_mat *m, unsigned int row, double num)`\n   - Multiplies all elements from row `row` in matrix `m` with scalar `num`. A new matrix is returned. `m` remains un-altered.\n* `int nml_mat_row_mult_r(nml_mat *m, unsigned int row, double num)`\n   - Multiplies all elements from row `row` in matrix `m` with scalar `num`. The changes are done directly on matrix `m`.\n   \nExample:  \n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *a = nml_mat_new(4,5);\n    nml_mat_all_set(a, 1.0);\n    int i = 0;\n    for(; i \u003c a-\u003enum_rows; ++i) {\n        // Changes are doing on matrix a\n        // row[i] is multiplied with (double) i\n        nml_mat_row_mult_r(a, i, (double)i);\n    }\n    nml_mat_print(a);\n\n    // Create a new matrix b by multiplying row[1] \n    // in matrix a with 5.0.\n    // Matrix a remains unchanged\n    nml_mat *b = nml_mat_row_mult(a, 1, 5.0);\n    nml_mat_print(b);\n    nml_mat_free(a);\n    nml_mat_free(b);\n    return 0;\n}\n````\n\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/multiply_rows.ex\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/multiply_rows.ex\n```\n\n### Add rows\n\nThe following methods are used to add a row to another row (with a multiplicator). This method is usally used when implementing various forms of matrix reduction or decompositions.\n\nUse:\n\n* `nml_mat *nml_mat_row_addrow(nml_mat *m, unsigned int where, unsigned int row, double multiplier)`\n   - This will do the following: `m-\u003edata[where][...] *= m-\u003edata[row][...] * multiplier`. The results will be kept in a new matrix. Matrix `m` remains unchanged.\n* `int nml_mat_row_addrow_r(nml_mat *m, unsigned int where, unsigned int row, double multiplier)`\n   - This will do the following: `m-\u003edata[where][...] *= m-\u003edata[row][...] * multiplier`. The changes are done directly on `m`.\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n    nml_mat *m = nml_mat_rnd(5, 4, 1.0, 2.0);\n    nml_mat_print(m);\n\n    // Add row[1] elements to row[2] elements\n\n    nml_mat_row_addrow_r(m, 2, 1, 1.0);\n\n    // Add row[1] to row[0] with a multiplier of 2.0\n\n    nml_mat_row_addrow_r(m, 0, 1, 2.0);\n\n    nml_mat_print(m);\n    nml_mat_free(m);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/row_plus_row.ex\n```\n\n## Modifying the matrix structure\n\n### Remove rows and columns\n\nTo remove columns:\n* `nml_mat *nml_mat_col_rem(nml_mat *m, unsigned int column)`\n  - A new matrix is being created, `m` remains the same.\n\nTo remove rows:\n* `nml_mat *nml_mat_row_rem(nml_mat *m, unsigned int row)`\n  - A new matrix is being created, `m` remains the same.\n  \n Example:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n    nml_mat *m = nml_mat_sqr_rnd(4, 1.0, 2.0);\n    nml_mat_print(m);\n\n    // Remove column[1] from m\n    // m remains the same\n    // less_columns is another matrix \n    nml_mat *less_columns = nml_mat_col_rem(m, 1);\n    nml_mat_print(less_columns);\n\n    // Remove row[0] from less_columns\n    // less_columns remains the same\n    // less_rows is another matrix\n    nml_mat *less_rows = nml_mat_row_rem(less_columns, 0);\n    nml_mat_print(less_rows);\n\n    nml_mat_free(m);\n    nml_mat_free(less_columns);\n    nml_mat_free(less_rows);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh examples \u0026\u0026 ./examples/remove_columns_rows.ex\n```\n\n### Swap rows and columns\n\nUse:\n\n* `nml_mat *nml_mat_row_swap(nml_mat *m, unsigned int row1, unsigned int row2)`\n* `int nml_mat_row_swap_r(nml_mat *m, unsigned int row1, unsigned int row2)`\n* `nml_mat *nml_mat_col_swap(nml_mat *m, unsigned int col1, unsigned int col2)`\n* `int nml_mat_col_swap_r(nml_mat *m, unsigned int col1, unsigned int col2)`\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003ctime.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n  srand(time(NULL));\n\n  nml_mat *m = nml_mat_sqr_rnd(8, 0.0, 10.0);\n\n  printf(\"m=\");\n  nml_mat_print(m);\n\n  printf(\"m= (...after swapping col1=%d with col2=%d):\\n\", 1, 2);\n  nml_mat_col_swap_r(m, 1, 2);\n  nml_mat_print(m);\n\n  printf(\"newm= (...after swapping col1=%d with col2=%d and creating a new matrix):\\n\", 0, 1);\n  nml_mat *newm = nml_mat_col_swap(m, 0, 1);\n  nml_mat_print(newm);\n\n  printf(\"m= (...after swapping row1=%d with row2=%d)\\n\", 0, 2);\n  nml_mat_row_swap_r(m, 0, 2);\n  nml_mat_print(m);\n\n  nml_mat_free(m);\n  nml_mat_free(newm);\n\n  return 0;\n}\n```\n\nOutput:\n\n```\nm=\n3.467541\t\t8.965948\t\t0.685298\t\t7.802247\t\t2.363902\t\t0.097955\t\t6.325767\t\t7.162469\n9.613042\t\t6.399923\t\t3.512556\t\t5.528620\t\t9.520015\t\t2.886378\t\t1.363232\t\t1.838682\n2.722997\t\t5.410983\t\t2.397803\t\t9.870863\t\t9.601451\t\t1.591262\t\t4.335792\t\t1.660161\n2.318266\t\t3.094436\t\t8.189400\t\t9.242210\t\t3.818718\t\t1.198454\t\t2.423213\t\t6.939399\n0.471069\t\t7.252268\t\t8.869578\t\t0.994544\t\t5.301898\t\t9.007567\t\t0.172999\t\t7.586261\n2.295128\t\t4.212713\t\t3.072580\t\t0.849523\t\t7.941120\t\t6.407214\t\t6.049472\t\t3.469933\n9.157250\t\t5.896395\t\t0.705688\t\t0.491878\t\t6.985944\t\t2.762460\t\t8.673238\t\t1.114106\n4.783565\t\t7.369584\t\t0.592299\t\t4.774641\t\t7.395844\t\t1.942471\t\t7.115440\t\t9.204845\n\nm= (...after swapping col1=1 with col2=2):\n\n3.467541\t\t0.685298\t\t8.965948\t\t7.802247\t\t2.363902\t\t0.097955\t\t6.325767\t\t7.162469\n9.613042\t\t3.512556\t\t6.399923\t\t5.528620\t\t9.520015\t\t2.886378\t\t1.363232\t\t1.838682\n2.722997\t\t2.397803\t\t5.410983\t\t9.870863\t\t9.601451\t\t1.591262\t\t4.335792\t\t1.660161\n2.318266\t\t8.189400\t\t3.094436\t\t9.242210\t\t3.818718\t\t1.198454\t\t2.423213\t\t6.939399\n0.471069\t\t8.869578\t\t7.252268\t\t0.994544\t\t5.301898\t\t9.007567\t\t0.172999\t\t7.586261\n2.295128\t\t3.072580\t\t4.212713\t\t0.849523\t\t7.941120\t\t6.407214\t\t6.049472\t\t3.469933\n9.157250\t\t0.705688\t\t5.896395\t\t0.491878\t\t6.985944\t\t2.762460\t\t8.673238\t\t1.114106\n4.783565\t\t0.592299\t\t7.369584\t\t4.774641\t\t7.395844\t\t1.942471\t\t7.115440\t\t9.204845\n\nnewm= (...after swapping col1=0 with col2=1 and creating a new matrix):\n\n0.685298\t\t3.467541\t\t8.965948\t\t7.802247\t\t2.363902\t\t0.097955\t\t6.325767\t\t7.162469\n3.512556\t\t9.613042\t\t6.399923\t\t5.528620\t\t9.520015\t\t2.886378\t\t1.363232\t\t1.838682\n2.397803\t\t2.722997\t\t5.410983\t\t9.870863\t\t9.601451\t\t1.591262\t\t4.335792\t\t1.660161\n8.189400\t\t2.318266\t\t3.094436\t\t9.242210\t\t3.818718\t\t1.198454\t\t2.423213\t\t6.939399\n8.869578\t\t0.471069\t\t7.252268\t\t0.994544\t\t5.301898\t\t9.007567\t\t0.172999\t\t7.586261\n3.072580\t\t2.295128\t\t4.212713\t\t0.849523\t\t7.941120\t\t6.407214\t\t6.049472\t\t3.469933\n0.705688\t\t9.157250\t\t5.896395\t\t0.491878\t\t6.985944\t\t2.762460\t\t8.673238\t\t1.114106\n0.592299\t\t4.783565\t\t7.369584\t\t4.774641\t\t7.395844\t\t1.942471\t\t7.115440\t\t9.204845\n\nm= (...after swapping row1=0 with row2=2)\n\n2.722997\t\t2.397803\t\t5.410983\t\t9.870863\t\t9.601451\t\t1.591262\t\t4.335792\t\t1.660161\n9.613042\t\t3.512556\t\t6.399923\t\t5.528620\t\t9.520015\t\t2.886378\t\t1.363232\t\t1.838682\n3.467541\t\t0.685298\t\t8.965948\t\t7.802247\t\t2.363902\t\t0.097955\t\t6.325767\t\t7.162469\n2.318266\t\t8.189400\t\t3.094436\t\t9.242210\t\t3.818718\t\t1.198454\t\t2.423213\t\t6.939399\n0.471069\t\t8.869578\t\t7.252268\t\t0.994544\t\t5.301898\t\t9.007567\t\t0.172999\t\t7.586261\n2.295128\t\t3.072580\t\t4.212713\t\t0.849523\t\t7.941120\t\t6.407214\t\t6.049472\t\t3.469933\n9.157250\t\t0.705688\t\t5.896395\t\t0.491878\t\t6.985944\t\t2.762460\t\t8.673238\t\t1.114106\n4.783565\t\t0.592299\t\t7.369584\t\t4.774641\t\t7.395844\t\t1.942471\t\t7.115440\t\t9.204845\n```\n\nTo run the example:\n\n```sh\n./nml.sh examples \u0026\u0026 ./examples/swap_rows_and_columns.ex\n```\n\n### Concatenate matrices\n\nTwo or more matrices can be concatenated (horizontally) or (vertically) into one matrix.\n\nTo achieve this, please use:\n\n* `nml_mat *nml_mat_cath(unsigned int mnun, nml_mat **matrices)`\n   - For horizontal concatenation. A new matrix is returned.\n   - `num` represents the number of matrices to concatenate.\n   - `matrices` the matrices to be concatenated.\n* `nml_mat *nml_mat_catv(unsigned int mnum, nml_mat **matrices)`\n   - For vertical concatenation. A new matrix is returned.\n   - `num` represents the number of matrices to concatenate.\n   - `matrices` the matrices to be concatenated.  \n   \nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n  nml_mat *I = nml_mat_eye(3);\n  nml_mat *Ix2 = nml_mat_smult(I, 2.0);\n  nml_mat *rndm = nml_mat_rnd(3, 4, 1.0, 5.0);\n\n  nml_mat **ms = malloc(sizeof(*ms) * 2);\n  ms[0] = I;\n  ms[1] = Ix2;\n  \n  nml_mat *concats1 = nml_mat_cath(2, ms);\n\n  ms[0] = concats1;\n  ms[1] = rndm;\n\n  nml_mat *concats2 = nml_mat_cath(2, ms);\n\n  printf(\"\\nConcatenate horizontally\\n\");\n  printf(\"I=\\n\");\n  nml_mat_print(I);\n  printf(\"Ix2=\\n\");\n  nml_mat_print(Ix2);\n  printf(\"rndm=\\n\");\n  nml_mat_print(rndm);\n  printf(\"concats1=\\n\");\n  nml_mat_print(concats1);\n  printf(\"concats2=\\n\");\n  nml_mat_print(concats2);\n\n  free(ms);\n  nml_mat_free(I);\n  nml_mat_free(Ix2);\n  nml_mat_free(concats1);\n  nml_mat_free(concats2);\n  nml_mat_free(rndm);\n\n  // -------------------------------------\n  // Vertical concatenation\n  // -------------------------------------\n\n  nml_mat *A = nml_mat_rnd(3, 4, 1.0, 4.0);\n  nml_mat *B = nml_mat_rnd(5, 4, 10.0, 20.0);\n  nml_mat *C = nml_mat_eye(4);\n\n  nml_mat **ABarr = malloc(sizeof(*ABarr) * 2);\n  ABarr[0] = A;\n  ABarr[1] = B;\n  nml_mat *ABCat = nml_mat_catv(2, ABarr);\n\n  printf(\"\\nA=\\n\");\n  nml_mat_print(A);\n  printf(\"\\nB=\\n\");\n  nml_mat_print(B);\n  printf(\"\\nC=\\n\");\n  nml_mat_print(C);\n  printf(\"\\nA concat B =\\n\");\n  nml_mat_print(ABCat);\n\n  free(ABarr);\n  nml_mat_free(A);\n  nml_mat_free(B);\n  nml_mat_free(C);\n\n  return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/concatenate_matrices.ex\n```\n\n## Matrices operations\n\n### Add and subtract matrices\n\nTo add or subtract two matrices, the following methods can be used:\n\n* `nml_mat *nml_mat_add(nml_mat *m1, nml_mat *m2)`\n  - Adds two matrices, the results are kept in a new `nml_mat*`. `m1` and `m2` remain unchanged.\n* `int nml_mat_add_r(nml_mat *m1, nml_mat *m2)`\n  - Add two matrices, the results are kept in `m1`. `m2` remains unchanged.\n* `nml_mat *nml_mat_sub(nml_mat *m1, nml_mat *m2)`\n  - Subtracts two matrices, the results are kept in a new `nml_mat*`. `m1` and `m2` remain unchanged.\n* `int nml_mat_sub_r(nml_mat *m1, nml_mat *m2)`\n  - Subtracts two matrices, the results are kept in `m1`. `m2` remains unchanged.\n  \nExample:  \n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m1 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n    nml_mat *m2 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n    printf(\"m1=\\n\");\n    nml_mat_print(m1);\n    \n    printf(\"m2=\\n\");\n    nml_mat_print(m2);\n\n\n    // Add the matrices to, result is kept in m3\n    // m1 and m2 remain unchanged\n    nml_mat *m3 = nml_mat_add(m1, m2);\n    printf(\"m3=\\n\");\n    nml_mat_print(m3);\n\n    // Add the matrices, the result is kept in m1\n    // m1 is modified, m2 remains unchanged\n    nml_mat_add_r(m1, m2);\n    printf(\"m1=\\n\");\n    nml_mat_print(m1);\n    \n    nml_mat_free(m1);\n    nml_mat_free(m2);\n    nml_mat_free(m3);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh examples \u0026\u0026 examples/add_matrices.ex\n```\n\n### Multiply matrices (dot)\n\nTo multiply two matrices, the following method can be used:\n\n* `nml_mat *nml_mat_dot(nml_mat *m1, nml_mat *m2)`\n  - Multiplies two matrices, the result is kept in a new `nml_mat*`. `m1` and `m2` remain unchanged.\n  \nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m1 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n    nml_mat *m2 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n\n    printf(\"m1=\\n\");\n    nml_mat_print(m1);\n    \n    printf(\"m2=\\n\");\n    nml_mat_print(m2);\n\n    // Multiply matrices\n    nml_mat *m3 = nml_mat_dot(m1, m2);\n    printf(\"m3=\\n\");\n    nml_mat_print(m3);\n\n    nml_mat_free(m1);\n    nml_mat_free(m2);\n    nml_mat_free(m3);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh examples \u0026\u0026 examples/dot_matrices.ex\n```\n\n## Transpose matrices\n\nTo transpose a matrix, the following method can be used:\n\n* `nml_mat *nml_mat_transp(nml_mat *m)`\n  - A new `nml_mat*` will be created, representing the transpose matrix of `m`. `m` remains unchanged.\n \nExample: \n  \n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m1 = nml_mat_rnd(1, 5, 1.0, 10.0);\n    nml_mat_print(m1);\n\n    nml_mat *m2 = nml_mat_transp(m1);\n    nml_mat_print(m2);\n\n    nml_mat_free(m1);\n    nml_mat_free(m2);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/transpose.ex\n```\n\n## Calculate trace\n\nTo calculate the trace of the matrix the following method can be used: `double nml_mat_trace(nml_mat* m)`.\n\n## Row Echelon \n\n### Calculate Row Echelon Form using Gaussian Elimination\n\nTo bring the matrix in Row Echelon Form the following method can be used: `nml_mat *nml_mat_ref(nml_mat *m)`.\n\nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n  double v1[9] = {\n    0.0, 1.0, 2.0,\n    1.0, 2.0, 1.0,\n    2.0, 7.0, 8.0\n  };\n\n  nml_mat *m1 = nml_mat_from(3, 3, 9, v1);\n  printf(\"\\nm1=\\n\");\n  nml_mat_print(m1);\n  nml_mat *refm1 = nml_mat_ref(m1);\n  printf(\"\\nrefm1=\\n\");\n  nml_mat_print(refm1);\n\n  nml_mat_free(m1);\n  nml_mat_free(refm1);\n  return 0;\n}\n```\n\nOutput:\n\n```\nm1=\n\n0.000000\t\t1.000000\t\t2.000000\n1.000000\t\t2.000000\t\t1.000000\n2.000000\t\t7.000000\t\t8.000000\n\n\nrefm1=\n\n1.000000\t\t2.000000\t\t1.000000\n0.000000\t\t1.000000\t\t2.000000\n0.000000\t\t0.000000\t\t0.000000\n```\n\nTo run the example:\n\n```sh\n./nml.sh examples \u0026\u0026 ./examples/row_echelon.ex\n```\n\n### Calculate Reduced Row Echelon Form using Gauss-Jordan\n\nTo bring the matrix in Reduced Row Echelon Form the following method can be used: `nml_mat *nml_mat_rref(nml_mat *m)`.\n\nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n\n  double v1[9] = {\n    0.0, 1.0, 2.0,\n    1.0, 2.0, 1.0,\n    2.0, 7.0, 8.0\n  };\n\n  nml_mat *m1 = nml_mat_from(3, 3, 9, v1);\n  printf(\"\\nm1=\\n\");\n  nml_mat_print(m1);\n  nml_mat *rrefm1 = nml_mat_rref(m1);\n  printf(\"\\nrrefm1=\\n\");\n  nml_mat_print(rrefm1);\n\n  nml_mat_free(m1);\n  nml_mat_free(rrefm1);\n  return 0;\n}\n```\n\nOutput:\n\n```\nm1=\n\n0.000000\t\t1.000000\t\t2.000000\n1.000000\t\t2.000000\t\t1.000000\n2.000000\t\t7.000000\t\t8.000000\n\n\nrrefm1=\n\n1.000000\t\t0.000000\t\t-3.000000\n-0.000000\t\t1.000000\t\t2.000000\n0.000000\t\t0.000000\t\t0.000000\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/reduced_row_echelon.ex\n```\n\n\n## LU(P) Decomposition\n\nTo decompose a matrix using LU you can use: `nml_mat_lup *nml_mat_lup_solve(nml_mat *m)`.\n\nThe result is a pointer `nml_mat_lup*`:\n\n```c\ntypedef struct nml_mat_lup_s {\n  nml_mat *L;\n  nml_mat *U;\n  nml_mat *P;\n  unsigned int num_permutations;\n} nml_mat_lup;\n```\n\nTo free the `nml_mat_lup*`. Please use `void nml_mat_lup_free(nml_mat_lup* lu)`. This will also deallocate the memory for the three internal `nml_mat*` pointers.\n\nLU decomposition is used for solving linear systems of equations, computing the determinant and the inverse of a matrix.\n\nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m1 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n    printf(\"m1=\\n\");\n    nml_mat_print(m1);\n\n    nml_mat_lup *m1_lup = nml_mat_lup_solve(m1);\n    printf(\"L, U, P:\\n\");\n    nml_mat_lup_print(m1_lup);\n\n    nml_mat_free(m1);\n    nml_mat_lup_free(m1_lup);\n\n    return 0;\n}\n```\n\nOutput:\n\n```\nm1=\n\n0.000078\t\t1.315378\t\t7.556053\t\t4.586501\n5.327672\t\t2.189592\t\t0.470446\t\t6.788647\n6.792964\t\t9.346929\t\t3.835021\t\t5.194164\n8.309653\t\t0.345721\t\t0.534616\t\t5.297002\n\nL, U, P:\n\n1.000000\t\t0.000000\t\t0.000000\t\t0.000000\n0.817479\t\t1.000000\t\t0.000000\t\t0.000000\n0.000009\t\t0.145116\t\t1.000000\t\t0.000000\n0.641143\t\t0.217108\t\t-0.086373\t\t1.000000\n\n\n8.309653\t\t0.345721\t\t0.534616\t\t5.297002\n0.000000\t\t9.064309\t\t3.397983\t\t0.863978\n0.000000\t\t0.000000\t\t7.062947\t\t4.461075\n0.000000\t\t0.000000\t\t0.000000\t\t3.590254\n\n\n0.000000\t\t0.000000\t\t0.000000\t\t1.000000\n0.000000\t\t0.000000\t\t1.000000\t\t0.000000\n1.000000\t\t0.000000\t\t0.000000\t\t0.000000\n0.000000\t\t1.000000\t\t0.000000\t\t0.000000\n```\n\nRunning the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/lup.ex\n```\n\n## Matrix inverse\n\nCalculating the inverse requires to decompose the matrix LU(P) decomposition first.\n\nAfterwards obtaining the inverse is straightforward: `nml_mat *nml_mat_inv(nml_mat_lup *m)`.\n\nExample:\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n  printf(\"\\nInverse of a matrix:\\n\");\n  double m_v[16] = {\n    2.0, 7.0, 6.0, 1.0,\n    9.0, 5.0, 0.0, 2.0,\n    4.0, 3.0, 8.0, 3.0,\n    3.0, 5.0, 1.0, 9.0\n  };\n  nml_mat *m = nml_mat_from(4,4,16, m_v);\n  nml_mat_lup *lup = nml_mat_lup_solve(m);\n  nml_mat* minv = nml_mat_inv(lup);\n  nml_mat *mdotminv = nml_mat_dot(m, minv);\n\n  printf(\"m=\");\n  nml_mat_print(m);\n  printf(\"minv=\");\n  nml_mat_print(minv);\n  printf(\"(%%e) m * minv=\");\n  nml_mat_printf(mdotminv, \"%e\\t\");\n  printf(\"(%%f) m * minv=\");\n  nml_mat_printf(mdotminv, \"%f\\t\");\n\n  nml_mat_free(m);\n  nml_mat_free(minv);\n  nml_mat_free(mdotminv);\n  return 0;\n}\n```\n\nOutput:\n\n```\nm=\n2.000000\t\t7.000000\t\t6.000000\t\t1.000000\n9.000000\t\t5.000000\t\t0.000000\t\t2.000000\n4.000000\t\t3.000000\t\t8.000000\t\t3.000000\n3.000000\t\t5.000000\t\t1.000000\t\t9.000000\n\nminv=\n-0.081577\t\t0.112583\t\t0.065924\t\t-0.037929\n0.174895\t\t0.013245\t\t-0.133955\t\t0.022276\n0.001505\t\t-0.046358\t\t0.127935\t\t-0.032511\n-0.070138\t\t-0.039735\t\t0.038230\t\t0.114991\n\n(%e) m * minv=\n1.000000e+00\t4.163336e-17\t4.163336e-17\t-1.387779e-17\n0.000000e+00\t1.000000e+00\t-2.775558e-17\t2.775558e-17\n5.551115e-17\t6.938894e-17\t1.000000e+00\t5.551115e-17\n0.000000e+00\t5.551115e-17\t-5.551115e-17\t1.000000e+00\n\n(%f) m * minv=\n1.000000\t0.000000\t0.000000\t-0.000000\n0.000000\t1.000000\t-0.000000\t0.000000\n0.000000\t0.000000\t1.000000\t0.000000\n0.000000\t0.000000\t-0.000000\t1.000000\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/inverse.ex\n```\n\n## Matrix determinant\n\n\nCalculating the determinant requires to decompose the matrix LU(P) decomposition first.\n\nAfterwards obtaining the determinant is straightforward: `double nml_mat_det(nml_mat_lup* lup)`.\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *m1 = nml_mat_sqr_rnd(4, 0.0, 10.0);\n    nml_mat_lup *m1_lup = nml_mat_lup_solve(m1);\n    \n    printf(\"m1=\\n\");\n    nml_mat_print(m1);\n    printf(\"determinant=%lf\\n\", nml_mat_det(m1_lup));\n\n    nml_mat_free(m1);\n    nml_mat_lup_free(m1_lup);\n\n    return 0;\n}\n```\n\nOutput:\n\n```\nm1=\n\n0.000078\t\t1.315378\t\t7.556053\t\t4.586501\n5.327672\t\t2.189592\t\t0.470446\t\t6.788647\n6.792964\t\t9.346929\t\t3.835021\t\t5.194164\n8.309653\t\t0.345721\t\t0.534616\t\t5.297002\n\ndeterminant=-1909.979877\n```\n\nRunnning the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/determinant.ex\n```\n\n## Solve linear systems of equations\n\n### Solving `A * x = B` where A is lower triangular (Forward Substitution)\n\nUse: `nml_mat *nml_ls_solvefwd(nml_mat *low_triang, nml_mat *b)`.\n\n_Note: no validation will be performed to check is `low_triang` is a lower triangular matrix_\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    \n    FILE *input = fopen(\"./examples/data/matrix9_lower_triangular.data\", \"r\");\n\n    nml_mat *A = nml_mat_fromfilef(input);\n    nml_mat *B = nml_mat_fromfilef(input);\n    nml_mat *x = nml_ls_solvefwd(A, B);\n\n    nml_mat_print(A);\n    nml_mat_print(B);\n    nml_mat_print(x);\n\n    nml_mat_free(A);\n    nml_mat_free(B);\n    nml_mat_free(x);\n\n    fclose(input);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/forward_substition.ex\n```\n\n### Solving `A * x = B` where A is upper traingular (Backward Substition)\n\nUse: `nml_mat *nml_ls_solvebck(nml_mat *upper_triang, nml_mat *b)`.\n\n_Note: no validation will be performed to check is `upper_triang` is an upper triangular matrix_\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    \n    FILE *input = fopen(\"./examples/data/matrix10_upper_triangular.data\", \"r\");\n\n    nml_mat *A = nml_mat_fromfilef(input);\n    nml_mat *B = nml_mat_fromfilef(input);\n    nml_mat *x = nml_ls_solvebck(A, B);\n\n    nml_mat_print(A);\n    nml_mat_print(B);\n    nml_mat_print(x);\n\n    nml_mat_free(A);\n    nml_mat_free(B);\n    nml_mat_free(x);\n\n    fclose(input);\n\n    return 0;\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 examples/backward_substitution.ex\n```\n\n### Solving `A * x = B` using LU(P) decomposition\n\nUse: `nml_mat *nml_ls_solve(nml_mat_lup *lup, nml_mat* b)`.\n\n```c\n#include \u003cstdlib.h\u003e\n#include \u003cstdio.h\u003e\n\n#include \"lib/nml.h\"\n\nint main(int argc, char *argv[]) {\n    nml_mat *A = nml_mat_sqr_rnd(4, 1.0, 10.0);\n    nml_mat *B = nml_mat_rnd(4, 1, 1.0, 10.0);\n    nml_mat_lup *LUP = nml_mat_lup_solve(A);\n\n    nml_mat *x = nml_ls_solve(LUP, B);\n    nml_mat_print(x);\n\n    nml_mat_free(A);\n    nml_mat_free(B);\n    nml_mat_free(x);\n    nml_mat_lup_free(LUP);\n}\n```\n\nTo run the example:\n\n```sh\n./nml.sh clean examples \u0026\u0026 ./examples/ls_solve.ex\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fneat-matrix-library","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnomemory%2Fneat-matrix-library","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fneat-matrix-library/lists"}