It seems to me that it would be worth considering including this in
Sage. It only depends on matplotlib, numpy, and scipy, all of which
we include. Could somebody actually try it out?!
-- William
On Fri, Mar 27, 2009 at 10:00 PM, Hazem <hazem....@gmail.com> wrote:
>
>
> We can try it out online: http://ompclib.appspot.com/m2py
>
> Since I am not familiar with Python all that much, I cannot judge the
> quality of the Python code produced. I can only try to run it in Sage
> (Python Mode) and see it behaves like the original m-code. I will be
> trying this out over the next days and weeks to get an idea. Anybody
> want to suggest some benchmark tests?
>
> Generally I don't have alot of confidence in translators, but the
> authors claim to aspire for 100% compatibility. Scilab includes an m-
> file translator and it usually does not work without manual
> intervention. Keep in mind that Scilab and MATLAB syntax and semantics
> are very similar, much more so than with Python.
>
> If this works reasonably well, then it would be an exciting addition
> to Sage! Glad I found it!
Don't be glad; be excited! :-) I must thank you for such links. Many
of us, at least myself, wouldn't have come across the above paper. But
then trawling the web is a non-trivial task, even for a researcher.
Once again, thank you very much!
--
Regards
Minh Van Nguyen
I thought this article was very interesting. Thanks for posting it!
One thing that I thought was very interesting was their way of allowing
for custom inline operators in python. It inspired the following
@inline_operator decorator. Would this be useful in Sage?
class inline_operator:
def __init__(self, function):
self.function = function
self.left = None
self.right = None
def __rmul__(self, left):
if self.right is None:
self.left = left
return self
else:
right = self.right
self.right = None
return self.function(left, right)
def __mul__(self, right):
if self.left is None:
self.right = right
return self
else:
left = self.left
self.left = None
return self.function(left, right)
# EXAMPLE
a=[1,2,3]
b=[3,4,5]
# This emul operator returns the element-wise product of two lists...
@inline_operator
def emul(a,b):
return [i*j for i,j in zip(a,b)]
# Returns [3,8,15]
a *emul* b
Thanks,
Jason
On a related note about open access to scientific papers, I've come
across this little beauty:
http://blog.wired.com/wiredscience/2009/03/openmit.html
+1 for integrating this in sage. One very common application:
a *tensor* b *tensor* c
If it's doable to extend the BackslashOperator trick to allows for the user to
define his new operator without changing the performance, I'd like to advocate
for it. My feeling that by default, we should stick to python syntax. Indeed,
we don't want the user which learn sage to learn a different syntax. Moreover
as burcin pointed out on irc, if we allows for to much different syntax, it
might be hard to transfer code around.
On the other hand, good mathematics relies heavily on good notations. And this
is particularly true in combinatorics. So that, in my opinion we should allows
the user to define new operators. Maybe with the intend to keep the use of
those notations at the interractive level.
Here is an example of usage: I'm working on a particular class of algebras
called dendriform algebras. Here the product * is decomposed as the sum of two
operations say >> and <<:
a * b = a << b + a >> b
The operations >> and >> are some action of the algebra over itself, they
verify some relations such as
(a << b) << c = a << (b * c)
(a * b) >> c = a >> (b >> c)
I can't imagine working in this without using a good *infix* notation. For
this particular case I can *abuse* __lshift__ but I'd rather being able to
define new notations.
Any comment,
Florent
Yep, I totally agree.
>
> On the other hand, good mathematics relies heavily on good notations. And this
> is particularly true in combinatorics. So that, in my opinion we should allows
> the user to define new operators. Maybe with the intend to keep the use of
> those notations at the interractive level.
Yep, that's what I was intending. We could have a predefined set of
operators that the user could import into the global namespace to give
some sort of "blessed" syntax for interactive use. For example, there
are lots of different kinds of graph products for which having infix
notation would be very convenient.
>
> Here is an example of usage: I'm working on a particular class of algebras
> called dendriform algebras. Here the product * is decomposed as the sum of two
> operations say >> and <<:
> a * b = a << b + a >> b
>
> The operations >> and >> are some action of the algebra over itself, they
> verify some relations such as
> (a << b) << c = a << (b * c)
> (a * b) >> c = a >> (b >> c)
>
> I can't imagine working in this without using a good *infix* notation. For
Yes, thanks. For some reason, I was drawing a blank when trying to
remember the word "infix". The subject should have read "Custom infix
operators in python".
> this particular case I can *abuse* __lshift__ but I'd rather being able to
> define new notations.
I'd like to extend the above decorator to handle several different
common precedence levels, maybe just addition, multiplication, and power.
Thanks,
Jason
Aha, the one custom infix operator that I know of in Sage.
In the backslash operator and in the article posted, the rmul only
stored the argument and the __mul__ only performed the operation. Are
you always guaranteed that __rmul__ will be called right before __mul__
for the same invocation of the operation?
Thanks,
Jason
Hmm... probably not. Consider
A *emul* (B *emul* C)
Since multiplication is left-associative, this is:
(A*emul)*((B*emul)*C)
This is probably (I don't know if Python guarantees left-to-right
evaluation, but I'm guessing it does) evaluated in this order:
t1 = A*emul
t2 = B*emul
t3 = t2*C
t4 = t1*t3
So for safe general-purpose use, A*emul needs to return a new object.
Carl
Okay, how about this:
class inline_operator:
def __init__(self, function, left=None, right=None):
self.function = function
self.left = left
self.right = right
def __rmul__(self, left):
if self.right is None:
return inline_operator(self.function, left=left)
else:
return self.function(left, self.right)
def __mul__(self, right):
if self.left is None:
return inline_operator(self.function, right=right)
else:
return self.function(self.left, right)
# EXAMPLE
a=[1,2,3]
b=[3,4,5]
@inline_operator
def emul(a,b):
return [i*j for i,j in zip(a,b)]
# Returns [3,8,15]
a *emul* b
Jason
You probably mean :
class infix_operator:
...
"infix" remember "infix" :)
> # EXAMPLE
>
> a=[1,2,3]
> b=[3,4,5]
>
> @inline_operator
> def emul(a,b):
> return [i*j for i,j in zip(a,b)]
>
> # Returns [3,8,15]
> a *emul* b
Another suggestion: It allows also to define prefix postfix operator by
partial specialization::
sage: bla = emul*[1,2,3]
sage: [4,5,6]*bla
[4, 10, 18]
sage: bla = [1,2,3]*emul
sage: bla*[4,5,6]
[4, 10, 18]
which looks perfectly good to me. However I'd rather having an error it the
following two behavior::
sage: bla = emul*[1,2,3]*[1,2,4]
sage: [4,5,6]*bla
[4, 10, 24]
sage: bla = [1,2,4]*emul
sage: [1,1,1]*bla*[1,1,1]
[1, 1, 1]
That is when left or right are not None, multiplying raise an error instead of
replacing them silently::
def __rmul__(self, left):
if self.right is None:
if self.left is None:
return inline_operator(self.function, left=left)
else:
raise SyntaxError, "Infix operator already has its left argument"
else:
return self.function(left, self.right)
def __mul__(self, right):
if self.left is None:
if self.right is None:
return inline_operator(self.function, right=right)
else:
raise SyntaxError, "Infix operator already has its right argument"
else:
return self.function(self.left, right)
What do you think ?
Florent
Yes. Right. Thanks.
I think it's converging to a nice solution! Good job.
Jason
You mean that you what to support the following syntaxes ?
[1,2,3] +foo+ [1,2,3]
[1,2,3] **foo** [1,2,3]
I also like the following one because it has a very high precedence and also
because it reminds XML tags
[1,2,3] <foo> [1,2,3]
Cheers,
Florent, trying to imagine crazy strange syntaxes...
That one is nice; it's very pretty. Unfortunately, it doesn't work
with the same implementation, because "A <foo> B" is equivalent to
"(A<foo) and (foo>B)". (It could probably work with the original
implementation, that stored A inside the global foo; but that doesn't
work with (A <foo> (B <foo> C)). Maybe it could work if foo had a
stack, where A<foo pushed A on the stack and foo>B popped a value off
the stack. That seems like it's getting fairly fragile, though.)
(BTW, I think you mean "very low precedence".)
Carl