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 On Friday, November 4, 2022 at 8:51:05 PM UTC-5 pwil...@tkc.edu wrote: > 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. > > > On Friday, November 4, 2022 at 9:28:40 PM UTC-4 smi...@gmail.com wrote: > >> 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 >> On Friday, November 4, 2022 at 1:22:10 PM UTC-5 Aaron Meurer wrote: >> >>> 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). >>> >>> > >>> > 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. >>> >>> 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. >>> >>> >>> >> -- 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/73dfb06a-e31e-4089-87b3-4cfe8e04f64dn%40googlegroups.com.