ASKSAGE: Sage Q&A Forum - RSS feedhttps://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Mon, 08 Aug 2016 21:13:33 +0200How can I override the __call__ method of a matrixhttps://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:
class MyMatrix(Matrix):
def __call__(self, v):
return self*v
but this doesn't work. Here is the error message I get when I try the above code in sage:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.Tue, 02 Aug 2016 19:16:44 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/Comment by vdelecroix for <p>I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:</p>
<pre><code>class MyMatrix(Matrix):
def __call__(self, v):
return self*v
</code></pre>
<p>but this doesn't work. Here is the error message I get when I try the above code in sage:</p>
<pre><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
</code></pre>
<p>I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34329#post-id-34329The problem above comes from the fact that `Matrix` is **not** a class.
sage: isinstance(Matrix, type)
False
versus
sage: isinstance(Integer, type)
True
You need to inherit from a matrix class for example
sage: class MyMatrix(sage.matrix.matrix_integer_dense.Matrix_integer_dense):
....: def __call__(self, v):
....: return self*vThu, 04 Aug 2016 16:08:25 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34329#post-id-34329Comment by Saul Schleimer for <p>I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:</p>
<pre><code>class MyMatrix(Matrix):
def __call__(self, v):
return self*v
</code></pre>
<p>but this doesn't work. Here is the error message I get when I try the above code in sage:</p>
<pre><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
</code></pre>
<p>I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34339#post-id-34339Ok, I understand that Matrix is a metaclass, not a class. But I really want the functionality of Matrix, not some special case. In my particular usecase I don't know how the matrix will be given. I just know that the __init__ that comes with Matrix can handle the input. For example - what if the input has entries in some number field? Those are not integers...Fri, 05 Aug 2016 19:48:34 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34339#post-id-34339Comment by vdelecroix for <p>I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:</p>
<pre><code>class MyMatrix(Matrix):
def __call__(self, v):
return self*v
</code></pre>
<p>but this doesn't work. Here is the error message I get when I try the above code in sage:</p>
<pre><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
</code></pre>
<p>I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34375#post-id-34375Matrix is not even a metaclass, it is a class factory ;-) You can use the generic class but still the concrete matrix class constructor (i.e. __init__) does **not** handle the coefficient as you might think of. This is mostly done within the class factory Matrix.Mon, 08 Aug 2016 21:13:33 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34375#post-id-34375Answer by nbruin for <p>I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:</p>
<pre><code>class MyMatrix(Matrix):
def __call__(self, v):
return self*v
</code></pre>
<p>but this doesn't work. Here is the error message I get when I try the above code in sage:</p>
<pre><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
</code></pre>
<p>I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?answer=34311#post-id-34311There already is a way of constructing an object from a matrix that is callable and gives as a result a matrix-vector product:
sage: V=VectorSpace(QQ,2)
sage: M=matrix(QQ,2,2,[1,2,3,4])
sage: h=V.hom(M)
sage: h(V.0)
(1, 2)
sage: h(V.1)
(3, 4)
Note that vector spaces in sage are row vector spaces for most purposes, so you're getting the result of multiplying the vector to the right by the matrix. Judicious use of transposes should get you what you want.Wed, 03 Aug 2016 04:38:15 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?answer=34311#post-id-34311Comment by Saul Schleimer for <p>There already is a way of constructing an object from a matrix that is callable and gives as a result a matrix-vector product:</p>
<pre><code>sage: V=VectorSpace(QQ,2)
sage: M=matrix(QQ,2,2,[1,2,3,4])
sage: h=V.hom(M)
sage: h(V.0)
(1, 2)
sage: h(V.1)
(3, 4)
</code></pre>
<p>Note that vector spaces in sage are row vector spaces for most purposes, so you're getting the result of multiplying the vector to the right by the matrix. Judicious use of transposes should get you what you want.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34325#post-id-34325Neat - thanks for this.Wed, 03 Aug 2016 23:21:31 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34325#post-id-34325Comment by Saul Schleimer for <p>There already is a way of constructing an object from a matrix that is callable and gives as a result a matrix-vector product:</p>
<pre><code>sage: V=VectorSpace(QQ,2)
sage: M=matrix(QQ,2,2,[1,2,3,4])
sage: h=V.hom(M)
sage: h(V.0)
(1, 2)
sage: h(V.1)
(3, 4)
</code></pre>
<p>Note that vector spaces in sage are row vector spaces for most purposes, so you're getting the result of multiplying the vector to the right by the matrix. Judicious use of transposes should get you what you want.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34345#post-id-34345Ok, after thinking about it, I realise that this isn't quite what I want. The whole point of using Matrix is I don't have to commit to (or even think about) the base field or ring - the initialisation procedure for Matrix takes care of that for me.Fri, 05 Aug 2016 21:03:59 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34345#post-id-34345Answer by vdelecroix for <p>I'd like to override the __call__ method of a matrix so that M(v) returns M*v. That is, I'd like to use functional notation. So I tried the following:</p>
<pre><code>class MyMatrix(Matrix):
def __call__(self, v):
return self*v
</code></pre>
<p>but this doesn't work. Here is the error message I get when I try the above code in sage:</p>
<pre><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-e8d789594dd8> in <module>()
----> 1 class MyMatrix(Matrix):
2 def __call__(self, v):
3 return self*v
4
TypeError: Error when calling the metaclass bases
object() takes no parameters
</code></pre>
<p>I don't know anything about metaclasses. After banging my head against various walls, trying to learn, I am asking here.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?answer=34298#post-id-34298[EDIT] First of all there is a stupid reason for that. The method call is implemented as a componentwise call as in
sage: m = matrix(2, [cos(x), sin(x), -sin(x), cos(x)])
sage: m(pi/4)
<A TON OF WARNINGS>
[ 1/2*sqrt(2) 1/2*sqrt(2)]
[-1/2*sqrt(2) 1/2*sqrt(2)]
The above behavior is incompatible with having m(v) returning m*v for vectors v (because you might have functions that accept vectors as input). Whether the current behavior is desirable I do not know.
[ORIGINAL ANSWER] Then, I do not think it is easy without modifying Sage source code.
One problem is that most matrix classes are so called "extension class" with read-only attributes
sage: m = matrix([2])
sage: m.new_attr = 3
Traceback (most recent call last):
...
AttributeError: 'sage.matrix.matrix_integer_dense.Matrix_integer_dense' object has no attribute 'new_attr'
To be compared with
sage: p = Permutation([3,2,1])
sage: p.new_attr = 3
sage: print p.new_attr
3
You would have been able to do it on permutations via
sage: p = Permutation([3,2,1])
sage: p.__class__.new_method = lambda s: 1
sage: p.new_method() # it works!
1
sage: q = Permutation([4,3,2,1])
sage: q.new_method() # it also works!
1
But this approach would also fail for matrices since there are many classes of matrices.Tue, 02 Aug 2016 20:14:11 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?answer=34298#post-id-34298Comment by vdelecroix for <p>[EDIT] First of all there is a stupid reason for that. The method call is implemented as a componentwise call as in</p>
<pre><code>sage: m = matrix(2, [cos(x), sin(x), -sin(x), cos(x)])
sage: m(pi/4)
<A TON OF WARNINGS>
[ 1/2*sqrt(2) 1/2*sqrt(2)]
[-1/2*sqrt(2) 1/2*sqrt(2)]
</code></pre>
<p>The above behavior is incompatible with having m(v) returning m*v for vectors v (because you might have functions that accept vectors as input). Whether the current behavior is desirable I do not know.</p>
<p>[ORIGINAL ANSWER] Then, I do not think it is easy without modifying Sage source code.</p>
<p>One problem is that most matrix classes are so called "extension class" with read-only attributes</p>
<pre><code>sage: m = matrix([2])
sage: m.new_attr = 3
Traceback (most recent call last):
...
AttributeError: 'sage.matrix.matrix_integer_dense.Matrix_integer_dense' object has no attribute 'new_attr'
</code></pre>
<p>To be compared with</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.new_attr = 3
sage: print p.new_attr
3
</code></pre>
<p>You would have been able to do it on permutations via</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.__class__.new_method = lambda s: 1
sage: p.new_method() # it works!
1
sage: q = Permutation([4,3,2,1])
sage: q.new_method() # it also works!
1
</code></pre>
<p>But this approach would also fail for matrices since there are many classes of matrices.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34309#post-id-34309I edited my post to mention that there is already a call implemented (incompatible with what you propose)Wed, 03 Aug 2016 00:56:02 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34309#post-id-34309Comment by Saul Schleimer for <p>[EDIT] First of all there is a stupid reason for that. The method call is implemented as a componentwise call as in</p>
<pre><code>sage: m = matrix(2, [cos(x), sin(x), -sin(x), cos(x)])
sage: m(pi/4)
<A TON OF WARNINGS>
[ 1/2*sqrt(2) 1/2*sqrt(2)]
[-1/2*sqrt(2) 1/2*sqrt(2)]
</code></pre>
<p>The above behavior is incompatible with having m(v) returning m*v for vectors v (because you might have functions that accept vectors as input). Whether the current behavior is desirable I do not know.</p>
<p>[ORIGINAL ANSWER] Then, I do not think it is easy without modifying Sage source code.</p>
<p>One problem is that most matrix classes are so called "extension class" with read-only attributes</p>
<pre><code>sage: m = matrix([2])
sage: m.new_attr = 3
Traceback (most recent call last):
...
AttributeError: 'sage.matrix.matrix_integer_dense.Matrix_integer_dense' object has no attribute 'new_attr'
</code></pre>
<p>To be compared with</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.new_attr = 3
sage: print p.new_attr
3
</code></pre>
<p>You would have been able to do it on permutations via</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.__class__.new_method = lambda s: 1
sage: p.new_method() # it works!
1
sage: q = Permutation([4,3,2,1])
sage: q.new_method() # it also works!
1
</code></pre>
<p>But this approach would also fail for matrices since there are many classes of matrices.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34301#post-id-34301Yes, I see that. But there should be a way to define a new class (or new metaclass) that inherits from matrix and does what I want?Tue, 02 Aug 2016 20:35:48 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34301#post-id-34301Comment by vdelecroix for <p>[EDIT] First of all there is a stupid reason for that. The method call is implemented as a componentwise call as in</p>
<pre><code>sage: m = matrix(2, [cos(x), sin(x), -sin(x), cos(x)])
sage: m(pi/4)
<A TON OF WARNINGS>
[ 1/2*sqrt(2) 1/2*sqrt(2)]
[-1/2*sqrt(2) 1/2*sqrt(2)]
</code></pre>
<p>The above behavior is incompatible with having m(v) returning m*v for vectors v (because you might have functions that accept vectors as input). Whether the current behavior is desirable I do not know.</p>
<p>[ORIGINAL ANSWER] Then, I do not think it is easy without modifying Sage source code.</p>
<p>One problem is that most matrix classes are so called "extension class" with read-only attributes</p>
<pre><code>sage: m = matrix([2])
sage: m.new_attr = 3
Traceback (most recent call last):
...
AttributeError: 'sage.matrix.matrix_integer_dense.Matrix_integer_dense' object has no attribute 'new_attr'
</code></pre>
<p>To be compared with</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.new_attr = 3
sage: print p.new_attr
3
</code></pre>
<p>You would have been able to do it on permutations via</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.__class__.new_method = lambda s: 1
sage: p.new_method() # it works!
1
sage: q = Permutation([4,3,2,1])
sage: q.new_method() # it also works!
1
</code></pre>
<p>But this approach would also fail for matrices since there are many classes of matrices.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34308#post-id-34308yes but then you need to figure out how to actually get an instance of your new class! It is not clear what the constructor (i.e. the __init__ method) of the matrix class takes as argument. You have to look into the source code to figure it out. And there is no guarantee that it will work in the future.Wed, 03 Aug 2016 00:49:15 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34308#post-id-34308Comment by Saul Schleimer for <p>[EDIT] First of all there is a stupid reason for that. The method call is implemented as a componentwise call as in</p>
<pre><code>sage: m = matrix(2, [cos(x), sin(x), -sin(x), cos(x)])
sage: m(pi/4)
<A TON OF WARNINGS>
[ 1/2*sqrt(2) 1/2*sqrt(2)]
[-1/2*sqrt(2) 1/2*sqrt(2)]
</code></pre>
<p>The above behavior is incompatible with having m(v) returning m*v for vectors v (because you might have functions that accept vectors as input). Whether the current behavior is desirable I do not know.</p>
<p>[ORIGINAL ANSWER] Then, I do not think it is easy without modifying Sage source code.</p>
<p>One problem is that most matrix classes are so called "extension class" with read-only attributes</p>
<pre><code>sage: m = matrix([2])
sage: m.new_attr = 3
Traceback (most recent call last):
...
AttributeError: 'sage.matrix.matrix_integer_dense.Matrix_integer_dense' object has no attribute 'new_attr'
</code></pre>
<p>To be compared with</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.new_attr = 3
sage: print p.new_attr
3
</code></pre>
<p>You would have been able to do it on permutations via</p>
<pre><code>sage: p = Permutation([3,2,1])
sage: p.__class__.new_method = lambda s: 1
sage: p.new_method() # it works!
1
sage: q = Permutation([4,3,2,1])
sage: q.new_method() # it also works!
1
</code></pre>
<p>But this approach would also fail for matrices since there are many classes of matrices.</p>
https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34326#post-id-34326Ok, I see that perhaps I can't use the same __init__ method, as I want a MyMatrix, not a Matrix. But we haven't gotten there yet - my toy example throws an error on the first line, not when I try to use it. I'll add the error message to the post.
Regarding the call that is already implemented - it is exactly that method which I wish to override.Wed, 03 Aug 2016 23:25:40 +0200https://ask.sagemath.org/question/34296/how-can-i-override-the-__call__-method-of-a-matrix/?comment=34326#post-id-34326