Simple methods for row operations

82 views
Skip to first unread message

Phil Williams

unread,
Nov 4, 2022, 10:23:24 AM11/4/22
to sympy
I use sympy for matrix calculations in my Finite Math class that I teach. I have students working in a Jupyter Notebook. What I want is a student-friendly interface for in-place row operations on matrices, so that they can work problems step by step that require these operations (e.g. solving systems by row reduction). Right now the Matrix class in sympy has methods row_swap, and row_op. The former, row_swap is fine, but row_op has a general functorial definition that is too advanced for them. I want instead row_add and row_mult methods that specify the basic data of the operation as inputs (e.g. for row_add, source row, target row, and factor that the source row gets multiplied by before adding to target), and modifies the matrix in place. 

Right now, I write a bit of code for them to redefine the Matrix class and adds these two methods to it, and then have them work with that. However, I'm wondering if these methods can be added to sympy. It would be useful to them and perhaps others using sympy in a classroom. I'm confident I know what needs to be done, but I'm inexperienced with open source and I'm not sure where to begin in suggesting this change be incorporated. Just exploring this question led me to the idea that posting here might be a good first step. Any advice would be appreciated!
Thank you. 

kuldeepborkarjr765

unread,
Nov 4, 2022, 10:40:40 AM11/4/22
to sympy
I would suggest you can open an issue on sympy git repository issues tab https://github.com/sympy/sympy/issues and describe which new feature you would like to add in SymPy and discuss there for a bit if that could be implemented in SymPy or not and then to get started working on that issue you can check this out https://github.com/sympy/sympy/wiki/Development-workflow I think this would surely help, go through this once and if you require any help along the way then you can just post comments on that issue or ask for help regarding the same, SymPy community will be there to help you : )


--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/a769d661-0dbd-41f6-bd8e-9cf579f268aan%40googlegroups.com.

gu...@uwosh.edu

unread,
Nov 4, 2022, 11:46:57 AM11/4/22
to sympy
If there is a need to extend sympy operations in a jupyter friendly manner, it might also be possible to add the operations you want to the Algebra-with-Sympy package. The hope is the user interface utilities will eventually be incorporated into sympy proper.

Full disclosure: I am the primary author of Algebra-with-Sympy.

Jonathan

Oscar Benjamin

unread,
Nov 4, 2022, 1:28:47 PM11/4/22
to sy...@googlegroups.com
On Fri, 4 Nov 2022 at 14:23, Phil Williams <pwil...@tkc.edu> wrote:

Hi Phil,

> I use sympy for matrix calculations in my Finite Math class that I teach. I have students working in a Jupyter Notebook. What I want is a student-friendly interface for in-place row operations on matrices, so that they can work problems step by step that require these operations (e.g. solving systems by row reduction). Right now the Matrix class in sympy has methods row_swap, and row_op. The former, row_swap is fine, but row_op has a general functorial definition that is too advanced for them. I want instead row_add and row_mult methods that specify the basic data of the operation as inputs (e.g. for row_add, source row, target row, and factor that the source row gets multiplied by before adding to target), and modifies the matrix in place.
>
> Right now, I write a bit of code for them to redefine the Matrix class and adds these two methods to it, and then have them work with that. However, I'm wondering if these methods can be added to sympy. It would be useful to them and perhaps others using sympy in a classroom. I'm confident I know what needs to be done, but I'm inexperienced with open source and I'm not sure where to begin in suggesting this change be incorporated. Just exploring this question led me to the idea that posting here might be a good first step. Any advice would be appreciated!
> Thank you.

I agree that row_op has a weird interface. Probably whoever wrote that
thought that it's good to try to make things as general as possible
but in fact it's really turning a one liner into something that is
more complicated than just writing the code directly without using the
row_op method. The Matrix class already has far too many redundant
methods though and I'm not sure it's a good idea to add more. If
anything I'd rather just remove the row_op method if the interface was
being redesigned from scratch.

It isn't hard to make your own function to do this:

def row_mult(M, i, f):
"""Multiply row i of Matrix M by f in place and return M"""
M[i, :] *= f
return M

That being said, the function is just a one-liner and if you taught
the students about the more general concept of slicing then they could
do it themselves:

In [20]: M = eye(3)

In [21]: M[1,:] *= -3
Out[21]:
⎡1 0 0⎤
⎢ ⎥
⎢0 -3 0⎥
⎢ ⎥
⎣0 0 1⎦

In [22]: M[1,:] -= 2*M[0,:]

In [23]: M
Out[23]:
⎡1 0 0⎤
⎢ ⎥
⎢-2 -3 0⎥
⎢ ⎥
⎣0 0 1⎦

If they can understand how that slicing works then they can also
translate that to an understanding of many other things in Python like
lists, strings, numpy arrays etc because slicing is a fairly
ubiquitous idiom in Python.

Personally if I was teaching this stuff to students then I think I
would want them to make the function or code that does this themselves
using a loop so that they can understand the row operation in more
elementary algorithmic terms. Obviously that depends on exactly what
you're trying to teach so I'm not saying that your approach there is
wrong in any way. What I am saying though is that there are many
different ways that things like this could be taught and I'm not sure
we should add methods to the Matrix class to accommodate one
particular way.

--
Oscar

Aaron Meurer

unread,
Nov 4, 2022, 2:22:10 PM11/4/22
to sy...@googlegroups.com
On Fri, Nov 4, 2022 at 11:28 AM Oscar Benjamin
<oscar.j....@gmail.com> wrote:
>
> On Fri, 4 Nov 2022 at 14:23, Phil Williams <pwil...@tkc.edu> wrote:
>
> Hi Phil,
>
> > I use sympy for matrix calculations in my Finite Math class that I teach. I have students working in a Jupyter Notebook. What I want is a student-friendly interface for in-place row operations on matrices, so that they can work problems step by step that require these operations (e.g. solving systems by row reduction). Right now the Matrix class in sympy has methods row_swap, and row_op. The former, row_swap is fine, but row_op has a general functorial definition that is too advanced for them. I want instead row_add and row_mult methods that specify the basic data of the operation as inputs (e.g. for row_add, source row, target row, and factor that the source row gets multiplied by before adding to target), and modifies the matrix in place.
> >
> > Right now, I write a bit of code for them to redefine the Matrix class and adds these two methods to it, and then have them work with that. However, I'm wondering if these methods can be added to sympy. It would be useful to them and perhaps others using sympy in a classroom. I'm confident I know what needs to be done, but I'm inexperienced with open source and I'm not sure where to begin in suggesting this change be incorporated. Just exploring this question led me to the idea that posting here might be a good first step. Any advice would be appreciated!
> > Thank you.
>
> I agree that row_op has a weird interface. Probably whoever wrote that
> thought that it's good to try to make things as general as possible
> but in fact it's really turning a one liner into something that is
> more complicated than just writing the code directly without using the
> row_op method. The Matrix class already has far too many redundant
> methods though and I'm not sure it's a good idea to add more. If
> anything I'd rather just remove the row_op method if the interface was
> being redesigned from scratch.

Personally I think it's fine to have the fundamental row operations as
basic methods on the matrix class. We already have swap as a method.
You should open an issue about this on the issue tracker (or start a
PR if you want to go ahead and implement it).
You can also consider whether it makes sense to use a mutating
operation like this or to return a new matrix. SymPy matrices are
mutable by default, but this is different from every other SymPy
object. The usual way to work with SymPy expressions is to return a
new expression. Maybe this is a little more complicated to do, which
is why it might make sense to have these as methods on matrix.

Either way, though, I agree with Oscar that if a method is missing
from Matrix or any other SymPy class, you are better off just defining
it as a function rather than trying to subclass the class to add it as
a method.

Aaron Meurer

>
> --
> Oscar
>
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CAHVvXxSgP5%3DudLruO6a%3Da%3DHPrJW9soJVxChNUrENs73juLiYFw%40mail.gmail.com.

Chris Smith

unread,
Nov 4, 2022, 9:28:40 PM11/4/22
to sympy
Instead of redefining the class, why not use Python's ability to modify the class directly. Use the built-in `row_op` in the sugar you wish to add:

    >>> row_add = lambda M,i,j,m=1: M.row_op(i,lambda v,k: v+m*M[j,k])
    >>> Matrix.row_add = row_add
    >>> N = eye(3)
    >>> N.row_add(0,1); N
    Matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]])
    >>> N.row_add(0,1,2); N
    Matrix([[1, 3, 0], [0, 1, 0], [0, 0, 1]])

/c

Phil Williams

unread,
Nov 4, 2022, 9:51:05 PM11/4/22
to sympy
Thank you all for the responses! This is all very helpful. 

Jonathan: I'll check out Algebra-with-Sympy. Looks interesting. Thanks for sharing.

Oscar and Aaron: a bit on what I'm doing in the class. My approach is basically to convince them that using Python and Jupyter is easier and more powerful than using a graphing calculator, and will be more useful training to them in the long run. It's fundamentally a math class though, light on the actual programming. I don't want to make them do anything that's harder than using their ti-89 or whatever. And so anything that makes them prefer to reach for the calculator because it's "easier" is something I want to find a way around. They want to be able to do the row operations in place step by step, like they can on their calculator. So mutable operations defined as simple methods (or as functions) works well towards these ends. 

That said, I really do like the slicing approach too. Perhaps I can convince them it's actually a better way to think of the row operations. I may try it out on them as an alternative, and see if they take to it. 

Chris: this is very helpful, I didn't actually know you can do this. Good to know.

I'll explore the workflow and maybe even go ahead and try to do a pull request. 


Chris Smith

unread,
Nov 5, 2022, 3:24:05 PM11/5/22
to sympy
See also 'elementary_row_op' and consider storing the string hints as 'mul, swap, add' and redefine (for typing convenience) the method as `do`:

mul = "n->kn"
swap = "n<->m"
add = "n->n+km"
Matrix.do = Matrix.elementary_row_op
e=eye(3)
assert e.do(mul, 0, 5) == Matrix([[5, 0, 0], [0, 1, 0], [0, 0, 1]])
assert e.do(swap, 0, 1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
assert e.do(add, 0, 5, 1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]])

In an interactive session you can keep using the `_` to refer to the last output so

eye(3)
_.do(mul, 0, 5)
_.do(swap, 0, 1)
_.do(add, 0, 3, 2)

will produce, as the last output,

Matrix([[0, 1, 3], [5, 0, 0], [0, 0, 1]])

/c

S.Y. Lee

unread,
Nov 10, 2022, 12:44:13 AM11/10/22
to sympy
This could be similar and have applications like intrinsic functions.
In lower-level programming, it is often more efficient to use more specific methods (like unsigned + unsigned addition, scalar and vector multiplication, vector and vector multiplication)
than using more higher level methods that abstracts addition, multiplication, indices, and such that.
If this is possible for row operations, we should be able to prove that how methods like rref can be refactored to use such method, with some performance gain.
Reply all
Reply to author
Forward
0 new messages