Recommend a lightweight matrix library in C, suitable for mcu ? - Page 1
Forum section: electronics / general

author: julian1
author_rank: Frequent Contributor
timestamp: January 21, 2022, 09:54:27 pm
content: There are many heavyweight libraries around.For example Meschach. But the code just for memory handling is already at 1000LOC,https://github.com/yageek/Meschach/blob/master/memory.c.I found the "Matrix Library in C" project, which looks perfect in terms of scope, just covering the basic matrix operations. And the code only runs to a few pages,https://www.codeproject.com/Articles/5283245/Matrix-Library-in-CBut in testing,I found several computation errors.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2022, 12:10:57 am
content: What are the operations you need? And how large are the typical matrices you'd be using?

author: julian1
author_rank: Frequent Contributor
timestamp: January 22, 2022, 12:39:45 am
content: Operations are the basics - concat, transpose, multiply, inverse, determinant. Like the codeproject example.matrices are small, and will fit in available ram, with any kind of contiguous representation. I don't require sparse support.

author: ledtester
author_rank: Super Contributor
timestamp: January 22, 2022, 12:46:57 am
content: Can you use C++? Found this simple template library:https://gist.github.com/MihailJP/3937550and also this:https://github.com/Tellicious/MatLib

author: julian1
author_rank: Frequent Contributor
timestamp: January 22, 2022, 12:54:51 am
content: Quote from: ledtester on January 22, 2022, 12:46:57 amI noted that one. the matrix dims look to be parametrized/templatized for speed/ and better typechecking. My preference would be for smaller code size, and 'conventional' C like interface, but I may come back to it.

author: rstofer
author_rank: Super Contributor
timestamp: January 25, 2022, 06:38:16 pm
content: Perhaps you can find what you want in "Numerical Recipes in C"https://www.amazon.com/Numerical-Recipes-Art-Scientific-Computing/dp/B007YZZ310I have both the C and Fortran versions of the book, just in case...

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 25, 2022, 07:20:50 pm
content: Quote from: rstofer on January 25, 2022, 06:38:16 pmI second the books. Have used that to implement LU decomposition for a circuit simulator. And on other occasions.Sure you can use well-tested and respected libraries such as OpenBLAS, but when those are largely overkill for a given application, nothing beats making your own implementation, tailored to your needs.If you don't need to handle sparse matrices and are not looking for heavily optimized algorithms, implementing the base operations for matrices is a matter of a few lines of code for each.So, short of using one of the well-known libraries (which have been well tested), I do think your best bet would be your own implementation, rather than finding a random piece of code online and relying on it.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 25, 2022, 07:53:30 pm
content: I use my own. It is not difficult to customize a simple one, but there are some details one needs to consider first.Usage and matrix sizesMatrices can be used to represent various different things, from systems of equations (in linear algebra) to rotations and transforms inD-dimensional geometry.If the matrix sizes and/or shapes are limited to a relatively small set, it is often more computationally efficient to implement the basic operations separately for each.OP already mentioned they don't need sparse matrices, which simplifies such a library a lot already.Things like "all my matrices are either square or one-dimensional (vectors)", or "my matrices have at most 32 rows/columns", can simplify the library a lot.Matrix inversion approachThere are algebraic expressions for square matrix inversion, but they are only feasible for small square matrices (say up to 3×3 or 4×4). For larger square matrices, there are severalmethods to choose from.For non-square matrices, we usegeneralized inverse, or pseudoinverse; useful in e.g. linear algebra, when seeking solutions to a system of equations (with equal number of unknowns as lineraly independent equations).In particular, if the matrices are only used to represent systems of equations, it would make sense to use a different interface than just a generic "invert this matrix, please". In particular, most cases can be simplified toAx=ywithyand matrixAknown, butxunknown; the solution being the traditionalx=A⁻¹y, where matrixA⁻¹is the (generalized) inverse of matrixA, so a dedicated interface for that would be better than having the programmer remember the sequence of "pure" linear algebra operations themselves.Memory fragmentationIf the matrices have varying lifetimes –– especially if you have sequences like "create matrix A, create matrix B, create matrix C, delete matrix B, create matrix D, delete matrix A, delete matrix C, ..., delete matrix D" –– it is possible to end up with badly fragmented heap, with small matrices scattered around with roughly matrix-sized holes in between, so that even though almost half of the memory is still available, you suddenly cannot allocate a slightly larger matrix anymore, because the only holes available are all too small.For example, if there are a limited number of matrices at any point in time, then referring to them using an index would allow the matrix data memory manager to compact existing matrices every now and then, basically avoiding all issues with memory fragmentation, at the cost of occasional cleanup work.I personally use matrix and vector structures that can be declared as local variables (i.e., they are structures, not pointers to structures), with views to other matrices and vectors indistinguishable from the original matrices and vectors (similar to Unix/POSIX inodes and dentries). The actual data is stored in separate reference-counted "data owner" structures, which are deleted when the last vector or matrix referring to it is deleted.If the maximum matrix size is small enough, and the maximum number of concurrently used unique matrices small enough, memory fragmentation can be avoided by always using the maximum data owner size.I do not keep a ready-made library handy, because when I need computational power, I use Gnu Scientific Library and others; and when I need something small and lightweight, I write/rewrite my 'library' to fit the needs of the particular use case.If I knew what OP uses the matrices for, and what are the actual matrix size and shape limits, and what kind of embedded system the code is intended to run on (8-bit with FP emulation? Fixed point? 32-bit with FP emulation? 32-bit with hardware single-precision floating point support? 32-bit with double-precision emulation?), I might be able to give practical advice. The library itself is simple to write, but choosing the appropriate inversion method depends on the actual use case. One can even make tradeoffs between speed and accuracy. It is the "general" case that is the most painful, because that really requires implementing more than one, and using heuristics to detect when to switch; especially so with single-precision floating point numbers, as many almost-singular matrices do have a generalized inverse, but finding it numerically is tricky.

author: ledtester
author_rank: Super Contributor
timestamp: January 26, 2022, 02:23:03 am
content: Found a reference to EIGEN - a C++ template matrix library:https://eigen.tuxfamily.org/Reference:https://news.ycombinator.com/item?id=30073186#30077487

author: julian1
author_rank: Frequent Contributor
timestamp: January 26, 2022, 10:56:19 pm
content: Thank you for the suggestions.Another one that looks interesting is nml.https://github.com/nomemory/neat-matrix-libraryhttps://github.com/nomemory/neat-matrix-library/blob/main/nml.cAlbeit, the raised issue. with adding non-square matrices suggests it is not completely mature.https://github.com/nomemory/neat-matrix-library/pull/4I ended compiling a subset of meschach, and stubbing out unneeded functions to link it. This gets me basic double-prec float support.Not sure about the compiled code size in isolation. But the size of a simple app that includes the library is around 40k on 32bit Arm which is fine for my needs.