Matrix library for MicroPython

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Iyassou
Posts: 42
Joined: Sun Jun 26, 2016 9:15 am

Re: Matrix library for MicroPython

Post by Iyassou » Sat Aug 25, 2018 5:43 pm

efahl wrote:
Fri Aug 24, 2018 7:57 pm
Just an aside, what are you using these 3x3 matrices for?
At the moment I'm not actively using umatrix. Back when I needed it I wanted to handle RGB and later RGB-IR photosensor measurements for a particular application. I decided to write it because the alternative 350 ms were too costly for me. I only got into quadcopters and some of the math applied on them a year later and that was when I understood the need for fast matrix inversion and decided to pursue it for others' needs.
efahl wrote:
Fri Aug 24, 2018 7:57 pm
If they are 3D spatial transformations, then the matrix is orthonormal and its inverse is also its transpose. Our multibody dynamics code uses this to good advantage, and we have also added multiply_inverse and divide_inverse methods on the matrix class so we don't even take the transpose, we just flip the order of evaluation in the inner loop, resulting in enormous speed improvements over actually calculating inverses.
Are you talking about 4x4 quaternion matrices? I found quaternions and 3D rotations to be fascinating but difficult so I haven't grasped all their aspects: pardon me if the previous question is ignorant.
Either way this is very cool and neat to know, thanks for sharing :)

efahl
Posts: 15
Joined: Sat Dec 23, 2017 2:02 pm

Re: Matrix library for MicroPython

Post by efahl » Wed Aug 29, 2018 2:27 pm

Iyassou wrote:
Sat Aug 25, 2018 5:43 pm
Are you talking about 4x4 quaternion matrices? I found quaternions and 3D rotations to be fascinating but difficult so I haven't grasped all their aspects: pardon me if the previous question is ignorant.
Either way this is very cool and neat to know, thanks for sharing :)
No, 3x3 direction cosine matrices (just the 3D extension of planar 2x2 rotation matrices). It's basically the same thing you do render the pixels of a line on the screen at some angle, but generalized to 3-space and applied to the various landmarks on physical bodies.

mohamed.hany
Posts: 1
Joined: Tue Feb 01, 2022 6:24 pm

Re: Matrix library for MicroPython

Post by mohamed.hany » Tue Feb 01, 2022 6:30 pm

Iyassou wrote:
Fri Aug 17, 2018 8:44 am
Hello all.

About two years ago I needed a matrix library and the available option was jalawson's umatrix library. One of the operations I needed was 3x3 matrix inversion. However, as jalawson stated, the library wasn't designed to be particularly fast so 3x3 matrix inversion takes about 350 ms on a Pyboard.

I was learning both MicroPython and Python 3 then (and still now), so after many revisions I've completed a presentable version of my matrix library. So far, I've tested it on a Pyboard v1.1 and a Pyboard v1.0 lite: inverting a 3x3 matrix "at worst" (details in the README.md) takes around 1.7 ms and 2.8 ms respectively.

The library includes support for complex numbers, and useful functions like copy, transpose, round, and others.

Here it is on GitHub.

Let me know what you think :)
hello, there seems to be a bug that I can't solve. I would appreciate it if you would help me with it. Using your library, when I create any column vector of zeros (for example: x = zeros(10, 1)), and then set the value of any element of this vector (for example: x[4][0] = 7), the whole vector elements change to 7 instead of only the 5th row.
Thank you in advance.

Iyassou
Posts: 42
Joined: Sun Jun 26, 2016 9:15 am

Re: Matrix library for MicroPython

Post by Iyassou » Tue Feb 01, 2022 9:27 pm

Hiya.

Thanks for bringing this issue to my attention! :D
The issue lies with the following portion of code in the fill function:

Code: Select all

[[x]*(num_cols if num_cols is not None else order)]*order
which boils down to

Code: Select all

[[x] * a] * b]
My intention when writing this code then was that in order to create a list of the same value repeated multiple times over, I could just create a singleton list [x] and multiply that by however many copies I want.

For types like ints (floats too) the first list multiplication works fine i.e. as intended. Independent copies of the same data are created for each entry in the list, and AFAIAA none of them point to the same memory location. This is because ints are fairly cheap to create. You can see this for yourself by trying out the following code snippet:

Code: Select all

>>> x = [0]*5
>>> x[0] = 77
>>> x
[77, 0, 0, 0, 0]
The issue arises with the second multiplication, where we're no longer multiplying an integer singleton list by a number, but an entire list by a number. Here, independent copies of the original list are not created for each entry in the nested list, since taking this approach is memory exhaustive as duplicating a list is more expensive. Instead, dependent copies i.e. copies that point to the same data in memory are created.

The bit of code I singled out in the library uses the list multiplication approach twice, first to create the row of independent copies of whatever coefficient value (which works fine), and then second to create dependent copies of this same row (list) to obtain the final matrix (which doesn't work as intended). This is why the modification was happening over all rows, as you've pointed out.

The fix for this is to use nested list comprehensions instead. This is because the value you supply to the list comprehension is re-evaluated at each iteration of the for-loop.

Code: Select all

[[x for j in range(a)] for i in range(b)]
A stylistic note: since you're not using either for-loop variables, you could get rid of them altogether and rewrite the nested list comprehension as

Code: Select all

[[x for _ in range(a)] for __ in range(b)]
(note the double underscore for the second variable), but that's for you to decide.

I've just added this fix in version 1.1.3 :)

Post Reply