Loading repository data…
Loading repository data…
nomemory / repository
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.
.----------------. .----------------. .----------------.
| .--------------. || .--------------. || .--------------. |
| | ____ _____ | || | ____ ____ | || | _____ | |
| ||_ \|_ _| | || ||_ \ / _|| || | |_ _| | |
| | | \ | | | || | | \/ | | || | | | | |
| | | |\ \| | | || | | |\ /| | | || | | | _ | |
| | _| |_\ |_ | || | _| |_\/_| |_ | || | _| |__/ | | |
| ||_____|\____| | || ||_____||_____|| || | |________| | |
| | | || | | || | | |
| '--------------' || '--------------' || '--------------' | Neat Matrix Library
'----------------' '----------------' '----------------'
nml is a simple matrix and linear algebra library written in standard C.
Code should be portable and there are no dependencies.
For a detailed explanation of the library code please check this blog post.
It currently supports:
The 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.)
The build file for the library it's called nml.sh.
It's actually a bash script (not a makefile!).
./nml.sh clean build
This will compile the library, create a dist folder where you will find *.a static library file and the header files.
gcc and ar should be available in $PATH.
If 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.
Nothing else should be changed.
# COMPILING RELATED
CC=clang #<----------------- here
CCFLAGS="-Wall -c"
CCFLAGS_EXAMPLES="-Wall"
Examples can be found in the ./examples folder.
To build the code examples:
./nml.sh clean examples
examples/lib folder where the libnml.a and the header files will be copied;examples/*.c will be compiled with the latest version of libnml;examples/*.c an executable (*.ex) will be created.To run an example:
# ./nml.sh clean examples && ./examples/<example name>.ex
./nml.sh clean examples && ./examples/playground.ex
To run the tests
./nml.sh clean test
test/lib folder where the libnml.a and the header files will be copied;tests/*.c will be compiled with the latest version of libnml;tests/*/c an executable (*.ex) will be created.The test data was generated using sympy.
In the tests/generators/ folder you can find the python3 (.py) scripts used to generate the data.
./nml.sh clean
This will clean everything (*.o,*.ex,*.a) and will leave the library folder in a clean state.
A few examples can be found in the ./examples folder folder.
All the methods are interacting with the nml_mat struct:
typedef struct nml_mat_s {
unsigned int num_rows;
unsigned int num_cols;
double **data;
int is_square;
} nml_mat;
To interact the elements of the matrix:
nml_mat *m = ...
m->data[i][j] = ...
The methods for a creating a new matrix are:
nml_mat *nml_mat_new(unsigned int num_rows, unsigned int num_cols)
num_rows * num_cols matrix of zeroes.nml_mat *nml_mat_sqr(unsigned int size)
size * size matrix of zeroes.nml_mat *nml_mat_eye(unsigned int size)
size * size matrix.nml_mat *nml_mat_cp(nml_mat *m)
m.Everytime we create a matrix, we dynamically allocate memory.
To free the memory please use: nml_mat_free(nml_mat *m).
#include <stdlib.h>
#include <stdio.h>
#include "lib/nml.h"
int main(int argc, char *argv[]) {
nml_mat* m, *mx;
printf("\nCreating an empty matrix with 2x3\n");
m = nml_mat_new(2,3);
nml_mat_print(m);
nml_mat_free(m);
printf("\nCreating a square matrix 5x5 \n");
m = nml_mat_sqr(5);
nml_mat_print(m);
nml_mat_free(m);
printf("\nCreating an ID 7x7 Matrix and copying it into another matrix:\n");
m = nml_mat_eye(7);
mx = nml_mat_cp(m);
nml_mat_print(m);
nml_mat_print(mx);
nml_mat_free(m);
nml_mat_free(mx);
return 0;
}
To run the example:
./nml.sh clean examples && examples/creating_a_matrix.ex
double[N])An array can be used as the "data source" for the Matrix by using:
nml_mat *nml_mat_from(unsigned int num_rows, unsigned int num_cols, unsigned int n_vals, double *vals)
num_rows and num_cols represent the dimensions of the matrix;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;vals the array containing double values.#include <stdlib.h>
#include <stdio.h>
#include "lib/nml.h"
int main(int argc, char *argv[]) {
double array[6] = {
1.0, 0.2, 3.0, 4.0, 5.0, 3.1
};
nml_mat* my;
// 3 rows, 2 columns
// read exactly 6 numbers from array[6]
my = nml_mat_from(3, 2, 6, array);
nml_mat_print(my);
nml_mat_free(my);
// 4 rows, 2 columns
// read exactly 3 numbers from array[6]
my = nml_mat_from(4, 2, 3, array);
nml_mat_print(my);
nml_mat_free(my);
return 0;
}
To run the example:
./nml.sh clean examples && examples/creating_a_matrix_from_an_array.ex
The two methods that can be used to create a matrix from a file on disk are:
nml_mat *nml_mat_fromfile(const char *file)
file path. If the file cannot be opened a NULL matrix will be returned.nml_mat *nml_mat_fromfilef(FILE *f)
f. Does not automatically close the stream (FILE).In the file, the matrix has the following format:
4 5
0.0 1.0 2.0 5.0 3.0
3.0 8.0 9.0 1.0 4.0
2.0 3.0 7.0 1.0 1.0
0.0 0.0 4.0 3.0 8.0
On the first line 4 represents the number of rows and 5 represents the number of columns of the Matrix
Then next lines contain the matrix elements: 4 * 5 = 20 numbers.
Example code:
#include <stdlib.h>
#include <stdio.h>
#include "lib/nml.h"
int main(int argc, char *argv[]) {
const char *f = "examples/data/matrix1.data";
nml_mat *from_file = nml_mat_fromfile(f);
nml_mat_print(from_file);
nml_mat_free(from_file);
// Or if the file is already opened
FILE *m_file = fopen("examples/data/matrix2.data", "r");
nml_mat *from_file2 = nml_mat_fromfilef(m_file);
nml_mat_print(from_file2);
nml_mat_free(from_file2);
fclose(m_file);
return 0;
}
To run the example:
./nml.sh clean examples && ./examples/creating_a_matrix_from_file.ex
The nml_mat *nml_mat_fromfilef(FILE *f) can be called, with f=stdin.
Code example:
#include <stdlib.h>
#include <stdio.h>
#include "lib/nml.h"
int main(int argc, char *argv[]) {
nml_mat *from_file2 = nml_mat_fromfilef(stdin);
nml_mat_print(from_file2);
nml_mat_free(from_file2);
return 0;
}
To run the example:
./nml.sh clean examples && examples/creating_a_matrix_from_user_input.ex
Creating a randomized matrix can be done with the following two methods:
nml_mat *nml_mat_rnd(unsigned int num_rows, unsigned int num_cols, double min, double max)
num_rows * num_cols;min and max;nml_mat *nml_mat_sqr_rnd(unsigned int size, double min, double max)
size * size;min and max;#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "lib/nml.h"
int main(int argc, char *argv[]) {
srand(time(NULL)); // Should be called once per program
nml_mat *m = nml_mat_rnd(5, 5, -10.0, 10.0);
nml_mat_print(m);
nml_mat_free(m);
return 0;
}
To run the example:
./nml.sh clean examples && examples/create_randomized_matrix.ex
There are two "equality" methods for matrices:
int nml_mat_eqdim(nml_mat *m1, nml_mat *m2)
`int nml_mat_eq(nml_mat *m1, nml_mat